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