|
|
1.1 ! root 1: # include <stdio.h> ! 2: # include <pwd.h> ! 3: # include <signal.h> ! 4: # include "dlvrmail.h" ! 5: # ifdef LOG ! 6: # include <log.h> ! 7: # endif LOG ! 8: ! 9: static char SccsId[] = "@(#)deliver.c 1.11 10/27/80"; ! 10: ! 11: /* ! 12: ** DELIVER -- Deliver a message to a particular address. ! 13: ** ! 14: ** Algorithm: ! 15: ** Compute receiving network (i.e., mailer), host, & user. ! 16: ** If local, see if this is really a program name. ! 17: ** Build argument for the mailer. ! 18: ** Create pipe through edit fcn if appropriate. ! 19: ** Fork. ! 20: ** Child: call mailer ! 21: ** Parent: call editfcn if specified. ! 22: ** Wait for mailer to finish. ! 23: ** Interpret exit status. ! 24: ** ! 25: ** Parameters: ! 26: ** to -- the address to deliver the message to. ! 27: ** editfcn -- if non-NULL, we want to call this function ! 28: ** to output the letter (instead of just out- ! 29: ** putting it raw). ! 30: ** ! 31: ** Returns: ! 32: ** zero -- successfully delivered. ! 33: ** else -- some failure, see ExitStat for more info. ! 34: ** ! 35: ** Side Effects: ! 36: ** The standard input is passed off to someone. ! 37: ** ! 38: ** WARNING: ! 39: ** The standard input is shared amongst all children, ! 40: ** including the file pointer. It is critical that the ! 41: ** parent waits for the child to finish before forking ! 42: ** another child. ! 43: ** ! 44: ** Called By: ! 45: ** main ! 46: ** savemail ! 47: ** ! 48: ** Files: ! 49: ** standard input -- must be opened to the message to ! 50: ** deliver. ! 51: */ ! 52: ! 53: deliver(to, editfcn) ! 54: addrq *to; ! 55: int (*editfcn)(); ! 56: { ! 57: register struct mailer *m; ! 58: char *host; ! 59: char *user; ! 60: extern struct passwd *getpwnam(); ! 61: char **pvp; ! 62: extern char **buildargv(); ! 63: auto int st; ! 64: register int i; ! 65: register char *p; ! 66: int pid; ! 67: int pvect[2]; ! 68: extern FILE *fdopen(); ! 69: extern int errno; ! 70: FILE *mfile; ! 71: extern putheader(); ! 72: extern pipesig(); ! 73: ! 74: /* ! 75: ** Compute receiving mailer, host, and to addreses. ! 76: ** Do some initialization first. To is the to address ! 77: ** for error messages. ! 78: */ ! 79: ! 80: To = to->q_paddr; ! 81: m = to->q_mailer; ! 82: user = to->q_user; ! 83: host = to->q_host; ! 84: Errors = 0; ! 85: errno = 0; ! 86: # ifdef DEBUG ! 87: if (Debug) ! 88: printf("deliver(%s [%d, `%s', `%s'])\n", To, m, host, user); ! 89: # endif DEBUG ! 90: ! 91: /* ! 92: ** Remove quote bits from user/host. ! 93: */ ! 94: ! 95: for (p = user; (*p++ &= 0177) != '\0'; ) ! 96: continue; ! 97: if (host != NULL) ! 98: for (p = host; (*p++ &= 0177) != '\0'; ) ! 99: continue; ! 100: ! 101: /* ! 102: ** Strip quote bits from names if the mailer wants it. ! 103: */ ! 104: ! 105: if (flagset(M_STRIPQ, m->m_flags)) ! 106: { ! 107: stripquotes(user); ! 108: stripquotes(host); ! 109: } ! 110: ! 111: /* ! 112: ** See if this user name is "special". ! 113: ** If the user is a program, diddle with the mailer spec. ! 114: ** If the user name has a slash in it, assume that this ! 115: ** is a file -- send it off without further ado. ! 116: ** Note that this means that editfcn's will not ! 117: ** be applied to the message. ! 118: */ ! 119: ! 120: if (m == &Mailer[0]) ! 121: { ! 122: if (*user == '|') ! 123: { ! 124: user++; ! 125: m = &Mailer[1]; ! 126: } ! 127: else ! 128: { ! 129: if (index(user, '/') != NULL) ! 130: { ! 131: i = mailfile(user); ! 132: giveresponse(i, TRUE, m); ! 133: return (i); ! 134: } ! 135: } ! 136: } ! 137: ! 138: /* ! 139: ** See if the user exists. ! 140: ** Strictly, this is only needed to print a pretty ! 141: ** error message. ! 142: ** ! 143: ** >>>>>>>>>> This clause assumes that the local mailer ! 144: ** >> NOTE >> cannot do any further aliasing; that ! 145: ** >>>>>>>>>> function is subsumed by delivermail. ! 146: */ ! 147: ! 148: if (m == &Mailer[0]) ! 149: { ! 150: if (getpwnam(user) == NULL) ! 151: { ! 152: giveresponse(EX_NOUSER, TRUE, m); ! 153: return (EX_NOUSER); ! 154: } ! 155: } ! 156: ! 157: /* ! 158: ** If the mailer wants a From line, insert a new editfcn. ! 159: */ ! 160: ! 161: if (flagset(M_HDR, m->m_flags) && editfcn == NULL) ! 162: editfcn = putheader; ! 163: ! 164: /* ! 165: ** Call the mailer. ! 166: ** The argument vector gets built, pipes through 'editfcn' ! 167: ** are created as necessary, and we fork & exec as ! 168: ** appropriate. In the parent, we call 'editfcn'. ! 169: */ ! 170: ! 171: pvp = buildargv(m->m_argv, m->m_flags, host, user, From.q_paddr); ! 172: if (pvp == NULL) ! 173: { ! 174: usrerr("name too long"); ! 175: return (-1); ! 176: } ! 177: rewind(stdin); ! 178: ! 179: /* create a pipe if we will need one */ ! 180: if (editfcn != NULL && pipe(pvect) < 0) ! 181: { ! 182: syserr("pipe"); ! 183: return (-1); ! 184: } ! 185: # ifdef VFORK ! 186: pid = vfork(); ! 187: # else ! 188: pid = fork(); ! 189: # endif ! 190: if (pid < 0) ! 191: { ! 192: syserr("Cannot fork"); ! 193: if (editfcn != NULL) ! 194: { ! 195: close(pvect[0]); ! 196: close(pvect[1]); ! 197: } ! 198: return (-1); ! 199: } ! 200: else if (pid == 0) ! 201: { ! 202: /* child -- set up input & exec mailer */ ! 203: /* make diagnostic output be standard output */ ! 204: close(2); ! 205: dup(1); ! 206: signal(SIGINT, SIG_IGN); ! 207: if (editfcn != NULL) ! 208: { ! 209: close(0); ! 210: if (dup(pvect[0]) < 0) ! 211: { ! 212: syserr("Cannot dup to zero!"); ! 213: _exit(EX_OSERR); ! 214: } ! 215: close(pvect[0]); ! 216: close(pvect[1]); ! 217: } ! 218: if (!flagset(M_RESTR, m->m_flags)) ! 219: setuid(getuid()); ! 220: # ifdef LOG ! 221: initlog(NULL, 0, LOG_CLOSE); ! 222: # endif LOG ! 223: # ifndef VFORK ! 224: /* ! 225: * We have to be careful with vfork - we can't mung up the ! 226: * memory but we don't want the mailer to inherit any extra ! 227: * open files. Chances are the mailer won't ! 228: * care about an extra file, but then again you never know. ! 229: * Actually, we would like to close(fileno(pwf)), but it's ! 230: * declared static so we can't. But if we fclose(pwf), which ! 231: * is what endpwent does, it closes it in the parent too and ! 232: * the next getpwnam will be slower. If you have a weird mailer ! 233: * that chokes on the extra file you should do the endpwent(). ! 234: */ ! 235: endpwent(); ! 236: # endif ! 237: execv(m->m_mailer, pvp); ! 238: /* syserr fails because log is closed */ ! 239: /* syserr("Cannot exec %s", m->m_mailer); */ ! 240: _exit(EX_UNAVAILABLE); ! 241: } ! 242: ! 243: /* arrange to write out header message if error */ ! 244: if (editfcn != NULL) ! 245: { ! 246: close(pvect[0]); ! 247: signal(SIGPIPE, pipesig); ! 248: mfile = fdopen(pvect[1], "w"); ! 249: (*editfcn)(mfile); ! 250: fclose(mfile); ! 251: } ! 252: ! 253: /* ! 254: ** Wait for child to die and report status. ! 255: ** We should never get fatal errors (e.g., segmentation ! 256: ** violation), so we report those specially. For other ! 257: ** errors, we choose a status message (into statmsg), ! 258: ** and if it represents an error, we print it. ! 259: */ ! 260: ! 261: while ((i = wait(&st)) > 0 && i != pid) ! 262: continue; ! 263: if (i < 0) ! 264: { ! 265: syserr("wait"); ! 266: return (-1); ! 267: } ! 268: if ((st & 0377) != 0) ! 269: { ! 270: syserr("%s: stat %o", pvp[0], st); ! 271: ExitStat = EX_UNAVAILABLE; ! 272: return (-1); ! 273: } ! 274: i = (st >> 8) & 0377; ! 275: giveresponse(i, FALSE, m); ! 276: return (i); ! 277: } ! 278: /* ! 279: ** GIVERESPONSE -- Interpret an error response from a mailer ! 280: ** ! 281: ** Parameters: ! 282: ** stat -- the status code from the mailer (high byte ! 283: ** only; core dumps must have been taken care of ! 284: ** already). ! 285: ** force -- if set, force an error message output, even ! 286: ** if the mailer seems to like to print its own ! 287: ** messages. ! 288: ** m -- the mailer descriptor for this mailer. ! 289: ** ! 290: ** Returns: ! 291: ** none. ! 292: ** ! 293: ** Side Effects: ! 294: ** Errors may be incremented. ! 295: ** ExitStat may be set. ! 296: ** ! 297: ** Called By: ! 298: ** deliver ! 299: */ ! 300: ! 301: giveresponse(stat, force, m) ! 302: int stat; ! 303: int force; ! 304: register struct mailer *m; ! 305: { ! 306: register char *statmsg; ! 307: extern char *SysExMsg[]; ! 308: register int i; ! 309: extern int N_SysEx; ! 310: extern long MsgSize; ! 311: char buf[30]; ! 312: ! 313: i = stat - EX__BASE; ! 314: if (i < 0 || i > N_SysEx) ! 315: statmsg = NULL; ! 316: else ! 317: statmsg = SysExMsg[i]; ! 318: if (stat == 0) ! 319: statmsg = "ok"; ! 320: else ! 321: { ! 322: Errors++; ! 323: if (statmsg == NULL && m->m_badstat != 0) ! 324: { ! 325: stat = m->m_badstat; ! 326: i = stat - EX__BASE; ! 327: # ifdef DEBUG ! 328: if (i < 0 || i >= N_SysEx) ! 329: syserr("Bad m_badstat %d", stat); ! 330: else ! 331: # endif DEBUG ! 332: statmsg = SysExMsg[i]; ! 333: } ! 334: if (statmsg == NULL) ! 335: usrerr("unknown mailer response %d", stat); ! 336: else if (force || !flagset(M_QUIET, m->m_flags)) ! 337: usrerr("%s", statmsg); ! 338: } ! 339: ! 340: /* ! 341: ** Final cleanup. ! 342: ** Log a record of the transaction. Compute the new ! 343: ** ExitStat -- if we already had an error, stick with ! 344: ** that. ! 345: */ ! 346: ! 347: if (statmsg == NULL) ! 348: { ! 349: sprintf(buf, "error %d", stat); ! 350: statmsg = buf; ! 351: } ! 352: ! 353: # ifdef LOG ! 354: logmsg(LOG_INFO, "%s->%s: %ld: %s", From.q_paddr, To, MsgSize, statmsg); ! 355: # endif LOG ! 356: setstat(stat); ! 357: return (stat); ! 358: } ! 359: /* ! 360: ** PUTHEADER -- insert the From header into some mail ! 361: ** ! 362: ** For mailers such as 'msgs' that want the header inserted ! 363: ** into the mail, this edit filter inserts the From line and ! 364: ** then passes the rest of the message through. ! 365: ** ! 366: ** Parameters: ! 367: ** fp -- the file pointer for the output. ! 368: ** ! 369: ** Returns: ! 370: ** none ! 371: ** ! 372: ** Side Effects: ! 373: ** Puts a "From" line in UNIX format, and then ! 374: ** outputs the rest of the message. ! 375: ** ! 376: ** Called By: ! 377: ** deliver ! 378: */ ! 379: ! 380: putheader(fp) ! 381: register FILE *fp; ! 382: { ! 383: char buf[MAXLINE + 1]; ! 384: long tim; ! 385: extern char *ctime(); ! 386: ! 387: time(&tim); ! 388: fprintf(fp, "From %s %s", From.q_paddr, ctime(&tim)); ! 389: while (fgets(buf, sizeof buf, stdin) != NULL && !ferror(fp)) ! 390: fputs(buf, fp); ! 391: if (ferror(fp)) ! 392: { ! 393: syserr("putheader: write error"); ! 394: setstat(EX_IOERR); ! 395: } ! 396: } ! 397: /* ! 398: ** PIPESIG -- Handle broken pipe signals ! 399: ** ! 400: ** This just logs an error. ! 401: ** ! 402: ** Parameters: ! 403: ** none ! 404: ** ! 405: ** Returns: ! 406: ** none ! 407: ** ! 408: ** Side Effects: ! 409: ** logs an error message. ! 410: */ ! 411: ! 412: pipesig() ! 413: { ! 414: syserr("Broken pipe"); ! 415: signal(SIGPIPE, SIG_IGN); ! 416: } ! 417: /* ! 418: ** SENDTO -- Designate a send list. ! 419: ** ! 420: ** The parameter is a comma-separated list of people to send to. ! 421: ** This routine arranges to send to all of them. ! 422: ** ! 423: ** Parameters: ! 424: ** list -- the send list. ! 425: ** copyf -- the copy flag; passed to parse. ! 426: ** ! 427: ** Returns: ! 428: ** none ! 429: ** ! 430: ** Side Effects: ! 431: ** none. ! 432: ** ! 433: ** Called By: ! 434: ** main ! 435: ** alias ! 436: */ ! 437: ! 438: sendto(list, copyf) ! 439: char *list; ! 440: int copyf; ! 441: { ! 442: register char *p; ! 443: register char *q; ! 444: register char c; ! 445: addrq *a; ! 446: extern addrq *parse(); ! 447: bool more; ! 448: ! 449: /* more keeps track of what the previous delimiter was */ ! 450: more = TRUE; ! 451: for (p = list; more; ) ! 452: { ! 453: /* find the end of this address */ ! 454: q = p; ! 455: while ((c = *p++) != '\0' && c != ',' && c != '\n') ! 456: continue; ! 457: more = c != '\0'; ! 458: *--p = '\0'; ! 459: if (more) ! 460: p++; ! 461: ! 462: /* parse the address */ ! 463: if ((a = parse(q, (addrq *) NULL, copyf)) == NULL) ! 464: continue; ! 465: ! 466: /* arrange to send to this person */ ! 467: recipient(a, &SendQ); ! 468: } ! 469: To = NULL; ! 470: } ! 471: /* ! 472: ** RECIPIENT -- Designate a message recipient ! 473: ** ! 474: ** Saves the named person for future mailing. ! 475: ** ! 476: ** Designates a person as a recipient. This routine ! 477: ** does the initial parsing, and checks to see if ! 478: ** this person has already received the mail. ! 479: ** It also supresses local network names and turns them into ! 480: ** local names. ! 481: ** ! 482: ** Parameters: ! 483: ** a -- the (preparsed) address header for the recipient. ! 484: ** targetq -- the queue to add the name to. ! 485: ** ! 486: ** Returns: ! 487: ** none. ! 488: ** ! 489: ** Side Effects: ! 490: ** none. ! 491: ** ! 492: ** Called By: ! 493: ** sendto ! 494: ** main ! 495: */ ! 496: ! 497: recipient(a, targetq) ! 498: register addrq *a; ! 499: addrq *targetq; ! 500: { ! 501: register addrq *q; ! 502: register struct mailer *m; ! 503: register char **pvp; ! 504: extern char *xalloc(); ! 505: extern bool forward(); ! 506: extern int errno; ! 507: extern bool sameaddr(); ! 508: ! 509: To = a->q_paddr; ! 510: m = a->q_mailer; ! 511: errno = 0; ! 512: # ifdef DEBUG ! 513: if (Debug) ! 514: printf("recipient(%s)\n", To); ! 515: # endif DEBUG ! 516: ! 517: /* ! 518: ** Look up this person in the recipient list. If they ! 519: ** are there already, return, otherwise continue. ! 520: */ ! 521: ! 522: if (!ForceMail) ! 523: { ! 524: for (q = &SendQ; (q = nxtinq(q)) != NULL; ) ! 525: if (sameaddr(q, a, FALSE)) ! 526: { ! 527: # ifdef DEBUG ! 528: if (Debug) ! 529: printf("(%s in SendQ)\n", a->q_paddr); ! 530: # endif DEBUG ! 531: return; ! 532: } ! 533: for (q = &AliasQ; (q = nxtinq(q)) != NULL; ) ! 534: if (sameaddr(q, a, FALSE)) ! 535: { ! 536: # ifdef DEBUG ! 537: if (Debug) ! 538: printf("(%s in AliasQ)\n", a->q_paddr); ! 539: # endif DEBUG ! 540: return; ! 541: } ! 542: } ! 543: ! 544: /* ! 545: ** See if the user wants hir mail forwarded. ! 546: ** `Forward' must do the forwarding recursively. ! 547: */ ! 548: ! 549: if (m == &Mailer[0] && !NoAlias && targetq == &SendQ && forward(a)) ! 550: return; ! 551: ! 552: /* ! 553: ** Put the user onto the target queue. ! 554: */ ! 555: ! 556: if (targetq != NULL) ! 557: { ! 558: putonq(a, targetq); ! 559: } ! 560: ! 561: return; ! 562: } ! 563: /* ! 564: ** BUILDARGV -- Build an argument vector for a mail server. ! 565: ** ! 566: ** Using a template defined in config.c, an argv is built. ! 567: ** The format of the template is already a vector. The ! 568: ** items of this vector are copied, unless a dollar sign ! 569: ** is encountered. In this case, the next character ! 570: ** specifies something else to copy in. These can be ! 571: ** $f The from address. ! 572: ** $h The host. ! 573: ** $u The user. ! 574: ** $c The hop count. ! 575: ** The vector is built in a local buffer. A pointer to ! 576: ** the static argv is returned. ! 577: ** ! 578: ** Parameters: ! 579: ** tmplt -- a template for an argument vector. ! 580: ** flags -- the flags for this server. ! 581: ** host -- the host name to send to. ! 582: ** user -- the user name to send to. ! 583: ** from -- the person this mail is from. ! 584: ** ! 585: ** Returns: ! 586: ** A pointer to an argv. ! 587: ** ! 588: ** Side Effects: ! 589: ** none ! 590: ** ! 591: ** WARNING: ! 592: ** Since the argv is staticly allocated, any subsequent ! 593: ** calls will clobber the old argv. ! 594: ** ! 595: ** Called By: ! 596: ** deliver ! 597: */ ! 598: ! 599: char ** ! 600: buildargv(tmplt, flags, host, user, from) ! 601: char **tmplt; ! 602: int flags; ! 603: char *host; ! 604: char *user; ! 605: char *from; ! 606: { ! 607: register char *p; ! 608: register char *q; ! 609: static char *pv[MAXPV+1]; ! 610: char **pvp; ! 611: char **mvp; ! 612: static char buf[512]; ! 613: register char *bp; ! 614: char pbuf[30]; ! 615: ! 616: /* ! 617: ** Do initial argv setup. ! 618: ** Insert the mailer name. Notice that $x expansion is ! 619: ** NOT done on the mailer name. Then, if the mailer has ! 620: ** a picky -f flag, we insert it as appropriate. This ! 621: ** code does not check for 'pv' overflow; this places a ! 622: ** manifest lower limit of 4 for MAXPV. ! 623: */ ! 624: ! 625: pvp = pv; ! 626: bp = buf; ! 627: ! 628: *pvp++ = tmplt[0]; ! 629: ! 630: /* insert -f or -r flag as appropriate */ ! 631: if (flagset(M_FOPT|M_ROPT, flags) && FromFlag) ! 632: { ! 633: if (flagset(M_FOPT, flags)) ! 634: *pvp++ = "-f"; ! 635: else ! 636: *pvp++ = "-r"; ! 637: *pvp++ = From.q_paddr; ! 638: } ! 639: ! 640: /* ! 641: ** Build the rest of argv. ! 642: ** For each prototype parameter, the prototype is ! 643: ** scanned character at a time. If a dollar-sign is ! 644: ** found, 'q' is set to the appropriate expansion, ! 645: ** otherwise it is null. Then either the string ! 646: ** pointed to by q, or the original character, is ! 647: ** interpolated into the buffer. Buffer overflow is ! 648: ** checked. ! 649: */ ! 650: ! 651: for (mvp = tmplt; (p = *++mvp) != NULL; ) ! 652: { ! 653: if (pvp >= &pv[MAXPV]) ! 654: { ! 655: syserr("Too many parameters to %s", pv[0]); ! 656: return (NULL); ! 657: } ! 658: *pvp++ = bp; ! 659: for (; *p != '\0'; p++) ! 660: { ! 661: /* q will be the interpolated quantity */ ! 662: q = NULL; ! 663: if (*p == '$') ! 664: { ! 665: switch (*++p) ! 666: { ! 667: case 'f': /* from person */ ! 668: q = from; ! 669: break; ! 670: ! 671: case 'u': /* user */ ! 672: q = user; ! 673: break; ! 674: ! 675: case 'h': /* host */ ! 676: q = host; ! 677: break; ! 678: ! 679: case 'c': /* hop count */ ! 680: sprintf(pbuf, "%d", HopCount); ! 681: q = pbuf; ! 682: break; ! 683: } ! 684: } ! 685: ! 686: /* ! 687: ** Interpolate q or output one character ! 688: ** Strip quote bits as we proceed..... ! 689: */ ! 690: ! 691: if (q != NULL) ! 692: { ! 693: while (bp < &buf[sizeof buf - 1] && (*bp++ = *q++) != '\0') ! 694: continue; ! 695: bp--; ! 696: } ! 697: else if (bp < &buf[sizeof buf - 1]) ! 698: *bp++ = *p; ! 699: } ! 700: *bp++ = '\0'; ! 701: if (bp >= &buf[sizeof buf - 1]) ! 702: return (NULL); ! 703: } ! 704: *pvp = NULL; ! 705: ! 706: # ifdef DEBUG ! 707: if (Debug) ! 708: { ! 709: printf("Interpolated argv is:\n"); ! 710: for (mvp = pv; *mvp != NULL; mvp++) ! 711: printf("\t%s\n", *mvp); ! 712: } ! 713: # endif DEBUG ! 714: ! 715: return (pv); ! 716: } ! 717: /* ! 718: ** MAILFILE -- Send a message to a file. ! 719: ** ! 720: ** Parameters: ! 721: ** filename -- the name of the file to send to. ! 722: ** ! 723: ** Returns: ! 724: ** The exit code associated with the operation. ! 725: ** ! 726: ** Side Effects: ! 727: ** none. ! 728: ** ! 729: ** Called By: ! 730: ** deliver ! 731: */ ! 732: ! 733: mailfile(filename) ! 734: char *filename; ! 735: { ! 736: char buf[MAXLINE]; ! 737: register FILE *f; ! 738: auto long tim; ! 739: extern char *ctime(); ! 740: ! 741: f = fopen(filename, "a"); ! 742: if (f == NULL) ! 743: return (EX_CANTCREAT); ! 744: ! 745: /* output the timestamp */ ! 746: time(&tim); ! 747: fprintf(f, "From %s %s", From.q_paddr, ctime(&tim)); ! 748: rewind(stdin); ! 749: while (fgets(buf, sizeof buf, stdin) != NULL) ! 750: { ! 751: fputs(buf, f); ! 752: if (ferror(f)) ! 753: { ! 754: fclose(f); ! 755: return (EX_IOERR); ! 756: } ! 757: } ! 758: fputs("\n", f); ! 759: fclose(f); ! 760: return (EX_OK); ! 761: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.