1 # include <pwd.h> 2 # include "sendmail.h" 3 # include <sys/stat.h> 4 5 SCCSID(@(#)recipient.c 3.33 01/23/82); 6 7 /* 8 ** SENDTO -- Designate a send list. 9 ** 10 ** The parameter is a comma-separated list of people to send to. 11 ** This routine arranges to send to all of them. 12 ** 13 ** Parameters: 14 ** list -- the send list. 15 ** copyf -- the copy flag; passed to parse. 16 ** ctladdr -- the address template for the person to 17 ** send to -- effective uid/gid are important. 18 ** This is typically the alias that caused this 19 ** expansion. 20 ** sendq -- a pointer to the head of a queue to put 21 ** these people into. 22 ** 23 ** Returns: 24 ** none 25 ** 26 ** Side Effects: 27 ** none. 28 */ 29 30 # define MAXRCRSN 10 31 32 sendto(list, copyf, ctladdr, sendq) 33 char *list; 34 int copyf; 35 ADDRESS *ctladdr; 36 ADDRESS **sendq; 37 { 38 register char *p; 39 bool more; /* set if more addresses to send to */ 40 ADDRESS *al; /* list of addresses to send to */ 41 bool firstone; /* set on first address sent */ 42 bool selfref; /* set if this list includes ctladdr */ 43 44 # ifdef DEBUG 45 if (Debug > 1) 46 { 47 printf("sendto: %s\n ctladdr=", list); 48 printaddr(ctladdr, FALSE); 49 } 50 # endif DEBUG 51 52 more = TRUE; 53 firstone = TRUE; 54 selfref = FALSE; 55 al = NULL; 56 for (p = list; more; ) 57 { 58 register char *q; 59 register char c; 60 ADDRESS *a; 61 62 /* find the end of this address */ 63 while (*p == ' ' || *p == '\t') 64 p++; 65 q = p; 66 while ((c = *p++) != '\0' && c != ',' && c != '\n') 67 continue; 68 more = c != '\0'; 69 *--p = '\0'; 70 if (more) 71 p++; 72 if (*q == '\0') 73 continue; 74 75 /* parse the address */ 76 if ((a = parse(q, (ADDRESS *) NULL, copyf)) == NULL) 77 continue; 78 a->q_next = al; 79 a->q_alias = ctladdr; 80 81 /* see if this should be marked as a primary address */ 82 if (ctladdr == NULL || 83 (firstone && !more && bitset(QPRIMARY, ctladdr->q_flags))) 84 a->q_flags |= QPRIMARY; 85 86 /* put on send queue or suppress self-reference */ 87 if (ctladdr != NULL && sameaddr(ctladdr, a, FALSE)) 88 selfref = TRUE; 89 else 90 al = a; 91 firstone = FALSE; 92 } 93 94 /* if this alias doesn't include itself, delete ctladdr */ 95 if (!selfref && ctladdr != NULL) 96 ctladdr->q_flags |= QDONTSEND; 97 98 /* arrange to send to everyone on the local send list */ 99 while (al != NULL) 100 { 101 register ADDRESS *a = al; 102 103 al = a->q_next; 104 recipient(a, sendq); 105 106 /* arrange to inherit full name */ 107 if (a->q_fullname == NULL && ctladdr != NULL) 108 a->q_fullname = ctladdr->q_fullname; 109 } 110 111 To = NULL; 112 } 113 /* 114 ** RECIPIENT -- Designate a message recipient 115 ** 116 ** Saves the named person for future mailing. 117 ** 118 ** Parameters: 119 ** a -- the (preparsed) address header for the recipient. 120 ** sendq -- a pointer to the head of a queue to put the 121 ** recipient in. Duplicate supression is done 122 ** in this queue. 123 ** 124 ** Returns: 125 ** none. 126 ** 127 ** Side Effects: 128 ** none. 129 */ 130 131 recipient(a, sendq) 132 register ADDRESS *a; 133 register ADDRESS **sendq; 134 { 135 register ADDRESS *q; 136 ADDRESS **pq; 137 register struct mailer *m; 138 extern ADDRESS *getctladdr(); 139 extern bool safefile(); 140 141 To = a->q_paddr; 142 m = a->q_mailer; 143 errno = 0; 144 # ifdef DEBUG 145 if (Debug) 146 { 147 printf("\nrecipient: "); 148 printaddr(a, FALSE); 149 } 150 # endif DEBUG 151 152 /* break aliasing loops */ 153 if (AliasLevel > MAXRCRSN) 154 { 155 usrerr("aliasing/forwarding loop broken"); 156 return; 157 } 158 159 /* 160 ** Finish setting up address structure. 161 */ 162 163 a->q_timeout = TimeOut; 164 165 /* do sickly crude mapping for program mailing, etc. */ 166 if (a->q_mailer == LocalMailer) 167 { 168 if (a->q_user[0] == '|') 169 { 170 a->q_mailer = m = ProgMailer; 171 a->q_user++; 172 if (a->q_alias == NULL && Debug == 0 && !QueueRun && !ForceMail) 173 { 174 usrerr("Cannot mail directly to programs"); 175 a->q_flags |= QDONTSEND; 176 } 177 } 178 } 179 180 /* 181 ** Look up this person in the recipient list. 182 ** If they are there already, return, otherwise continue. 183 ** If the list is empty, just add it. Notice the cute 184 ** hack to make from addresses suppress things correctly: 185 ** the QDONTSEND bit will be set in the send list. 186 ** [Please note: the emphasis is on "hack."] 187 */ 188 189 for (pq = sendq; (q = *pq) != NULL; pq = &q->q_next) 190 { 191 if (!ForceMail && sameaddr(q, a, FALSE)) 192 { 193 # ifdef DEBUG 194 if (Debug) 195 { 196 printf("%s in sendq: ", a->q_paddr); 197 printaddr(q, FALSE); 198 } 199 # endif DEBUG 200 if (Verbose && !bitset(QDONTSEND, a->q_flags)) 201 message(Arpa_Info, "duplicate suppressed"); 202 if (!bitset(QPRIMARY, q->q_flags)) 203 q->q_flags |= a->q_flags; 204 return; 205 } 206 } 207 208 /* add address on list */ 209 *pq = a; 210 a->q_next = NULL; 211 if (DontSend) 212 a->q_flags |= QDONTSEND; 213 214 /* 215 ** Alias the name and handle :include: specs. 216 */ 217 218 if (a->q_mailer == LocalMailer) 219 { 220 if (strncmp(a->q_user, ":include:", 9) == 0) 221 { 222 a->q_flags |= QDONTSEND; 223 if (a->q_alias == NULL && Debug == 0 && !QueueRun && !ForceMail) 224 usrerr("Cannot mail directly to :include:s"); 225 else 226 { 227 if (Verbose) 228 message(Arpa_Info, "including file %s", &a->q_user[9]); 229 include(&a->q_user[9], " sending", a, sendq); 230 } 231 } 232 else 233 alias(a, sendq); 234 } 235 236 /* 237 ** If the user is local and still being sent, verify that 238 ** the address is good. If it is, try to forward. 239 ** If the address is already good, we have a forwarding 240 ** loop. This can be broken by just sending directly to 241 ** the user (which is probably correct anyway). 242 */ 243 244 if (!bitset(QDONTSEND, a->q_flags) && a->q_mailer == LocalMailer) 245 { 246 char buf[MAXNAME]; 247 register char *p; 248 struct stat stb; 249 extern bool writable(); 250 bool quoted = FALSE; 251 252 strcpy(buf, a->q_user); 253 for (p = buf; *p != '\0' && !quoted; p++) 254 { 255 if (!isascii(*p) && (*p & 0377) != (SPACESUB & 0377)) 256 quoted = TRUE; 257 } 258 stripquotes(buf, TRUE); 259 260 /* see if this is to a file */ 261 if (buf[0] == '/') 262 { 263 p = rindex(buf, '/'); 264 /* check if writable or creatable */ 265 if (a->q_alias == NULL && Debug == 0 && !QueueRun && !ForceMail) 266 { 267 usrerr("Cannot mail directly to files"); 268 a->q_flags |= QDONTSEND; 269 } 270 else if ((stat(buf, &stb) >= 0) ? (!writable(&stb)) : 271 (*p = '\0', !safefile(buf, getruid(), S_IWRITE|S_IEXEC))) 272 { 273 a->q_flags |= QBADADDR; 274 giveresponse(EX_CANTCREAT, TRUE, m); 275 } 276 } 277 else 278 { 279 register struct passwd *pw; 280 extern struct passwd *finduser(); 281 282 /* warning -- finduser may trash buf */ 283 pw = finduser(buf); 284 if (pw == NULL) 285 { 286 a->q_flags |= QBADADDR; 287 giveresponse(EX_NOUSER, TRUE, m); 288 } 289 else 290 { 291 char nbuf[MAXNAME]; 292 293 if (strcmp(a->q_user, pw->pw_name) != 0) 294 { 295 a->q_user = newstr(pw->pw_name); 296 strcpy(buf, pw->pw_name); 297 } 298 a->q_home = newstr(pw->pw_dir); 299 a->q_uid = pw->pw_uid; 300 a->q_gid = pw->pw_gid; 301 a->q_flags |= QGOODUID; 302 buildfname(pw->pw_gecos, pw->pw_name, nbuf); 303 if (nbuf[0] != '\0') 304 a->q_fullname = newstr(nbuf); 305 if (!quoted) 306 forward(a, sendq); 307 } 308 } 309 } 310 } 311 /* 312 ** FINDUSER -- find the password entry for a user. 313 ** 314 ** This looks a lot like getpwnam, except that it may want to 315 ** do some fancier pattern matching in /etc/passwd. 316 ** 317 ** Parameters: 318 ** name -- the name to match against. 319 ** 320 ** Returns: 321 ** A pointer to a pw struct. 322 ** NULL if name is unknown or ambiguous. 323 ** 324 ** Side Effects: 325 ** may modify name. 326 */ 327 328 struct passwd * 329 finduser(name) 330 char *name; 331 { 332 extern struct passwd *getpwent(); 333 register struct passwd *pw; 334 register char *p; 335 336 /* 337 ** Make name canonical. 338 */ 339 340 for (p = name; *p != '\0'; p++) 341 { 342 if (*p == (SPACESUB & 0177) || *p == '_') 343 *p = ' '; 344 } 345 346 setpwent(); 347 while ((pw = getpwent()) != NULL) 348 { 349 char buf[MAXNAME]; 350 extern bool sameword(); 351 352 if (strcmp(pw->pw_name, name) == 0) 353 return (pw); 354 buildfname(pw->pw_gecos, pw->pw_name, buf); 355 if (index(buf, ' ') != NULL && sameword(buf, name)) 356 { 357 if (Verbose) 358 message(Arpa_Info, "sending to login name %s", 359 pw->pw_name); 360 return (pw); 361 } 362 } 363 return (NULL); 364 } 365 /* 366 ** WRITABLE -- predicate returning if the file is writable. 367 ** 368 ** This routine must duplicate the algorithm in sys/fio.c. 369 ** Unfortunately, we cannot use the access call since we 370 ** won't necessarily be the real uid when we try to 371 ** actually open the file. 372 ** 373 ** Notice that ANY file with ANY execute bit is automatically 374 ** not writable. This is also enforced by mailfile. 375 ** 376 ** Parameters: 377 ** s -- pointer to a stat struct for the file. 378 ** 379 ** Returns: 380 ** TRUE -- if we will be able to write this file. 381 ** FALSE -- if we cannot write this file. 382 ** 383 ** Side Effects: 384 ** none. 385 */ 386 387 bool 388 writable(s) 389 register struct stat *s; 390 { 391 int euid, egid; 392 int bits; 393 394 if (bitset(0111, s->st_mode)) 395 return (FALSE); 396 euid = getruid(); 397 egid = getrgid(); 398 if (geteuid() == 0) 399 { 400 if (bitset(S_ISUID, s->st_mode)) 401 euid = s->st_uid; 402 if (bitset(S_ISGID, s->st_mode)) 403 egid = s->st_gid; 404 } 405 406 if (euid == 0) 407 return (TRUE); 408 bits = S_IWRITE; 409 if (euid != s->st_uid) 410 { 411 bits >>= 3; 412 if (egid != s->st_gid) 413 bits >>= 3; 414 } 415 return ((s->st_mode & bits) != 0); 416 } 417 /* 418 ** INCLUDE -- handle :include: specification. 419 ** 420 ** Parameters: 421 ** fname -- filename to include. 422 ** msg -- message to print in verbose mode. 423 ** ctladdr -- address template to use to fill in these 424 ** addresses -- effective user/group id are 425 ** the important things. 426 ** sendq -- a pointer to the head of the send queue 427 ** to put these addresses in. 428 ** 429 ** Returns: 430 ** none. 431 ** 432 ** Side Effects: 433 ** reads the :include: file and sends to everyone 434 ** listed in that file. 435 */ 436 437 include(fname, msg, ctladdr, sendq) 438 char *fname; 439 char *msg; 440 ADDRESS *ctladdr; 441 ADDRESS **sendq; 442 { 443 char buf[MAXLINE]; 444 register FILE *fp; 445 char *oldto = To; 446 447 fp = fopen(fname, "r"); 448 if (fp == NULL) 449 { 450 usrerr("Cannot open %s", fname); 451 return; 452 } 453 if (getctladdr(ctladdr) == NULL) 454 { 455 struct stat st; 456 457 if (fstat(fileno(fp), &st) < 0) 458 syserr("Cannot fstat %s!", fname); 459 ctladdr->q_uid = st.st_uid; 460 ctladdr->q_gid = st.st_gid; 461 ctladdr->q_flags |= QGOODUID; 462 } 463 464 /* read the file -- each line is a comma-separated list. */ 465 while (fgets(buf, sizeof buf, fp) != NULL) 466 { 467 register char *p = index(buf, '\n'); 468 469 if (p != NULL) 470 *p = '\0'; 471 if (buf[0] == '\0') 472 continue; 473 To = oldto; 474 if (Verbose) 475 message(Arpa_Info, "%s to %s", msg, buf); 476 AliasLevel++; 477 sendto(buf, 1, ctladdr, sendq); 478 AliasLevel--; 479 } 480 481 (void) fclose(fp); 482 } 483 /* 484 ** SENDTOARGV -- send to an argument vector. 485 ** 486 ** Parameters: 487 ** argv -- argument vector to send to. 488 ** 489 ** Returns: 490 ** none. 491 ** 492 ** Side Effects: 493 ** puts all addresses on the argument vector onto the 494 ** send queue. 495 */ 496 497 sendtoargv(argv) 498 register char **argv; 499 { 500 register char *p; 501 extern bool sameword(); 502 503 while ((p = *argv++) != NULL) 504 { 505 if (argv[0] != NULL && argv[1] != NULL && sameword(argv[0], "at")) 506 { 507 char nbuf[MAXNAME]; 508 509 if (strlen(p) + strlen(argv[1]) + 2 > sizeof nbuf) 510 usrerr("address overflow"); 511 else 512 { 513 (void) strcpy(nbuf, p); 514 (void) strcat(nbuf, "@"); 515 (void) strcat(nbuf, argv[1]); 516 p = newstr(nbuf); 517 argv += 2; 518 } 519 } 520 sendto(p, 0, (ADDRESS *) NULL, &SendQueue); 521 } 522 } 523 /* 524 ** GETCTLADDR -- get controlling address from an address header. 525 ** 526 ** If none, get one corresponding to the effective userid. 527 ** 528 ** Parameters: 529 ** a -- the address to find the controller of. 530 ** 531 ** Returns: 532 ** the controlling address. 533 ** 534 ** Side Effects: 535 ** none. 536 */ 537 538 ADDRESS * 539 getctladdr(a) 540 register ADDRESS *a; 541 { 542 while (a != NULL && !bitset(QGOODUID, a->q_flags)) 543 a = a->q_alias; 544 return (a); 545 } 546