1 /* 2 * Copyright (c) 1983 Eric P. Allman 3 * Copyright (c) 1988, 1993 4 * The Regents of the University of California. All rights reserved. 5 * 6 * %sccs.include.redist.c% 7 */ 8 9 #ifndef lint 10 static char sccsid[] = "@(#)envelope.c 8.3 (Berkeley) 07/13/93"; 11 #endif /* not lint */ 12 13 #include "sendmail.h" 14 #include <sys/time.h> 15 #include <pwd.h> 16 17 /* 18 ** NEWENVELOPE -- allocate a new envelope 19 ** 20 ** Supports inheritance. 21 ** 22 ** Parameters: 23 ** e -- the new envelope to fill in. 24 ** parent -- the envelope to be the parent of e. 25 ** 26 ** Returns: 27 ** e. 28 ** 29 ** Side Effects: 30 ** none. 31 */ 32 33 ENVELOPE * 34 newenvelope(e, parent) 35 register ENVELOPE *e; 36 register ENVELOPE *parent; 37 { 38 extern putheader(), putbody(); 39 extern ENVELOPE BlankEnvelope; 40 41 if (e == parent && e->e_parent != NULL) 42 parent = e->e_parent; 43 clearenvelope(e, TRUE); 44 if (e == CurEnv) 45 bcopy((char *) &NullAddress, (char *) &e->e_from, sizeof e->e_from); 46 else 47 bcopy((char *) &CurEnv->e_from, (char *) &e->e_from, sizeof e->e_from); 48 e->e_parent = parent; 49 e->e_ctime = curtime(); 50 if (parent != NULL) 51 e->e_msgpriority = parent->e_msgsize; 52 e->e_puthdr = putheader; 53 e->e_putbody = putbody; 54 if (CurEnv->e_xfp != NULL) 55 (void) fflush(CurEnv->e_xfp); 56 57 return (e); 58 } 59 /* 60 ** DROPENVELOPE -- deallocate an envelope. 61 ** 62 ** Parameters: 63 ** e -- the envelope to deallocate. 64 ** 65 ** Returns: 66 ** none. 67 ** 68 ** Side Effects: 69 ** housekeeping necessary to dispose of an envelope. 70 ** Unlocks this queue file. 71 */ 72 73 void 74 dropenvelope(e) 75 register ENVELOPE *e; 76 { 77 bool queueit = FALSE; 78 register ADDRESS *q; 79 char *id = e->e_id; 80 char buf[MAXLINE]; 81 82 if (tTd(50, 1)) 83 { 84 printf("dropenvelope %x: id=", e); 85 xputs(e->e_id); 86 printf(", flags=%o\n", e->e_flags); 87 if (tTd(50, 10)) 88 { 89 printf("sendq="); 90 printaddr(e->e_sendqueue, TRUE); 91 } 92 } 93 94 /* we must have an id to remove disk files */ 95 if (id == NULL) 96 return; 97 98 #ifdef LOG 99 if (LogLevel > 84) 100 syslog(LOG_DEBUG, "dropenvelope, id=%s, flags=%o, pid=%d", 101 id, e->e_flags, getpid()); 102 #endif /* LOG */ 103 104 /* post statistics */ 105 poststats(StatFile); 106 107 /* 108 ** Extract state information from dregs of send list. 109 */ 110 111 for (q = e->e_sendqueue; q != NULL; q = q->q_next) 112 { 113 if (bitset(QQUEUEUP, q->q_flags)) 114 queueit = TRUE; 115 } 116 117 /* 118 ** See if the message timed out. 119 */ 120 121 if (!queueit) 122 /* nothing to do */ ; 123 else if (curtime() > e->e_ctime + TimeOuts.to_q_return) 124 { 125 if (!bitset(EF_TIMEOUT, e->e_flags)) 126 { 127 (void) sprintf(buf, "Cannot send message for %s", 128 pintvl(TimeOuts.to_q_return, FALSE)); 129 if (e->e_message != NULL) 130 free(e->e_message); 131 e->e_message = newstr(buf); 132 message(buf); 133 } 134 e->e_flags |= EF_TIMEOUT|EF_CLRQUEUE; 135 fprintf(e->e_xfp, "Message could not be delivered for %s\n", 136 pintvl(TimeOuts.to_q_return, FALSE)); 137 fprintf(e->e_xfp, "Message will be deleted from queue\n"); 138 for (q = e->e_sendqueue; q != NULL; q = q->q_next) 139 { 140 if (bitset(QQUEUEUP, q->q_flags)) 141 q->q_flags |= QBADADDR; 142 } 143 } 144 else if (TimeOuts.to_q_warning > 0 && 145 curtime() > e->e_ctime + TimeOuts.to_q_warning) 146 { 147 if (!bitset(EF_WARNING|EF_RESPONSE, e->e_flags) && 148 e->e_class >= 0 && 149 strcmp(e->e_from.q_paddr, "<>") != 0) 150 { 151 (void) sprintf(buf, 152 "warning: cannot send message for %s", 153 pintvl(TimeOuts.to_q_warning, FALSE)); 154 if (e->e_message != NULL) 155 free(e->e_message); 156 e->e_message = newstr(buf); 157 message(buf); 158 e->e_flags |= EF_WARNING|EF_TIMEOUT; 159 } 160 fprintf(e->e_xfp, 161 "Warning: message still undelivered after %s\n", 162 pintvl(TimeOuts.to_q_warning, FALSE)); 163 fprintf(e->e_xfp, "Will keep trying until message is %s old\n", 164 pintvl(TimeOuts.to_q_return, FALSE)); 165 for (q = e->e_sendqueue; q != NULL; q = q->q_next) 166 { 167 if (bitset(QQUEUEUP, q->q_flags)) 168 q->q_flags |= QREPORT; 169 } 170 } 171 172 /* 173 ** Send back return receipts as requested. 174 */ 175 176 if (e->e_receiptto != NULL && bitset(EF_SENDRECEIPT, e->e_flags)) 177 { 178 auto ADDRESS *rlist = NULL; 179 180 (void) sendtolist(e->e_receiptto, (ADDRESS *) NULL, &rlist, e); 181 (void) returntosender("Return receipt", rlist, FALSE, e); 182 } 183 184 /* 185 ** Arrange to send error messages if there are fatal errors. 186 */ 187 188 if (bitset(EF_FATALERRS|EF_TIMEOUT, e->e_flags) && 189 e->e_errormode != EM_QUIET) 190 savemail(e); 191 192 /* 193 ** Instantiate or deinstantiate the queue. 194 */ 195 196 if ((!queueit && !bitset(EF_KEEPQUEUE, e->e_flags)) || 197 bitset(EF_CLRQUEUE, e->e_flags)) 198 { 199 if (tTd(50, 2)) 200 printf("Dropping envelope\n"); 201 if (e->e_df != NULL) 202 xunlink(e->e_df); 203 xunlink(queuename(e, 'q')); 204 } 205 else if (queueit || !bitset(EF_INQUEUE, e->e_flags)) 206 { 207 #ifdef QUEUE 208 queueup(e, FALSE, FALSE); 209 #else /* QUEUE */ 210 syserr("554 dropenvelope: queueup"); 211 #endif /* QUEUE */ 212 } 213 214 /* now unlock the job */ 215 closexscript(e); 216 unlockqueue(e); 217 218 /* make sure that this envelope is marked unused */ 219 if (e->e_dfp != NULL) 220 (void) xfclose(e->e_dfp, "dropenvelope", e->e_df); 221 e->e_dfp = NULL; 222 e->e_id = e->e_df = NULL; 223 224 #ifdef LOG 225 if (LogLevel > 74) 226 syslog(LOG_INFO, "%s: done", id); 227 #endif /* LOG */ 228 } 229 /* 230 ** CLEARENVELOPE -- clear an envelope without unlocking 231 ** 232 ** This is normally used by a child process to get a clean 233 ** envelope without disturbing the parent. 234 ** 235 ** Parameters: 236 ** e -- the envelope to clear. 237 ** fullclear - if set, the current envelope is total 238 ** garbage and should be ignored; otherwise, 239 ** release any resources it may indicate. 240 ** 241 ** Returns: 242 ** none. 243 ** 244 ** Side Effects: 245 ** Closes files associated with the envelope. 246 ** Marks the envelope as unallocated. 247 */ 248 249 void 250 clearenvelope(e, fullclear) 251 register ENVELOPE *e; 252 bool fullclear; 253 { 254 register HDR *bh; 255 register HDR **nhp; 256 extern ENVELOPE BlankEnvelope; 257 258 if (!fullclear) 259 { 260 /* clear out any file information */ 261 if (e->e_xfp != NULL) 262 (void) xfclose(e->e_xfp, "clearenvelope xfp", e->e_id); 263 if (e->e_dfp != NULL) 264 (void) xfclose(e->e_dfp, "clearenvelope dfp", e->e_df); 265 e->e_xfp = e->e_dfp = NULL; 266 } 267 268 /* now clear out the data */ 269 STRUCTCOPY(BlankEnvelope, *e); 270 if (Verbose) 271 e->e_sendmode = SM_DELIVER; 272 bh = BlankEnvelope.e_header; 273 nhp = &e->e_header; 274 while (bh != NULL) 275 { 276 *nhp = (HDR *) xalloc(sizeof *bh); 277 bcopy((char *) bh, (char *) *nhp, sizeof *bh); 278 bh = bh->h_link; 279 nhp = &(*nhp)->h_link; 280 } 281 } 282 /* 283 ** INITSYS -- initialize instantiation of system 284 ** 285 ** In Daemon mode, this is done in the child. 286 ** 287 ** Parameters: 288 ** none. 289 ** 290 ** Returns: 291 ** none. 292 ** 293 ** Side Effects: 294 ** Initializes the system macros, some global variables, 295 ** etc. In particular, the current time in various 296 ** forms is set. 297 */ 298 299 void 300 initsys(e) 301 register ENVELOPE *e; 302 { 303 static char cbuf[5]; /* holds hop count */ 304 static char pbuf[10]; /* holds pid */ 305 #ifdef TTYNAME 306 static char ybuf[60]; /* holds tty id */ 307 register char *p; 308 #endif /* TTYNAME */ 309 extern char *ttyname(); 310 extern void settime(); 311 extern char Version[]; 312 313 /* 314 ** Give this envelope a reality. 315 ** I.e., an id, a transcript, and a creation time. 316 */ 317 318 openxscript(e); 319 e->e_ctime = curtime(); 320 321 /* 322 ** Set OutChannel to something useful if stdout isn't it. 323 ** This arranges that any extra stuff the mailer produces 324 ** gets sent back to the user on error (because it is 325 ** tucked away in the transcript). 326 */ 327 328 if (OpMode == MD_DAEMON && !bitset(EF_QUEUERUN, e->e_flags) && 329 e->e_xfp != NULL) 330 OutChannel = e->e_xfp; 331 332 /* 333 ** Set up some basic system macros. 334 */ 335 336 /* process id */ 337 (void) sprintf(pbuf, "%d", getpid()); 338 define('p', pbuf, e); 339 340 /* hop count */ 341 (void) sprintf(cbuf, "%d", e->e_hopcount); 342 define('c', cbuf, e); 343 344 /* time as integer, unix time, arpa time */ 345 settime(e); 346 347 #ifdef TTYNAME 348 /* tty name */ 349 if (macvalue('y', e) == NULL) 350 { 351 p = ttyname(2); 352 if (p != NULL) 353 { 354 if (strrchr(p, '/') != NULL) 355 p = strrchr(p, '/') + 1; 356 (void) strcpy(ybuf, p); 357 define('y', ybuf, e); 358 } 359 } 360 #endif /* TTYNAME */ 361 } 362 /* 363 ** SETTIME -- set the current time. 364 ** 365 ** Parameters: 366 ** none. 367 ** 368 ** Returns: 369 ** none. 370 ** 371 ** Side Effects: 372 ** Sets the various time macros -- $a, $b, $d, $t. 373 */ 374 375 void 376 settime(e) 377 register ENVELOPE *e; 378 { 379 register char *p; 380 auto time_t now; 381 static char tbuf[20]; /* holds "current" time */ 382 static char dbuf[30]; /* holds ctime(tbuf) */ 383 register struct tm *tm; 384 extern char *arpadate(); 385 extern struct tm *gmtime(); 386 387 now = curtime(); 388 tm = gmtime(&now); 389 (void) sprintf(tbuf, "%04d%02d%02d%02d%02d", tm->tm_year + 1900, 390 tm->tm_mon+1, tm->tm_mday, tm->tm_hour, tm->tm_min); 391 define('t', tbuf, e); 392 (void) strcpy(dbuf, ctime(&now)); 393 p = strchr(dbuf, '\n'); 394 if (p != NULL) 395 *p = '\0'; 396 define('d', dbuf, e); 397 p = newstr(arpadate(dbuf)); 398 if (macvalue('a', e) == NULL) 399 define('a', p, e); 400 define('b', p, e); 401 } 402 /* 403 ** OPENXSCRIPT -- Open transcript file 404 ** 405 ** Creates a transcript file for possible eventual mailing or 406 ** sending back. 407 ** 408 ** Parameters: 409 ** e -- the envelope to create the transcript in/for. 410 ** 411 ** Returns: 412 ** none 413 ** 414 ** Side Effects: 415 ** Creates the transcript file. 416 */ 417 418 #ifndef O_APPEND 419 #define O_APPEND 0 420 #endif 421 422 void 423 openxscript(e) 424 register ENVELOPE *e; 425 { 426 register char *p; 427 int fd; 428 429 if (e->e_xfp != NULL) 430 return; 431 p = queuename(e, 'x'); 432 fd = open(p, O_WRONLY|O_CREAT|O_APPEND, 0644); 433 if (fd < 0) 434 { 435 syserr("Can't create transcript file %s", p); 436 fd = open("/dev/null", O_WRONLY, 0644); 437 if (fd < 0) 438 syserr("!Can't open /dev/null"); 439 } 440 e->e_xfp = fdopen(fd, "w"); 441 } 442 /* 443 ** CLOSEXSCRIPT -- close the transcript file. 444 ** 445 ** Parameters: 446 ** e -- the envelope containing the transcript to close. 447 ** 448 ** Returns: 449 ** none. 450 ** 451 ** Side Effects: 452 ** none. 453 */ 454 455 void 456 closexscript(e) 457 register ENVELOPE *e; 458 { 459 if (e->e_xfp == NULL) 460 return; 461 (void) xfclose(e->e_xfp, "closexscript", e->e_id); 462 e->e_xfp = NULL; 463 } 464 /* 465 ** SETSENDER -- set the person who this message is from 466 ** 467 ** Under certain circumstances allow the user to say who 468 ** s/he is (using -f or -r). These are: 469 ** 1. The user's uid is zero (root). 470 ** 2. The user's login name is in an approved list (typically 471 ** from a network server). 472 ** 3. The address the user is trying to claim has a 473 ** "!" character in it (since #2 doesn't do it for 474 ** us if we are dialing out for UUCP). 475 ** A better check to replace #3 would be if the 476 ** effective uid is "UUCP" -- this would require me 477 ** to rewrite getpwent to "grab" uucp as it went by, 478 ** make getname more nasty, do another passwd file 479 ** scan, or compile the UID of "UUCP" into the code, 480 ** all of which are reprehensible. 481 ** 482 ** Assuming all of these fail, we figure out something 483 ** ourselves. 484 ** 485 ** Parameters: 486 ** from -- the person we would like to believe this message 487 ** is from, as specified on the command line. 488 ** e -- the envelope in which we would like the sender set. 489 ** delimptr -- if non-NULL, set to the location of the 490 ** trailing delimiter. 491 ** internal -- set if this address is coming from an internal 492 ** source such as an owner alias. 493 ** 494 ** Returns: 495 ** none. 496 ** 497 ** Side Effects: 498 ** sets sendmail's notion of who the from person is. 499 */ 500 501 void 502 setsender(from, e, delimptr, internal) 503 char *from; 504 register ENVELOPE *e; 505 char **delimptr; 506 bool internal; 507 { 508 register char **pvp; 509 char *realname = NULL; 510 register struct passwd *pw; 511 char delimchar; 512 char buf[MAXNAME]; 513 char pvpbuf[PSBUFSIZE]; 514 extern struct passwd *getpwnam(); 515 extern char *FullName; 516 517 if (tTd(45, 1)) 518 printf("setsender(%s)\n", from == NULL ? "" : from); 519 520 /* 521 ** Figure out the real user executing us. 522 ** Username can return errno != 0 on non-errors. 523 */ 524 525 if (bitset(EF_QUEUERUN, e->e_flags) || OpMode == MD_SMTP) 526 realname = from; 527 if (realname == NULL || realname[0] == '\0') 528 realname = username(); 529 530 if (ConfigLevel < 2) 531 SuprErrs = TRUE; 532 533 delimchar = internal ? '\0' : ' '; 534 if (from == NULL || 535 parseaddr(from, &e->e_from, 1, delimchar, delimptr, e) == NULL) 536 { 537 /* log garbage addresses for traceback */ 538 # ifdef LOG 539 if (from != NULL && LogLevel > 2) 540 { 541 char *p; 542 char ebuf[MAXNAME * 2 + 2]; 543 544 p = macvalue('_', e); 545 if (p == NULL) 546 { 547 char *host = RealHostName; 548 if (host == NULL) 549 host = MyHostName; 550 (void) sprintf(ebuf, "%s@%s", realname, host); 551 p = ebuf; 552 } 553 syslog(LOG_NOTICE, 554 "from=%s unparseable, received from %s", 555 from, p); 556 } 557 # endif /* LOG */ 558 if (from != NULL) 559 SuprErrs = TRUE; 560 if (from == realname || 561 parseaddr(from = newstr(realname), &e->e_from, 1, ' ', NULL, e) == NULL) 562 { 563 SuprErrs = TRUE; 564 if (parseaddr("postmaster", &e->e_from, 1, ' ', NULL, e) == NULL) 565 syserr("553 setsender: can't even parse postmaster!"); 566 } 567 } 568 else 569 FromFlag = TRUE; 570 e->e_from.q_flags |= QDONTSEND; 571 if (tTd(45, 5)) 572 { 573 printf("setsender: QDONTSEND "); 574 printaddr(&e->e_from, FALSE); 575 } 576 SuprErrs = FALSE; 577 578 pvp = NULL; 579 if (e->e_from.q_mailer == LocalMailer) 580 { 581 # ifdef USERDB 582 register char *p; 583 extern char *udbsender(); 584 # endif 585 586 if (!internal) 587 { 588 /* if the user has given fullname already, don't redefine */ 589 if (FullName == NULL) 590 FullName = macvalue('x', e); 591 if (FullName != NULL && FullName[0] == '\0') 592 FullName = NULL; 593 594 # ifdef USERDB 595 p = udbsender(from); 596 597 if (p != NULL) 598 { 599 /* 600 ** We have an alternate address for the sender 601 */ 602 603 pvp = prescan(p, '\0', pvpbuf, NULL); 604 } 605 # endif /* USERDB */ 606 } 607 608 if ((pw = getpwnam(e->e_from.q_user)) != NULL) 609 { 610 /* 611 ** Process passwd file entry. 612 */ 613 614 615 /* extract home directory */ 616 e->e_from.q_home = newstr(pw->pw_dir); 617 define('z', e->e_from.q_home, e); 618 619 /* extract user and group id */ 620 e->e_from.q_uid = pw->pw_uid; 621 e->e_from.q_gid = pw->pw_gid; 622 623 /* extract full name from passwd file */ 624 if (FullName == NULL && pw->pw_gecos != NULL && 625 strcmp(pw->pw_name, e->e_from.q_user) == 0 && 626 !internal) 627 { 628 buildfname(pw->pw_gecos, e->e_from.q_user, buf); 629 if (buf[0] != '\0') 630 FullName = newstr(buf); 631 } 632 } 633 if (FullName != NULL && !internal) 634 define('x', FullName, e); 635 } 636 else if (!internal) 637 { 638 if (e->e_from.q_home == NULL) 639 e->e_from.q_home = getenv("HOME"); 640 e->e_from.q_uid = RealUid; 641 e->e_from.q_gid = RealGid; 642 } 643 644 /* 645 ** Rewrite the from person to dispose of possible implicit 646 ** links in the net. 647 */ 648 649 if (pvp == NULL) 650 pvp = prescan(from, '\0', pvpbuf, NULL); 651 if (pvp == NULL) 652 { 653 /* don't need to give error -- prescan did that already */ 654 # ifdef LOG 655 if (LogLevel > 2) 656 syslog(LOG_NOTICE, "cannot prescan from (%s)", from); 657 # endif 658 finis(); 659 } 660 (void) rewrite(pvp, 3, e); 661 (void) rewrite(pvp, 1, e); 662 (void) rewrite(pvp, 4, e); 663 cataddr(pvp, NULL, buf, sizeof buf, '\0'); 664 e->e_sender = newstr(buf); 665 define('f', e->e_sender, e); 666 667 /* save the domain spec if this mailer wants it */ 668 if (!internal && e->e_from.q_mailer != NULL && 669 bitnset(M_CANONICAL, e->e_from.q_mailer->m_flags)) 670 { 671 extern char **copyplist(); 672 673 while (*pvp != NULL && strcmp(*pvp, "@") != 0) 674 pvp++; 675 if (*pvp != NULL) 676 e->e_fromdomain = copyplist(pvp, TRUE); 677 } 678 } 679