|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 1983 Eric P. Allman ! 3: * Copyright (c) 1988 Regents of the University of California. ! 4: * All rights reserved. ! 5: * ! 6: * Redistribution and use in source and binary forms are permitted ! 7: * provided that the above copyright notice and this paragraph are ! 8: * duplicated in all such forms and that any documentation, ! 9: * advertising materials, and other materials related to such ! 10: * distribution and use acknowledge that the software was developed ! 11: * by the University of California, Berkeley. The name of the ! 12: * University may not be used to endorse or promote products derived ! 13: * from this software without specific prior written permission. ! 14: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR ! 15: * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED ! 16: * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. ! 17: */ ! 18: ! 19: #ifndef lint ! 20: static char sccsid[] = "@(#)envelope.c 5.15 (Berkeley) 6/30/88"; ! 21: #endif /* not lint */ ! 22: ! 23: #include <pwd.h> ! 24: #include <sys/time.h> ! 25: #include "sendmail.h" ! 26: #include <sys/stat.h> ! 27: ! 28: /* ! 29: ** NEWENVELOPE -- allocate a new envelope ! 30: ** ! 31: ** Supports inheritance. ! 32: ** ! 33: ** Parameters: ! 34: ** e -- the new envelope to fill in. ! 35: ** ! 36: ** Returns: ! 37: ** e. ! 38: ** ! 39: ** Side Effects: ! 40: ** none. ! 41: */ ! 42: ! 43: ENVELOPE * ! 44: newenvelope(e) ! 45: register ENVELOPE *e; ! 46: { ! 47: register ENVELOPE *parent; ! 48: extern putheader(), putbody(); ! 49: extern ENVELOPE BlankEnvelope; ! 50: ! 51: parent = CurEnv; ! 52: if (e == CurEnv) ! 53: parent = e->e_parent; ! 54: clearenvelope(e, TRUE); ! 55: if (e == CurEnv) ! 56: bcopy((char *) &NullAddress, (char *) &e->e_from, sizeof e->e_from); ! 57: else ! 58: bcopy((char *) &CurEnv->e_from, (char *) &e->e_from, sizeof e->e_from); ! 59: e->e_parent = parent; ! 60: e->e_ctime = curtime(); ! 61: e->e_msgpriority = parent->e_msgsize; ! 62: e->e_puthdr = putheader; ! 63: e->e_putbody = putbody; ! 64: if (CurEnv->e_xfp != NULL) ! 65: (void) fflush(CurEnv->e_xfp); ! 66: ! 67: return (e); ! 68: } ! 69: /* ! 70: ** DROPENVELOPE -- deallocate an envelope. ! 71: ** ! 72: ** Parameters: ! 73: ** e -- the envelope to deallocate. ! 74: ** ! 75: ** Returns: ! 76: ** none. ! 77: ** ! 78: ** Side Effects: ! 79: ** housekeeping necessary to dispose of an envelope. ! 80: ** Unlocks this queue file. ! 81: */ ! 82: ! 83: dropenvelope(e) ! 84: register ENVELOPE *e; ! 85: { ! 86: bool queueit = FALSE; ! 87: register ADDRESS *q; ! 88: ! 89: #ifdef DEBUG ! 90: if (tTd(50, 1)) ! 91: { ! 92: printf("dropenvelope %x id=", e); ! 93: xputs(e->e_id); ! 94: printf(" flags=%o\n", e->e_flags); ! 95: } ! 96: #endif DEBUG ! 97: #ifdef LOG ! 98: if (LogLevel > 10) ! 99: syslog(LOG_DEBUG, "dropenvelope, id=%s, flags=%o, pid=%d", ! 100: e->e_id == NULL ? "(none)" : e->e_id, ! 101: e->e_flags, getpid()); ! 102: #endif LOG ! 103: ! 104: /* we must have an id to remove disk files */ ! 105: if (e->e_id == NULL) ! 106: return; ! 107: ! 108: /* ! 109: ** Extract state information from dregs of send list. ! 110: */ ! 111: ! 112: for (q = e->e_sendqueue; q != NULL; q = q->q_next) ! 113: { ! 114: if (bitset(QQUEUEUP, q->q_flags)) ! 115: queueit = TRUE; ! 116: } ! 117: ! 118: /* ! 119: ** Send back return receipts as requested. ! 120: */ ! 121: ! 122: if (e->e_receiptto != NULL && bitset(EF_SENDRECEIPT, e->e_flags)) ! 123: { ! 124: auto ADDRESS *rlist = NULL; ! 125: ! 126: sendtolist(CurEnv->e_receiptto, (ADDRESS *) NULL, &rlist); ! 127: (void) returntosender("Return receipt", rlist, FALSE); ! 128: } ! 129: ! 130: /* ! 131: ** Arrange to send error messages if there are fatal errors. ! 132: */ ! 133: ! 134: if (bitset(EF_FATALERRS|EF_TIMEOUT, e->e_flags) && ErrorMode != EM_QUIET) ! 135: savemail(e); ! 136: ! 137: /* ! 138: ** Instantiate or deinstantiate the queue. ! 139: */ ! 140: ! 141: if ((!queueit && !bitset(EF_KEEPQUEUE, e->e_flags)) || ! 142: bitset(EF_CLRQUEUE, e->e_flags)) ! 143: { ! 144: if (e->e_df != NULL) ! 145: xunlink(e->e_df); ! 146: xunlink(queuename(e, 'q')); ! 147: } ! 148: else if (queueit || !bitset(EF_INQUEUE, e->e_flags)) ! 149: { ! 150: #ifdef QUEUE ! 151: queueup(e, FALSE, FALSE); ! 152: #else QUEUE ! 153: syserr("dropenvelope: queueup"); ! 154: #endif QUEUE ! 155: } ! 156: ! 157: /* now unlock the job */ ! 158: closexscript(e); ! 159: unlockqueue(e); ! 160: ! 161: /* make sure that this envelope is marked unused */ ! 162: e->e_id = e->e_df = NULL; ! 163: if (e->e_dfp != NULL) ! 164: (void) fclose(e->e_dfp); ! 165: e->e_dfp = NULL; ! 166: } ! 167: /* ! 168: ** CLEARENVELOPE -- clear an envelope without unlocking ! 169: ** ! 170: ** This is normally used by a child process to get a clean ! 171: ** envelope without disturbing the parent. ! 172: ** ! 173: ** Parameters: ! 174: ** e -- the envelope to clear. ! 175: ** fullclear - if set, the current envelope is total ! 176: ** garbage and should be ignored; otherwise, ! 177: ** release any resources it may indicate. ! 178: ** ! 179: ** Returns: ! 180: ** none. ! 181: ** ! 182: ** Side Effects: ! 183: ** Closes files associated with the envelope. ! 184: ** Marks the envelope as unallocated. ! 185: */ ! 186: ! 187: clearenvelope(e, fullclear) ! 188: register ENVELOPE *e; ! 189: bool fullclear; ! 190: { ! 191: register HDR *bh; ! 192: register HDR **nhp; ! 193: extern ENVELOPE BlankEnvelope; ! 194: ! 195: if (!fullclear) ! 196: { ! 197: /* clear out any file information */ ! 198: if (e->e_xfp != NULL) ! 199: (void) fclose(e->e_xfp); ! 200: if (e->e_dfp != NULL) ! 201: (void) fclose(e->e_dfp); ! 202: } ! 203: ! 204: /* now clear out the data */ ! 205: STRUCTCOPY(BlankEnvelope, *e); ! 206: bh = BlankEnvelope.e_header; ! 207: nhp = &e->e_header; ! 208: while (bh != NULL) ! 209: { ! 210: *nhp = (HDR *) xalloc(sizeof *bh); ! 211: bcopy((char *) bh, (char *) *nhp, sizeof *bh); ! 212: bh = bh->h_link; ! 213: nhp = &(*nhp)->h_link; ! 214: } ! 215: } ! 216: /* ! 217: ** INITSYS -- initialize instantiation of system ! 218: ** ! 219: ** In Daemon mode, this is done in the child. ! 220: ** ! 221: ** Parameters: ! 222: ** none. ! 223: ** ! 224: ** Returns: ! 225: ** none. ! 226: ** ! 227: ** Side Effects: ! 228: ** Initializes the system macros, some global variables, ! 229: ** etc. In particular, the current time in various ! 230: ** forms is set. ! 231: */ ! 232: ! 233: initsys() ! 234: { ! 235: static char cbuf[5]; /* holds hop count */ ! 236: static char pbuf[10]; /* holds pid */ ! 237: #ifdef TTYNAME ! 238: static char ybuf[10]; /* holds tty id */ ! 239: register char *p; ! 240: #endif TTYNAME ! 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: #ifdef TTYNAME ! 279: /* tty name */ ! 280: if (macvalue('y', CurEnv) == NULL) ! 281: { ! 282: p = ttyname(2); ! 283: if (p != NULL) ! 284: { ! 285: if (rindex(p, '/') != NULL) ! 286: p = rindex(p, '/') + 1; ! 287: (void) strcpy(ybuf, p); ! 288: define('y', ybuf, CurEnv); ! 289: } ! 290: } ! 291: #endif TTYNAME ! 292: } ! 293: /* ! 294: ** SETTIME -- set the current time. ! 295: ** ! 296: ** Parameters: ! 297: ** none. ! 298: ** ! 299: ** Returns: ! 300: ** none. ! 301: ** ! 302: ** Side Effects: ! 303: ** Sets the various time macros -- $a, $b, $d, $t. ! 304: */ ! 305: ! 306: settime() ! 307: { ! 308: register char *p; ! 309: auto time_t now; ! 310: static char tbuf[20]; /* holds "current" time */ ! 311: static char dbuf[30]; /* holds ctime(tbuf) */ ! 312: register struct tm *tm; ! 313: extern char *arpadate(); ! 314: extern struct tm *gmtime(); ! 315: extern char *macvalue(); ! 316: ! 317: now = curtime(); ! 318: tm = gmtime(&now); ! 319: (void) sprintf(tbuf, "%02d%02d%02d%02d%02d", tm->tm_year, tm->tm_mon+1, ! 320: tm->tm_mday, tm->tm_hour, tm->tm_min); ! 321: define('t', tbuf, CurEnv); ! 322: (void) strcpy(dbuf, ctime(&now)); ! 323: *index(dbuf, '\n') = '\0'; ! 324: if (macvalue('d', CurEnv) == NULL) ! 325: define('d', dbuf, CurEnv); ! 326: p = newstr(arpadate(dbuf)); ! 327: if (macvalue('a', CurEnv) == NULL) ! 328: define('a', p, CurEnv); ! 329: define('b', p, CurEnv); ! 330: } ! 331: /* ! 332: ** OPENXSCRIPT -- Open transcript file ! 333: ** ! 334: ** Creates a transcript file for possible eventual mailing or ! 335: ** sending back. ! 336: ** ! 337: ** Parameters: ! 338: ** e -- the envelope to create the transcript in/for. ! 339: ** ! 340: ** Returns: ! 341: ** none ! 342: ** ! 343: ** Side Effects: ! 344: ** Creates the transcript file. ! 345: */ ! 346: ! 347: openxscript(e) ! 348: register ENVELOPE *e; ! 349: { ! 350: register char *p; ! 351: ! 352: # ifdef LOG ! 353: if (LogLevel > 19) ! 354: syslog(LOG_DEBUG, "%s: openx%s", e->e_id, e->e_xfp == NULL ? "" : " (no)"); ! 355: # endif LOG ! 356: if (e->e_xfp != NULL) ! 357: return; ! 358: p = queuename(e, 'x'); ! 359: e->e_xfp = fopen(p, "w"); ! 360: if (e->e_xfp == NULL) ! 361: syserr("Can't create %s", p); ! 362: else ! 363: (void) chmod(p, 0644); ! 364: } ! 365: /* ! 366: ** CLOSEXSCRIPT -- close the transcript file. ! 367: ** ! 368: ** Parameters: ! 369: ** e -- the envelope containing the transcript to close. ! 370: ** ! 371: ** Returns: ! 372: ** none. ! 373: ** ! 374: ** Side Effects: ! 375: ** none. ! 376: */ ! 377: ! 378: closexscript(e) ! 379: register ENVELOPE *e; ! 380: { ! 381: if (e->e_xfp == NULL) ! 382: return; ! 383: (void) fclose(e->e_xfp); ! 384: e->e_xfp = NULL; ! 385: } ! 386: /* ! 387: ** SETSENDER -- set the person who this message is from ! 388: ** ! 389: ** Under certain circumstances allow the user to say who ! 390: ** s/he is (using -f or -r). These are: ! 391: ** 1. The user's uid is zero (root). ! 392: ** 2. The user's login name is in an approved list (typically ! 393: ** from a network server). ! 394: ** 3. The address the user is trying to claim has a ! 395: ** "!" character in it (since #2 doesn't do it for ! 396: ** us if we are dialing out for UUCP). ! 397: ** A better check to replace #3 would be if the ! 398: ** effective uid is "UUCP" -- this would require me ! 399: ** to rewrite getpwent to "grab" uucp as it went by, ! 400: ** make getname more nasty, do another passwd file ! 401: ** scan, or compile the UID of "UUCP" into the code, ! 402: ** all of which are reprehensible. ! 403: ** ! 404: ** Assuming all of these fail, we figure out something ! 405: ** ourselves. ! 406: ** ! 407: ** Parameters: ! 408: ** from -- the person we would like to believe this message ! 409: ** is from, as specified on the command line. ! 410: ** ! 411: ** Returns: ! 412: ** none. ! 413: ** ! 414: ** Side Effects: ! 415: ** sets sendmail's notion of who the from person is. ! 416: */ ! 417: ! 418: setsender(from) ! 419: char *from; ! 420: { ! 421: register char **pvp; ! 422: char *realname = NULL; ! 423: register struct passwd *pw; ! 424: char buf[MAXNAME]; ! 425: char pvpbuf[PSBUFSIZE]; ! 426: extern struct passwd *getpwnam(); ! 427: extern char *macvalue(); ! 428: extern char **prescan(); ! 429: extern bool safefile(); ! 430: extern char *FullName; ! 431: ! 432: # ifdef DEBUG ! 433: if (tTd(45, 1)) ! 434: printf("setsender(%s)\n", from == NULL ? "" : from); ! 435: # endif DEBUG ! 436: ! 437: /* ! 438: ** Figure out the real user executing us. ! 439: ** Username can return errno != 0 on non-errors. ! 440: */ ! 441: ! 442: if (QueueRun || OpMode == MD_SMTP || OpMode == MD_ARPAFTP) ! 443: realname = from; ! 444: if (realname == NULL || realname[0] == '\0') ! 445: { ! 446: extern char *username(); ! 447: ! 448: realname = username(); ! 449: } ! 450: ! 451: /* ! 452: ** Determine if this real person is allowed to alias themselves. ! 453: */ ! 454: ! 455: if (from != NULL) ! 456: { ! 457: extern bool trusteduser(); ! 458: ! 459: if (!trusteduser(realname) && ! 460: # ifdef DEBUG ! 461: (!tTd(1, 9) || getuid() != geteuid()) && ! 462: # endif DEBUG ! 463: index(from, '!') == NULL && getuid() != 0) ! 464: { ! 465: /* network sends -r regardless (why why why?) */ ! 466: /* syserr("%s, you cannot use the -f flag", realname); */ ! 467: from = NULL; ! 468: } ! 469: } ! 470: ! 471: SuprErrs = TRUE; ! 472: if (from == NULL || parseaddr(from, &CurEnv->e_from, 1, '\0') == NULL) ! 473: { ! 474: /* log garbage addresses for traceback */ ! 475: if (from != NULL) ! 476: { ! 477: # ifdef LOG ! 478: if (LogLevel >= 1) ! 479: syslog(LOG_ERR, "Unparseable user %s wants to be %s", ! 480: realname, from); ! 481: # endif LOG ! 482: } ! 483: from = newstr(realname); ! 484: if (parseaddr(from, &CurEnv->e_from, 1, '\0') == NULL && ! 485: parseaddr("postmaster", &CurEnv->e_from, 1, '\0') == NULL) ! 486: { ! 487: syserr("setsender: can't even parse postmaster!"); ! 488: } ! 489: } ! 490: else ! 491: FromFlag = TRUE; ! 492: CurEnv->e_from.q_flags |= QDONTSEND; ! 493: loweraddr(&CurEnv->e_from); ! 494: SuprErrs = FALSE; ! 495: ! 496: if (CurEnv->e_from.q_mailer == LocalMailer && ! 497: (pw = getpwnam(CurEnv->e_from.q_user)) != NULL) ! 498: { ! 499: /* ! 500: ** Process passwd file entry. ! 501: */ ! 502: ! 503: ! 504: /* extract home directory */ ! 505: CurEnv->e_from.q_home = newstr(pw->pw_dir); ! 506: define('z', CurEnv->e_from.q_home, CurEnv); ! 507: ! 508: /* extract user and group id */ ! 509: CurEnv->e_from.q_uid = pw->pw_uid; ! 510: CurEnv->e_from.q_gid = pw->pw_gid; ! 511: ! 512: /* if the user has given fullname already, don't redefine */ ! 513: if (FullName == NULL) ! 514: FullName = macvalue('x', CurEnv); ! 515: if (FullName != NULL && FullName[0] == '\0') ! 516: FullName = NULL; ! 517: ! 518: /* extract full name from passwd file */ ! 519: if (FullName == NULL && pw->pw_gecos != NULL && ! 520: strcmp(pw->pw_name, CurEnv->e_from.q_user) == 0) ! 521: { ! 522: buildfname(pw->pw_gecos, CurEnv->e_from.q_user, buf); ! 523: if (buf[0] != '\0') ! 524: FullName = newstr(buf); ! 525: } ! 526: if (FullName != NULL) ! 527: define('x', FullName, CurEnv); ! 528: } ! 529: else ! 530: { ! 531: if (CurEnv->e_from.q_home == NULL) ! 532: CurEnv->e_from.q_home = getenv("HOME"); ! 533: CurEnv->e_from.q_uid = getuid(); ! 534: CurEnv->e_from.q_gid = getgid(); ! 535: } ! 536: ! 537: if (CurEnv->e_from.q_uid != 0) ! 538: { ! 539: DefUid = CurEnv->e_from.q_uid; ! 540: DefGid = CurEnv->e_from.q_gid; ! 541: } ! 542: ! 543: /* ! 544: ** Rewrite the from person to dispose of possible implicit ! 545: ** links in the net. ! 546: */ ! 547: ! 548: pvp = prescan(from, '\0', pvpbuf); ! 549: if (pvp == NULL) ! 550: { ! 551: syserr("cannot prescan from (%s)", from); ! 552: finis(); ! 553: } ! 554: rewrite(pvp, 3); ! 555: rewrite(pvp, 1); ! 556: rewrite(pvp, 4); ! 557: cataddr(pvp, buf, sizeof buf); ! 558: define('f', newstr(buf), CurEnv); ! 559: ! 560: /* save the domain spec if this mailer wants it */ ! 561: if (CurEnv->e_from.q_mailer != NULL && ! 562: bitnset(M_CANONICAL, CurEnv->e_from.q_mailer->m_flags)) ! 563: { ! 564: extern char **copyplist(); ! 565: ! 566: while (*pvp != NULL && strcmp(*pvp, "@") != 0) ! 567: pvp++; ! 568: if (*pvp != NULL) ! 569: CurEnv->e_fromdomain = copyplist(pvp, TRUE); ! 570: } ! 571: } ! 572: /* ! 573: ** TRUSTEDUSER -- tell us if this user is to be trusted. ! 574: ** ! 575: ** Parameters: ! 576: ** user -- the user to be checked. ! 577: ** ! 578: ** Returns: ! 579: ** TRUE if the user is in an approved list. ! 580: ** FALSE otherwise. ! 581: ** ! 582: ** Side Effects: ! 583: ** none. ! 584: */ ! 585: ! 586: bool ! 587: trusteduser(user) ! 588: char *user; ! 589: { ! 590: register char **ulist; ! 591: extern char *TrustedUsers[]; ! 592: ! 593: for (ulist = TrustedUsers; *ulist != NULL; ulist++) ! 594: if (strcmp(*ulist, user) == 0) ! 595: return (TRUE); ! 596: return (FALSE); ! 597: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.