14227346bSdist /* 2759969d8Seric * Copyright (c) 1983, 1995 Eric P. Allman 32b191fa3Sbostic * Copyright (c) 1988, 1993 42b191fa3Sbostic * The Regents of the University of California. All rights reserved. 5e70a7521Sbostic * 63bc94712Sbostic * %sccs.include.redist.c% 74227346bSdist */ 84227346bSdist 94227346bSdist #ifndef lint 10*86aab53cSeric static char sccsid[] = "@(#)deliver.c 8.158 (Berkeley) 06/13/95"; 11e70a7521Sbostic #endif /* not lint */ 124227346bSdist 13fcde9cc8Sbostic #include "sendmail.h" 14911693bfSbostic #include <errno.h> 159d4a8008Seric #if NAMED_BIND 16912a731aSbostic #include <resolv.h> 17f170942cSeric 18f170942cSeric extern int h_errno; 19134746fbSeric #endif 2025a99e2eSeric 215d437c4dSeric extern char SmtpError[]; 225d437c4dSeric 2325a99e2eSeric /* 249c9e68d9Seric ** SENDALL -- actually send all the messages. 259c9e68d9Seric ** 269c9e68d9Seric ** Parameters: 279c9e68d9Seric ** e -- the envelope to send. 289c9e68d9Seric ** mode -- the delivery mode to use. If SM_DEFAULT, use 299c9e68d9Seric ** the current e->e_sendmode. 309c9e68d9Seric ** 319c9e68d9Seric ** Returns: 329c9e68d9Seric ** none. 339c9e68d9Seric ** 349c9e68d9Seric ** Side Effects: 359c9e68d9Seric ** Scans the send lists and sends everything it finds. 369c9e68d9Seric ** Delivers any appropriate error messages. 379c9e68d9Seric ** If we are running in a non-interactive mode, takes the 389c9e68d9Seric ** appropriate action. 399c9e68d9Seric */ 409c9e68d9Seric 41b665faabSeric void 429c9e68d9Seric sendall(e, mode) 439c9e68d9Seric ENVELOPE *e; 449c9e68d9Seric char mode; 459c9e68d9Seric { 469c9e68d9Seric register ADDRESS *q; 479c9e68d9Seric char *owner; 489c9e68d9Seric int otherowners; 49b056abd0Seric register ENVELOPE *ee; 50b056abd0Seric ENVELOPE *splitenv = NULL; 51b665faabSeric bool oldverbose = Verbose; 52b665faabSeric bool somedeliveries = FALSE; 53b665faabSeric int pid; 54b665faabSeric extern void sendenvelope(); 559c9e68d9Seric 567880f3e4Seric /* 577880f3e4Seric ** If we have had global, fatal errors, don't bother sending 587880f3e4Seric ** the message at all if we are in SMTP mode. Local errors 597880f3e4Seric ** (e.g., a single address failing) will still cause the other 607880f3e4Seric ** addresses to be sent. 617880f3e4Seric */ 627880f3e4Seric 638d19a23dSeric if (bitset(EF_FATALERRS, e->e_flags) && 648d19a23dSeric (OpMode == MD_SMTP || OpMode == MD_DAEMON)) 65896b16f6Seric { 66896b16f6Seric e->e_flags |= EF_CLRQUEUE; 67896b16f6Seric return; 68896b16f6Seric } 69896b16f6Seric 709c9e68d9Seric /* determine actual delivery mode */ 71fbe2f963Seric CurrentLA = getla(); 729c9e68d9Seric if (mode == SM_DEFAULT) 739c9e68d9Seric { 749c9e68d9Seric mode = e->e_sendmode; 759c9e68d9Seric if (mode != SM_VERIFY && 769c9e68d9Seric shouldqueue(e->e_msgpriority, e->e_ctime)) 779c9e68d9Seric mode = SM_QUEUE; 789c9e68d9Seric } 799c9e68d9Seric 809c9e68d9Seric if (tTd(13, 1)) 819c9e68d9Seric { 82b665faabSeric extern void printenvflags(); 83b665faabSeric 840e484fe5Seric printf("\n===== SENDALL: mode %c, id %s, e_from ", 850e484fe5Seric mode, e->e_id); 869c9e68d9Seric printaddr(&e->e_from, FALSE); 87b665faabSeric printf("\te_flags = "); 88b665faabSeric printenvflags(e); 899c9e68d9Seric printf("sendqueue:\n"); 909c9e68d9Seric printaddr(e->e_sendqueue, TRUE); 919c9e68d9Seric } 929c9e68d9Seric 939c9e68d9Seric /* 949c9e68d9Seric ** Do any preprocessing necessary for the mode we are running. 959c9e68d9Seric ** Check to make sure the hop count is reasonable. 969c9e68d9Seric ** Delete sends to the sender in mailing lists. 979c9e68d9Seric */ 989c9e68d9Seric 999c9e68d9Seric CurEnv = e; 1009c9e68d9Seric 1019c9e68d9Seric if (e->e_hopcount > MaxHopCount) 1029c9e68d9Seric { 1039c9e68d9Seric errno = 0; 104b665faabSeric queueup(e, TRUE, mode == SM_QUEUE); 10527607809Seric e->e_flags |= EF_FATALERRS|EF_PM_NOTIFY|EF_CLRQUEUE; 106d95dad3eSeric syserr("554 Too many hops %d (%d max): from %s via %s, to %s", 1079c9e68d9Seric e->e_hopcount, MaxHopCount, e->e_from.q_paddr, 108f7869e68Seric RealHostName == NULL ? "localhost" : RealHostName, 109f7869e68Seric e->e_sendqueue->q_paddr); 110d95dad3eSeric e->e_sendqueue->q_status = "5.4.6"; 1119c9e68d9Seric return; 1129c9e68d9Seric } 1139c9e68d9Seric 114b8004690Seric /* 115b8004690Seric ** Do sender deletion. 116b8004690Seric ** 117b8004690Seric ** If the sender has the QQUEUEUP flag set, skip this. 118b8004690Seric ** This can happen if the name server is hosed when you 119b8004690Seric ** are trying to send mail. The result is that the sender 120b8004690Seric ** is instantiated in the queue as a recipient. 121b8004690Seric */ 122b8004690Seric 123e76a6a8fSeric if (!bitset(EF_METOO, e->e_flags) && 124e76a6a8fSeric !bitset(QQUEUEUP, e->e_from.q_flags)) 1259c9e68d9Seric { 1269c9e68d9Seric if (tTd(13, 5)) 1279c9e68d9Seric { 1289c9e68d9Seric printf("sendall: QDONTSEND "); 1299c9e68d9Seric printaddr(&e->e_from, FALSE); 1309c9e68d9Seric } 1319c9e68d9Seric e->e_from.q_flags |= QDONTSEND; 132b665faabSeric (void) recipient(&e->e_from, &e->e_sendqueue, 0, e); 1339c9e68d9Seric } 1349c9e68d9Seric 135ce5531bdSeric /* 136ce5531bdSeric ** Handle alias owners. 137ce5531bdSeric ** 138ce5531bdSeric ** We scan up the q_alias chain looking for owners. 139ce5531bdSeric ** We discard owners that are the same as the return path. 140ce5531bdSeric */ 141ce5531bdSeric 142ce5531bdSeric for (q = e->e_sendqueue; q != NULL; q = q->q_next) 143ce5531bdSeric { 144ce5531bdSeric register struct address *a; 145ce5531bdSeric 146ce5531bdSeric for (a = q; a != NULL && a->q_owner == NULL; a = a->q_alias) 147ce5531bdSeric continue; 148ce5531bdSeric if (a != NULL) 149ce5531bdSeric q->q_owner = a->q_owner; 150ce5531bdSeric 151ce5531bdSeric if (q->q_owner != NULL && 152ce5531bdSeric !bitset(QDONTSEND, q->q_flags) && 153ce5531bdSeric strcmp(q->q_owner, e->e_from.q_paddr) == 0) 154ce5531bdSeric q->q_owner = NULL; 155ce5531bdSeric } 156ce5531bdSeric 157ce5531bdSeric owner = ""; 158ce5531bdSeric otherowners = 1; 159ce5531bdSeric while (owner != NULL && otherowners > 0) 160ce5531bdSeric { 161ce5531bdSeric owner = NULL; 162ce5531bdSeric otherowners = 0; 163ce5531bdSeric 164ce5531bdSeric for (q = e->e_sendqueue; q != NULL; q = q->q_next) 165ce5531bdSeric { 166ce5531bdSeric if (bitset(QDONTSEND, q->q_flags)) 167ce5531bdSeric continue; 168ce5531bdSeric 169ce5531bdSeric if (q->q_owner != NULL) 170ce5531bdSeric { 171ce5531bdSeric if (owner == NULL) 172ce5531bdSeric owner = q->q_owner; 173ce5531bdSeric else if (owner != q->q_owner) 174ce5531bdSeric { 175ce5531bdSeric if (strcmp(owner, q->q_owner) == 0) 176ce5531bdSeric { 177ce5531bdSeric /* make future comparisons cheap */ 178ce5531bdSeric q->q_owner = owner; 179ce5531bdSeric } 180ce5531bdSeric else 181ce5531bdSeric { 182ce5531bdSeric otherowners++; 183ce5531bdSeric } 184ce5531bdSeric owner = q->q_owner; 185ce5531bdSeric } 186ce5531bdSeric } 187ce5531bdSeric else 188ce5531bdSeric { 189ce5531bdSeric otherowners++; 190ce5531bdSeric } 191b665faabSeric 192b665faabSeric /* 193b665faabSeric ** If this mailer is expensive, and if we don't 194b665faabSeric ** want to make connections now, just mark these 195b665faabSeric ** addresses and return. This is useful if we 196b665faabSeric ** want to batch connections to reduce load. This 197b665faabSeric ** will cause the messages to be queued up, and a 198b665faabSeric ** daemon will come along to send the messages later. 199b665faabSeric */ 200b665faabSeric 201b665faabSeric if (bitset(QBADADDR|QQUEUEUP, q->q_flags)) 202b665faabSeric continue; 203b665faabSeric if (NoConnect && !Verbose && 204b665faabSeric bitnset(M_EXPENSIVE, q->q_mailer->m_flags)) 205b665faabSeric { 206b665faabSeric q->q_flags |= QQUEUEUP; 207b665faabSeric e->e_to = q->q_paddr; 208b665faabSeric message("queued"); 209b665faabSeric if (LogLevel > 8) 210b665faabSeric logdelivery(q->q_mailer, NULL, 211b665faabSeric "queued", NULL, 212b665faabSeric (time_t) 0, e); 213b665faabSeric e->e_to = NULL; 214b665faabSeric } 215b665faabSeric else 216b665faabSeric { 217b665faabSeric somedeliveries = TRUE; 218b665faabSeric } 219ce5531bdSeric } 220ce5531bdSeric 221ce5531bdSeric if (owner != NULL && otherowners > 0) 222ce5531bdSeric { 223ce5531bdSeric extern HDR *copyheader(); 224ce5531bdSeric extern ADDRESS *copyqueue(); 225ce5531bdSeric 226ce5531bdSeric /* 227ce5531bdSeric ** Split this envelope into two. 228ce5531bdSeric */ 229ce5531bdSeric 230ce5531bdSeric ee = (ENVELOPE *) xalloc(sizeof(ENVELOPE)); 231ce5531bdSeric *ee = *e; 232ce5531bdSeric ee->e_id = NULL; 233ce5531bdSeric (void) queuename(ee, '\0'); 234ce5531bdSeric 235ce5531bdSeric if (tTd(13, 1)) 236ce5531bdSeric printf("sendall: split %s into %s\n", 237ce5531bdSeric e->e_id, ee->e_id); 238ce5531bdSeric 239ce5531bdSeric ee->e_header = copyheader(e->e_header); 240ce5531bdSeric ee->e_sendqueue = copyqueue(e->e_sendqueue); 241ce5531bdSeric ee->e_errorqueue = copyqueue(e->e_errorqueue); 242b665faabSeric ee->e_flags = e->e_flags & ~(EF_INQUEUE|EF_CLRQUEUE|EF_FATALERRS|EF_SENDRECEIPT|EF_RET_PARAM); 243fce3c07bSeric ee->e_flags |= EF_NORECEIPT; 244ce5531bdSeric setsender(owner, ee, NULL, TRUE); 245ce5531bdSeric if (tTd(13, 5)) 246ce5531bdSeric { 247ce5531bdSeric printf("sendall(split): QDONTSEND "); 248ce5531bdSeric printaddr(&ee->e_from, FALSE); 249ce5531bdSeric } 250ce5531bdSeric ee->e_from.q_flags |= QDONTSEND; 251ce5531bdSeric ee->e_dfp = NULL; 252ce5531bdSeric ee->e_xfp = NULL; 253ce5531bdSeric ee->e_errormode = EM_MAIL; 254b056abd0Seric ee->e_sibling = splitenv; 255b056abd0Seric splitenv = ee; 256ce5531bdSeric 257ce5531bdSeric for (q = e->e_sendqueue; q != NULL; q = q->q_next) 258b665faabSeric { 259ce5531bdSeric if (q->q_owner == owner) 260de1a6b1bSeric { 261ce5531bdSeric q->q_flags |= QDONTSEND; 262de1a6b1bSeric q->q_flags &= ~QQUEUEUP; 263de1a6b1bSeric } 264b665faabSeric } 265ce5531bdSeric for (q = ee->e_sendqueue; q != NULL; q = q->q_next) 266b665faabSeric { 267ce5531bdSeric if (q->q_owner != owner) 268de1a6b1bSeric { 269ce5531bdSeric q->q_flags |= QDONTSEND; 270de1a6b1bSeric q->q_flags &= ~QQUEUEUP; 271de1a6b1bSeric } 272b665faabSeric else 273ce5531bdSeric { 274b665faabSeric /* clear DSN parameters */ 275b665faabSeric q->q_flags &= ~(QHASNOTIFY|QPINGONSUCCESS); 276b665faabSeric q->q_flags |= QPINGONFAILURE|QPINGONDELAY; 277b665faabSeric } 278b665faabSeric } 279b665faabSeric 280b665faabSeric if (mode != SM_VERIFY && bitset(EF_HAS_DF, e->e_flags)) 281b665faabSeric { 282b665faabSeric char df1buf[20], df2buf[20]; 283b665faabSeric 284ce5531bdSeric ee->e_dfp = NULL; 285b665faabSeric strcpy(df1buf, queuename(e, 'd')); 286b665faabSeric strcpy(df2buf, queuename(ee, 'd')); 287b665faabSeric if (link(df1buf, df2buf) < 0) 288ce5531bdSeric { 289ce5531bdSeric syserr("sendall: link(%s, %s)", 290b665faabSeric df1buf, df2buf); 291ce5531bdSeric } 292ce5531bdSeric } 293ce5531bdSeric #ifdef LOG 294ce5531bdSeric if (LogLevel > 4) 295c8b70947Seric syslog(LOG_INFO, "%s: clone %s, owner=%s", 296c8b70947Seric ee->e_id, e->e_id, owner); 297ce5531bdSeric #endif 298ce5531bdSeric } 299ce5531bdSeric } 300ce5531bdSeric 301ce5531bdSeric if (owner != NULL) 302ce5531bdSeric { 303ce5531bdSeric setsender(owner, e, NULL, TRUE); 304ce5531bdSeric if (tTd(13, 5)) 305ce5531bdSeric { 306ce5531bdSeric printf("sendall(owner): QDONTSEND "); 307ce5531bdSeric printaddr(&e->e_from, FALSE); 308ce5531bdSeric } 309ce5531bdSeric e->e_from.q_flags |= QDONTSEND; 310ce5531bdSeric e->e_errormode = EM_MAIL; 311fce3c07bSeric e->e_flags |= EF_NORECEIPT; 312ce5531bdSeric } 313ce5531bdSeric 314b665faabSeric /* if nothing to be delivered, just queue up everything */ 315b665faabSeric if (!somedeliveries && mode != SM_QUEUE && mode != SM_VERIFY) 316b665faabSeric mode = SM_QUEUE; 317b665faabSeric 318c1ac89b1Seric # ifdef QUEUE 319c1ac89b1Seric if ((mode == SM_QUEUE || mode == SM_FORK || 320c1ac89b1Seric (mode != SM_VERIFY && SuperSafe)) && 321c1ac89b1Seric !bitset(EF_INQUEUE, e->e_flags)) 322c1ac89b1Seric { 323c1ac89b1Seric /* be sure everything is instantiated in the queue */ 324b665faabSeric queueup(e, TRUE, mode == SM_QUEUE); 325b056abd0Seric for (ee = splitenv; ee != NULL; ee = ee->e_sibling) 326b665faabSeric queueup(ee, TRUE, mode == SM_QUEUE); 327c1ac89b1Seric } 328c1ac89b1Seric #endif /* QUEUE */ 329c1ac89b1Seric 3307880f3e4Seric /* 331b665faabSeric ** If we belong in background, fork now. 3327880f3e4Seric */ 3337880f3e4Seric 334c1ac89b1Seric switch (mode) 335c1ac89b1Seric { 336c1ac89b1Seric case SM_VERIFY: 337c1ac89b1Seric Verbose = TRUE; 338c1ac89b1Seric break; 339c1ac89b1Seric 340c1ac89b1Seric case SM_QUEUE: 341c1ac89b1Seric queueonly: 342b665faabSeric if (e->e_nrcpts > 0) 343c1ac89b1Seric e->e_flags |= EF_INQUEUE|EF_KEEPQUEUE; 344c1ac89b1Seric return; 345c1ac89b1Seric 346c1ac89b1Seric case SM_FORK: 347c1ac89b1Seric if (e->e_xfp != NULL) 348c1ac89b1Seric (void) fflush(e->e_xfp); 349c1ac89b1Seric 350b269aa8eSeric # if !HASFLOCK 351c1ac89b1Seric /* 3526b2765c6Seric ** Since fcntl locking has the interesting semantic that 3536b2765c6Seric ** the lock is owned by a process, not by an open file 3546b2765c6Seric ** descriptor, we have to flush this to the queue, and 3556b2765c6Seric ** then restart from scratch in the child. 356c1ac89b1Seric */ 357c1ac89b1Seric 358b665faabSeric { 3596b2765c6Seric /* save id for future use */ 360b665faabSeric char *qid = e->e_id; 3616b2765c6Seric 3626b2765c6Seric /* now drop the envelope in the parent */ 3636b2765c6Seric e->e_flags |= EF_INQUEUE|EF_KEEPQUEUE; 3646b2765c6Seric dropenvelope(e); 3656b2765c6Seric 3666b2765c6Seric /* and reacquire in the child */ 367b665faabSeric (void) dowork(qid, TRUE, FALSE, e); 368b665faabSeric } 3696b2765c6Seric 3706b2765c6Seric return; 3716b2765c6Seric 3726b2765c6Seric # else /* HASFLOCK */ 373c1ac89b1Seric 374c1ac89b1Seric pid = fork(); 375c1ac89b1Seric if (pid < 0) 376c1ac89b1Seric { 377c1ac89b1Seric goto queueonly; 378c1ac89b1Seric } 379c1ac89b1Seric else if (pid > 0) 380c1ac89b1Seric { 3810e484fe5Seric /* be sure we leave the temp files to our child */ 3820e484fe5Seric /* can't call unlockqueue to avoid unlink of xfp */ 3830e484fe5Seric if (e->e_lockfp != NULL) 384b665faabSeric (void) xfclose(e->e_lockfp, "sendenvelope lockfp", e->e_id); 3850e484fe5Seric e->e_lockfp = NULL; 3860e484fe5Seric 3870e484fe5Seric /* close any random open files in the envelope */ 3880e484fe5Seric closexscript(e); 3890e484fe5Seric if (e->e_dfp != NULL) 390b665faabSeric (void) xfclose(e->e_dfp, "sendenvelope dfp", e->e_id); 3910e484fe5Seric e->e_dfp = NULL; 392b665faabSeric e->e_id = NULL; 393b665faabSeric e->e_flags &= ~EF_HAS_DF; 3949f9b003eSeric 3959f9b003eSeric /* catch intermediate zombie */ 3969f9b003eSeric (void) waitfor(pid); 397c1ac89b1Seric return; 398c1ac89b1Seric } 399c1ac89b1Seric 400c1ac89b1Seric /* double fork to avoid zombies */ 4019f9b003eSeric pid = fork(); 4029f9b003eSeric if (pid > 0) 403c1ac89b1Seric exit(EX_OK); 404c1ac89b1Seric 405c1ac89b1Seric /* be sure we are immune from the terminal */ 4067880f3e4Seric disconnect(1, e); 407c1ac89b1Seric 4089f9b003eSeric /* prevent parent from waiting if there was an error */ 4099f9b003eSeric if (pid < 0) 4109f9b003eSeric { 4119f9b003eSeric e->e_flags |= EF_INQUEUE|EF_KEEPQUEUE; 4129f9b003eSeric finis(); 4139f9b003eSeric } 4149f9b003eSeric 415c1ac89b1Seric /* 416c1ac89b1Seric ** Close any cached connections. 417c1ac89b1Seric ** 418c1ac89b1Seric ** We don't send the QUIT protocol because the parent 419c1ac89b1Seric ** still knows about the connection. 420c1ac89b1Seric ** 421c1ac89b1Seric ** This should only happen when delivering an error 422c1ac89b1Seric ** message. 423c1ac89b1Seric */ 424c1ac89b1Seric 425c1ac89b1Seric mci_flush(FALSE, NULL); 426c1ac89b1Seric 4276b2765c6Seric # endif /* HASFLOCK */ 4286b2765c6Seric 429c1ac89b1Seric break; 430c1ac89b1Seric } 431c1ac89b1Seric 432b665faabSeric if (splitenv != NULL) 433b665faabSeric { 434b665faabSeric if (tTd(13, 1)) 435b665faabSeric { 436b665faabSeric printf("\nsendall: Split queue; remaining queue:\n"); 437b665faabSeric printaddr(e->e_sendqueue, TRUE); 438b665faabSeric } 439b665faabSeric 440b665faabSeric for (ee = splitenv; ee != NULL; ee = ee->e_sibling) 441b665faabSeric { 442b665faabSeric CurEnv = ee; 443b665faabSeric if (mode != SM_VERIFY) 444b665faabSeric openxscript(ee); 445b665faabSeric sendenvelope(ee, mode); 446b665faabSeric dropenvelope(ee); 447b665faabSeric } 448b665faabSeric 449b665faabSeric CurEnv = e; 450b665faabSeric } 451b665faabSeric sendenvelope(e, mode); 452b665faabSeric Verbose = oldverbose; 453b665faabSeric } 454b665faabSeric 455b665faabSeric void 456b665faabSeric sendenvelope(e, mode) 457b665faabSeric register ENVELOPE *e; 458b665faabSeric char mode; 459b665faabSeric { 460b665faabSeric register ADDRESS *q; 461b665faabSeric bool didany; 462b665faabSeric 463b665faabSeric /* 464b665faabSeric ** If we have had global, fatal errors, don't bother sending 465b665faabSeric ** the message at all if we are in SMTP mode. Local errors 466b665faabSeric ** (e.g., a single address failing) will still cause the other 467b665faabSeric ** addresses to be sent. 468b665faabSeric */ 469b665faabSeric 470b665faabSeric if (bitset(EF_FATALERRS, e->e_flags) && 471b665faabSeric (OpMode == MD_SMTP || OpMode == MD_DAEMON)) 472b665faabSeric { 473b665faabSeric e->e_flags |= EF_CLRQUEUE; 474b665faabSeric return; 475b665faabSeric } 476b665faabSeric 477c1ac89b1Seric /* 4789c9e68d9Seric ** Run through the list and send everything. 4795288e21aSeric ** 4805288e21aSeric ** Set EF_GLOBALERRS so that error messages during delivery 4815288e21aSeric ** result in returned mail. 4829c9e68d9Seric */ 4839c9e68d9Seric 4849c9e68d9Seric e->e_nsent = 0; 4855288e21aSeric e->e_flags |= EF_GLOBALERRS; 486b665faabSeric didany = FALSE; 487faad2b16Seric 488faad2b16Seric /* now run through the queue */ 4899c9e68d9Seric for (q = e->e_sendqueue; q != NULL; q = q->q_next) 4909c9e68d9Seric { 491*86aab53cSeric #if XDEBUG 492fdc75a0fSeric char wbuf[MAXNAME + 20]; 493fdc75a0fSeric 494fdc75a0fSeric (void) sprintf(wbuf, "sendall(%s)", q->q_paddr); 495fdc75a0fSeric checkfd012(wbuf); 496fdc75a0fSeric #endif 4979c9e68d9Seric if (mode == SM_VERIFY) 4989c9e68d9Seric { 4999c9e68d9Seric e->e_to = q->q_paddr; 5009c9e68d9Seric if (!bitset(QDONTSEND|QBADADDR, q->q_flags)) 5018dfca105Seric { 502fafe46e1Seric if (q->q_host != NULL && q->q_host[0] != '\0') 5038dfca105Seric message("deliverable: mailer %s, host %s, user %s", 5048dfca105Seric q->q_mailer->m_name, 5058dfca105Seric q->q_host, 5068dfca105Seric q->q_user); 507fafe46e1Seric else 508fafe46e1Seric message("deliverable: mailer %s, user %s", 509fafe46e1Seric q->q_mailer->m_name, 510fafe46e1Seric q->q_user); 5118dfca105Seric } 5129c9e68d9Seric } 5139c9e68d9Seric else if (!bitset(QDONTSEND|QBADADDR, q->q_flags)) 5149c9e68d9Seric { 5159c9e68d9Seric # ifdef QUEUE 5169c9e68d9Seric /* 5179c9e68d9Seric ** Checkpoint the send list every few addresses 5189c9e68d9Seric */ 5199c9e68d9Seric 5209c9e68d9Seric if (e->e_nsent >= CheckpointInterval) 5219c9e68d9Seric { 5229c9e68d9Seric queueup(e, TRUE, FALSE); 5239c9e68d9Seric e->e_nsent = 0; 5249c9e68d9Seric } 5259c9e68d9Seric # endif /* QUEUE */ 5269c9e68d9Seric (void) deliver(e, q); 527b665faabSeric didany = TRUE; 5289c9e68d9Seric } 5299c9e68d9Seric } 530b665faabSeric if (didany) 531b665faabSeric { 532b665faabSeric e->e_dtime = curtime(); 533b665faabSeric e->e_ntries++; 534b665faabSeric } 5359c9e68d9Seric 536*86aab53cSeric #if XDEBUG 537fdc75a0fSeric checkfd012("end of sendenvelope"); 538fdc75a0fSeric #endif 539fdc75a0fSeric 5409c9e68d9Seric if (mode == SM_FORK) 5419c9e68d9Seric finis(); 5429c9e68d9Seric } 5439c9e68d9Seric /* 5449c9e68d9Seric ** DOFORK -- do a fork, retrying a couple of times on failure. 5459c9e68d9Seric ** 5469c9e68d9Seric ** This MUST be a macro, since after a vfork we are running 5479c9e68d9Seric ** two processes on the same stack!!! 5489c9e68d9Seric ** 5499c9e68d9Seric ** Parameters: 5509c9e68d9Seric ** none. 5519c9e68d9Seric ** 5529c9e68d9Seric ** Returns: 5539c9e68d9Seric ** From a macro??? You've got to be kidding! 5549c9e68d9Seric ** 5559c9e68d9Seric ** Side Effects: 5569c9e68d9Seric ** Modifies the ==> LOCAL <== variable 'pid', leaving: 5579c9e68d9Seric ** pid of child in parent, zero in child. 5589c9e68d9Seric ** -1 on unrecoverable error. 5599c9e68d9Seric ** 5609c9e68d9Seric ** Notes: 5619c9e68d9Seric ** I'm awfully sorry this looks so awful. That's 5629c9e68d9Seric ** vfork for you..... 5639c9e68d9Seric */ 5649c9e68d9Seric 5659c9e68d9Seric # define NFORKTRIES 5 5669c9e68d9Seric 5679c9e68d9Seric # ifndef FORK 5689c9e68d9Seric # define FORK fork 5699c9e68d9Seric # endif 5709c9e68d9Seric 5719c9e68d9Seric # define DOFORK(fORKfN) \ 5729c9e68d9Seric {\ 5739c9e68d9Seric register int i;\ 5749c9e68d9Seric \ 5759c9e68d9Seric for (i = NFORKTRIES; --i >= 0; )\ 5769c9e68d9Seric {\ 5779c9e68d9Seric pid = fORKfN();\ 5789c9e68d9Seric if (pid >= 0)\ 5799c9e68d9Seric break;\ 5809c9e68d9Seric if (i > 0)\ 5819c9e68d9Seric sleep((unsigned) NFORKTRIES - i);\ 5829c9e68d9Seric }\ 5839c9e68d9Seric } 5849c9e68d9Seric /* 5859c9e68d9Seric ** DOFORK -- simple fork interface to DOFORK. 5869c9e68d9Seric ** 5879c9e68d9Seric ** Parameters: 5889c9e68d9Seric ** none. 5899c9e68d9Seric ** 5909c9e68d9Seric ** Returns: 5919c9e68d9Seric ** pid of child in parent. 5929c9e68d9Seric ** zero in child. 5939c9e68d9Seric ** -1 on error. 5949c9e68d9Seric ** 5959c9e68d9Seric ** Side Effects: 5969c9e68d9Seric ** returns twice, once in parent and once in child. 5979c9e68d9Seric */ 5989c9e68d9Seric 599a6a073b5Seric int 6009c9e68d9Seric dofork() 6019c9e68d9Seric { 602b665faabSeric register int pid = -1; 6039c9e68d9Seric 6049c9e68d9Seric DOFORK(fork); 6059c9e68d9Seric return (pid); 6069c9e68d9Seric } 6079c9e68d9Seric /* 60813bbc08cSeric ** DELIVER -- Deliver a message to a list of addresses. 60913bbc08cSeric ** 61013bbc08cSeric ** This routine delivers to everyone on the same host as the 61113bbc08cSeric ** user on the head of the list. It is clever about mailers 61213bbc08cSeric ** that don't handle multiple users. It is NOT guaranteed 61313bbc08cSeric ** that it will deliver to all these addresses however -- so 61413bbc08cSeric ** deliver should be called once for each address on the 61513bbc08cSeric ** list. 61625a99e2eSeric ** 61725a99e2eSeric ** Parameters: 618588cad61Seric ** e -- the envelope to deliver. 619c77d1c25Seric ** firstto -- head of the address list to deliver to. 62025a99e2eSeric ** 62125a99e2eSeric ** Returns: 62225a99e2eSeric ** zero -- successfully delivered. 62325a99e2eSeric ** else -- some failure, see ExitStat for more info. 62425a99e2eSeric ** 62525a99e2eSeric ** Side Effects: 62625a99e2eSeric ** The standard input is passed off to someone. 62725a99e2eSeric */ 62825a99e2eSeric 629b665faabSeric int 630588cad61Seric deliver(e, firstto) 631588cad61Seric register ENVELOPE *e; 632c77d1c25Seric ADDRESS *firstto; 63325a99e2eSeric { 63478442df3Seric char *host; /* host being sent to */ 63578442df3Seric char *user; /* user being sent to */ 63625a99e2eSeric char **pvp; 6375dfc646bSeric register char **mvp; 63825a99e2eSeric register char *p; 639588cad61Seric register MAILER *m; /* mailer for this recipient */ 6406259796dSeric ADDRESS *ctladdr; 641b31e7f2bSeric register MCI *mci; 642c77d1c25Seric register ADDRESS *to = firstto; 643c579ef51Seric bool clever = FALSE; /* running user smtp to this mailer */ 644b665faabSeric ADDRESS *tochain = NULL; /* users chain in this mailer call */ 645911693bfSbostic int rcode; /* response code */ 646e103b48fSeric char *firstsig; /* signature of firstto */ 647b665faabSeric int pid = -1; 6489c9e68d9Seric char *curhost; 649b665faabSeric time_t xstart; 6509c9e68d9Seric int mpvect[2]; 6519c9e68d9Seric int rpvect[2]; 652ee6bf8dfSeric char *pv[MAXPV+1]; 653579ef0ddSeric char tobuf[TOBUFSIZE]; /* text line of to people */ 654b665faabSeric char buf[MAXNAME + 1]; 655b665faabSeric char rpathbuf[MAXNAME + 1]; /* translated return path */ 656fabb3bd4Seric extern int checkcompat(); 657a6a073b5Seric extern void markfailure __P((ENVELOPE *, ADDRESS *, MCI *, int)); 65825a99e2eSeric 65935490626Seric errno = 0; 660ee4b0922Seric if (bitset(QDONTSEND|QBADADDR|QQUEUEUP, to->q_flags)) 6615dfc646bSeric return (0); 66225a99e2eSeric 6639d4a8008Seric #if NAMED_BIND 664912a731aSbostic /* unless interactive, try twice, over a minute */ 6658d19a23dSeric if (OpMode == MD_DAEMON || OpMode == MD_SMTP) 6668d19a23dSeric { 667912a731aSbostic _res.retrans = 30; 668912a731aSbostic _res.retry = 2; 669912a731aSbostic } 670d4bd8f0eSbostic #endif 671912a731aSbostic 67251552439Seric m = to->q_mailer; 67351552439Seric host = to->q_host; 674c9be6216Seric CurEnv = e; /* just in case */ 6754384d521Seric e->e_statmsg = NULL; 676df106f0bSeric SmtpError[0] = '\0'; 677b665faabSeric xstart = curtime(); 67851552439Seric 6796ef48975Seric if (tTd(10, 1)) 680562ec147Seric printf("\n--deliver, id=%s, mailer=%s, host=`%s', first user=`%s'\n", 681562ec147Seric e->e_id, m->m_name, host, to->q_user); 682ab81ee53Seric if (tTd(10, 100)) 683ab81ee53Seric printopenfds(FALSE); 684f3dbc832Seric 685f3dbc832Seric /* 6865dfc646bSeric ** Do initial argv setup. 6875dfc646bSeric ** Insert the mailer name. Notice that $x expansion is 6885dfc646bSeric ** NOT done on the mailer name. Then, if the mailer has 6895dfc646bSeric ** a picky -f flag, we insert it as appropriate. This 6905dfc646bSeric ** code does not check for 'pv' overflow; this places a 6915dfc646bSeric ** manifest lower limit of 4 for MAXPV. 6923bea8136Seric ** The from address rewrite is expected to make 6933bea8136Seric ** the address relative to the other end. 6945dfc646bSeric */ 6955dfc646bSeric 69678442df3Seric /* rewrite from address, using rewriting rules */ 697efe54562Seric rcode = EX_OK; 698b665faabSeric if (bitnset(M_UDBENVELOPE, e->e_from.q_mailer->m_flags)) 699b665faabSeric p = e->e_sender; 700b665faabSeric else 701b665faabSeric p = e->e_from.q_paddr; 702b665faabSeric (void) strcpy(rpathbuf, remotename(p, m, 703efe54562Seric RF_SENDERADDR|RF_CANONICAL, 704efe54562Seric &rcode, e)); 705ee4b0922Seric define('g', rpathbuf, e); /* translated return path */ 706588cad61Seric define('h', host, e); /* to host */ 7075dfc646bSeric Errors = 0; 7085dfc646bSeric pvp = pv; 7095dfc646bSeric *pvp++ = m->m_argv[0]; 7105dfc646bSeric 7115dfc646bSeric /* insert -f or -r flag as appropriate */ 71257fc6f17Seric if (FromFlag && (bitnset(M_FOPT, m->m_flags) || bitnset(M_ROPT, m->m_flags))) 7135dfc646bSeric { 71457fc6f17Seric if (bitnset(M_FOPT, m->m_flags)) 7155dfc646bSeric *pvp++ = "-f"; 7165dfc646bSeric else 7175dfc646bSeric *pvp++ = "-r"; 718c23ed322Seric *pvp++ = newstr(rpathbuf); 7195dfc646bSeric } 7205dfc646bSeric 7215dfc646bSeric /* 7225dfc646bSeric ** Append the other fixed parts of the argv. These run 7235dfc646bSeric ** up to the first entry containing "$u". There can only 7245dfc646bSeric ** be one of these, and there are only a few more slots 7255dfc646bSeric ** in the pv after it. 7265dfc646bSeric */ 7275dfc646bSeric 7285dfc646bSeric for (mvp = m->m_argv; (p = *++mvp) != NULL; ) 7295dfc646bSeric { 7302bc47524Seric /* can't use strchr here because of sign extension problems */ 7312bc47524Seric while (*p != '\0') 7322bc47524Seric { 7332bc47524Seric if ((*p++ & 0377) == MACROEXPAND) 7342bc47524Seric { 7352bc47524Seric if (*p == 'u') 7365dfc646bSeric break; 7372bc47524Seric } 7382bc47524Seric } 7392bc47524Seric 7402bc47524Seric if (*p != '\0') 7415dfc646bSeric break; 7425dfc646bSeric 7435dfc646bSeric /* this entry is safe -- go ahead and process it */ 744b665faabSeric expand(*mvp, buf, sizeof buf, e); 7455dfc646bSeric *pvp++ = newstr(buf); 7465dfc646bSeric if (pvp >= &pv[MAXPV - 3]) 7475dfc646bSeric { 74808b25121Seric syserr("554 Too many parameters to %s before $u", pv[0]); 7495dfc646bSeric return (-1); 7505dfc646bSeric } 7515dfc646bSeric } 752c579ef51Seric 75333db8731Seric /* 75433db8731Seric ** If we have no substitution for the user name in the argument 75533db8731Seric ** list, we know that we must supply the names otherwise -- and 75633db8731Seric ** SMTP is the answer!! 75733db8731Seric */ 75833db8731Seric 7595dfc646bSeric if (*mvp == NULL) 760c579ef51Seric { 761c579ef51Seric /* running SMTP */ 7622c7e1b8dSeric # ifdef SMTP 763c579ef51Seric clever = TRUE; 764c579ef51Seric *pvp = NULL; 7656c2c3107Seric # else /* SMTP */ 76633db8731Seric /* oops! we don't implement SMTP */ 767df106f0bSeric syserr("554 SMTP style mailer not implemented"); 7682c7e1b8dSeric return (EX_SOFTWARE); 7696c2c3107Seric # endif /* SMTP */ 770c579ef51Seric } 7715dfc646bSeric 7725dfc646bSeric /* 7735dfc646bSeric ** At this point *mvp points to the argument with $u. We 7745dfc646bSeric ** run through our address list and append all the addresses 7755dfc646bSeric ** we can. If we run out of space, do not fret! We can 7765dfc646bSeric ** always send another copy later. 7775dfc646bSeric */ 7785dfc646bSeric 7795dfc646bSeric tobuf[0] = '\0'; 780588cad61Seric e->e_to = tobuf; 7816259796dSeric ctladdr = NULL; 782e103b48fSeric firstsig = hostsignature(firstto->q_mailer, firstto->q_host, e); 7835dfc646bSeric for (; to != NULL; to = to->q_next) 7845dfc646bSeric { 7855dfc646bSeric /* avoid sending multiple recipients to dumb mailers */ 78657fc6f17Seric if (tobuf[0] != '\0' && !bitnset(M_MUSER, m->m_flags)) 7875dfc646bSeric break; 7885dfc646bSeric 7895dfc646bSeric /* if already sent or not for this host, don't send */ 790ee4b0922Seric if (bitset(QDONTSEND|QBADADDR|QQUEUEUP, to->q_flags) || 791e103b48fSeric to->q_mailer != firstto->q_mailer || 792e103b48fSeric strcmp(hostsignature(to->q_mailer, to->q_host, e), firstsig) != 0) 7935dfc646bSeric continue; 7946259796dSeric 7954b22ea87Seric /* avoid overflowing tobuf */ 796aa50a568Sbostic if (sizeof tobuf < (strlen(to->q_paddr) + strlen(tobuf) + 2)) 7974b22ea87Seric break; 7984b22ea87Seric 7996ef48975Seric if (tTd(10, 1)) 800772e6e50Seric { 801772e6e50Seric printf("\nsend to "); 802772e6e50Seric printaddr(to, FALSE); 803772e6e50Seric } 804772e6e50Seric 8056259796dSeric /* compute effective uid/gid when sending */ 806b665faabSeric if (bitnset(M_RUNASRCPT, to->q_mailer->m_flags)) 8076259796dSeric ctladdr = getctladdr(to); 8086259796dSeric 809b665faabSeric if (tTd(10, 2)) 810b665faabSeric { 811b665faabSeric printf("ctladdr="); 812b665faabSeric printaddr(ctladdr, FALSE); 813b665faabSeric } 814b665faabSeric 8155dfc646bSeric user = to->q_user; 816588cad61Seric e->e_to = to->q_paddr; 81775f1ade9Seric if (tTd(10, 5)) 81875f1ade9Seric { 81975f1ade9Seric printf("deliver: QDONTSEND "); 82075f1ade9Seric printaddr(to, FALSE); 82175f1ade9Seric } 822ee4b0922Seric to->q_flags |= QDONTSEND; 8235dfc646bSeric 8245dfc646bSeric /* 8255dfc646bSeric ** Check to see that these people are allowed to 8265dfc646bSeric ** talk to each other. 8272a6e0786Seric */ 8282a6e0786Seric 82969582d2fSeric if (m->m_maxsize != 0 && e->e_msgsize > m->m_maxsize) 83069582d2fSeric { 831b665faabSeric e->e_flags |= EF_NO_BODY_RETN; 832a6a073b5Seric to->q_status = "5.2.3"; 83308b25121Seric usrerr("552 Message is too large; %ld bytes max", m->m_maxsize); 834b665faabSeric giveresponse(EX_UNAVAILABLE, m, NULL, ctladdr, xstart, e); 83569582d2fSeric continue; 83669582d2fSeric } 837b665faabSeric #if NAMED_BIND 838b665faabSeric h_errno = 0; 839b665faabSeric #endif 840fabb3bd4Seric rcode = checkcompat(to, e); 8411793c9c5Seric if (rcode != EX_OK) 8425dfc646bSeric { 843b665faabSeric markfailure(e, to, NULL, rcode); 844b665faabSeric giveresponse(rcode, m, NULL, ctladdr, xstart, e); 8455dfc646bSeric continue; 8465dfc646bSeric } 8472a6e0786Seric 8482a6e0786Seric /* 8499ec9501bSeric ** Strip quote bits from names if the mailer is dumb 8509ec9501bSeric ** about them. 85125a99e2eSeric */ 85225a99e2eSeric 85357fc6f17Seric if (bitnset(M_STRIPQ, m->m_flags)) 85425a99e2eSeric { 8551d8f1806Seric stripquotes(user); 8561d8f1806Seric stripquotes(host); 85725a99e2eSeric } 85825a99e2eSeric 859cdb828c5Seric /* hack attack -- delivermail compatibility */ 860cdb828c5Seric if (m == ProgMailer && *user == '|') 861cdb828c5Seric user++; 862cdb828c5Seric 86325a99e2eSeric /* 8643efaed6eSeric ** If an error message has already been given, don't 8653efaed6eSeric ** bother to send to this address. 8663efaed6eSeric ** 8673efaed6eSeric ** >>>>>>>>>> This clause assumes that the local mailer 8683efaed6eSeric ** >> NOTE >> cannot do any further aliasing; that 8693efaed6eSeric ** >>>>>>>>>> function is subsumed by sendmail. 8703efaed6eSeric */ 8713efaed6eSeric 8726cae517dSeric if (bitset(QBADADDR|QQUEUEUP, to->q_flags)) 8733efaed6eSeric continue; 8743efaed6eSeric 875f2fec898Seric /* save statistics.... */ 876588cad61Seric markstats(e, to); 877f2fec898Seric 8783efaed6eSeric /* 87925a99e2eSeric ** See if this user name is "special". 88025a99e2eSeric ** If the user name has a slash in it, assume that this 88151552439Seric ** is a file -- send it off without further ado. Note 88251552439Seric ** that this type of addresses is not processed along 88351552439Seric ** with the others, so we fudge on the To person. 88425a99e2eSeric */ 88525a99e2eSeric 88623a75c08Seric if (strcmp(m->m_mailer, "[FILE]") == 0) 88725a99e2eSeric { 88804a36717Seric rcode = mailfile(user, ctladdr, SFF_CREAT, e); 889b665faabSeric giveresponse(rcode, m, NULL, ctladdr, xstart, e); 890b665faabSeric e->e_nsent++; 891dde5acadSeric if (rcode == EX_OK) 892b665faabSeric { 893dde5acadSeric to->q_flags |= QSENT; 894b665faabSeric if (bitnset(M_LOCALMAILER, m->m_flags) && 895b665faabSeric (e->e_receiptto != NULL || 896b665faabSeric bitset(QPINGONSUCCESS, to->q_flags))) 897b665faabSeric { 8989070d157Seric to->q_flags |= QDELIVERED; 899d95dad3eSeric to->q_status = "2.1.5"; 900b665faabSeric fprintf(e->e_xfp, "%s... Successfully delivered\n", 901b665faabSeric to->q_paddr); 902b665faabSeric } 903b665faabSeric } 904b665faabSeric to->q_statdate = curtime(); 9055dfc646bSeric continue; 90625a99e2eSeric } 90725a99e2eSeric 90813bbc08cSeric /* 90913bbc08cSeric ** Address is verified -- add this user to mailer 91013bbc08cSeric ** argv, and add it to the print list of recipients. 91113bbc08cSeric */ 91213bbc08cSeric 913508daeccSeric /* link together the chain of recipients */ 914508daeccSeric to->q_tchain = tochain; 915508daeccSeric tochain = to; 916508daeccSeric 9175dfc646bSeric /* create list of users for error messages */ 918db8841e9Seric (void) strcat(tobuf, ","); 919db8841e9Seric (void) strcat(tobuf, to->q_paddr); 920588cad61Seric define('u', user, e); /* to user */ 921b6f89e6eSeric p = to->q_home; 922b6f89e6eSeric if (p == NULL && ctladdr != NULL) 923b6f89e6eSeric p = ctladdr->q_home; 924b6f89e6eSeric define('z', p, e); /* user's home */ 9255dfc646bSeric 926c579ef51Seric /* 927508daeccSeric ** Expand out this user into argument list. 928c579ef51Seric */ 929c579ef51Seric 930508daeccSeric if (!clever) 931c579ef51Seric { 932b665faabSeric expand(*mvp, buf, sizeof buf, e); 9335dfc646bSeric *pvp++ = newstr(buf); 9345dfc646bSeric if (pvp >= &pv[MAXPV - 2]) 9355dfc646bSeric { 9365dfc646bSeric /* allow some space for trailing parms */ 9375dfc646bSeric break; 9385dfc646bSeric } 9395dfc646bSeric } 940c579ef51Seric } 9415dfc646bSeric 942145b49b1Seric /* see if any addresses still exist */ 943145b49b1Seric if (tobuf[0] == '\0') 944c579ef51Seric { 945588cad61Seric define('g', (char *) NULL, e); 946145b49b1Seric return (0); 947c579ef51Seric } 948145b49b1Seric 9495dfc646bSeric /* print out messages as full list */ 95063780dbdSeric e->e_to = tobuf + 1; 9515dfc646bSeric 9525dfc646bSeric /* 9535dfc646bSeric ** Fill out any parameters after the $u parameter. 9545dfc646bSeric */ 9555dfc646bSeric 956c579ef51Seric while (!clever && *++mvp != NULL) 9575dfc646bSeric { 958b665faabSeric expand(*mvp, buf, sizeof buf, e); 9595dfc646bSeric *pvp++ = newstr(buf); 9605dfc646bSeric if (pvp >= &pv[MAXPV]) 96108b25121Seric syserr("554 deliver: pv overflow after $u for %s", pv[0]); 9625dfc646bSeric } 9635dfc646bSeric *pvp++ = NULL; 9645dfc646bSeric 96525a99e2eSeric /* 96625a99e2eSeric ** Call the mailer. 9676328bdf7Seric ** The argument vector gets built, pipes 96825a99e2eSeric ** are created as necessary, and we fork & exec as 9696328bdf7Seric ** appropriate. 970c579ef51Seric ** If we are running SMTP, we just need to clean up. 97125a99e2eSeric */ 97225a99e2eSeric 973960e665aSeric /*XXX this seems a bit wierd */ 974c875d42bSeric if (ctladdr == NULL && m != ProgMailer && m != FileMailer && 9754899f6b5Seric bitset(QGOODUID, e->e_from.q_flags)) 976960e665aSeric ctladdr = &e->e_from; 977960e665aSeric 9789d4a8008Seric #if NAMED_BIND 9792bcc6d2dSeric if (ConfigLevel < 2) 980912a731aSbostic _res.options &= ~(RES_DEFNAMES | RES_DNSRCH); /* XXX */ 981134746fbSeric #endif 9829c9e68d9Seric 9839c9e68d9Seric if (tTd(11, 1)) 984134746fbSeric { 9859c9e68d9Seric printf("openmailer:"); 9869c9e68d9Seric printav(pv); 9879c9e68d9Seric } 9889c9e68d9Seric errno = 0; 989b665faabSeric #if NAMED_BIND 990b665faabSeric h_errno = 0; 991b665faabSeric #endif 9929c9e68d9Seric 993b665faabSeric CurHostName = NULL; 9949c9e68d9Seric 9959c9e68d9Seric /* 9969c9e68d9Seric ** Deal with the special case of mail handled through an IPC 9979c9e68d9Seric ** connection. 9989c9e68d9Seric ** In this case we don't actually fork. We must be 9999c9e68d9Seric ** running SMTP for this to work. We will return a 10009c9e68d9Seric ** zero pid to indicate that we are running IPC. 10019c9e68d9Seric ** We also handle a debug version that just talks to stdin/out. 10029c9e68d9Seric */ 10039c9e68d9Seric 10049c9e68d9Seric curhost = NULL; 1005c931b82bSeric SmtpPhase = NULL; 1006df106f0bSeric mci = NULL; 10079c9e68d9Seric 1008*86aab53cSeric #if XDEBUG 10097febfd66Seric { 10107febfd66Seric char wbuf[MAXLINE]; 10117febfd66Seric 10127febfd66Seric /* make absolutely certain 0, 1, and 2 are in use */ 10137febfd66Seric sprintf(wbuf, "%s... openmailer(%s)", e->e_to, m->m_name); 10147febfd66Seric checkfd012(wbuf); 10157febfd66Seric } 10167febfd66Seric #endif 10177febfd66Seric 1018b665faabSeric /* check for 8-bit available */ 1019b665faabSeric if (bitset(EF_HAS8BIT, e->e_flags) && 1020b665faabSeric bitnset(M_7BITS, m->m_flags) && 1021b665faabSeric !bitset(MM_MIME8BIT, MimeMode)) 1022b665faabSeric { 1023b665faabSeric usrerr("554 Cannot send 8-bit data to 7-bit destination"); 1024b665faabSeric rcode = EX_DATAERR; 10255b068d51Seric e->e_status = "5.6.3"; 1026b665faabSeric goto give_up; 1027b665faabSeric } 1028b665faabSeric 10299c9e68d9Seric /* check for Local Person Communication -- not for mortals!!! */ 10309c9e68d9Seric if (strcmp(m->m_mailer, "[LPC]") == 0) 10319c9e68d9Seric { 10329c9e68d9Seric mci = (MCI *) xalloc(sizeof *mci); 10339c9e68d9Seric bzero((char *) mci, sizeof *mci); 10349c9e68d9Seric mci->mci_in = stdin; 10359c9e68d9Seric mci->mci_out = stdout; 10369c9e68d9Seric mci->mci_state = clever ? MCIS_OPENING : MCIS_OPEN; 10379c9e68d9Seric mci->mci_mailer = m; 10389c9e68d9Seric } 10399c9e68d9Seric else if (strcmp(m->m_mailer, "[IPC]") == 0 || 10409c9e68d9Seric strcmp(m->m_mailer, "[TCP]") == 0) 10419c9e68d9Seric { 10429c9e68d9Seric #ifdef DAEMON 10439c9e68d9Seric register int i; 1044b665faabSeric register u_short port = 0; 10459c9e68d9Seric 1046a5d44642Seric if (pv[0] == NULL || pv[1] == NULL || pv[1][0] == '\0') 1047a5d44642Seric { 1048a5d44642Seric syserr("null host name for %s mailer", m->m_mailer); 1049a5d44642Seric rcode = EX_CONFIG; 1050a5d44642Seric goto give_up; 1051a5d44642Seric } 1052a5d44642Seric 10539c9e68d9Seric CurHostName = pv[1]; 10549c9e68d9Seric curhost = hostsignature(m, pv[1], e); 10559c9e68d9Seric 10569c9e68d9Seric if (curhost == NULL || curhost[0] == '\0') 10579c9e68d9Seric { 1058a5d44642Seric syserr("null host signature for %s", pv[1]); 1059dfebe401Seric rcode = EX_CONFIG; 1060b31e7f2bSeric goto give_up; 1061b31e7f2bSeric } 10629c9e68d9Seric 10639c9e68d9Seric if (!clever) 10649c9e68d9Seric { 10659c9e68d9Seric syserr("554 non-clever IPC"); 1066df106f0bSeric rcode = EX_CONFIG; 10679c9e68d9Seric goto give_up; 10689c9e68d9Seric } 10699c9e68d9Seric if (pv[2] != NULL) 10700784fccbSeric { 10710784fccbSeric port = htons(atoi(pv[2])); 10720784fccbSeric if (port == 0) 10730784fccbSeric { 10740784fccbSeric struct servent *sp = getservbyname(pv[2], "tcp"); 10750784fccbSeric 10760784fccbSeric if (sp == NULL) 10770784fccbSeric syserr("Service %s unknown", pv[2]); 10780784fccbSeric else 10790784fccbSeric port = sp->s_port; 10800784fccbSeric } 10810784fccbSeric } 10829c9e68d9Seric tryhost: 10839c9e68d9Seric while (*curhost != '\0') 10849c9e68d9Seric { 10859c9e68d9Seric register char *p; 1086b665faabSeric static char hostbuf[MAXNAME + 1]; 10879c9e68d9Seric 10889c9e68d9Seric /* pull the next host from the signature */ 10899c9e68d9Seric p = strchr(curhost, ':'); 10909c9e68d9Seric if (p == NULL) 10919c9e68d9Seric p = &curhost[strlen(curhost)]; 1092df106f0bSeric if (p == curhost) 1093df106f0bSeric { 1094df106f0bSeric syserr("deliver: null host name in signature"); 10958087428aSeric curhost++; 1096df106f0bSeric continue; 1097df106f0bSeric } 10989c9e68d9Seric strncpy(hostbuf, curhost, p - curhost); 10999c9e68d9Seric hostbuf[p - curhost] = '\0'; 11009c9e68d9Seric if (*p != '\0') 11019c9e68d9Seric p++; 11029c9e68d9Seric curhost = p; 11039c9e68d9Seric 11049c9e68d9Seric /* see if we already know that this host is fried */ 11059c9e68d9Seric CurHostName = hostbuf; 11069c9e68d9Seric mci = mci_get(hostbuf, m); 11079c9e68d9Seric if (mci->mci_state != MCIS_CLOSED) 11089c9e68d9Seric { 11099c9e68d9Seric if (tTd(11, 1)) 11109c9e68d9Seric { 11119c9e68d9Seric printf("openmailer: "); 11124052916eSeric mci_dump(mci, FALSE); 11139c9e68d9Seric } 11149c9e68d9Seric CurHostName = mci->mci_host; 1115b665faabSeric message("Using cached connection to %s via %s...", 1116b665faabSeric hostbuf, m->m_name); 11179c9e68d9Seric break; 11189c9e68d9Seric } 11199c9e68d9Seric mci->mci_mailer = m; 11209c9e68d9Seric if (mci->mci_exitstat != EX_OK) 11219c9e68d9Seric continue; 11229c9e68d9Seric 11239c9e68d9Seric /* try the connection */ 11249c9e68d9Seric setproctitle("%s %s: %s", e->e_id, hostbuf, "user open"); 1125b665faabSeric message("Connecting to %s via %s...", 11269c9e68d9Seric hostbuf, m->m_name); 11279c9e68d9Seric i = makeconnection(hostbuf, port, mci, 11289c9e68d9Seric bitnset(M_SECURE_PORT, m->m_flags)); 11299c9e68d9Seric mci->mci_exitstat = i; 11309c9e68d9Seric mci->mci_errno = errno; 11319d4a8008Seric #if NAMED_BIND 1132f170942cSeric mci->mci_herrno = h_errno; 1133f170942cSeric #endif 11349c9e68d9Seric if (i == EX_OK) 11359c9e68d9Seric { 11369c9e68d9Seric mci->mci_state = MCIS_OPENING; 11379c9e68d9Seric mci_cache(mci); 1138f170942cSeric if (TrafficLogFile != NULL) 1139f170942cSeric fprintf(TrafficLogFile, "%05d == CONNECT %s\n", 1140f170942cSeric getpid(), hostbuf); 11419c9e68d9Seric break; 11429c9e68d9Seric } 11439c9e68d9Seric else if (tTd(11, 1)) 11449c9e68d9Seric printf("openmailer: makeconnection => stat=%d, errno=%d\n", 11459c9e68d9Seric i, errno); 11469c9e68d9Seric 11479c9e68d9Seric /* enter status of this host */ 11489c9e68d9Seric setstat(i); 1149df106f0bSeric 1150df106f0bSeric /* should print some message here for -v mode */ 1151df106f0bSeric } 1152df106f0bSeric if (mci == NULL) 1153df106f0bSeric { 1154df106f0bSeric syserr("deliver: no host name"); 1155df106f0bSeric rcode = EX_OSERR; 1156df106f0bSeric goto give_up; 11579c9e68d9Seric } 11589c9e68d9Seric mci->mci_pid = 0; 11599c9e68d9Seric #else /* no DAEMON */ 11609c9e68d9Seric syserr("554 openmailer: no IPC"); 11619c9e68d9Seric if (tTd(11, 1)) 11629c9e68d9Seric printf("openmailer: NULL\n"); 1163df106f0bSeric rcode = EX_UNAVAILABLE; 1164df106f0bSeric goto give_up; 11659c9e68d9Seric #endif /* DAEMON */ 11669c9e68d9Seric } 11679c9e68d9Seric else 11689c9e68d9Seric { 1169b665faabSeric /* flush any expired connections */ 1170b665faabSeric (void) mci_scan(NULL); 1171b665faabSeric 1172b665faabSeric /* announce the connection to verbose listeners */ 1173b665faabSeric if (host == NULL || host[0] == '\0') 1174b665faabSeric message("Connecting to %s...", m->m_name); 1175b665faabSeric else 1176b665faabSeric message("Connecting to %s via %s...", host, m->m_name); 1177f170942cSeric if (TrafficLogFile != NULL) 11780e3bfef5Seric { 1179f170942cSeric char **av; 1180f170942cSeric 1181f170942cSeric fprintf(TrafficLogFile, "%05d === EXEC", getpid()); 1182f170942cSeric for (av = pv; *av != NULL; av++) 1183f170942cSeric fprintf(TrafficLogFile, " %s", *av); 1184f170942cSeric fprintf(TrafficLogFile, "\n"); 11856fe8c3bcSeric } 11866fe8c3bcSeric 11879c9e68d9Seric /* create a pipe to shove the mail through */ 11889c9e68d9Seric if (pipe(mpvect) < 0) 11899c9e68d9Seric { 11900e3bfef5Seric syserr("%s... openmailer(%s): pipe (to mailer)", 11910e3bfef5Seric e->e_to, m->m_name); 11929c9e68d9Seric if (tTd(11, 1)) 11939c9e68d9Seric printf("openmailer: NULL\n"); 11949c9e68d9Seric rcode = EX_OSERR; 11959c9e68d9Seric goto give_up; 11969c9e68d9Seric } 11979c9e68d9Seric 11989c9e68d9Seric /* if this mailer speaks smtp, create a return pipe */ 11999c9e68d9Seric if (clever && pipe(rpvect) < 0) 12009c9e68d9Seric { 12010e3bfef5Seric syserr("%s... openmailer(%s): pipe (from mailer)", 12020e3bfef5Seric e->e_to, m->m_name); 12039c9e68d9Seric (void) close(mpvect[0]); 12049c9e68d9Seric (void) close(mpvect[1]); 12059c9e68d9Seric if (tTd(11, 1)) 12069c9e68d9Seric printf("openmailer: NULL\n"); 12079c9e68d9Seric rcode = EX_OSERR; 12089c9e68d9Seric goto give_up; 12099c9e68d9Seric } 12109c9e68d9Seric 12119c9e68d9Seric /* 12129c9e68d9Seric ** Actually fork the mailer process. 12139c9e68d9Seric ** DOFORK is clever about retrying. 12149c9e68d9Seric ** 12159c9e68d9Seric ** Dispose of SIGCHLD signal catchers that may be laying 12169c9e68d9Seric ** around so that endmail will get it. 12179c9e68d9Seric */ 12189c9e68d9Seric 12199c9e68d9Seric if (e->e_xfp != NULL) 12209c9e68d9Seric (void) fflush(e->e_xfp); /* for debugging */ 12219c9e68d9Seric (void) fflush(stdout); 12229c9e68d9Seric # ifdef SIGCHLD 12232b9178d3Seric (void) setsignal(SIGCHLD, SIG_DFL); 12249c9e68d9Seric # endif /* SIGCHLD */ 12259c9e68d9Seric DOFORK(FORK); 12269c9e68d9Seric /* pid is set by DOFORK */ 12279c9e68d9Seric if (pid < 0) 12289c9e68d9Seric { 12299c9e68d9Seric /* failure */ 12300e3bfef5Seric syserr("%s... openmailer(%s): cannot fork", 12310e3bfef5Seric e->e_to, m->m_name); 12329c9e68d9Seric (void) close(mpvect[0]); 12339c9e68d9Seric (void) close(mpvect[1]); 12349c9e68d9Seric if (clever) 12359c9e68d9Seric { 12369c9e68d9Seric (void) close(rpvect[0]); 12379c9e68d9Seric (void) close(rpvect[1]); 12389c9e68d9Seric } 12399c9e68d9Seric if (tTd(11, 1)) 12409c9e68d9Seric printf("openmailer: NULL\n"); 12419c9e68d9Seric rcode = EX_OSERR; 12429c9e68d9Seric goto give_up; 12439c9e68d9Seric } 12449c9e68d9Seric else if (pid == 0) 12459c9e68d9Seric { 12469c9e68d9Seric int i; 12479c9e68d9Seric int saveerrno; 1248f24c4f81Seric struct stat stb; 12499c9e68d9Seric extern int DtableSize; 12509c9e68d9Seric 1251f2e4d5e8Seric if (e->e_lockfp != NULL) 1252ac5a49f9Seric (void) close(fileno(e->e_lockfp)); 1253f2e4d5e8Seric 12549c9e68d9Seric /* child -- set up input & exec mailer */ 12552b9178d3Seric (void) setsignal(SIGINT, SIG_IGN); 12562b9178d3Seric (void) setsignal(SIGHUP, SIG_IGN); 12572b9178d3Seric (void) setsignal(SIGTERM, SIG_DFL); 12589c9e68d9Seric 125992051585Seric if (m != FileMailer || stat(tochain->q_user, &stb) < 0) 1260f24c4f81Seric stb.st_mode = 0; 1261f24c4f81Seric 126235427e30Seric /* tweak niceness */ 126335427e30Seric if (m->m_nice != 0) 126435427e30Seric nice(m->m_nice); 126535427e30Seric 1266f24c4f81Seric /* reset group id */ 1267b665faabSeric if (bitnset(M_SPECIFIC_UID, m->m_flags)) 1268b665faabSeric (void) setgid(m->m_gid); 1269f24c4f81Seric else if (bitset(S_ISGID, stb.st_mode)) 1270f24c4f81Seric (void) setgid(stb.st_gid); 1271f24c4f81Seric else if (ctladdr != NULL && ctladdr->q_gid != 0) 127244f2317fSeric { 127344f2317fSeric (void) initgroups(ctladdr->q_ruser? 127444f2317fSeric ctladdr->q_ruser: ctladdr->q_user, 127544f2317fSeric ctladdr->q_gid); 127651cfe111Seric (void) setgid(ctladdr->q_gid); 127744f2317fSeric } 1278b665faabSeric else 1279b665faabSeric { 1280b665faabSeric (void) initgroups(DefUser, DefGid); 1281b665faabSeric if (m->m_gid == 0) 1282b665faabSeric (void) setgid(DefGid); 1283b665faabSeric else 1284b665faabSeric (void) setgid(m->m_gid); 1285f24c4f81Seric } 1286f24c4f81Seric 1287f24c4f81Seric /* reset user id */ 1288f24c4f81Seric if (bitnset(M_SPECIFIC_UID, m->m_flags)) 1289f24c4f81Seric (void) setuid(m->m_uid); 1290f24c4f81Seric else if (bitset(S_ISUID, stb.st_mode)) 1291f24c4f81Seric (void) setuid(stb.st_uid); 1292f24c4f81Seric else if (ctladdr != NULL && ctladdr->q_uid != 0) 1293f24c4f81Seric (void) setuid(ctladdr->q_uid); 1294f24c4f81Seric else 1295f24c4f81Seric { 1296b665faabSeric if (m->m_uid == 0) 1297b665faabSeric (void) setuid(DefUid); 1298b665faabSeric else 1299b665faabSeric (void) setuid(m->m_uid); 130044f2317fSeric } 130144f2317fSeric 130244f2317fSeric if (tTd(11, 2)) 130344f2317fSeric printf("openmailer: running as r/euid=%d/%d\n", 130444f2317fSeric getuid(), geteuid()); 130544f2317fSeric 1306b986f6aaSeric /* move into some "safe" directory */ 1307b986f6aaSeric if (m->m_execdir != NULL) 1308b986f6aaSeric { 1309b986f6aaSeric char *p, *q; 1310b665faabSeric char buf[MAXLINE + 1]; 1311b986f6aaSeric 1312b986f6aaSeric for (p = m->m_execdir; p != NULL; p = q) 1313b986f6aaSeric { 1314b986f6aaSeric q = strchr(p, ':'); 1315b986f6aaSeric if (q != NULL) 1316b986f6aaSeric *q = '\0'; 1317b665faabSeric expand(p, buf, sizeof buf, e); 1318b986f6aaSeric if (q != NULL) 1319b986f6aaSeric *q++ = ':'; 1320b986f6aaSeric if (tTd(11, 20)) 1321b986f6aaSeric printf("openmailer: trydir %s\n", 1322b986f6aaSeric buf); 1323b986f6aaSeric if (buf[0] != '\0' && chdir(buf) >= 0) 1324b986f6aaSeric break; 1325b986f6aaSeric } 1326b986f6aaSeric } 1327b986f6aaSeric 13289c9e68d9Seric /* arrange to filter std & diag output of command */ 13299c9e68d9Seric if (clever) 13309c9e68d9Seric { 13319c9e68d9Seric (void) close(rpvect[0]); 13326fe8c3bcSeric if (dup2(rpvect[1], STDOUT_FILENO) < 0) 13336fe8c3bcSeric { 13340e3bfef5Seric syserr("%s... openmailer(%s): cannot dup pipe %d for stdout", 13350e3bfef5Seric e->e_to, m->m_name, rpvect[1]); 13366fe8c3bcSeric _exit(EX_OSERR); 13376fe8c3bcSeric } 13389c9e68d9Seric (void) close(rpvect[1]); 13399c9e68d9Seric } 13408b40b0a4Seric else if (OpMode == MD_SMTP || OpMode == MD_DAEMON || 13418b40b0a4Seric HoldErrs || DisConnected) 13429c9e68d9Seric { 13439c9e68d9Seric /* put mailer output in transcript */ 13446fe8c3bcSeric if (dup2(fileno(e->e_xfp), STDOUT_FILENO) < 0) 13456fe8c3bcSeric { 13460e3bfef5Seric syserr("%s... openmailer(%s): cannot dup xscript %d for stdout", 13470e3bfef5Seric e->e_to, m->m_name, 13486fe8c3bcSeric fileno(e->e_xfp)); 13496fe8c3bcSeric _exit(EX_OSERR); 13509c9e68d9Seric } 13516fe8c3bcSeric } 13526fe8c3bcSeric if (dup2(STDOUT_FILENO, STDERR_FILENO) < 0) 13536fe8c3bcSeric { 13540e3bfef5Seric syserr("%s... openmailer(%s): cannot dup stdout for stderr", 13550e3bfef5Seric e->e_to, m->m_name); 13566fe8c3bcSeric _exit(EX_OSERR); 13576fe8c3bcSeric } 13589c9e68d9Seric 13599c9e68d9Seric /* arrange to get standard input */ 13609c9e68d9Seric (void) close(mpvect[1]); 13619c9e68d9Seric if (dup2(mpvect[0], STDIN_FILENO) < 0) 13629c9e68d9Seric { 13630e3bfef5Seric syserr("%s... openmailer(%s): cannot dup pipe %d for stdin", 13640e3bfef5Seric e->e_to, m->m_name, mpvect[0]); 13659c9e68d9Seric _exit(EX_OSERR); 13669c9e68d9Seric } 13679c9e68d9Seric (void) close(mpvect[0]); 13689c9e68d9Seric 13699c9e68d9Seric /* arrange for all the files to be closed */ 13709c9e68d9Seric for (i = 3; i < DtableSize; i++) 13719c9e68d9Seric { 13729c9e68d9Seric register int j; 137344f2317fSeric 13749c9e68d9Seric if ((j = fcntl(i, F_GETFD, 0)) != -1) 13759c9e68d9Seric (void) fcntl(i, F_SETFD, j | 1); 13769c9e68d9Seric } 13779c9e68d9Seric 1378929277f2Seric /* run disconnected from terminal */ 1379929277f2Seric (void) setsid(); 1380929277f2Seric 13819c9e68d9Seric /* try to execute the mailer */ 13825d5999efSeric execve(m->m_mailer, (ARGV_T) pv, (ARGV_T) UserEnviron); 13839c9e68d9Seric saveerrno = errno; 13849c9e68d9Seric syserr("Cannot exec %s", m->m_mailer); 1385b665faabSeric if (bitnset(M_LOCALMAILER, m->m_flags) || 1386b665faabSeric transienterror(saveerrno)) 13877c941fd2Seric _exit(EX_OSERR); 13889c9e68d9Seric _exit(EX_UNAVAILABLE); 13899c9e68d9Seric } 13909c9e68d9Seric 13919c9e68d9Seric /* 13929c9e68d9Seric ** Set up return value. 13939c9e68d9Seric */ 13949c9e68d9Seric 13959c9e68d9Seric mci = (MCI *) xalloc(sizeof *mci); 13969c9e68d9Seric bzero((char *) mci, sizeof *mci); 13979c9e68d9Seric mci->mci_mailer = m; 13989c9e68d9Seric mci->mci_state = clever ? MCIS_OPENING : MCIS_OPEN; 13999c9e68d9Seric mci->mci_pid = pid; 14009c9e68d9Seric (void) close(mpvect[0]); 14019c9e68d9Seric mci->mci_out = fdopen(mpvect[1], "w"); 1402335eae58Seric if (mci->mci_out == NULL) 1403335eae58Seric { 1404335eae58Seric syserr("deliver: cannot create mailer output channel, fd=%d", 1405335eae58Seric mpvect[1]); 1406335eae58Seric (void) close(mpvect[1]); 1407335eae58Seric if (clever) 1408335eae58Seric { 1409335eae58Seric (void) close(rpvect[0]); 1410335eae58Seric (void) close(rpvect[1]); 1411335eae58Seric } 1412335eae58Seric rcode = EX_OSERR; 1413335eae58Seric goto give_up; 1414335eae58Seric } 14159c9e68d9Seric if (clever) 14169c9e68d9Seric { 14179c9e68d9Seric (void) close(rpvect[1]); 14189c9e68d9Seric mci->mci_in = fdopen(rpvect[0], "r"); 1419335eae58Seric if (mci->mci_in == NULL) 1420335eae58Seric { 1421335eae58Seric syserr("deliver: cannot create mailer input channel, fd=%d", 1422335eae58Seric mpvect[1]); 1423335eae58Seric (void) close(rpvect[0]); 1424335eae58Seric fclose(mci->mci_out); 1425335eae58Seric mci->mci_out = NULL; 1426335eae58Seric rcode = EX_OSERR; 1427335eae58Seric goto give_up; 1428335eae58Seric } 14299c9e68d9Seric } 14309c9e68d9Seric else 14319c9e68d9Seric { 14329c9e68d9Seric mci->mci_flags |= MCIF_TEMP; 14339c9e68d9Seric mci->mci_in = NULL; 14349c9e68d9Seric } 14359c9e68d9Seric } 14369c9e68d9Seric 14379c9e68d9Seric /* 14389c9e68d9Seric ** If we are in SMTP opening state, send initial protocol. 14399c9e68d9Seric */ 14409c9e68d9Seric 14419c9e68d9Seric if (clever && mci->mci_state != MCIS_CLOSED) 14429c9e68d9Seric { 14439c9e68d9Seric smtpinit(m, mci, e); 14449c9e68d9Seric } 1445b665faabSeric 1446b665faabSeric if (bitset(EF_HAS8BIT, e->e_flags) && bitnset(M_7BITS, m->m_flags)) 1447b665faabSeric mci->mci_flags |= MCIF_CVT8TO7; 1448b665faabSeric else 1449b665faabSeric mci->mci_flags &= ~MCIF_CVT8TO7; 1450b665faabSeric 14519c9e68d9Seric if (tTd(11, 1)) 14529c9e68d9Seric { 14539c9e68d9Seric printf("openmailer: "); 14544052916eSeric mci_dump(mci, FALSE); 14559c9e68d9Seric } 14569c9e68d9Seric 14579c9e68d9Seric if (mci->mci_state != MCIS_OPEN) 1458b31e7f2bSeric { 1459b31e7f2bSeric /* couldn't open the mailer */ 1460b31e7f2bSeric rcode = mci->mci_exitstat; 14612a6bc25bSeric errno = mci->mci_errno; 14629d4a8008Seric #if NAMED_BIND 1463f170942cSeric h_errno = mci->mci_herrno; 1464f170942cSeric #endif 1465b31e7f2bSeric if (rcode == EX_OK) 1466b31e7f2bSeric { 1467b31e7f2bSeric /* shouldn't happen */ 146808b25121Seric syserr("554 deliver: rcode=%d, mci_state=%d, sig=%s", 14696b0f339dSeric rcode, mci->mci_state, firstsig); 1470b31e7f2bSeric rcode = EX_SOFTWARE; 1471b31e7f2bSeric } 1472b665faabSeric else if (curhost != NULL && *curhost != '\0') 147390891494Seric { 147490891494Seric /* try next MX site */ 147590891494Seric goto tryhost; 147690891494Seric } 1477b31e7f2bSeric } 1478b31e7f2bSeric else if (!clever) 1479b31e7f2bSeric { 1480b31e7f2bSeric /* 1481b31e7f2bSeric ** Format and send message. 1482b31e7f2bSeric */ 148315d084d5Seric 14845aa0f353Seric putfromline(mci, e); 1485b665faabSeric (*e->e_puthdr)(mci, e->e_header, e); 14866ffc2dd1Seric (*e->e_putbody)(mci, e, NULL); 1487b31e7f2bSeric 1488b31e7f2bSeric /* get the exit status */ 1489c9be6216Seric rcode = endmailer(mci, e, pv); 1490134746fbSeric } 1491134746fbSeric else 1492b31e7f2bSeric #ifdef SMTP 1493134746fbSeric { 1494b31e7f2bSeric /* 1495b31e7f2bSeric ** Send the MAIL FROM: protocol 1496b31e7f2bSeric */ 149715d084d5Seric 1498b31e7f2bSeric rcode = smtpmailfrom(m, mci, e); 1499b31e7f2bSeric if (rcode == EX_OK) 150075889e88Seric { 1501ded0d3daSkarels register char *t = tobuf; 1502ded0d3daSkarels register int i; 1503ded0d3daSkarels 1504588cad61Seric /* send the recipient list */ 150563780dbdSeric tobuf[0] = '\0'; 150675889e88Seric for (to = tochain; to != NULL; to = to->q_tchain) 150775889e88Seric { 150863780dbdSeric e->e_to = to->q_paddr; 150915d084d5Seric if ((i = smtprcpt(to, m, mci, e)) != EX_OK) 151075889e88Seric { 1511b665faabSeric markfailure(e, to, mci, i); 1512b665faabSeric giveresponse(i, m, mci, ctladdr, xstart, e); 151363780dbdSeric } 151475889e88Seric else 151575889e88Seric { 1516911693bfSbostic *t++ = ','; 1517b31e7f2bSeric for (p = to->q_paddr; *p; *t++ = *p++) 1518b31e7f2bSeric continue; 1519ee39df61Seric *t = '\0'; 1520588cad61Seric } 1521588cad61Seric } 1522588cad61Seric 152363780dbdSeric /* now send the data */ 152463780dbdSeric if (tobuf[0] == '\0') 1525b31e7f2bSeric { 15269c9e68d9Seric rcode = EX_OK; 152763780dbdSeric e->e_to = NULL; 1528b31e7f2bSeric if (bitset(MCIF_CACHED, mci->mci_flags)) 1529b31e7f2bSeric smtprset(m, mci, e); 1530b31e7f2bSeric } 153175889e88Seric else 153275889e88Seric { 153363780dbdSeric e->e_to = tobuf + 1; 153475889e88Seric rcode = smtpdata(m, mci, e); 153563780dbdSeric } 153663780dbdSeric 153763780dbdSeric /* now close the connection */ 1538b31e7f2bSeric if (!bitset(MCIF_CACHED, mci->mci_flags)) 153915d084d5Seric smtpquit(m, mci, e); 154063780dbdSeric } 1541cb082c5bSeric if (rcode != EX_OK && curhost != NULL && *curhost != '\0') 15429c9e68d9Seric { 15439c9e68d9Seric /* try next MX site */ 15449c9e68d9Seric goto tryhost; 15459c9e68d9Seric } 1546c579ef51Seric } 1547b31e7f2bSeric #else /* not SMTP */ 1548a05b3449Sbostic { 154908b25121Seric syserr("554 deliver: need SMTP compiled to use clever mailer"); 1550845e533cSeric rcode = EX_CONFIG; 1551b31e7f2bSeric goto give_up; 1552a05b3449Sbostic } 1553b31e7f2bSeric #endif /* SMTP */ 15549d4a8008Seric #if NAMED_BIND 15552bcc6d2dSeric if (ConfigLevel < 2) 1556912a731aSbostic _res.options |= RES_DEFNAMES | RES_DNSRCH; /* XXX */ 1557134746fbSeric #endif 15585dfc646bSeric 1559b31e7f2bSeric /* arrange a return receipt if requested */ 1560df106f0bSeric if (rcode == EX_OK && e->e_receiptto != NULL && 1561df106f0bSeric bitnset(M_LOCALMAILER, m->m_flags)) 1562b31e7f2bSeric { 1563b31e7f2bSeric e->e_flags |= EF_SENDRECEIPT; 1564b31e7f2bSeric /* do we want to send back more info? */ 1565b31e7f2bSeric } 1566b31e7f2bSeric 1567c77d1c25Seric /* 156863780dbdSeric ** Do final status disposal. 156963780dbdSeric ** We check for something in tobuf for the SMTP case. 1570c77d1c25Seric ** If we got a temporary failure, arrange to queue the 1571c77d1c25Seric ** addressees. 1572c77d1c25Seric */ 1573c77d1c25Seric 1574b31e7f2bSeric give_up: 157563780dbdSeric if (tobuf[0] != '\0') 1576b665faabSeric giveresponse(rcode, m, mci, ctladdr, xstart, e); 1577772e6e50Seric for (to = tochain; to != NULL; to = to->q_tchain) 1578b31e7f2bSeric { 1579dde5acadSeric if (rcode != EX_OK) 1580b665faabSeric markfailure(e, to, mci, rcode); 1581b665faabSeric else if (!bitset(QBADADDR|QQUEUEUP, to->q_flags)) 1582655518ecSeric { 1583dde5acadSeric to->q_flags |= QSENT; 1584b665faabSeric to->q_statdate = curtime(); 1585655518ecSeric e->e_nsent++; 1586b665faabSeric if (bitnset(M_LOCALMAILER, m->m_flags) && 1587b665faabSeric (e->e_receiptto != NULL || 1588b665faabSeric bitset(QPINGONSUCCESS, to->q_flags))) 1589df106f0bSeric { 15909070d157Seric to->q_flags |= QDELIVERED; 1591d95dad3eSeric to->q_status = "2.1.5"; 1592df106f0bSeric fprintf(e->e_xfp, "%s... Successfully delivered\n", 1593df106f0bSeric to->q_paddr); 1594df106f0bSeric } 1595b665faabSeric else if (bitset(QPINGONSUCCESS, to->q_flags) && 1596b665faabSeric bitset(QPRIMARY, to->q_flags) && 1597b665faabSeric !bitset(MCIF_DSN, mci->mci_flags)) 1598b665faabSeric { 1599b665faabSeric to->q_flags |= QRELAYED; 1600b665faabSeric fprintf(e->e_xfp, "%s... relayed; expect no further notifications\n", 1601b665faabSeric to->q_paddr); 1602b665faabSeric } 1603655518ecSeric } 1604b31e7f2bSeric } 1605b31e7f2bSeric 1606b31e7f2bSeric /* 1607b31e7f2bSeric ** Restore state and return. 1608b31e7f2bSeric */ 1609c77d1c25Seric 1610*86aab53cSeric #if XDEBUG 16117febfd66Seric { 16127febfd66Seric char wbuf[MAXLINE]; 16137febfd66Seric 16147febfd66Seric /* make absolutely certain 0, 1, and 2 are in use */ 161544622ea3Seric sprintf(wbuf, "%s... end of deliver(%s)", 161644622ea3Seric e->e_to == NULL ? "NO-TO-LIST" : e->e_to, 161744622ea3Seric m->m_name); 16187febfd66Seric checkfd012(wbuf); 16197febfd66Seric } 16207febfd66Seric #endif 16217febfd66Seric 162235490626Seric errno = 0; 1623588cad61Seric define('g', (char *) NULL, e); 16245826d9d3Seric return (rcode); 162525a99e2eSeric } 16265dfc646bSeric /* 162783b7ddc9Seric ** MARKFAILURE -- mark a failure on a specific address. 162883b7ddc9Seric ** 162983b7ddc9Seric ** Parameters: 163083b7ddc9Seric ** e -- the envelope we are sending. 163183b7ddc9Seric ** q -- the address to mark. 1632b665faabSeric ** mci -- mailer connection information. 163383b7ddc9Seric ** rcode -- the code signifying the particular failure. 163483b7ddc9Seric ** 163583b7ddc9Seric ** Returns: 163683b7ddc9Seric ** none. 163783b7ddc9Seric ** 163883b7ddc9Seric ** Side Effects: 163983b7ddc9Seric ** marks the address (and possibly the envelope) with the 164083b7ddc9Seric ** failure so that an error will be returned or 164183b7ddc9Seric ** the message will be queued, as appropriate. 164283b7ddc9Seric */ 164383b7ddc9Seric 1644a6a073b5Seric void 1645b665faabSeric markfailure(e, q, mci, rcode) 164683b7ddc9Seric register ENVELOPE *e; 164783b7ddc9Seric register ADDRESS *q; 1648b665faabSeric register MCI *mci; 164983b7ddc9Seric int rcode; 165083b7ddc9Seric { 1651b665faabSeric char *stat = NULL; 165219c47125Seric 1653d5aafa3cSeric switch (rcode) 1654d5aafa3cSeric { 1655d5aafa3cSeric case EX_OK: 1656d5aafa3cSeric break; 1657d5aafa3cSeric 1658d5aafa3cSeric case EX_TEMPFAIL: 1659d5aafa3cSeric case EX_IOERR: 1660d5aafa3cSeric case EX_OSERR: 166183b7ddc9Seric q->q_flags |= QQUEUEUP; 1662d5aafa3cSeric break; 1663d5aafa3cSeric 1664d5aafa3cSeric default: 1665f170942cSeric q->q_flags |= QBADADDR; 1666d5aafa3cSeric break; 1667d5aafa3cSeric } 1668b665faabSeric 16695b068d51Seric /* find most specific error code possible */ 1670b665faabSeric if (q->q_status == NULL && mci != NULL) 1671b665faabSeric q->q_status = mci->mci_status; 16725b068d51Seric if (q->q_status == NULL) 16735b068d51Seric q->q_status = e->e_status; 16745b068d51Seric if (q->q_status == NULL) 16755b068d51Seric { 1676b665faabSeric switch (rcode) 1677b665faabSeric { 1678b665faabSeric case EX_USAGE: 1679b665faabSeric stat = "5.5.4"; 1680b665faabSeric break; 1681b665faabSeric 1682b665faabSeric case EX_DATAERR: 1683b665faabSeric stat = "5.5.2"; 1684b665faabSeric break; 1685b665faabSeric 1686b665faabSeric case EX_NOUSER: 1687b665faabSeric stat = "5.1.1"; 1688b665faabSeric break; 1689b665faabSeric 16905b068d51Seric case EX_NOHOST: 16915b068d51Seric stat = "5.1.2"; 16925b068d51Seric break; 16935b068d51Seric 1694b665faabSeric case EX_NOINPUT: 1695b665faabSeric case EX_CANTCREAT: 1696b665faabSeric case EX_NOPERM: 1697b665faabSeric stat = "5.3.0"; 1698b665faabSeric break; 1699b665faabSeric 1700b665faabSeric case EX_UNAVAILABLE: 1701b665faabSeric case EX_SOFTWARE: 1702b665faabSeric case EX_OSFILE: 1703b665faabSeric case EX_PROTOCOL: 1704b665faabSeric case EX_CONFIG: 1705b665faabSeric stat = "5.5.0"; 1706b665faabSeric break; 1707b665faabSeric 1708b665faabSeric case EX_OSERR: 1709b665faabSeric case EX_IOERR: 1710b665faabSeric stat = "4.5.0"; 1711b665faabSeric break; 1712b665faabSeric 1713b665faabSeric case EX_TEMPFAIL: 1714b665faabSeric stat = "4.2.0"; 1715b665faabSeric break; 1716b665faabSeric } 1717d95dad3eSeric if (stat != NULL) 1718b665faabSeric q->q_status = stat; 17195b068d51Seric } 1720b665faabSeric 1721b665faabSeric q->q_statdate = curtime(); 1722b665faabSeric if (CurHostName != NULL && CurHostName[0] != '\0') 1723b665faabSeric q->q_statmta = newstr(CurHostName); 1724b665faabSeric if (rcode != EX_OK && q->q_rstatus == NULL) 1725b665faabSeric { 1726b665faabSeric char buf[30]; 1727b665faabSeric 1728b665faabSeric (void) sprintf(buf, "%d", rcode); 1729b665faabSeric q->q_rstatus = newstr(buf); 1730b665faabSeric } 173183b7ddc9Seric } 173283b7ddc9Seric /* 1733c579ef51Seric ** ENDMAILER -- Wait for mailer to terminate. 1734c579ef51Seric ** 1735c579ef51Seric ** We should never get fatal errors (e.g., segmentation 1736c579ef51Seric ** violation), so we report those specially. For other 1737c579ef51Seric ** errors, we choose a status message (into statmsg), 1738c579ef51Seric ** and if it represents an error, we print it. 1739c579ef51Seric ** 1740c579ef51Seric ** Parameters: 1741c579ef51Seric ** pid -- pid of mailer. 1742c9be6216Seric ** e -- the current envelope. 1743c9be6216Seric ** pv -- the parameter vector that invoked the mailer 1744c9be6216Seric ** (for error messages). 1745c579ef51Seric ** 1746c579ef51Seric ** Returns: 1747c579ef51Seric ** exit code of mailer. 1748c579ef51Seric ** 1749c579ef51Seric ** Side Effects: 1750c579ef51Seric ** none. 1751c579ef51Seric */ 1752c579ef51Seric 1753a6a073b5Seric int 1754c9be6216Seric endmailer(mci, e, pv) 1755b31e7f2bSeric register MCI *mci; 1756c9be6216Seric register ENVELOPE *e; 1757c9be6216Seric char **pv; 1758c579ef51Seric { 1759588cad61Seric int st; 1760c579ef51Seric 176175889e88Seric /* close any connections */ 176275889e88Seric if (mci->mci_in != NULL) 176376f3d53fSeric (void) xfclose(mci->mci_in, mci->mci_mailer->m_name, "mci_in"); 176475889e88Seric if (mci->mci_out != NULL) 176576f3d53fSeric (void) xfclose(mci->mci_out, mci->mci_mailer->m_name, "mci_out"); 176675889e88Seric mci->mci_in = mci->mci_out = NULL; 176775889e88Seric mci->mci_state = MCIS_CLOSED; 176875889e88Seric 176933db8731Seric /* in the IPC case there is nothing to wait for */ 177075889e88Seric if (mci->mci_pid == 0) 177133db8731Seric return (EX_OK); 177233db8731Seric 177333db8731Seric /* wait for the mailer process to die and collect status */ 177475889e88Seric st = waitfor(mci->mci_pid); 1775588cad61Seric if (st == -1) 177678de67c1Seric { 1777c9be6216Seric syserr("endmailer %s: wait", pv[0]); 1778588cad61Seric return (EX_SOFTWARE); 1779c579ef51Seric } 178033db8731Seric 1781bf9bc890Seric if (WIFEXITED(st)) 1782c579ef51Seric { 1783bf9bc890Seric /* normal death -- return status */ 1784bf9bc890Seric return (WEXITSTATUS(st)); 1785bf9bc890Seric } 1786bf9bc890Seric 1787bf9bc890Seric /* it died a horrid death */ 1788550092c3Seric syserr("451 mailer %s died with signal %o", 1789550092c3Seric mci->mci_mailer->m_name, st); 1790c9be6216Seric 1791c9be6216Seric /* log the arguments */ 17923c930db3Seric if (pv != NULL && e->e_xfp != NULL) 1793c9be6216Seric { 1794c9be6216Seric register char **av; 1795c9be6216Seric 1796c9be6216Seric fprintf(e->e_xfp, "Arguments:"); 1797c9be6216Seric for (av = pv; *av != NULL; av++) 1798c9be6216Seric fprintf(e->e_xfp, " %s", *av); 1799c9be6216Seric fprintf(e->e_xfp, "\n"); 1800c9be6216Seric } 1801c9be6216Seric 18025f73204aSeric ExitStat = EX_TEMPFAIL; 18035f73204aSeric return (EX_TEMPFAIL); 1804c579ef51Seric } 1805c579ef51Seric /* 180625a99e2eSeric ** GIVERESPONSE -- Interpret an error response from a mailer 180725a99e2eSeric ** 180825a99e2eSeric ** Parameters: 180925a99e2eSeric ** stat -- the status code from the mailer (high byte 181025a99e2eSeric ** only; core dumps must have been taken care of 181125a99e2eSeric ** already). 181281161401Seric ** m -- the mailer info for this mailer. 181381161401Seric ** mci -- the mailer connection info -- can be NULL if the 181481161401Seric ** response is given before the connection is made. 18154dee0003Seric ** ctladdr -- the controlling address for the recipient 18164dee0003Seric ** address(es). 1817b665faabSeric ** xstart -- the transaction start time, for computing 1818b665faabSeric ** transaction delays. 181981161401Seric ** e -- the current envelope. 182025a99e2eSeric ** 182125a99e2eSeric ** Returns: 1822db8841e9Seric ** none. 182325a99e2eSeric ** 182425a99e2eSeric ** Side Effects: 1825c1f9df2cSeric ** Errors may be incremented. 182625a99e2eSeric ** ExitStat may be set. 182725a99e2eSeric */ 182825a99e2eSeric 1829a6a073b5Seric void 1830b665faabSeric giveresponse(stat, m, mci, ctladdr, xstart, e) 183125a99e2eSeric int stat; 1832588cad61Seric register MAILER *m; 183381161401Seric register MCI *mci; 18344dee0003Seric ADDRESS *ctladdr; 1835b665faabSeric time_t xstart; 1836198d9be0Seric ENVELOPE *e; 183725a99e2eSeric { 18389c16475dSeric register const char *statmsg; 183925a99e2eSeric extern char *SysExMsg[]; 184025a99e2eSeric register int i; 1841d4bd8f0eSbostic extern int N_SysEx; 1842198d9be0Seric char buf[MAXLINE]; 184325a99e2eSeric 184413bbc08cSeric /* 184513bbc08cSeric ** Compute status message from code. 184613bbc08cSeric */ 184713bbc08cSeric 184825a99e2eSeric i = stat - EX__BASE; 1849588cad61Seric if (stat == 0) 18506fe8c3bcSeric { 1851588cad61Seric statmsg = "250 Sent"; 1852ce5531bdSeric if (e->e_statmsg != NULL) 18536fe8c3bcSeric { 1854ce5531bdSeric (void) sprintf(buf, "%s (%s)", statmsg, e->e_statmsg); 18556fe8c3bcSeric statmsg = buf; 18566fe8c3bcSeric } 18576fe8c3bcSeric } 1858588cad61Seric else if (i < 0 || i > N_SysEx) 1859588cad61Seric { 1860588cad61Seric (void) sprintf(buf, "554 unknown mailer error %d", stat); 1861588cad61Seric stat = EX_UNAVAILABLE; 1862588cad61Seric statmsg = buf; 1863588cad61Seric } 1864198d9be0Seric else if (stat == EX_TEMPFAIL) 1865198d9be0Seric { 18667d55540cSeric (void) strcpy(buf, SysExMsg[i] + 1); 18679d4a8008Seric #if NAMED_BIND 1868f28da541Smiriam if (h_errno == TRY_AGAIN) 18694d50702aSeric statmsg = errstring(h_errno+E_DNSBASE); 1870f28da541Smiriam else 1871d4bd8f0eSbostic #endif 1872f28da541Smiriam { 18738557d168Seric if (errno != 0) 1874d87e85f3Seric statmsg = errstring(errno); 1875d87e85f3Seric else 1876d87e85f3Seric { 1877d87e85f3Seric #ifdef SMTP 1878d87e85f3Seric statmsg = SmtpError; 18796c2c3107Seric #else /* SMTP */ 1880d87e85f3Seric statmsg = NULL; 18816c2c3107Seric #endif /* SMTP */ 1882d87e85f3Seric } 1883f28da541Smiriam } 1884d87e85f3Seric if (statmsg != NULL && statmsg[0] != '\0') 1885d87e85f3Seric { 188687c9b3e7Seric (void) strcat(buf, ": "); 1887d87e85f3Seric (void) strcat(buf, statmsg); 18888557d168Seric } 1889198d9be0Seric statmsg = buf; 1890198d9be0Seric } 18919d4a8008Seric #if NAMED_BIND 1892f170942cSeric else if (stat == EX_NOHOST && h_errno != 0) 1893f170942cSeric { 18944d50702aSeric statmsg = errstring(h_errno + E_DNSBASE); 1895862934b2Seric (void) sprintf(buf, "%s (%s)", SysExMsg[i] + 1, statmsg); 1896f170942cSeric statmsg = buf; 1897f170942cSeric } 1898f170942cSeric #endif 189925a99e2eSeric else 1900d87e85f3Seric { 190125a99e2eSeric statmsg = SysExMsg[i]; 19027d55540cSeric if (*statmsg++ == ':') 19037d55540cSeric { 19047d55540cSeric (void) sprintf(buf, "%s: %s", statmsg, errstring(errno)); 19057d55540cSeric statmsg = buf; 19067d55540cSeric } 1907d87e85f3Seric } 1908588cad61Seric 1909588cad61Seric /* 1910588cad61Seric ** Print the message as appropriate 1911588cad61Seric */ 1912588cad61Seric 1913198d9be0Seric if (stat == EX_OK || stat == EX_TEMPFAIL) 1914df106f0bSeric { 1915df106f0bSeric extern char MsgBuf[]; 1916df106f0bSeric 19171f96bd0bSeric message("%s", &statmsg[4]); 1918df106f0bSeric if (stat == EX_TEMPFAIL && e->e_xfp != NULL) 1919df106f0bSeric fprintf(e->e_xfp, "%s\n", &MsgBuf[4]); 1920df106f0bSeric } 192125a99e2eSeric else 192225a99e2eSeric { 1923862934b2Seric char mbuf[8]; 1924862934b2Seric 1925c1f9df2cSeric Errors++; 1926862934b2Seric sprintf(mbuf, "%.3s %%s", statmsg); 1927862934b2Seric usrerr(mbuf, &statmsg[4]); 192825a99e2eSeric } 192925a99e2eSeric 193025a99e2eSeric /* 193125a99e2eSeric ** Final cleanup. 193225a99e2eSeric ** Log a record of the transaction. Compute the new 193325a99e2eSeric ** ExitStat -- if we already had an error, stick with 193425a99e2eSeric ** that. 193525a99e2eSeric */ 193625a99e2eSeric 19372f624c86Seric if (LogLevel > ((stat == EX_TEMPFAIL) ? 8 : (stat == EX_OK) ? 7 : 6)) 1938b665faabSeric logdelivery(m, mci, &statmsg[4], ctladdr, xstart, e); 1939eb238f8cSeric 19405d3f0ed4Seric if (tTd(11, 2)) 19415d3f0ed4Seric printf("giveresponse: stat=%d, e->e_message=%s\n", 19422c8ac7e0Seric stat, e->e_message == NULL ? "<NULL>" : e->e_message); 19435d3f0ed4Seric 1944eb238f8cSeric if (stat != EX_TEMPFAIL) 1945eb238f8cSeric setstat(stat); 19461097d4c9Seric if (stat != EX_OK && (stat != EX_TEMPFAIL || e->e_message == NULL)) 1947198d9be0Seric { 1948198d9be0Seric if (e->e_message != NULL) 1949198d9be0Seric free(e->e_message); 1950198d9be0Seric e->e_message = newstr(&statmsg[4]); 1951198d9be0Seric } 19528557d168Seric errno = 0; 19539d4a8008Seric #if NAMED_BIND 1954f28da541Smiriam h_errno = 0; 1955d4bd8f0eSbostic #endif 1956eb238f8cSeric } 1957eb238f8cSeric /* 1958eb238f8cSeric ** LOGDELIVERY -- log the delivery in the system log 1959eb238f8cSeric ** 19602c9b4f99Seric ** Care is taken to avoid logging lines that are too long, because 19612c9b4f99Seric ** some versions of syslog have an unfortunate proclivity for core 19622c9b4f99Seric ** dumping. This is a hack, to be sure, that is at best empirical. 19632c9b4f99Seric ** 1964eb238f8cSeric ** Parameters: 196581161401Seric ** m -- the mailer info. Can be NULL for initial queue. 196681161401Seric ** mci -- the mailer connection info -- can be NULL if the 196781161401Seric ** log is occuring when no connection is active. 196881161401Seric ** stat -- the message to print for the status. 19694dee0003Seric ** ctladdr -- the controlling address for the to list. 1970b665faabSeric ** xstart -- the transaction start time, used for 1971b665faabSeric ** computing transaction delay. 197281161401Seric ** e -- the current envelope. 1973eb238f8cSeric ** 1974eb238f8cSeric ** Returns: 1975eb238f8cSeric ** none 1976eb238f8cSeric ** 1977eb238f8cSeric ** Side Effects: 1978eb238f8cSeric ** none 1979eb238f8cSeric */ 1980eb238f8cSeric 1981a6a073b5Seric void 1982b665faabSeric logdelivery(m, mci, stat, ctladdr, xstart, e) 198381161401Seric MAILER *m; 198481161401Seric register MCI *mci; 1985a6a073b5Seric const char *stat; 19864dee0003Seric ADDRESS *ctladdr; 1987b665faabSeric time_t xstart; 1988b31e7f2bSeric register ENVELOPE *e; 19895cf56be3Seric { 1990eb238f8cSeric # ifdef LOG 19914dee0003Seric register char *bp; 19922c9b4f99Seric register char *p; 19932c9b4f99Seric int l; 1994d6acf3eeSeric char buf[512]; 19959507d1f9Seric 19963a100e8bSeric # if (SYSLOG_BUFSIZE) >= 256 19974dee0003Seric bp = buf; 19984dee0003Seric if (ctladdr != NULL) 19994dee0003Seric { 20004dee0003Seric strcpy(bp, ", ctladdr="); 2001f62f08c7Seric strcat(bp, shortenstring(ctladdr->q_paddr, 83)); 20024dee0003Seric bp += strlen(bp); 20034dee0003Seric if (bitset(QGOODUID, ctladdr->q_flags)) 20044dee0003Seric { 20054dee0003Seric (void) sprintf(bp, " (%d/%d)", 20064dee0003Seric ctladdr->q_uid, ctladdr->q_gid); 20074dee0003Seric bp += strlen(bp); 20084dee0003Seric } 20094dee0003Seric } 20104dee0003Seric 2011b665faabSeric sprintf(bp, ", delay=%s", pintvl(curtime() - e->e_ctime, TRUE)); 20124dee0003Seric bp += strlen(bp); 201381161401Seric 2014b665faabSeric if (xstart != (time_t) 0) 2015b665faabSeric { 2016b665faabSeric sprintf(bp, ", xdelay=%s", pintvl(curtime() - xstart, TRUE)); 2017b665faabSeric bp += strlen(bp); 2018b665faabSeric } 2019b665faabSeric 202048ed5d33Seric if (m != NULL) 202171ff6caaSeric { 20224dee0003Seric (void) strcpy(bp, ", mailer="); 20234dee0003Seric (void) strcat(bp, m->m_name); 20244dee0003Seric bp += strlen(bp); 202571ff6caaSeric } 202648ed5d33Seric 202748ed5d33Seric if (mci != NULL && mci->mci_host != NULL) 202871ff6caaSeric { 202971ff6caaSeric # ifdef DAEMON 2030e2f2f828Seric extern SOCKADDR CurHostAddr; 203148ed5d33Seric # endif 203271ff6caaSeric 20334dee0003Seric (void) strcpy(bp, ", relay="); 20344dee0003Seric (void) strcat(bp, mci->mci_host); 203548ed5d33Seric 203648ed5d33Seric # ifdef DAEMON 20372bdfc6b9Seric (void) strcat(bp, " ["); 20384dee0003Seric (void) strcat(bp, anynet_ntoa(&CurHostAddr)); 20392bdfc6b9Seric (void) strcat(bp, "]"); 204071ff6caaSeric # endif 204171ff6caaSeric } 2042bcb9b028Seric else if (strcmp(stat, "queued") != 0) 204348ed5d33Seric { 204448ed5d33Seric char *p = macvalue('h', e); 20459507d1f9Seric 204648ed5d33Seric if (p != NULL && p[0] != '\0') 204748ed5d33Seric { 20484dee0003Seric (void) strcpy(bp, ", relay="); 20494dee0003Seric (void) strcat(bp, p); 205048ed5d33Seric } 205148ed5d33Seric } 2052cb082c5bSeric bp += strlen(bp); 2053d6acf3eeSeric 20543a100e8bSeric #define STATLEN (((SYSLOG_BUFSIZE) - 100) / 4) 20553a100e8bSeric #if (STATLEN) < 63 20563a100e8bSeric # undef STATLEN 20573a100e8bSeric # define STATLEN 63 20583a100e8bSeric #endif 20593a100e8bSeric #if (STATLEN) > 203 20603a100e8bSeric # undef STATLEN 20613a100e8bSeric # define STATLEN 203 20623a100e8bSeric #endif 20633a100e8bSeric 20643a100e8bSeric if ((bp - buf) > (sizeof buf - ((STATLEN) + 20))) 20652c9b4f99Seric { 20662c9b4f99Seric /* desperation move -- truncate data */ 20673a100e8bSeric bp = buf + sizeof buf - ((STATLEN) + 17); 20682c9b4f99Seric strcpy(bp, "..."); 20692c9b4f99Seric bp += 3; 20702c9b4f99Seric } 20712c9b4f99Seric 20722c9b4f99Seric (void) strcpy(bp, ", stat="); 20732c9b4f99Seric bp += strlen(bp); 20743a100e8bSeric 20753a100e8bSeric (void) strcpy(bp, shortenstring(stat, (STATLEN))); 20762c9b4f99Seric 20772c9b4f99Seric l = SYSLOG_BUFSIZE - 100 - strlen(buf); 20782c9b4f99Seric p = e->e_to; 2079972b1942Seric while (strlen(p) >= (SIZE_T) l) 20802c9b4f99Seric { 20812c9b4f99Seric register char *q = strchr(p + l, ','); 20822c9b4f99Seric 20832a1b6b73Seric if (q == NULL) 20842c9b4f99Seric break; 20852c9b4f99Seric syslog(LOG_INFO, "%s: to=%.*s [more]%s", 20862c9b4f99Seric e->e_id, ++q - p, p, buf); 20872c9b4f99Seric p = q; 20882c9b4f99Seric } 20892c9b4f99Seric syslog(LOG_INFO, "%s: to=%s%s", e->e_id, p, buf); 20903a100e8bSeric 20913a100e8bSeric # else /* we have a very short log buffer size */ 20923a100e8bSeric 209327607809Seric l = SYSLOG_BUFSIZE - 85; 20943a100e8bSeric p = e->e_to; 20953a100e8bSeric while (strlen(p) >= l) 20963a100e8bSeric { 20973a100e8bSeric register char *q = strchr(p + l, ','); 20983a100e8bSeric 20993a100e8bSeric if (q == NULL) 21003a100e8bSeric break; 21013a100e8bSeric syslog(LOG_INFO, "%s: to=%.*s [more]", 21023a100e8bSeric e->e_id, ++q - p, p); 21033a100e8bSeric p = q; 21043a100e8bSeric } 21053a100e8bSeric syslog(LOG_INFO, "%s: to=%s", e->e_id, p); 21063a100e8bSeric 21073a100e8bSeric if (ctladdr != NULL) 21083a100e8bSeric { 21093a100e8bSeric bp = buf; 21103a100e8bSeric strcpy(buf, "ctladdr="); 21113a100e8bSeric bp += strlen(buf); 21123a100e8bSeric strcpy(bp, shortenstring(ctladdr->q_paddr, 83)); 21133a100e8bSeric bp += strlen(buf); 21143a100e8bSeric if (bitset(QGOODUID, ctladdr->q_flags)) 21153a100e8bSeric { 21163a100e8bSeric (void) sprintf(bp, " (%d/%d)", 21173a100e8bSeric ctladdr->q_uid, ctladdr->q_gid); 21183a100e8bSeric bp += strlen(bp); 21193a100e8bSeric } 21203a100e8bSeric syslog(LOG_INFO, "%s: %s", e->e_id, buf); 21213a100e8bSeric } 21224e797715Seric bp = buf; 21234e797715Seric sprintf(bp, "delay=%s", pintvl(curtime() - e->e_ctime, TRUE)); 21244e797715Seric bp += strlen(bp); 2125b665faabSeric if (xstart != (time_t) 0) 2126b665faabSeric { 2127b665faabSeric sprintf(bp, ", xdelay=%s", pintvl(curtime() - xstart, TRUE)); 2128b665faabSeric bp += strlen(bp); 2129b665faabSeric } 21303a100e8bSeric 21313a100e8bSeric if (m != NULL) 21324e797715Seric { 21334e797715Seric sprintf(bp, ", mailer=%s", m->m_name); 21344e797715Seric bp += strlen(bp); 21354e797715Seric } 2136b056abd0Seric syslog(LOG_INFO, "%s: %s", e->e_id, buf); 21373a100e8bSeric 2138b056abd0Seric buf[0] = '\0'; 21393a100e8bSeric if (mci != NULL && mci->mci_host != NULL) 21403a100e8bSeric { 21413a100e8bSeric # ifdef DAEMON 21423a100e8bSeric extern SOCKADDR CurHostAddr; 21433a100e8bSeric # endif 21443a100e8bSeric 2145d2ece200Seric sprintf(buf, "relay=%s", mci->mci_host); 21463a100e8bSeric 21473a100e8bSeric # ifdef DAEMON 2148b056abd0Seric (void) strcat(buf, " ["); 2149b056abd0Seric (void) strcat(buf, anynet_ntoa(&CurHostAddr)); 2150b056abd0Seric (void) strcat(buf, "]"); 21513a100e8bSeric # endif 21523a100e8bSeric } 2153bcb9b028Seric else if (strcmp(stat, "queued") != 0) 21543a100e8bSeric { 21553a100e8bSeric char *p = macvalue('h', e); 21563a100e8bSeric 21573a100e8bSeric if (p != NULL && p[0] != '\0') 2158d2ece200Seric sprintf(buf, "relay=%s", p); 21593a100e8bSeric } 2160b056abd0Seric if (buf[0] != '\0') 21614e797715Seric syslog(LOG_INFO, "%s: %s", e->e_id, buf); 21623a100e8bSeric 21633a100e8bSeric syslog(LOG_INFO, "%s: stat=%s", e->e_id, shortenstring(stat, 63)); 21643a100e8bSeric # endif /* short log buffer */ 21656c2c3107Seric # endif /* LOG */ 216625a99e2eSeric } 216725a99e2eSeric /* 216851552439Seric ** PUTFROMLINE -- output a UNIX-style from line (or whatever) 216925a99e2eSeric ** 217051552439Seric ** This can be made an arbitrary message separator by changing $l 217151552439Seric ** 21729b6c17a6Seric ** One of the ugliest hacks seen by human eyes is contained herein: 21739b6c17a6Seric ** UUCP wants those stupid "remote from <host>" lines. Why oh why 21749b6c17a6Seric ** does a well-meaning programmer such as myself have to deal with 21759b6c17a6Seric ** this kind of antique garbage???? 217625a99e2eSeric ** 217725a99e2eSeric ** Parameters: 21785aa0f353Seric ** mci -- the connection information. 21795aa0f353Seric ** e -- the envelope. 218025a99e2eSeric ** 218125a99e2eSeric ** Returns: 218251552439Seric ** none 218325a99e2eSeric ** 218425a99e2eSeric ** Side Effects: 218551552439Seric ** outputs some text to fp. 218625a99e2eSeric */ 218725a99e2eSeric 2188a6a073b5Seric void 21895aa0f353Seric putfromline(mci, e) 21905aa0f353Seric register MCI *mci; 2191b31e7f2bSeric ENVELOPE *e; 219225a99e2eSeric { 21932bc47524Seric char *template = "\201l\n"; 219451552439Seric char buf[MAXLINE]; 219525a99e2eSeric 21965aa0f353Seric if (bitnset(M_NHDR, mci->mci_mailer->m_flags)) 219751552439Seric return; 219813bbc08cSeric 21995aa0f353Seric if (bitnset(M_UGLYUUCP, mci->mci_mailer->m_flags)) 220074b6e67bSeric { 2201ea09d6edSeric char *bang; 2202ea09d6edSeric char xbuf[MAXLINE]; 220374b6e67bSeric 2204b665faabSeric expand("\201g", buf, sizeof buf, e); 22056c2c3107Seric bang = strchr(buf, '!'); 220674b6e67bSeric if (bang == NULL) 220734fcca25Seric { 220834fcca25Seric errno = 0; 220934fcca25Seric syserr("554 No ! in UUCP From address! (%s given)", buf); 221034fcca25Seric } 221174b6e67bSeric else 2212588cad61Seric { 2213ea09d6edSeric *bang++ = '\0'; 22142bc47524Seric (void) sprintf(xbuf, "From %s \201d remote from %s\n", bang, buf); 2215ea09d6edSeric template = xbuf; 221674b6e67bSeric } 2217588cad61Seric } 2218b665faabSeric expand(template, buf, sizeof buf, e); 2219d95dad3eSeric putxline(buf, mci, PXLF_NOTHINGSPECIAL); 2220bc6e2962Seric } 2221bc6e2962Seric /* 222251552439Seric ** PUTBODY -- put the body of a message. 222351552439Seric ** 222451552439Seric ** Parameters: 22255aa0f353Seric ** mci -- the connection information. 22269a6a5f55Seric ** e -- the envelope to put out. 222703c02fdeSeric ** separator -- if non-NULL, a message separator that must 222803c02fdeSeric ** not be permitted in the resulting message. 222951552439Seric ** 223051552439Seric ** Returns: 223151552439Seric ** none. 223251552439Seric ** 223351552439Seric ** Side Effects: 223451552439Seric ** The message is written onto fp. 223551552439Seric */ 223651552439Seric 2237b665faabSeric /* values for output state variable */ 2238b665faabSeric #define OS_HEAD 0 /* at beginning of line */ 2239b665faabSeric #define OS_CR 1 /* read a carriage return */ 2240b665faabSeric #define OS_INLINE 2 /* putting rest of line */ 2241b665faabSeric 2242a6a073b5Seric void 22436ffc2dd1Seric putbody(mci, e, separator) 22445aa0f353Seric register MCI *mci; 22459a6a5f55Seric register ENVELOPE *e; 224603c02fdeSeric char *separator; 224751552439Seric { 224877b52738Seric char buf[MAXLINE]; 224951552439Seric 225051552439Seric /* 225151552439Seric ** Output the body of the message 225251552439Seric */ 225351552439Seric 2254b665faabSeric if (e->e_dfp == NULL && bitset(EF_HAS_DF, e->e_flags)) 22559a6a5f55Seric { 2256b665faabSeric char *df = queuename(e, 'd'); 2257b665faabSeric 2258b665faabSeric e->e_dfp = fopen(df, "r"); 22599a6a5f55Seric if (e->e_dfp == NULL) 22608f9146b0Srick syserr("putbody: Cannot open %s for %s from %s", 2261b665faabSeric df, e->e_to, e->e_from.q_paddr); 2262b665faabSeric } 2263b665faabSeric if (e->e_dfp == NULL) 2264b665faabSeric { 2265b665faabSeric if (bitset(MCIF_INHEADER, mci->mci_flags)) 2266b665faabSeric { 2267b665faabSeric putline("", mci); 2268b665faabSeric mci->mci_flags &= ~MCIF_INHEADER; 2269b665faabSeric } 2270b665faabSeric putline("<<< No Message Collected >>>", mci); 2271b665faabSeric goto endofmessage; 2272b665faabSeric } 2273b665faabSeric if (e->e_dfino == (ino_t) 0) 2274b665faabSeric { 2275b665faabSeric struct stat stbuf; 2276b665faabSeric 2277b665faabSeric if (fstat(fileno(e->e_dfp), &stbuf) < 0) 2278b665faabSeric e->e_dfino = -1; 2279b665faabSeric else 2280b665faabSeric { 2281b665faabSeric e->e_dfdev = stbuf.st_dev; 2282b665faabSeric e->e_dfino = stbuf.st_ino; 2283b665faabSeric } 2284b665faabSeric } 2285b665faabSeric rewind(e->e_dfp); 2286b665faabSeric 228704cf0889Seric #if MIME8TO7 2288b665faabSeric if (bitset(MCIF_CVT8TO7, mci->mci_flags)) 2289b665faabSeric { 2290b665faabSeric char *boundaries[MAXMIMENESTING + 1]; 2291b665faabSeric 2292b665faabSeric /* 2293b665faabSeric ** Do 8 to 7 bit MIME conversion. 2294b665faabSeric */ 2295b665faabSeric 2296b665faabSeric /* make sure it looks like a MIME message */ 2297b665faabSeric if (hvalue("MIME-Version", e->e_header) == NULL) 2298b665faabSeric putline("MIME-Version: 1.0", mci); 2299b665faabSeric 2300b665faabSeric if (hvalue("Content-Type", e->e_header) == NULL) 2301b665faabSeric { 2302b665faabSeric sprintf(buf, "Content-Type: text/plain; charset=%s", 2303b665faabSeric defcharset(e)); 2304b665faabSeric putline(buf, mci); 2305b665faabSeric } 2306b665faabSeric 2307b665faabSeric /* now do the hard work */ 2308b665faabSeric boundaries[0] = NULL; 2309b665faabSeric mime8to7(mci, e->e_header, e, boundaries, M87F_OUTER); 23109a6a5f55Seric } 2311bd4e74cdSeric else 231204cf0889Seric #endif 2313b665faabSeric { 2314b665faabSeric int ostate; 2315b665faabSeric register char *bp; 2316b665faabSeric register char *pbp; 2317b665faabSeric register int c; 2318b665faabSeric int padc; 2319b665faabSeric char *buflim; 2320b665faabSeric int pos = 0; 2321b665faabSeric char peekbuf[10]; 2322b665faabSeric 2323b665faabSeric /* we can pass it through unmodified */ 2324b665faabSeric if (bitset(MCIF_INHEADER, mci->mci_flags)) 2325b665faabSeric { 2326b665faabSeric putline("", mci); 2327b665faabSeric mci->mci_flags &= ~MCIF_INHEADER; 232864187506Seric } 2329b665faabSeric 2330b665faabSeric /* determine end of buffer; allow for short mailer lines */ 2331b665faabSeric buflim = &buf[sizeof buf - 1]; 2332b665faabSeric if (mci->mci_mailer->m_linelimit > 0 && 2333b665faabSeric mci->mci_mailer->m_linelimit < sizeof buf - 1) 2334b665faabSeric buflim = &buf[mci->mci_mailer->m_linelimit - 1]; 2335b665faabSeric 2336b665faabSeric /* copy temp file to output with mapping */ 2337b665faabSeric ostate = OS_HEAD; 2338b665faabSeric bp = buf; 2339b665faabSeric pbp = peekbuf; 2340b665faabSeric while (!ferror(mci->mci_out)) 2341519e7d80Seric { 2342b665faabSeric register char *xp; 2343b665faabSeric 2344b665faabSeric if (pbp > peekbuf) 2345b665faabSeric c = *--pbp; 23464ff9b170Seric else if ((c = getc(e->e_dfp)) == EOF) 2347b665faabSeric break; 2348b665faabSeric if (bitset(MCIF_7BIT, mci->mci_flags)) 2349b665faabSeric c &= 0x7f; 2350b665faabSeric switch (ostate) 2351a6ce3008Seric { 2352b665faabSeric case OS_HEAD: 2353b665faabSeric if (c != '\r' && c != '\n' && bp < buflim) 2354b665faabSeric { 2355b665faabSeric *bp++ = c; 2356b665faabSeric break; 2357b665faabSeric } 2358b665faabSeric 2359b665faabSeric /* check beginning of line for special cases */ 2360b665faabSeric *bp = '\0'; 2361b665faabSeric pos = 0; 2362b665faabSeric padc = EOF; 23635aa0f353Seric if (buf[0] == 'F' && 23645aa0f353Seric bitnset(M_ESCFROM, mci->mci_mailer->m_flags) && 2365d6fa2b58Sbostic strncmp(buf, "From ", 5) == 0) 2366b665faabSeric { 2367b665faabSeric padc = '>'; 2368b665faabSeric } 2369b665faabSeric if (buf[0] == '-' && buf[1] == '-' && 2370b665faabSeric separator != NULL) 237103c02fdeSeric { 237203c02fdeSeric /* possible separator */ 237303c02fdeSeric int sl = strlen(separator); 237403c02fdeSeric 237503c02fdeSeric if (strncmp(&buf[2], separator, sl) == 0) 2376b665faabSeric padc = ' '; 237703c02fdeSeric } 2378b665faabSeric if (buf[0] == '.' && 2379b665faabSeric bitnset(M_XDOT, mci->mci_mailer->m_flags)) 2380b665faabSeric { 2381b665faabSeric padc = '.'; 2382b665faabSeric } 2383b665faabSeric 2384b665faabSeric /* now copy out saved line */ 2385b665faabSeric if (TrafficLogFile != NULL) 2386b665faabSeric { 2387b665faabSeric fprintf(TrafficLogFile, "%05d >>> ", getpid()); 2388b665faabSeric if (padc != EOF) 23894ff9b170Seric putc(padc, TrafficLogFile); 2390b665faabSeric for (xp = buf; xp < bp; xp++) 23914ff9b170Seric putc(*xp, TrafficLogFile); 2392b665faabSeric if (c == '\n') 2393b665faabSeric fputs(mci->mci_mailer->m_eol, 2394b665faabSeric TrafficLogFile); 2395b665faabSeric } 2396b665faabSeric if (padc != EOF) 2397b665faabSeric { 23984ff9b170Seric putc(padc, mci->mci_out); 2399b665faabSeric pos++; 2400b665faabSeric } 2401b665faabSeric for (xp = buf; xp < bp; xp++) 24024ff9b170Seric putc(*xp, mci->mci_out); 2403b665faabSeric if (c == '\n') 2404b665faabSeric { 2405b665faabSeric fputs(mci->mci_mailer->m_eol, 2406b665faabSeric mci->mci_out); 2407b665faabSeric pos = 0; 2408b665faabSeric } 2409b665faabSeric else 2410b665faabSeric { 2411b665faabSeric pos += bp - buf; 2412b665faabSeric if (c != '\r') 2413b665faabSeric *pbp++ = c; 2414b665faabSeric } 2415b665faabSeric bp = buf; 2416b665faabSeric 2417b665faabSeric /* determine next state */ 2418b665faabSeric if (c == '\n') 2419b665faabSeric ostate = OS_HEAD; 2420b665faabSeric else if (c == '\r') 2421b665faabSeric ostate = OS_CR; 2422b665faabSeric else 2423b665faabSeric ostate = OS_INLINE; 2424b665faabSeric continue; 2425b665faabSeric 2426b665faabSeric case OS_CR: 2427b665faabSeric if (c == '\n') 2428b665faabSeric { 2429b665faabSeric /* got CRLF */ 2430b665faabSeric fputs(mci->mci_mailer->m_eol, mci->mci_out); 2431b665faabSeric if (TrafficLogFile != NULL) 2432b665faabSeric { 2433b665faabSeric fputs(mci->mci_mailer->m_eol, 2434b665faabSeric TrafficLogFile); 2435b665faabSeric } 2436b665faabSeric ostate = OS_HEAD; 2437b665faabSeric continue; 2438b665faabSeric } 2439b665faabSeric 2440b665faabSeric /* had a naked carriage return */ 2441b665faabSeric *pbp++ = c; 2442b665faabSeric c = '\r'; 2443b665faabSeric goto putch; 2444b665faabSeric 2445b665faabSeric case OS_INLINE: 2446b665faabSeric if (c == '\r') 2447b665faabSeric { 2448b665faabSeric ostate = OS_CR; 2449b665faabSeric continue; 2450b665faabSeric } 2451b665faabSeric putch: 2452b665faabSeric if (mci->mci_mailer->m_linelimit > 0 && 2453b665faabSeric pos > mci->mci_mailer->m_linelimit && 2454b665faabSeric c != '\n') 2455b665faabSeric { 2456b665faabSeric putc('!', mci->mci_out); 2457b665faabSeric fputs(mci->mci_mailer->m_eol, mci->mci_out); 2458b665faabSeric if (TrafficLogFile != NULL) 2459b665faabSeric { 2460b665faabSeric fprintf(TrafficLogFile, "!%s", 2461b665faabSeric mci->mci_mailer->m_eol); 2462b665faabSeric } 2463b665faabSeric ostate = OS_HEAD; 2464b665faabSeric *pbp++ = c; 2465b665faabSeric continue; 2466b665faabSeric } 2467b665faabSeric if (TrafficLogFile != NULL) 24684ff9b170Seric putc(c, TrafficLogFile); 2469b665faabSeric putc(c, mci->mci_out); 2470b665faabSeric pos++; 2471b665faabSeric ostate = c == '\n' ? OS_HEAD : OS_INLINE; 2472b665faabSeric break; 2473b665faabSeric } 2474b665faabSeric } 2475a6ce3008Seric } 247651552439Seric 24779a6a5f55Seric if (ferror(e->e_dfp)) 247851552439Seric { 2479b665faabSeric syserr("putbody: df%s: read error", e->e_id); 248051552439Seric ExitStat = EX_IOERR; 248151552439Seric } 248251552439Seric 2483b665faabSeric endofmessage: 24840890ba1fSeric /* some mailers want extra blank line at end of message */ 24855aa0f353Seric if (bitnset(M_BLANKEND, mci->mci_mailer->m_flags) && 24865aa0f353Seric buf[0] != '\0' && buf[0] != '\n') 24875aa0f353Seric putline("", mci); 24880890ba1fSeric 24895aa0f353Seric (void) fflush(mci->mci_out); 24905aa0f353Seric if (ferror(mci->mci_out) && errno != EPIPE) 249151552439Seric { 249251552439Seric syserr("putbody: write error"); 249351552439Seric ExitStat = EX_IOERR; 249451552439Seric } 249551552439Seric errno = 0; 249625a99e2eSeric } 249725a99e2eSeric /* 249825a99e2eSeric ** MAILFILE -- Send a message to a file. 249925a99e2eSeric ** 2500f129ec7dSeric ** If the file has the setuid/setgid bits set, but NO execute 2501f129ec7dSeric ** bits, sendmail will try to become the owner of that file 2502f129ec7dSeric ** rather than the real user. Obviously, this only works if 2503f129ec7dSeric ** sendmail runs as root. 2504f129ec7dSeric ** 2505588cad61Seric ** This could be done as a subordinate mailer, except that it 2506588cad61Seric ** is used implicitly to save messages in ~/dead.letter. We 2507588cad61Seric ** view this as being sufficiently important as to include it 2508588cad61Seric ** here. For example, if the system is dying, we shouldn't have 2509588cad61Seric ** to create another process plus some pipes to save the message. 2510588cad61Seric ** 251125a99e2eSeric ** Parameters: 251225a99e2eSeric ** filename -- the name of the file to send to. 25136259796dSeric ** ctladdr -- the controlling address header -- includes 25146259796dSeric ** the userid/groupid to be when sending. 251504a36717Seric ** sfflags -- flags for opening. 251604a36717Seric ** e -- the current envelope. 251725a99e2eSeric ** 251825a99e2eSeric ** Returns: 251925a99e2eSeric ** The exit code associated with the operation. 252025a99e2eSeric ** 252125a99e2eSeric ** Side Effects: 252225a99e2eSeric ** none. 252325a99e2eSeric */ 252425a99e2eSeric 2525a6a073b5Seric int 252604a36717Seric mailfile(filename, ctladdr, sfflags, e) 252725a99e2eSeric char *filename; 25286259796dSeric ADDRESS *ctladdr; 252904a36717Seric int sfflags; 2530b31e7f2bSeric register ENVELOPE *e; 253125a99e2eSeric { 253225a99e2eSeric register FILE *f; 2533b665faabSeric register int pid = -1; 253415d084d5Seric int mode; 253525a99e2eSeric 2536671745f3Seric if (tTd(11, 1)) 2537671745f3Seric { 2538671745f3Seric printf("mailfile %s\n ctladdr=", filename); 2539671745f3Seric printaddr(ctladdr, FALSE); 2540671745f3Seric } 2541671745f3Seric 2542f170942cSeric if (e->e_xfp != NULL) 2543f170942cSeric fflush(e->e_xfp); 2544f170942cSeric 254532d19d43Seric /* 254632d19d43Seric ** Fork so we can change permissions here. 254732d19d43Seric ** Note that we MUST use fork, not vfork, because of 254832d19d43Seric ** the complications of calling subroutines, etc. 254932d19d43Seric */ 255032d19d43Seric 255132d19d43Seric DOFORK(fork); 255232d19d43Seric 255332d19d43Seric if (pid < 0) 255432d19d43Seric return (EX_OSERR); 255532d19d43Seric else if (pid == 0) 255632d19d43Seric { 255732d19d43Seric /* child -- actually write to file */ 2558f129ec7dSeric struct stat stb; 2559f2e4d5e8Seric struct stat fsb; 25605aa0f353Seric MCI mcibuf; 25614ef13b77Seric int oflags = O_WRONLY|O_APPEND; 2562f129ec7dSeric 2563f2e4d5e8Seric if (e->e_lockfp != NULL) 256452099264Seric (void) close(fileno(e->e_lockfp)); 2565f2e4d5e8Seric 25662b9178d3Seric (void) setsignal(SIGINT, SIG_DFL); 25672b9178d3Seric (void) setsignal(SIGHUP, SIG_DFL); 25682b9178d3Seric (void) setsignal(SIGTERM, SIG_DFL); 25693462ad9eSeric (void) umask(OldUmask); 257004a36717Seric e->e_to = filename; 257104a36717Seric ExitStat = EX_OK; 257295f16dc0Seric 2573b665faabSeric #ifdef HASLSTAT 2574b665faabSeric if ((SafeFileEnv != NULL ? lstat(filename, &stb) 2575b665faabSeric : stat(filename, &stb)) < 0) 2576b665faabSeric #else 2577f129ec7dSeric if (stat(filename, &stb) < 0) 2578b665faabSeric #endif 25794ef13b77Seric { 25803a98e7eaSeric stb.st_mode = FileMode; 25814ef13b77Seric oflags |= O_CREAT|O_EXCL; 25824ef13b77Seric } 2583b665faabSeric else if (bitset(0111, stb.st_mode) || stb.st_nlink != 1 || 2584b665faabSeric (SafeFileEnv != NULL && !S_ISREG(stb.st_mode))) 2585f2e4d5e8Seric exit(EX_CANTCREAT); 258615d084d5Seric mode = stb.st_mode; 258795f16dc0Seric 258895f16dc0Seric /* limit the errors to those actually caused in the child */ 258995f16dc0Seric errno = 0; 259095f16dc0Seric ExitStat = EX_OK; 259195f16dc0Seric 259204a36717Seric if (ctladdr != NULL || bitset(SFF_RUNASREALUID, sfflags)) 259315d084d5Seric { 259415d084d5Seric /* ignore setuid and setgid bits */ 259515d084d5Seric mode &= ~(S_ISGID|S_ISUID); 259615d084d5Seric } 259715d084d5Seric 25988f9146b0Srick /* we have to open the dfile BEFORE setuid */ 2599b665faabSeric if (e->e_dfp == NULL && bitset(EF_HAS_DF, e->e_flags)) 26008f9146b0Srick { 2601b665faabSeric char *df = queuename(e, 'd'); 2602b665faabSeric 2603b665faabSeric e->e_dfp = fopen(df, "r"); 260495f16dc0Seric if (e->e_dfp == NULL) 260595f16dc0Seric { 26068f9146b0Srick syserr("mailfile: Cannot open %s for %s from %s", 2607b665faabSeric df, e->e_to, e->e_from.q_paddr); 26088f9146b0Srick } 26098f9146b0Srick } 26108f9146b0Srick 2611b665faabSeric if (SafeFileEnv != NULL && SafeFileEnv[0] != '\0') 2612b665faabSeric { 2613b665faabSeric int i; 2614b665faabSeric 2615b665faabSeric if (chroot(SafeFileEnv) < 0) 2616b665faabSeric { 2617b665faabSeric syserr("mailfile: Cannot chroot(%s)", 2618b665faabSeric SafeFileEnv); 2619b665faabSeric exit(EX_CANTCREAT); 2620b665faabSeric } 2621b665faabSeric i = strlen(SafeFileEnv); 2622b665faabSeric if (strncmp(SafeFileEnv, filename, i) == 0) 2623b665faabSeric filename += i; 2624b665faabSeric } 2625b665faabSeric if (chdir("/") < 0) 2626b665faabSeric syserr("mailfile: cannot chdir(/)"); 2627b665faabSeric 262804a36717Seric /* select a new user to run as */ 262904a36717Seric if (!bitset(SFF_RUNASREALUID, sfflags)) 2630e36b99e2Seric { 263104a36717Seric if (bitset(S_ISUID, mode)) 263204a36717Seric { 263304a36717Seric RealUserName = NULL; 263404a36717Seric RealUid = stb.st_uid; 2635e36b99e2Seric } 263604a36717Seric else if (ctladdr != NULL && ctladdr->q_uid != 0) 2637e36b99e2Seric { 263804a36717Seric if (ctladdr->q_ruser != NULL) 263904a36717Seric RealUserName = ctladdr->q_ruser; 264004a36717Seric else 264104a36717Seric RealUserName = ctladdr->q_user; 264204a36717Seric RealUid = ctladdr->q_uid; 264304a36717Seric } 2644b665faabSeric else if (FileMailer != NULL && FileMailer->m_uid != 0) 264504a36717Seric { 264604a36717Seric RealUserName = DefUser; 264704a36717Seric RealUid = FileMailer->m_uid; 2648e36b99e2Seric } 264904a36717Seric else 265004a36717Seric { 265104a36717Seric RealUserName = DefUser; 265204a36717Seric RealUid = DefUid; 265304a36717Seric } 265404a36717Seric 265504a36717Seric /* select a new group to run as */ 265604a36717Seric if (bitset(S_ISGID, mode)) 265704a36717Seric RealGid = stb.st_gid; 265804a36717Seric else if (ctladdr != NULL && ctladdr->q_uid != 0) 265904a36717Seric RealGid = ctladdr->q_gid; 266004a36717Seric else if (FileMailer != NULL && FileMailer->m_gid != 0) 266104a36717Seric RealGid = FileMailer->m_gid; 266204a36717Seric else 266304a36717Seric RealGid = DefGid; 266404a36717Seric } 266504a36717Seric 266604a36717Seric /* last ditch */ 266704a36717Seric if (!bitset(SFF_ROOTOK, sfflags)) 266804a36717Seric { 266904a36717Seric if (RealUid == 0) 267004a36717Seric RealUid = DefUid; 267104a36717Seric if (RealGid == 0) 267204a36717Seric RealGid = DefGid; 267304a36717Seric } 267404a36717Seric 267504a36717Seric /* now set the group and user ids */ 267604a36717Seric if (RealUserName != NULL) 267704a36717Seric (void) initgroups(RealUserName, RealGid); 267804a36717Seric else 267904a36717Seric (void) setgid(RealGid); 268004a36717Seric (void) setuid(RealUid); 268104a36717Seric 268204a36717Seric sfflags |= SFF_NOPATHCHECK; 268304a36717Seric sfflags &= ~SFF_OPENASROOT; 268404a36717Seric f = safefopen(filename, oflags, FileMode, sfflags); 268525a99e2eSeric if (f == NULL) 268695f16dc0Seric { 2687b6a0de9dSeric message("554 cannot open: %s", errstring(errno)); 268832d19d43Seric exit(EX_CANTCREAT); 268995f16dc0Seric } 269025a99e2eSeric 26915aa0f353Seric bzero(&mcibuf, sizeof mcibuf); 26925aa0f353Seric mcibuf.mci_mailer = FileMailer; 26935aa0f353Seric mcibuf.mci_out = f; 26945aa0f353Seric if (bitnset(M_7BITS, FileMailer->m_flags)) 26955aa0f353Seric mcibuf.mci_flags |= MCIF_7BIT; 26965aa0f353Seric 26975aa0f353Seric putfromline(&mcibuf, e); 2698b665faabSeric (*e->e_puthdr)(&mcibuf, e->e_header, e); 26996ffc2dd1Seric (*e->e_putbody)(&mcibuf, e, NULL); 27005aa0f353Seric putline("\n", &mcibuf); 270195f16dc0Seric if (ferror(f)) 270295f16dc0Seric { 2703b6a0de9dSeric message("451 I/O error: %s", errstring(errno)); 270495f16dc0Seric setstat(EX_IOERR); 270595f16dc0Seric } 2706ee4b0922Seric (void) xfclose(f, "mailfile", filename); 270732d19d43Seric (void) fflush(stdout); 2708e36b99e2Seric 270927628d59Seric /* reset ISUID & ISGID bits for paranoid systems */ 2710c77d1c25Seric (void) chmod(filename, (int) stb.st_mode); 271195f16dc0Seric exit(ExitStat); 271213bbc08cSeric /*NOTREACHED*/ 271332d19d43Seric } 271432d19d43Seric else 271532d19d43Seric { 271632d19d43Seric /* parent -- wait for exit status */ 2717588cad61Seric int st; 271832d19d43Seric 2719588cad61Seric st = waitfor(pid); 2720bf9bc890Seric if (WIFEXITED(st)) 2721bf9bc890Seric return (WEXITSTATUS(st)); 2722588cad61Seric else 2723b6a0de9dSeric { 2724b6a0de9dSeric syserr("child died on signal %d", st); 2725bf9bc890Seric return (EX_UNAVAILABLE); 2726b6a0de9dSeric } 27278f9146b0Srick /*NOTREACHED*/ 272832d19d43Seric } 272925a99e2eSeric } 2730ea4dc939Seric /* 2731e103b48fSeric ** HOSTSIGNATURE -- return the "signature" for a host. 2732e103b48fSeric ** 2733e103b48fSeric ** The signature describes how we are going to send this -- it 2734e103b48fSeric ** can be just the hostname (for non-Internet hosts) or can be 2735e103b48fSeric ** an ordered list of MX hosts. 2736e103b48fSeric ** 2737e103b48fSeric ** Parameters: 2738e103b48fSeric ** m -- the mailer describing this host. 2739e103b48fSeric ** host -- the host name. 2740e103b48fSeric ** e -- the current envelope. 2741e103b48fSeric ** 2742e103b48fSeric ** Returns: 2743e103b48fSeric ** The signature for this host. 2744e103b48fSeric ** 2745e103b48fSeric ** Side Effects: 2746e103b48fSeric ** Can tweak the symbol table. 2747e103b48fSeric */ 2748e103b48fSeric 2749e103b48fSeric char * 2750e103b48fSeric hostsignature(m, host, e) 2751e103b48fSeric register MAILER *m; 2752e103b48fSeric char *host; 2753e103b48fSeric ENVELOPE *e; 2754e103b48fSeric { 2755e103b48fSeric register char *p; 2756e103b48fSeric register STAB *s; 2757e103b48fSeric int i; 2758e103b48fSeric int len; 27599d4a8008Seric #if NAMED_BIND 2760e103b48fSeric int nmx; 2761e103b48fSeric auto int rcode; 2762bafdc4e5Seric char *hp; 2763bafdc4e5Seric char *endp; 2764b665faabSeric int oldoptions = _res.options; 2765e103b48fSeric char *mxhosts[MAXMXHOSTS + 1]; 2766e103b48fSeric #endif 2767e103b48fSeric 2768e103b48fSeric /* 2769e103b48fSeric ** Check to see if this uses IPC -- if not, it can't have MX records. 2770e103b48fSeric */ 2771e103b48fSeric 2772e103b48fSeric p = m->m_mailer; 2773e103b48fSeric if (strcmp(p, "[IPC]") != 0 && strcmp(p, "[TCP]") != 0) 2774e103b48fSeric { 2775e103b48fSeric /* just an ordinary mailer */ 2776e103b48fSeric return host; 2777e103b48fSeric } 2778e103b48fSeric 2779e103b48fSeric /* 2780e103b48fSeric ** Look it up in the symbol table. 2781e103b48fSeric */ 2782e103b48fSeric 2783e103b48fSeric s = stab(host, ST_HOSTSIG, ST_ENTER); 2784e103b48fSeric if (s->s_hostsig != NULL) 2785e103b48fSeric return s->s_hostsig; 2786e103b48fSeric 2787e103b48fSeric /* 2788e103b48fSeric ** Not already there -- create a signature. 2789e103b48fSeric */ 2790e103b48fSeric 27919d4a8008Seric #if NAMED_BIND 2792516782b4Seric if (ConfigLevel < 2) 2793516782b4Seric _res.options &= ~(RES_DEFNAMES | RES_DNSRCH); /* XXX */ 2794516782b4Seric 2795bafdc4e5Seric for (hp = host; hp != NULL; hp = endp) 2796bafdc4e5Seric { 2797bafdc4e5Seric endp = strchr(hp, ':'); 2798bafdc4e5Seric if (endp != NULL) 2799bafdc4e5Seric *endp = '\0'; 2800bafdc4e5Seric 28017bf809e6Seric nmx = getmxrr(hp, mxhosts, TRUE, &rcode); 28027d55540cSeric 2803e103b48fSeric if (nmx <= 0) 2804e103b48fSeric { 2805e103b48fSeric register MCI *mci; 2806e103b48fSeric 2807e103b48fSeric /* update the connection info for this host */ 2808bafdc4e5Seric mci = mci_get(hp, m); 2809e103b48fSeric mci->mci_exitstat = rcode; 2810e103b48fSeric mci->mci_errno = errno; 2811f170942cSeric mci->mci_herrno = h_errno; 2812e103b48fSeric 2813e103b48fSeric /* and return the original host name as the signature */ 2814bafdc4e5Seric nmx = 1; 2815bafdc4e5Seric mxhosts[0] = hp; 2816e103b48fSeric } 2817e103b48fSeric 2818e103b48fSeric len = 0; 2819e103b48fSeric for (i = 0; i < nmx; i++) 2820e103b48fSeric { 2821e103b48fSeric len += strlen(mxhosts[i]) + 1; 2822e103b48fSeric } 2823bafdc4e5Seric if (s->s_hostsig != NULL) 2824bafdc4e5Seric len += strlen(s->s_hostsig) + 1; 2825bafdc4e5Seric p = xalloc(len); 2826bafdc4e5Seric if (s->s_hostsig != NULL) 2827bafdc4e5Seric { 2828bafdc4e5Seric (void) strcpy(p, s->s_hostsig); 2829bafdc4e5Seric free(s->s_hostsig); 2830bafdc4e5Seric s->s_hostsig = p; 2831bafdc4e5Seric p += strlen(p); 2832bafdc4e5Seric *p++ = ':'; 2833bafdc4e5Seric } 2834bafdc4e5Seric else 2835bafdc4e5Seric s->s_hostsig = p; 2836e103b48fSeric for (i = 0; i < nmx; i++) 2837e103b48fSeric { 2838e103b48fSeric if (i != 0) 2839e103b48fSeric *p++ = ':'; 2840e103b48fSeric strcpy(p, mxhosts[i]); 2841e103b48fSeric p += strlen(p); 2842e103b48fSeric } 2843bafdc4e5Seric if (endp != NULL) 2844bafdc4e5Seric *endp++ = ':'; 2845bafdc4e5Seric } 2846e103b48fSeric makelower(s->s_hostsig); 2847516782b4Seric if (ConfigLevel < 2) 2848516782b4Seric _res.options = oldoptions; 2849e103b48fSeric #else 2850e103b48fSeric /* not using BIND -- the signature is just the host name */ 2851e103b48fSeric s->s_hostsig = host; 2852e103b48fSeric #endif 2853e103b48fSeric if (tTd(17, 1)) 2854e103b48fSeric printf("hostsignature(%s) = %s\n", host, s->s_hostsig); 2855e103b48fSeric return s->s_hostsig; 2856e103b48fSeric } 2857