1294Seric # include <signal.h> 24123Seric # include <errno.h> 34327Seric # include <sys/types.h> 44327Seric # include <sys/stat.h> 53310Seric # include "sendmail.h" 6294Seric # ifdef LOG 72774Seric # include <syslog.h> 8294Seric # endif LOG 9294Seric 10*4370Seric static char SccsId[] = "@(#)deliver.c 3.37 09/12/81"; 11405Seric 12294Seric /* 134315Seric ** DELIVER -- Deliver a message to a list of addresses. 14294Seric ** 154315Seric ** This routine delivers to everyone on the same host as the 164315Seric ** user on the head of the list. It is clever about mailers 174315Seric ** that don't handle multiple users. It is NOT guaranteed 184315Seric ** that it will deliver to all these addresses however -- so 194315Seric ** deliver should be called once for each address on the 204315Seric ** list. 214315Seric ** 22294Seric ** Parameters: 234315Seric ** to -- head of the address list to deliver to. 24294Seric ** editfcn -- if non-NULL, we want to call this function 25294Seric ** to output the letter (instead of just out- 26294Seric ** putting it raw). 27294Seric ** 28294Seric ** Returns: 29294Seric ** zero -- successfully delivered. 30294Seric ** else -- some failure, see ExitStat for more info. 31294Seric ** 32294Seric ** Side Effects: 33294Seric ** The standard input is passed off to someone. 34294Seric */ 35294Seric 36294Seric deliver(to, editfcn) 372968Seric ADDRESS *to; 38294Seric int (*editfcn)(); 39294Seric { 40294Seric char *host; 41294Seric char *user; 42294Seric char **pvp; 433233Seric register char **mvp; 443233Seric register char *p; 453233Seric register struct mailer *m; 46294Seric register int i; 472898Seric extern putmessage(); 482968Seric extern bool checkcompat(); 493233Seric char *pv[MAXPV+1]; 503233Seric char tobuf[MAXLINE]; 513233Seric char buf[MAXNAME]; 523233Seric bool firstone; 53294Seric 544311Seric if (!ForceMail && bitset(QDONTSEND, to->q_flags)) 553233Seric return (0); 56294Seric 57294Seric # ifdef DEBUG 58294Seric if (Debug) 593233Seric printf("\n--deliver, mailer=%d, host=`%s', first user=`%s'\n", 603233Seric to->q_mailer, to->q_host, to->q_user); 61294Seric # endif DEBUG 62294Seric 63294Seric /* 643233Seric ** Do initial argv setup. 653233Seric ** Insert the mailer name. Notice that $x expansion is 663233Seric ** NOT done on the mailer name. Then, if the mailer has 673233Seric ** a picky -f flag, we insert it as appropriate. This 683233Seric ** code does not check for 'pv' overflow; this places a 693233Seric ** manifest lower limit of 4 for MAXPV. 702968Seric */ 712968Seric 723233Seric m = Mailer[to->q_mailer]; 733233Seric host = to->q_host; 743233Seric define('g', m->m_from); /* translated from address */ 753233Seric define('h', host); /* to host */ 763233Seric Errors = 0; 773233Seric errno = 0; 783233Seric pvp = pv; 793233Seric *pvp++ = m->m_argv[0]; 802968Seric 813233Seric /* insert -f or -r flag as appropriate */ 823233Seric if (bitset(M_FOPT|M_ROPT, m->m_flags) && FromFlag) 833233Seric { 843233Seric if (bitset(M_FOPT, m->m_flags)) 853233Seric *pvp++ = "-f"; 863233Seric else 873233Seric *pvp++ = "-r"; 884082Seric (void) expand("$g", buf, &buf[sizeof buf - 1]); 893233Seric *pvp++ = newstr(buf); 903233Seric } 91294Seric 92294Seric /* 933233Seric ** Append the other fixed parts of the argv. These run 943233Seric ** up to the first entry containing "$u". There can only 953233Seric ** be one of these, and there are only a few more slots 963233Seric ** in the pv after it. 97294Seric */ 98294Seric 993233Seric for (mvp = m->m_argv; (p = *++mvp) != NULL; ) 100294Seric { 1013233Seric while ((p = index(p, '$')) != NULL) 1023233Seric if (*++p == 'u') 1033233Seric break; 1043233Seric if (p != NULL) 1053233Seric break; 1063233Seric 1073233Seric /* this entry is safe -- go ahead and process it */ 1084082Seric (void) expand(*mvp, buf, &buf[sizeof buf - 1]); 1093233Seric *pvp++ = newstr(buf); 1103233Seric if (pvp >= &pv[MAXPV - 3]) 1113233Seric { 1123233Seric syserr("Too many parameters to %s before $u", pv[0]); 1133233Seric return (-1); 1143233Seric } 115294Seric } 1163233Seric if (*mvp == NULL) 1173233Seric syserr("No $u in mailer argv for %s", pv[0]); 118294Seric 119294Seric /* 1203233Seric ** At this point *mvp points to the argument with $u. We 1213233Seric ** run through our address list and append all the addresses 1223233Seric ** we can. If we run out of space, do not fret! We can 1233233Seric ** always send another copy later. 124294Seric */ 125294Seric 1263233Seric tobuf[0] = '\0'; 1273233Seric firstone = TRUE; 1283233Seric To = tobuf; 1293233Seric for (; to != NULL; to = to->q_next) 130294Seric { 1313233Seric /* avoid sending multiple recipients to dumb mailers */ 1323233Seric if (!firstone && !bitset(M_MUSER, m->m_flags)) 1333233Seric break; 1343233Seric 1353233Seric /* if already sent or not for this host, don't send */ 1364311Seric if ((!ForceMail && bitset(QDONTSEND, to->q_flags)) || 1374311Seric strcmp(to->q_host, host) != 0) 1383233Seric continue; 1393233Seric user = to->q_user; 1403233Seric To = to->q_paddr; 1413233Seric to->q_flags |= QDONTSEND; 1423233Seric # ifdef DEBUG 1433233Seric if (Debug) 1443233Seric printf(" send to `%s'\n", user); 1453233Seric # endif DEBUG 1463233Seric 1473233Seric /* 1483233Seric ** Check to see that these people are allowed to 1493233Seric ** talk to each other. 1503233Seric */ 1513233Seric 1523233Seric if (!checkcompat(to)) 153294Seric { 1543233Seric giveresponse(EX_UNAVAILABLE, TRUE, m); 1553233Seric continue; 156294Seric } 1573233Seric 1583233Seric /* 1594099Seric ** Strip quote bits from names if the mailer is dumb 1604099Seric ** about them. 1613233Seric */ 1623233Seric 1633233Seric if (bitset(M_STRIPQ, m->m_flags)) 164294Seric { 1654099Seric stripquotes(user, TRUE); 1664099Seric stripquotes(host, TRUE); 1673233Seric } 1684099Seric else 1694099Seric { 1704099Seric stripquotes(user, FALSE); 1714099Seric stripquotes(host, FALSE); 1724099Seric } 1733233Seric 1743233Seric /* 1754161Seric ** If an error message has already been given, don't 1764161Seric ** bother to send to this address. 1774161Seric ** 1784161Seric ** >>>>>>>>>> This clause assumes that the local mailer 1794161Seric ** >> NOTE >> cannot do any further aliasing; that 1804161Seric ** >>>>>>>>>> function is subsumed by sendmail. 1814161Seric */ 1824161Seric 1834161Seric if (bitset(QBADADDR, to->q_flags)) 1844161Seric continue; 1854161Seric 1864283Seric /* save statistics.... */ 1874283Seric Stat.stat_nt[to->q_mailer]++; 1884283Seric Stat.stat_bt[to->q_mailer] += kbytes(MsgSize); 1894283Seric 1904161Seric /* 1913233Seric ** See if this user name is "special". 1923233Seric ** If the user name has a slash in it, assume that this 1933233Seric ** is a file -- send it off without further ado. 1943233Seric ** Note that this means that editfcn's will not 1953233Seric ** be applied to the message. Also note that 1963233Seric ** this type of addresses is not processed along 1973233Seric ** with the others, so we fudge on the To person. 1983233Seric */ 1993233Seric 2004194Seric if (m == Mailer[MN_LOCAL]) 2013233Seric { 202294Seric if (index(user, '/') != NULL) 203294Seric { 204294Seric i = mailfile(user); 205294Seric giveresponse(i, TRUE, m); 2063233Seric continue; 207294Seric } 208294Seric } 2093233Seric 2104315Seric /* 2114315Seric ** Address is verified -- add this user to mailer 2124315Seric ** argv, and add it to the print list of recipients. 2134315Seric */ 2144315Seric 2153233Seric /* create list of users for error messages */ 2163233Seric if (tobuf[0] != '\0') 2174082Seric (void) strcat(tobuf, ","); 2184082Seric (void) strcat(tobuf, to->q_paddr); 2193233Seric define('u', user); /* to user */ 2204078Seric define('z', to->q_home); /* user's home */ 2213233Seric 2223233Seric /* expand out this user */ 2234305Seric (void) expand(*mvp, buf, &buf[sizeof buf - 1]); 2243233Seric *pvp++ = newstr(buf); 2253233Seric if (pvp >= &pv[MAXPV - 2]) 2263233Seric { 2273233Seric /* allow some space for trailing parms */ 2283233Seric break; 2293233Seric } 230294Seric } 231294Seric 2324067Seric /* see if any addresses still exist */ 2334067Seric if (tobuf[0] == '\0') 2344067Seric return (0); 2354067Seric 2363233Seric /* print out messages as full list */ 2373233Seric To = tobuf; 2383233Seric 239294Seric /* 2403233Seric ** Fill out any parameters after the $u parameter. 241294Seric */ 242294Seric 2433233Seric while (*++mvp != NULL) 244294Seric { 2454082Seric (void) expand(*mvp, buf, &buf[sizeof buf - 1]); 2463233Seric *pvp++ = newstr(buf); 2473233Seric if (pvp >= &pv[MAXPV]) 2483233Seric syserr("deliver: pv overflow after $u for %s", pv[0]); 249294Seric } 2503233Seric *pvp++ = NULL; 251294Seric 252294Seric /* 253294Seric ** Call the mailer. 2542898Seric ** The argument vector gets built, pipes 255294Seric ** are created as necessary, and we fork & exec as 2562898Seric ** appropriate. 257294Seric */ 258294Seric 2593233Seric if (editfcn == NULL) 2603233Seric editfcn = putmessage; 2613233Seric i = sendoff(m, pv, editfcn); 2623233Seric 2633233Seric return (i); 2643233Seric } 2653233Seric /* 2664214Seric ** DOFORK -- do a fork, retrying a couple of times on failure. 2674214Seric ** 2684214Seric ** This MUST be a macro, since after a vfork we are running 2694214Seric ** two processes on the same stack!!! 2704214Seric ** 2714214Seric ** Parameters: 2724214Seric ** none. 2734214Seric ** 2744214Seric ** Returns: 2754214Seric ** From a macro??? You've got to be kidding! 2764214Seric ** 2774214Seric ** Side Effects: 2784214Seric ** Modifies the ==> LOCAL <== variable 'pid', leaving: 2794214Seric ** pid of child in parent, zero in child. 2804214Seric ** -1 on unrecoverable error. 2814214Seric ** 2824214Seric ** Notes: 2834214Seric ** I'm awfully sorry this looks so awful. That's 2844214Seric ** vfork for you..... 2854214Seric */ 2864214Seric 2874214Seric # define NFORKTRIES 5 2884214Seric # ifdef VFORK 2894214Seric # define XFORK vfork 2904214Seric # else VFORK 2914214Seric # define XFORK fork 2924214Seric # endif VFORK 2934214Seric 2944214Seric # define DOFORK(fORKfN) \ 2954214Seric {\ 2964214Seric register int i;\ 2974214Seric \ 2984214Seric for (i = NFORKTRIES; i-- > 0; )\ 2994214Seric {\ 3004214Seric pid = fORKfN();\ 3014214Seric if (pid >= 0)\ 3024214Seric break;\ 3034214Seric sleep((unsigned) NFORKTRIES - i);\ 3044214Seric }\ 3054214Seric } 3064214Seric /* 3073233Seric ** SENDOFF -- send off call to mailer & collect response. 3083233Seric ** 3093233Seric ** Parameters: 3103233Seric ** m -- mailer descriptor. 3113233Seric ** pvp -- parameter vector to send to it. 3123233Seric ** editfcn -- function to pipe it through. 3133233Seric ** 3143233Seric ** Returns: 3153233Seric ** exit status of mailer. 3163233Seric ** 3173233Seric ** Side Effects: 3183233Seric ** none. 3193233Seric */ 3203233Seric 3213233Seric sendoff(m, pvp, editfcn) 3223233Seric struct mailer *m; 3233233Seric char **pvp; 3243233Seric int (*editfcn)(); 3253233Seric { 3263233Seric auto int st; 3273233Seric register int i; 3283233Seric int pid; 3293233Seric int pvect[2]; 3303233Seric FILE *mfile; 3313233Seric extern putmessage(); 3323233Seric extern FILE *fdopen(); 3333233Seric 3343233Seric # ifdef DEBUG 3353233Seric if (Debug) 336294Seric { 3373233Seric printf("Sendoff:\n"); 3383233Seric printav(pvp); 339294Seric } 3403233Seric # endif DEBUG 3413233Seric 3422898Seric /* create a pipe to shove the mail through */ 3432898Seric if (pipe(pvect) < 0) 344294Seric { 345294Seric syserr("pipe"); 346294Seric return (-1); 347294Seric } 3484214Seric DOFORK(XFORK); 3494327Seric /* pid is set by DOFORK */ 350294Seric if (pid < 0) 351294Seric { 352294Seric syserr("Cannot fork"); 3534082Seric (void) close(pvect[0]); 3544082Seric (void) close(pvect[1]); 355294Seric return (-1); 356294Seric } 357294Seric else if (pid == 0) 358294Seric { 359294Seric /* child -- set up input & exec mailer */ 3601621Seric /* make diagnostic output be standard output */ 3614215Seric (void) signal(SIGINT, SIG_DFL); 3624215Seric (void) signal(SIGHUP, SIG_DFL); 3634215Seric (void) signal(SIGTERM, SIG_DFL); 3644082Seric (void) close(2); 3654082Seric (void) dup(1); 3664082Seric (void) close(0); 3672898Seric if (dup(pvect[0]) < 0) 368294Seric { 3692898Seric syserr("Cannot dup to zero!"); 3702898Seric _exit(EX_OSERR); 371294Seric } 3724082Seric (void) close(pvect[0]); 3734082Seric (void) close(pvect[1]); 3742968Seric if (!bitset(M_RESTR, m->m_flags)) 3754215Seric { 3764082Seric (void) setuid(getuid()); 3774215Seric (void) setgid(getgid()); 3784215Seric } 3792774Seric # ifndef VFORK 3802774Seric /* 3812774Seric ** We have to be careful with vfork - we can't mung up the 3822774Seric ** memory but we don't want the mailer to inherit any extra 3832774Seric ** open files. Chances are the mailer won't 3842774Seric ** care about an extra file, but then again you never know. 3852774Seric ** Actually, we would like to close(fileno(pwf)), but it's 3862774Seric ** declared static so we can't. But if we fclose(pwf), which 3872774Seric ** is what endpwent does, it closes it in the parent too and 3882774Seric ** the next getpwnam will be slower. If you have a weird 3892774Seric ** mailer that chokes on the extra file you should do the 3902774Seric ** endpwent(). 3912774Seric ** 3922774Seric ** Similar comments apply to log. However, openlog is 3932774Seric ** clever enough to set the FIOCLEX mode on the file, 3942774Seric ** so it will be closed automatically on the exec. 3952774Seric */ 3962774Seric 3972774Seric endpwent(); 398294Seric # ifdef LOG 3992089Seric closelog(); 400294Seric # endif LOG 4012774Seric # endif VFORK 402294Seric execv(m->m_mailer, pvp); 403294Seric /* syserr fails because log is closed */ 404294Seric /* syserr("Cannot exec %s", m->m_mailer); */ 4054214Seric printf("Cannot exec '%s' errno=%d\n", m->m_mailer, errno); 4064082Seric (void) fflush(stdout); 4071619Seric _exit(EX_UNAVAILABLE); 408294Seric } 409294Seric 4102898Seric /* write out message to mailer */ 4114082Seric (void) close(pvect[0]); 4124123Seric (void) signal(SIGPIPE, SIG_IGN); 4132898Seric mfile = fdopen(pvect[1], "w"); 4142898Seric if (editfcn == NULL) 4152898Seric editfcn = putmessage; 4162898Seric (*editfcn)(mfile, m); 4174082Seric (void) fclose(mfile); 418294Seric 419294Seric /* 420294Seric ** Wait for child to die and report status. 421294Seric ** We should never get fatal errors (e.g., segmentation 422294Seric ** violation), so we report those specially. For other 423294Seric ** errors, we choose a status message (into statmsg), 424294Seric ** and if it represents an error, we print it. 425294Seric */ 426294Seric 427294Seric while ((i = wait(&st)) > 0 && i != pid) 428294Seric continue; 429294Seric if (i < 0) 430294Seric { 431294Seric syserr("wait"); 432294Seric return (-1); 433294Seric } 434294Seric if ((st & 0377) != 0) 435294Seric { 436294Seric syserr("%s: stat %o", pvp[0], st); 4371597Seric ExitStat = EX_UNAVAILABLE; 438294Seric return (-1); 439294Seric } 440294Seric i = (st >> 8) & 0377; 4412343Seric giveresponse(i, TRUE, m); 442294Seric return (i); 443294Seric } 444294Seric /* 445294Seric ** GIVERESPONSE -- Interpret an error response from a mailer 446294Seric ** 447294Seric ** Parameters: 448294Seric ** stat -- the status code from the mailer (high byte 449294Seric ** only; core dumps must have been taken care of 450294Seric ** already). 451294Seric ** force -- if set, force an error message output, even 452294Seric ** if the mailer seems to like to print its own 453294Seric ** messages. 454294Seric ** m -- the mailer descriptor for this mailer. 455294Seric ** 456294Seric ** Returns: 4574082Seric ** none. 458294Seric ** 459294Seric ** Side Effects: 4601518Seric ** Errors may be incremented. 461294Seric ** ExitStat may be set. 462294Seric */ 463294Seric 464294Seric giveresponse(stat, force, m) 465294Seric int stat; 466294Seric int force; 467294Seric register struct mailer *m; 468294Seric { 469294Seric register char *statmsg; 470294Seric extern char *SysExMsg[]; 471294Seric register int i; 472294Seric extern int N_SysEx; 4731624Seric char buf[30]; 474294Seric 4754315Seric /* 4764315Seric ** Compute status message from code. 4774315Seric */ 4784315Seric 479294Seric i = stat - EX__BASE; 480294Seric if (i < 0 || i > N_SysEx) 481294Seric statmsg = NULL; 482294Seric else 483294Seric statmsg = SysExMsg[i]; 484294Seric if (stat == 0) 4854065Seric { 4864194Seric if (bitset(M_LOCAL, m->m_flags)) 4874161Seric statmsg = "delivered"; 4884161Seric else 4894161Seric statmsg = "queued"; 4904065Seric if (Verbose) 4914166Seric message(Arpa_Info, statmsg); 4924065Seric } 493294Seric else 494294Seric { 4951518Seric Errors++; 496294Seric if (statmsg == NULL && m->m_badstat != 0) 497294Seric { 498294Seric stat = m->m_badstat; 499294Seric i = stat - EX__BASE; 500294Seric # ifdef DEBUG 501294Seric if (i < 0 || i >= N_SysEx) 502294Seric syserr("Bad m_badstat %d", stat); 503294Seric else 504294Seric # endif DEBUG 505294Seric statmsg = SysExMsg[i]; 506294Seric } 507294Seric if (statmsg == NULL) 508294Seric usrerr("unknown mailer response %d", stat); 5094065Seric else if (force || !bitset(M_QUIET, m->m_flags) || Verbose) 510294Seric usrerr("%s", statmsg); 511294Seric } 512294Seric 513294Seric /* 514294Seric ** Final cleanup. 515294Seric ** Log a record of the transaction. Compute the new 516294Seric ** ExitStat -- if we already had an error, stick with 517294Seric ** that. 518294Seric */ 519294Seric 5201624Seric if (statmsg == NULL) 5211624Seric { 5224082Seric (void) sprintf(buf, "error %d", stat); 5231624Seric statmsg = buf; 5241624Seric } 5251624Seric 526294Seric # ifdef LOG 5272774Seric syslog(LOG_INFO, "%s->%s: %ld: %s", From.q_paddr, To, MsgSize, statmsg); 528294Seric # endif LOG 5291389Seric setstat(stat); 530294Seric } 531294Seric /* 5322898Seric ** PUTMESSAGE -- output a message to the final mailer. 533294Seric ** 5342898Seric ** This routine takes care of recreating the header from the 5352898Seric ** in-core copy, etc. 536294Seric ** 537294Seric ** Parameters: 5382898Seric ** fp -- file to output onto. 5392898Seric ** m -- a mailer descriptor. 540294Seric ** 541294Seric ** Returns: 5422898Seric ** none. 543294Seric ** 544294Seric ** Side Effects: 5452898Seric ** The message is written onto fp. 546294Seric */ 547294Seric 5482898Seric putmessage(fp, m) 5492898Seric FILE *fp; 5502898Seric struct mailer *m; 551294Seric { 5522898Seric char buf[BUFSIZ]; 5532898Seric register int i; 5544315Seric register HDR *h; 5552898Seric extern char *arpadate(); 5562898Seric bool anyheader = FALSE; 5573044Seric extern char *capitalize(); 558*4370Seric extern char *hvalue(); 559*4370Seric extern bool samefrom(); 560294Seric 5614315Seric /* 5624315Seric ** Output "From" line unless supressed 5634315Seric */ 5644315Seric 5653186Seric if (!bitset(M_NHDR, m->m_flags)) 5664205Seric { 5674205Seric (void) expand("$l", buf, &buf[sizeof buf - 1]); 5684205Seric fprintf(fp, "%s\n", buf); 5694205Seric } 5703186Seric 5714315Seric /* 5724315Seric ** Output all header lines 5734315Seric */ 5744315Seric 5752898Seric for (h = Header; h != NULL; h = h->h_link) 5761828Seric { 5774315Seric register char *p; 578*4370Seric char *origfrom = OrigFrom; 5794315Seric 5803389Seric if (bitset(H_CHECK|H_ACHECK, h->h_flags) && !bitset(h->h_mflags, m->m_flags)) 5814209Seric { 5824209Seric p = ")><("; /* can't happen (I hope) */ 5834209Seric goto checkfrom; 5844209Seric } 585*4370Seric if (strcmp(h->h_field, "from") == 0 && origfrom != NULL && 586*4370Seric strcmp(m->m_from, "$f") == 0) 5873385Seric { 588*4370Seric p = origfrom; 589*4370Seric origfrom = NULL; 590*4370Seric } 591*4370Seric else if (bitset(H_DEFAULT, h->h_flags)) 592*4370Seric { 5934082Seric (void) expand(h->h_value, buf, &buf[sizeof buf]); 5943385Seric p = buf; 5953385Seric } 5962898Seric else 5973385Seric p = h->h_value; 5983389Seric if (*p == '\0') 5993389Seric continue; 6003385Seric fprintf(fp, "%s: %s\n", capitalize(h->h_field), p); 6012898Seric h->h_flags |= H_USED; 6022898Seric anyheader = TRUE; 6034209Seric 6044209Seric /* hack, hack -- output Original-From field if different */ 6054209Seric checkfrom: 606*4370Seric if (strcmp(h->h_field, "from") == 0 && origfrom != NULL && 607*4370Seric !samefrom(p, origfrom) && hvalue("original-from") == NULL) 6084209Seric { 609*4370Seric fprintf(fp, "Original-From: %s\n", origfrom); 610*4370Seric anyheader = TRUE; 6114209Seric } 6122898Seric } 6132898Seric if (anyheader) 6142898Seric fprintf(fp, "\n"); 6152898Seric 6164315Seric /* 6174315Seric ** Output the body of the message 6184315Seric */ 6194315Seric 6204181Seric rewind(TempFile); 6214181Seric while (!ferror(fp) && (i = fread(buf, 1, BUFSIZ, TempFile)) > 0) 6224082Seric (void) fwrite(buf, 1, i, fp); 6232898Seric 6244123Seric if (ferror(fp) && errno != EPIPE) 625294Seric { 6262898Seric syserr("putmessage: write error"); 627294Seric setstat(EX_IOERR); 628294Seric } 6294123Seric errno = 0; 630294Seric } 631294Seric /* 632*4370Seric ** SAMEFROM -- tell if two text addresses represent the same from address. 633*4370Seric ** 634*4370Seric ** Parameters: 635*4370Seric ** ifrom -- internally generated form of from address. 636*4370Seric ** efrom -- external form of from address. 637*4370Seric ** 638*4370Seric ** Returns: 639*4370Seric ** TRUE -- if they convey the same info. 640*4370Seric ** FALSE -- if any information has been lost. 641*4370Seric ** 642*4370Seric ** Side Effects: 643*4370Seric ** none. 644*4370Seric */ 645*4370Seric 646*4370Seric bool 647*4370Seric samefrom(ifrom, efrom) 648*4370Seric char *ifrom; 649*4370Seric char *efrom; 650*4370Seric { 651*4370Seric return (strcmp(ifrom, efrom) == 0); 652*4370Seric } 653*4370Seric /* 654294Seric ** MAILFILE -- Send a message to a file. 655294Seric ** 6564327Seric ** If the file has the setuid/setgid bits set, but NO execute 6574327Seric ** bits, sendmail will try to become the owner of that file 6584327Seric ** rather than the real user. Obviously, this only works if 6594327Seric ** sendmail runs as root. 6604327Seric ** 661294Seric ** Parameters: 662294Seric ** filename -- the name of the file to send to. 663294Seric ** 664294Seric ** Returns: 665294Seric ** The exit code associated with the operation. 666294Seric ** 667294Seric ** Side Effects: 668294Seric ** none. 669294Seric */ 670294Seric 671294Seric mailfile(filename) 672294Seric char *filename; 673294Seric { 674294Seric register FILE *f; 6754214Seric register int pid; 676294Seric 6774214Seric /* 6784214Seric ** Fork so we can change permissions here. 6794214Seric ** Note that we MUST use fork, not vfork, because of 6804214Seric ** the complications of calling subroutines, etc. 6814214Seric */ 6824067Seric 6834214Seric DOFORK(fork); 6844214Seric 6854214Seric if (pid < 0) 6864214Seric return (EX_OSERR); 6874214Seric else if (pid == 0) 6884214Seric { 6894214Seric /* child -- actually write to file */ 6904327Seric struct stat stb; 6914327Seric 6924215Seric (void) signal(SIGINT, SIG_DFL); 6934215Seric (void) signal(SIGHUP, SIG_DFL); 6944215Seric (void) signal(SIGTERM, SIG_DFL); 6954327Seric umask(OldUmask); 6964327Seric if (stat(filename, &stb) < 0) 6974327Seric stb.st_mode = 0; 6984327Seric if (bitset(0111, stb.st_mode)) 6994327Seric exit(EX_CANTCREAT); 7004327Seric if (!bitset(S_ISGID, stb.st_mode) || setgid(stb.st_gid) < 0) 7014327Seric (void) setgid(getgid()); 7024327Seric if (!bitset(S_ISUID, stb.st_mode) || setuid(stb.st_uid) < 0) 7034327Seric (void) setuid(getuid()); 7044214Seric f = fopen(filename, "a"); 7054214Seric if (f == NULL) 7064214Seric exit(EX_CANTCREAT); 7074214Seric 7084214Seric putmessage(f, Mailer[1]); 7094214Seric fputs("\n", f); 7104214Seric (void) fclose(f); 7114214Seric (void) fflush(stdout); 7124214Seric exit(EX_OK); 7134315Seric /*NOTREACHED*/ 7144214Seric } 7154214Seric else 7164214Seric { 7174214Seric /* parent -- wait for exit status */ 7184214Seric register int i; 7194214Seric auto int stat; 7204214Seric 7214214Seric while ((i = wait(&stat)) != pid) 7224214Seric { 7234214Seric if (i < 0) 7244214Seric { 7254214Seric stat = EX_OSERR << 8; 7264214Seric break; 7274214Seric } 7284214Seric } 7294215Seric if ((stat & 0377) != 0) 7304215Seric stat = EX_UNAVAILABLE << 8; 7314214Seric return ((stat >> 8) & 0377); 7324214Seric } 733294Seric } 734