1: #include <pwd.h> 2: #include <time.h> 3: #include "sendmail.h" 4: #include <sys/stat.h> 5: 6: SCCSID(@(#)envelope.c 4.2 8/21/83); 7: 8: /* 9: ** NEWENVELOPE -- allocate a new envelope 10: ** 11: ** Supports inheritance. 12: ** 13: ** Parameters: 14: ** e -- the new envelope to fill in. 15: ** 16: ** Returns: 17: ** e. 18: ** 19: ** Side Effects: 20: ** none. 21: */ 22: 23: ENVELOPE * 24: newenvelope(e) 25: register ENVELOPE *e; 26: { 27: register HDR *bh; 28: register HDR **nhp; 29: register ENVELOPE *parent; 30: extern putheader(), putbody(); 31: extern ENVELOPE BlankEnvelope; 32: 33: parent = CurEnv; 34: if (e == CurEnv) 35: parent = e->e_parent; 36: clear((char *) e, sizeof *e); 37: bmove((char *) &CurEnv->e_from, (char *) &e->e_from, sizeof e->e_from); 38: e->e_parent = parent; 39: e->e_ctime = curtime(); 40: e->e_puthdr = putheader; 41: e->e_putbody = putbody; 42: bh = BlankEnvelope.e_header; 43: nhp = &e->e_header; 44: while (bh != NULL) 45: { 46: *nhp = (HDR *) xalloc(sizeof *bh); 47: bmove((char *) bh, (char *) *nhp, sizeof *bh); 48: bh = bh->h_link; 49: nhp = &(*nhp)->h_link; 50: } 51: if (CurEnv->e_xfp != NULL) 52: (void) fflush(CurEnv->e_xfp); 53: 54: return (e); 55: } 56: /* 57: ** DROPENVELOPE -- deallocate an envelope. 58: ** 59: ** Parameters: 60: ** e -- the envelope to deallocate. 61: ** 62: ** Returns: 63: ** none. 64: ** 65: ** Side Effects: 66: ** housekeeping necessary to dispose of an envelope. 67: ** Unlocks this queue file. 68: */ 69: 70: dropenvelope(e) 71: register ENVELOPE *e; 72: { 73: bool queueit = FALSE; 74: register ADDRESS *q; 75: 76: #ifdef DEBUG 77: if (tTd(50, 1)) 78: { 79: printf("dropenvelope %x id=", e); 80: xputs(e->e_id); 81: printf(" flags=%o\n", e->e_flags); 82: } 83: #endif DEBUG 84: #ifdef LOG 85: if (LogLevel > 10) 86: syslog(LOG_DEBUG, "dropenvelope, id=%s, flags=%o, pid=%d", 87: e->e_id == NULL ? "(none)" : e->e_id, 88: e->e_flags, getpid()); 89: #endif LOG 90: 91: /* we must have an id to remove disk files */ 92: if (e->e_id == NULL) 93: return; 94: 95: /* 96: ** Extract state information from dregs of send list. 97: */ 98: 99: for (q = e->e_sendqueue; q != NULL; q = q->q_next) 100: { 101: if (bitset(QQUEUEUP, q->q_flags)) 102: queueit = TRUE; 103: } 104: 105: /* 106: ** Send back return receipts as requested. 107: */ 108: 109: if (e->e_receiptto != NULL && bitset(EF_SENDRECEIPT, e->e_flags)) 110: { 111: auto ADDRESS *rlist = NULL; 112: 113: sendtolist(CurEnv->e_receiptto, (ADDRESS *) NULL, &rlist); 114: (void) returntosender("Return receipt", rlist, FALSE); 115: } 116: 117: /* 118: ** Arrange to send error messages if there are fatal errors. 119: */ 120: 121: if (bitset(EF_FATALERRS|EF_TIMEOUT, e->e_flags) && ErrorMode != EM_QUIET) 122: savemail(e); 123: 124: /* 125: ** Instantiate or deinstantiate the queue. 126: */ 127: 128: if ((!queueit && !bitset(EF_KEEPQUEUE, e->e_flags)) || 129: bitset(EF_CLRQUEUE, e->e_flags)) 130: { 131: if (e->e_dfp != NULL) 132: (void) fclose(e->e_dfp); 133: if (e->e_df != NULL) 134: xunlink(e->e_df); 135: xunlink(queuename(e, 'q')); 136: } 137: else if (queueit || !bitset(EF_INQUEUE, e->e_flags)) 138: { 139: #ifdef QUEUE 140: queueup(e, FALSE, FALSE); 141: #else QUEUE 142: syserr("dropenvelope: queueup"); 143: #endif QUEUE 144: } 145: 146: /* now unlock the job */ 147: closexscript(e); 148: unlockqueue(e); 149: 150: /* make sure that this envelope is marked unused */ 151: e->e_id = e->e_df = NULL; 152: e->e_dfp = NULL; 153: } 154: /* 155: ** CLEARENVELOPE -- clear an envelope without unlocking 156: ** 157: ** This is normally used by a child process to get a clean 158: ** envelope without disturbing the parent. 159: ** 160: ** Parameters: 161: ** e -- the envelope to clear. 162: ** 163: ** Returns: 164: ** none. 165: ** 166: ** Side Effects: 167: ** Closes files associated with the envelope. 168: ** Marks the envelope as unallocated. 169: */ 170: 171: clearenvelope(e) 172: register ENVELOPE *e; 173: { 174: /* clear out any file information */ 175: if (e->e_xfp != NULL) 176: (void) fclose(e->e_xfp); 177: if (e->e_dfp != NULL) 178: (void) fclose(e->e_dfp); 179: e->e_xfp = e->e_dfp = NULL; 180: 181: /* now expunge names of objects */ 182: e->e_df = e->e_id = NULL; 183: 184: /* and the flags which are now meaningless */ 185: e->e_flags = 0; 186: } 187: /* 188: ** UNLOCKQUEUE -- unlock the queue entry for a specified envelope 189: ** 190: ** Parameters: 191: ** e -- the envelope to unlock. 192: ** 193: ** Returns: 194: ** none 195: ** 196: ** Side Effects: 197: ** unlocks the queue for `e'. 198: */ 199: 200: unlockqueue(e) 201: ENVELOPE *e; 202: { 203: /* remove the transcript */ 204: #ifdef DEBUG 205: # ifdef LOG 206: if (LogLevel > 19) 207: syslog(LOG_DEBUG, "%s: unlock", e->e_id); 208: # endif LOG 209: if (!tTd(51, 4)) 210: #endif DEBUG 211: xunlink(queuename(e, 'x')); 212: 213: # ifdef QUEUE 214: /* last but not least, remove the lock */ 215: xunlink(queuename(e, 'l')); 216: # endif QUEUE 217: } 218: /* 219: ** INITSYS -- initialize instantiation of system 220: ** 221: ** In Daemon mode, this is done in the child. 222: ** 223: ** Parameters: 224: ** none. 225: ** 226: ** Returns: 227: ** none. 228: ** 229: ** Side Effects: 230: ** Initializes the system macros, some global variables, 231: ** etc. In particular, the current time in various 232: ** forms is set. 233: */ 234: 235: initsys() 236: { 237: static char cbuf[5]; /* holds hop count */ 238: static char pbuf[10]; /* holds pid */ 239: static char ybuf[10]; /* holds tty id */ 240: register char *p; 241: extern char *ttyname(); 242: extern char *macvalue(); 243: extern char Version[]; 244: 245: /* 246: ** Give this envelope a reality. 247: ** I.e., an id, a transcript, and a creation time. 248: */ 249: 250: openxscript(CurEnv); 251: CurEnv->e_ctime = curtime(); 252: 253: /* 254: ** Set OutChannel to something useful if stdout isn't it. 255: ** This arranges that any extra stuff the mailer produces 256: ** gets sent back to the user on error (because it is 257: ** tucked away in the transcript). 258: */ 259: 260: if (OpMode == MD_DAEMON && QueueRun) 261: OutChannel = CurEnv->e_xfp; 262: 263: /* 264: ** Set up some basic system macros. 265: */ 266: 267: /* process id */ 268: (void) sprintf(pbuf, "%d", getpid()); 269: define('p', pbuf, CurEnv); 270: 271: /* hop count */ 272: (void) sprintf(cbuf, "%d", CurEnv->e_hopcount); 273: define('c', cbuf, CurEnv); 274: 275: /* time as integer, unix time, arpa time */ 276: settime(); 277: 278: /* tty name */ 279: if (macvalue('y', CurEnv) == NULL) 280: { 281: p = ttyname(2); 282: if (p != NULL) 283: { 284: if (rindex(p, '/') != NULL) 285: p = rindex(p, '/') + 1; 286: (void) strcpy(ybuf, p); 287: define('y', ybuf, CurEnv); 288: } 289: } 290: } 291: /* 292: ** SETTIME -- set the current time. 293: ** 294: ** Parameters: 295: ** none. 296: ** 297: ** Returns: 298: ** none. 299: ** 300: ** Side Effects: 301: ** Sets the various time macros -- $a, $b, $d, $t. 302: */ 303: 304: settime() 305: { 306: register char *p; 307: auto time_t now; 308: static char tbuf[20]; /* holds "current" time */ 309: static char dbuf[30]; /* holds ctime(tbuf) */ 310: register struct tm *tm; 311: extern char *arpadate(); 312: extern struct tm *gmtime(); 313: extern char *macvalue(); 314: 315: now = curtime(); 316: tm = gmtime(&now); 317: (void) sprintf(tbuf, "%02d%02d%02d%02d%02d", tm->tm_year, tm->tm_mon+1, 318: tm->tm_mday, tm->tm_hour, tm->tm_min); 319: define('t', tbuf, CurEnv); 320: (void) strcpy(dbuf, ctime(&now)); 321: *index(dbuf, '\n') = '\0'; 322: if (macvalue('d', CurEnv) == NULL) 323: define('d', dbuf, CurEnv); 324: p = newstr(arpadate(dbuf)); 325: if (macvalue('a', CurEnv) == NULL) 326: define('a', p, CurEnv); 327: define('b', p, CurEnv); 328: } 329: /* 330: ** QUEUENAME -- build a file name in the queue directory for this envelope. 331: ** 332: ** Assigns an id code if one does not already exist. 333: ** This code is very careful to avoid trashing existing files 334: ** under any circumstances. 335: ** We first create an nf file that is only used when 336: ** assigning an id. This file is always empty, so that 337: ** we can never accidently truncate an lf file. 338: ** 339: ** Parameters: 340: ** e -- envelope to build it in/from. 341: ** type -- the file type, used as the first character 342: ** of the file name. 343: ** 344: ** Returns: 345: ** a pointer to the new file name (in a static buffer). 346: ** 347: ** Side Effects: 348: ** Will create the lf and qf files if no id code is 349: ** already assigned. This will cause the envelope 350: ** to be modified. 351: */ 352: 353: char * 354: queuename(e, type) 355: register ENVELOPE *e; 356: char type; 357: { 358: static char buf[MAXNAME]; 359: static int pid = -1; 360: char c1 = 'A'; 361: char c2 = 'A'; 362: 363: if (e->e_id == NULL) 364: { 365: char qf[20]; 366: char lf[20]; 367: char nf[20]; 368: 369: /* find a unique id */ 370: if (pid != getpid()) 371: { 372: /* new process -- start back at "AA" */ 373: pid = getpid(); 374: c1 = 'A'; 375: c2 = 'A' - 1; 376: } 377: (void) sprintf(qf, "qfAA%05d", pid); 378: strcpy(lf, qf); 379: lf[0] = 'l'; 380: strcpy(nf, qf); 381: nf[0] = 'n'; 382: 383: while (c1 < '~' || c2 < 'Z') 384: { 385: int i; 386: 387: if (c2 >= 'Z') 388: { 389: c1++; 390: c2 = 'A' - 1; 391: } 392: qf[2] = lf[2] = nf[2] = c1; 393: qf[3] = lf[3] = nf[3] = ++c2; 394: # ifdef DEBUG 395: if (tTd(7, 20)) 396: printf("queuename: trying \"%s\"\n", nf); 397: # endif DEBUG 398: # ifdef QUEUE 399: if (access(lf, 0) >= 0 || access(qf, 0) >= 0) 400: continue; 401: errno = 0; 402: i = creat(nf, FileMode); 403: if (i < 0) 404: { 405: (void) unlink(nf); /* kernel bug */ 406: continue; 407: } 408: (void) close(i); 409: i = link(nf, lf); 410: (void) unlink(nf); 411: if (i < 0) 412: continue; 413: if (link(lf, qf) >= 0) 414: break; 415: (void) unlink(lf); 416: # else QUEUE 417: if (close(creat(qf, FileMode)) < 0) 418: continue; 419: # endif QUEUE 420: } 421: if (c1 >= '~' && c2 >= 'Z') 422: { 423: syserr("queuename: Cannot create \"%s\" in \"%s\"", 424: lf, QueueDir); 425: exit(EX_OSERR); 426: } 427: e->e_id = newstr(&qf[2]); 428: define('i', e->e_id, e); 429: # ifdef DEBUG 430: if (tTd(7, 1)) 431: printf("queuename: assigned id %s, env=%x\n", e->e_id, e); 432: # ifdef LOG 433: if (LogLevel > 16) 434: syslog(LOG_DEBUG, "%s: assigned id", e->e_id); 435: # endif LOG 436: # endif DEBUG 437: } 438: 439: if (type == '\0') 440: return (NULL); 441: (void) sprintf(buf, "%cf%s", type, e->e_id); 442: # ifdef DEBUG 443: if (tTd(7, 2)) 444: printf("queuename: %s\n", buf); 445: # endif DEBUG 446: return (buf); 447: } 448: /* 449: ** OPENXSCRIPT -- Open transcript file 450: ** 451: ** Creates a transcript file for possible eventual mailing or 452: ** sending back. 453: ** 454: ** Parameters: 455: ** e -- the envelope to create the transcript in/for. 456: ** 457: ** Returns: 458: ** none 459: ** 460: ** Side Effects: 461: ** Creates the transcript file. 462: */ 463: 464: openxscript(e) 465: register ENVELOPE *e; 466: { 467: register char *p; 468: 469: # ifdef LOG 470: if (LogLevel > 19) 471: syslog(LOG_DEBUG, "%s: openx%s", e->e_id, e->e_xfp == NULL ? "" : " (no)"); 472: # endif LOG 473: if (e->e_xfp != NULL) 474: return; 475: p = queuename(e, 'x'); 476: e->e_xfp = fopen(p, "w"); 477: if (e->e_xfp == NULL) 478: syserr("Can't create %s", p); 479: else 480: (void) chmod(p, 0644); 481: } 482: /* 483: ** CLOSEXSCRIPT -- close the transcript file. 484: ** 485: ** Parameters: 486: ** e -- the envelope containing the transcript to close. 487: ** 488: ** Returns: 489: ** none. 490: ** 491: ** Side Effects: 492: ** none. 493: */ 494: 495: closexscript(e) 496: register ENVELOPE *e; 497: { 498: if (e->e_xfp == NULL) 499: return; 500: (void) fclose(e->e_xfp); 501: e->e_xfp = NULL; 502: } 503: /* 504: ** SETSENDER -- set the person who this message is from 505: ** 506: ** Under certain circumstances allow the user to say who 507: ** s/he is (using -f or -r). These are: 508: ** 1. The user's uid is zero (root). 509: ** 2. The user's login name is in an approved list (typically 510: ** from a network server). 511: ** 3. The address the user is trying to claim has a 512: ** "!" character in it (since #2 doesn't do it for 513: ** us if we are dialing out for UUCP). 514: ** A better check to replace #3 would be if the 515: ** effective uid is "UUCP" -- this would require me 516: ** to rewrite getpwent to "grab" uucp as it went by, 517: ** make getname more nasty, do another passwd file 518: ** scan, or compile the UID of "UUCP" into the code, 519: ** all of which are reprehensible. 520: ** 521: ** Assuming all of these fail, we figure out something 522: ** ourselves. 523: ** 524: ** Parameters: 525: ** from -- the person we would like to believe this message 526: ** is from, as specified on the command line. 527: ** 528: ** Returns: 529: ** none. 530: ** 531: ** Side Effects: 532: ** sets sendmail's notion of who the from person is. 533: */ 534: 535: setsender(from) 536: char *from; 537: { 538: register char **pvp; 539: register struct passwd *pw = NULL; 540: char *realname = NULL; 541: char buf[MAXNAME]; 542: extern char *macvalue(); 543: extern char **prescan(); 544: extern bool safefile(); 545: extern char *FullName; 546: 547: # ifdef DEBUG 548: if (tTd(45, 1)) 549: printf("setsender(%s)\n", from == NULL ? "" : from); 550: # endif DEBUG 551: 552: /* 553: ** Figure out the real user executing us. 554: ** Username can return errno != 0 on non-errors. 555: */ 556: 557: if (QueueRun || OpMode == MD_SMTP || OpMode == MD_ARPAFTP) 558: realname = from; 559: if (realname == NULL || realname[0] == '\0') 560: { 561: extern char *username(); 562: 563: realname = username(); 564: errno = 0; 565: } 566: if (realname == NULL || realname[0] == '\0') 567: { 568: extern struct passwd *getpwuid(); 569: 570: pw = getpwuid(getruid()); 571: if (pw != NULL) 572: realname = pw->pw_name; 573: } 574: if (realname == NULL || realname[0] == '\0') 575: { 576: syserr("Who are you?"); 577: realname = "root"; 578: } 579: 580: /* 581: ** Determine if this real person is allowed to alias themselves. 582: */ 583: 584: if (from != NULL) 585: { 586: extern bool trusteduser(); 587: 588: if (!trusteduser(realname) && 589: # ifdef DEBUG 590: (!tTd(1, 9) || getuid() != geteuid()) && 591: # endif DEBUG 592: index(from, '!') == NULL && getuid() != 0) 593: { 594: /* network sends -r regardless (why why why?) */ 595: /* syserr("%s, you cannot use the -f flag", realname); */ 596: from = NULL; 597: } 598: else if (strcmp(from, realname) != 0) 599: pw = NULL; 600: } 601: 602: SuprErrs = TRUE; 603: if (from == NULL || parseaddr(from, &CurEnv->e_from, 1, '\0') == NULL) 604: { 605: from = newstr(realname); 606: (void) parseaddr(from, &CurEnv->e_from, 1, '\0'); 607: } 608: else 609: FromFlag = TRUE; 610: CurEnv->e_from.q_flags |= QDONTSEND; 611: SuprErrs = FALSE; 612: 613: if (pw == NULL && CurEnv->e_from.q_mailer == LocalMailer) 614: { 615: extern struct passwd *getpwnam(); 616: 617: pw = getpwnam(CurEnv->e_from.q_user); 618: } 619: 620: /* 621: ** Process passwd file entry. 622: */ 623: 624: if (pw != NULL) 625: { 626: /* extract home directory */ 627: CurEnv->e_from.q_home = newstr(pw->pw_dir); 628: 629: /* extract user and group id */ 630: CurEnv->e_from.q_uid = pw->pw_uid; 631: CurEnv->e_from.q_gid = pw->pw_gid; 632: 633: /* run user's .mailcf file */ 634: define('z', CurEnv->e_from.q_home, CurEnv); 635: expand("$z/.mailcf", buf, &buf[sizeof buf - 1], CurEnv); 636: if (safefile(buf, getruid(), S_IREAD)) 637: readcf(buf, FALSE); 638: 639: /* if the user has given fullname already, don't redefine */ 640: if (FullName == NULL) 641: FullName = macvalue('x', CurEnv); 642: if (FullName != NULL && FullName[0] == '\0') 643: FullName = NULL; 644: 645: /* extract full name from passwd file */ 646: if (FullName == NULL && pw->pw_gecos != NULL && 647: strcmp(pw->pw_name, CurEnv->e_from.q_user) == 0) 648: { 649: buildfname(pw->pw_gecos, CurEnv->e_from.q_user, buf); 650: if (buf[0] != '\0') 651: FullName = newstr(buf); 652: } 653: if (FullName != NULL) 654: define('x', FullName, CurEnv); 655: } 656: else 657: { 658: #ifndef V6 659: if (CurEnv->e_from.q_home == NULL) 660: CurEnv->e_from.q_home = getenv("HOME"); 661: #endif V6 662: CurEnv->e_from.q_uid = getuid(); 663: CurEnv->e_from.q_gid = getgid(); 664: } 665: 666: if (CurEnv->e_from.q_uid != 0) 667: { 668: DefUid = CurEnv->e_from.q_uid; 669: DefGid = CurEnv->e_from.q_gid; 670: } 671: 672: /* 673: ** Rewrite the from person to dispose of possible implicit 674: ** links in the net. 675: */ 676: 677: pvp = prescan(from, '\0'); 678: if (pvp == NULL) 679: { 680: syserr("cannot prescan from (%s)", from); 681: finis(); 682: } 683: rewrite(pvp, 3); 684: rewrite(pvp, 1); 685: rewrite(pvp, 4); 686: cataddr(pvp, buf, sizeof buf); 687: define('f', newstr(buf), CurEnv); 688: 689: /* save the domain spec if this mailer wants it */ 690: if (bitnset(M_CANONICAL, CurEnv->e_from.q_mailer->m_flags)) 691: { 692: extern char **copyplist(); 693: 694: while (*pvp != NULL && strcmp(*pvp, "@") != 0) 695: pvp++; 696: if (*pvp != NULL) 697: CurEnv->e_fromdomain = copyplist(pvp, TRUE); 698: } 699: } 700: /* 701: ** TRUSTEDUSER -- tell us if this user is to be trusted. 702: ** 703: ** Parameters: 704: ** user -- the user to be checked. 705: ** 706: ** Returns: 707: ** TRUE if the user is in an approved list. 708: ** FALSE otherwise. 709: ** 710: ** Side Effects: 711: ** none. 712: */ 713: 714: bool 715: trusteduser(user) 716: char *user; 717: { 718: register char **ulist; 719: extern char *TrustedUsers[]; 720: 721: for (ulist = TrustedUsers; *ulist != NULL; ulist++) 722: if (strcmp(*ulist, user) == 0) 723: return (TRUE); 724: return (FALSE); 725: }