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