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*23a75c08Seric static char sccsid[] = "@(#)deliver.c 8.149 (Berkeley) 04/25/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 { 491fdc75a0fSeric #ifdef 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 536fdc75a0fSeric #ifdef 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 5999c9e68d9Seric dofork() 6009c9e68d9Seric { 601b665faabSeric register int pid = -1; 6029c9e68d9Seric 6039c9e68d9Seric DOFORK(fork); 6049c9e68d9Seric return (pid); 6059c9e68d9Seric } 6069c9e68d9Seric /* 60713bbc08cSeric ** DELIVER -- Deliver a message to a list of addresses. 60813bbc08cSeric ** 60913bbc08cSeric ** This routine delivers to everyone on the same host as the 61013bbc08cSeric ** user on the head of the list. It is clever about mailers 61113bbc08cSeric ** that don't handle multiple users. It is NOT guaranteed 61213bbc08cSeric ** that it will deliver to all these addresses however -- so 61313bbc08cSeric ** deliver should be called once for each address on the 61413bbc08cSeric ** list. 61525a99e2eSeric ** 61625a99e2eSeric ** Parameters: 617588cad61Seric ** e -- the envelope to deliver. 618c77d1c25Seric ** firstto -- head of the address list to deliver to. 61925a99e2eSeric ** 62025a99e2eSeric ** Returns: 62125a99e2eSeric ** zero -- successfully delivered. 62225a99e2eSeric ** else -- some failure, see ExitStat for more info. 62325a99e2eSeric ** 62425a99e2eSeric ** Side Effects: 62525a99e2eSeric ** The standard input is passed off to someone. 62625a99e2eSeric */ 62725a99e2eSeric 628b665faabSeric int 629588cad61Seric deliver(e, firstto) 630588cad61Seric register ENVELOPE *e; 631c77d1c25Seric ADDRESS *firstto; 63225a99e2eSeric { 63378442df3Seric char *host; /* host being sent to */ 63478442df3Seric char *user; /* user being sent to */ 63525a99e2eSeric char **pvp; 6365dfc646bSeric register char **mvp; 63725a99e2eSeric register char *p; 638588cad61Seric register MAILER *m; /* mailer for this recipient */ 6396259796dSeric ADDRESS *ctladdr; 640b31e7f2bSeric register MCI *mci; 641c77d1c25Seric register ADDRESS *to = firstto; 642c579ef51Seric bool clever = FALSE; /* running user smtp to this mailer */ 643b665faabSeric ADDRESS *tochain = NULL; /* users chain in this mailer call */ 644911693bfSbostic int rcode; /* response code */ 645e103b48fSeric char *firstsig; /* signature of firstto */ 646b665faabSeric int pid = -1; 6479c9e68d9Seric char *curhost; 648b665faabSeric time_t xstart; 6499c9e68d9Seric int mpvect[2]; 6509c9e68d9Seric int rpvect[2]; 651ee6bf8dfSeric char *pv[MAXPV+1]; 652579ef0ddSeric char tobuf[TOBUFSIZE]; /* text line of to people */ 653b665faabSeric char buf[MAXNAME + 1]; 654b665faabSeric char rpathbuf[MAXNAME + 1]; /* translated return path */ 655fabb3bd4Seric extern int checkcompat(); 65625a99e2eSeric 65735490626Seric errno = 0; 658ee4b0922Seric if (bitset(QDONTSEND|QBADADDR|QQUEUEUP, to->q_flags)) 6595dfc646bSeric return (0); 66025a99e2eSeric 6619d4a8008Seric #if NAMED_BIND 662912a731aSbostic /* unless interactive, try twice, over a minute */ 6638d19a23dSeric if (OpMode == MD_DAEMON || OpMode == MD_SMTP) 6648d19a23dSeric { 665912a731aSbostic _res.retrans = 30; 666912a731aSbostic _res.retry = 2; 667912a731aSbostic } 668d4bd8f0eSbostic #endif 669912a731aSbostic 67051552439Seric m = to->q_mailer; 67151552439Seric host = to->q_host; 672c9be6216Seric CurEnv = e; /* just in case */ 6734384d521Seric e->e_statmsg = NULL; 674df106f0bSeric SmtpError[0] = '\0'; 675b665faabSeric xstart = curtime(); 67651552439Seric 6776ef48975Seric if (tTd(10, 1)) 678562ec147Seric printf("\n--deliver, id=%s, mailer=%s, host=`%s', first user=`%s'\n", 679562ec147Seric e->e_id, m->m_name, host, to->q_user); 680ab81ee53Seric if (tTd(10, 100)) 681ab81ee53Seric printopenfds(FALSE); 682f3dbc832Seric 683f3dbc832Seric /* 6845dfc646bSeric ** Do initial argv setup. 6855dfc646bSeric ** Insert the mailer name. Notice that $x expansion is 6865dfc646bSeric ** NOT done on the mailer name. Then, if the mailer has 6875dfc646bSeric ** a picky -f flag, we insert it as appropriate. This 6885dfc646bSeric ** code does not check for 'pv' overflow; this places a 6895dfc646bSeric ** manifest lower limit of 4 for MAXPV. 6903bea8136Seric ** The from address rewrite is expected to make 6913bea8136Seric ** the address relative to the other end. 6925dfc646bSeric */ 6935dfc646bSeric 69478442df3Seric /* rewrite from address, using rewriting rules */ 695efe54562Seric rcode = EX_OK; 696b665faabSeric if (bitnset(M_UDBENVELOPE, e->e_from.q_mailer->m_flags)) 697b665faabSeric p = e->e_sender; 698b665faabSeric else 699b665faabSeric p = e->e_from.q_paddr; 700b665faabSeric (void) strcpy(rpathbuf, remotename(p, m, 701efe54562Seric RF_SENDERADDR|RF_CANONICAL, 702efe54562Seric &rcode, e)); 703ee4b0922Seric define('g', rpathbuf, e); /* translated return path */ 704588cad61Seric define('h', host, e); /* to host */ 7055dfc646bSeric Errors = 0; 7065dfc646bSeric pvp = pv; 7075dfc646bSeric *pvp++ = m->m_argv[0]; 7085dfc646bSeric 7095dfc646bSeric /* insert -f or -r flag as appropriate */ 71057fc6f17Seric if (FromFlag && (bitnset(M_FOPT, m->m_flags) || bitnset(M_ROPT, m->m_flags))) 7115dfc646bSeric { 71257fc6f17Seric if (bitnset(M_FOPT, m->m_flags)) 7135dfc646bSeric *pvp++ = "-f"; 7145dfc646bSeric else 7155dfc646bSeric *pvp++ = "-r"; 716c23ed322Seric *pvp++ = newstr(rpathbuf); 7175dfc646bSeric } 7185dfc646bSeric 7195dfc646bSeric /* 7205dfc646bSeric ** Append the other fixed parts of the argv. These run 7215dfc646bSeric ** up to the first entry containing "$u". There can only 7225dfc646bSeric ** be one of these, and there are only a few more slots 7235dfc646bSeric ** in the pv after it. 7245dfc646bSeric */ 7255dfc646bSeric 7265dfc646bSeric for (mvp = m->m_argv; (p = *++mvp) != NULL; ) 7275dfc646bSeric { 7282bc47524Seric /* can't use strchr here because of sign extension problems */ 7292bc47524Seric while (*p != '\0') 7302bc47524Seric { 7312bc47524Seric if ((*p++ & 0377) == MACROEXPAND) 7322bc47524Seric { 7332bc47524Seric if (*p == 'u') 7345dfc646bSeric break; 7352bc47524Seric } 7362bc47524Seric } 7372bc47524Seric 7382bc47524Seric if (*p != '\0') 7395dfc646bSeric break; 7405dfc646bSeric 7415dfc646bSeric /* this entry is safe -- go ahead and process it */ 742b665faabSeric expand(*mvp, buf, sizeof buf, e); 7435dfc646bSeric *pvp++ = newstr(buf); 7445dfc646bSeric if (pvp >= &pv[MAXPV - 3]) 7455dfc646bSeric { 74608b25121Seric syserr("554 Too many parameters to %s before $u", pv[0]); 7475dfc646bSeric return (-1); 7485dfc646bSeric } 7495dfc646bSeric } 750c579ef51Seric 75133db8731Seric /* 75233db8731Seric ** If we have no substitution for the user name in the argument 75333db8731Seric ** list, we know that we must supply the names otherwise -- and 75433db8731Seric ** SMTP is the answer!! 75533db8731Seric */ 75633db8731Seric 7575dfc646bSeric if (*mvp == NULL) 758c579ef51Seric { 759c579ef51Seric /* running SMTP */ 7602c7e1b8dSeric # ifdef SMTP 761c579ef51Seric clever = TRUE; 762c579ef51Seric *pvp = NULL; 7636c2c3107Seric # else /* SMTP */ 76433db8731Seric /* oops! we don't implement SMTP */ 765df106f0bSeric syserr("554 SMTP style mailer not implemented"); 7662c7e1b8dSeric return (EX_SOFTWARE); 7676c2c3107Seric # endif /* SMTP */ 768c579ef51Seric } 7695dfc646bSeric 7705dfc646bSeric /* 7715dfc646bSeric ** At this point *mvp points to the argument with $u. We 7725dfc646bSeric ** run through our address list and append all the addresses 7735dfc646bSeric ** we can. If we run out of space, do not fret! We can 7745dfc646bSeric ** always send another copy later. 7755dfc646bSeric */ 7765dfc646bSeric 7775dfc646bSeric tobuf[0] = '\0'; 778588cad61Seric e->e_to = tobuf; 7796259796dSeric ctladdr = NULL; 780e103b48fSeric firstsig = hostsignature(firstto->q_mailer, firstto->q_host, e); 7815dfc646bSeric for (; to != NULL; to = to->q_next) 7825dfc646bSeric { 7835dfc646bSeric /* avoid sending multiple recipients to dumb mailers */ 78457fc6f17Seric if (tobuf[0] != '\0' && !bitnset(M_MUSER, m->m_flags)) 7855dfc646bSeric break; 7865dfc646bSeric 7875dfc646bSeric /* if already sent or not for this host, don't send */ 788ee4b0922Seric if (bitset(QDONTSEND|QBADADDR|QQUEUEUP, to->q_flags) || 789e103b48fSeric to->q_mailer != firstto->q_mailer || 790e103b48fSeric strcmp(hostsignature(to->q_mailer, to->q_host, e), firstsig) != 0) 7915dfc646bSeric continue; 7926259796dSeric 7934b22ea87Seric /* avoid overflowing tobuf */ 794aa50a568Sbostic if (sizeof tobuf < (strlen(to->q_paddr) + strlen(tobuf) + 2)) 7954b22ea87Seric break; 7964b22ea87Seric 7976ef48975Seric if (tTd(10, 1)) 798772e6e50Seric { 799772e6e50Seric printf("\nsend to "); 800772e6e50Seric printaddr(to, FALSE); 801772e6e50Seric } 802772e6e50Seric 8036259796dSeric /* compute effective uid/gid when sending */ 804b665faabSeric if (bitnset(M_RUNASRCPT, to->q_mailer->m_flags)) 8056259796dSeric ctladdr = getctladdr(to); 8066259796dSeric 807b665faabSeric if (tTd(10, 2)) 808b665faabSeric { 809b665faabSeric printf("ctladdr="); 810b665faabSeric printaddr(ctladdr, FALSE); 811b665faabSeric } 812b665faabSeric 8135dfc646bSeric user = to->q_user; 814588cad61Seric e->e_to = to->q_paddr; 81575f1ade9Seric if (tTd(10, 5)) 81675f1ade9Seric { 81775f1ade9Seric printf("deliver: QDONTSEND "); 81875f1ade9Seric printaddr(to, FALSE); 81975f1ade9Seric } 820ee4b0922Seric to->q_flags |= QDONTSEND; 8215dfc646bSeric 8225dfc646bSeric /* 8235dfc646bSeric ** Check to see that these people are allowed to 8245dfc646bSeric ** talk to each other. 8252a6e0786Seric */ 8262a6e0786Seric 82769582d2fSeric if (m->m_maxsize != 0 && e->e_msgsize > m->m_maxsize) 82869582d2fSeric { 829b665faabSeric e->e_flags |= EF_NO_BODY_RETN; 8305b068d51Seric mci->mci_status = "5.2.3"; 83108b25121Seric usrerr("552 Message is too large; %ld bytes max", m->m_maxsize); 832b665faabSeric giveresponse(EX_UNAVAILABLE, m, NULL, ctladdr, xstart, e); 83369582d2fSeric continue; 83469582d2fSeric } 835b665faabSeric #if NAMED_BIND 836b665faabSeric h_errno = 0; 837b665faabSeric #endif 838fabb3bd4Seric rcode = checkcompat(to, e); 8391793c9c5Seric if (rcode != EX_OK) 8405dfc646bSeric { 841b665faabSeric markfailure(e, to, NULL, rcode); 842b665faabSeric giveresponse(rcode, m, NULL, ctladdr, xstart, e); 8435dfc646bSeric continue; 8445dfc646bSeric } 8452a6e0786Seric 8462a6e0786Seric /* 8479ec9501bSeric ** Strip quote bits from names if the mailer is dumb 8489ec9501bSeric ** about them. 84925a99e2eSeric */ 85025a99e2eSeric 85157fc6f17Seric if (bitnset(M_STRIPQ, m->m_flags)) 85225a99e2eSeric { 8531d8f1806Seric stripquotes(user); 8541d8f1806Seric stripquotes(host); 85525a99e2eSeric } 85625a99e2eSeric 857cdb828c5Seric /* hack attack -- delivermail compatibility */ 858cdb828c5Seric if (m == ProgMailer && *user == '|') 859cdb828c5Seric user++; 860cdb828c5Seric 86125a99e2eSeric /* 8623efaed6eSeric ** If an error message has already been given, don't 8633efaed6eSeric ** bother to send to this address. 8643efaed6eSeric ** 8653efaed6eSeric ** >>>>>>>>>> This clause assumes that the local mailer 8663efaed6eSeric ** >> NOTE >> cannot do any further aliasing; that 8673efaed6eSeric ** >>>>>>>>>> function is subsumed by sendmail. 8683efaed6eSeric */ 8693efaed6eSeric 8706cae517dSeric if (bitset(QBADADDR|QQUEUEUP, to->q_flags)) 8713efaed6eSeric continue; 8723efaed6eSeric 873f2fec898Seric /* save statistics.... */ 874588cad61Seric markstats(e, to); 875f2fec898Seric 8763efaed6eSeric /* 87725a99e2eSeric ** See if this user name is "special". 87825a99e2eSeric ** If the user name has a slash in it, assume that this 87951552439Seric ** is a file -- send it off without further ado. Note 88051552439Seric ** that this type of addresses is not processed along 88151552439Seric ** with the others, so we fudge on the To person. 88225a99e2eSeric */ 88325a99e2eSeric 884*23a75c08Seric if (strcmp(m->m_mailer, "[FILE]") == 0) 88525a99e2eSeric { 88603463a75Seric rcode = mailfile(user, ctladdr, e); 887b665faabSeric giveresponse(rcode, m, NULL, ctladdr, xstart, e); 888b665faabSeric e->e_nsent++; 889dde5acadSeric if (rcode == EX_OK) 890b665faabSeric { 891dde5acadSeric to->q_flags |= QSENT; 892b665faabSeric if (bitnset(M_LOCALMAILER, m->m_flags) && 893b665faabSeric (e->e_receiptto != NULL || 894b665faabSeric bitset(QPINGONSUCCESS, to->q_flags))) 895b665faabSeric { 8969070d157Seric to->q_flags |= QDELIVERED; 897d95dad3eSeric to->q_status = "2.1.5"; 898b665faabSeric fprintf(e->e_xfp, "%s... Successfully delivered\n", 899b665faabSeric to->q_paddr); 900b665faabSeric } 901b665faabSeric } 902b665faabSeric to->q_statdate = curtime(); 9035dfc646bSeric continue; 90425a99e2eSeric } 90525a99e2eSeric 90613bbc08cSeric /* 90713bbc08cSeric ** Address is verified -- add this user to mailer 90813bbc08cSeric ** argv, and add it to the print list of recipients. 90913bbc08cSeric */ 91013bbc08cSeric 911508daeccSeric /* link together the chain of recipients */ 912508daeccSeric to->q_tchain = tochain; 913508daeccSeric tochain = to; 914508daeccSeric 9155dfc646bSeric /* create list of users for error messages */ 916db8841e9Seric (void) strcat(tobuf, ","); 917db8841e9Seric (void) strcat(tobuf, to->q_paddr); 918588cad61Seric define('u', user, e); /* to user */ 919b6f89e6eSeric p = to->q_home; 920b6f89e6eSeric if (p == NULL && ctladdr != NULL) 921b6f89e6eSeric p = ctladdr->q_home; 922b6f89e6eSeric define('z', p, e); /* user's home */ 9235dfc646bSeric 924c579ef51Seric /* 925508daeccSeric ** Expand out this user into argument list. 926c579ef51Seric */ 927c579ef51Seric 928508daeccSeric if (!clever) 929c579ef51Seric { 930b665faabSeric expand(*mvp, buf, sizeof buf, e); 9315dfc646bSeric *pvp++ = newstr(buf); 9325dfc646bSeric if (pvp >= &pv[MAXPV - 2]) 9335dfc646bSeric { 9345dfc646bSeric /* allow some space for trailing parms */ 9355dfc646bSeric break; 9365dfc646bSeric } 9375dfc646bSeric } 938c579ef51Seric } 9395dfc646bSeric 940145b49b1Seric /* see if any addresses still exist */ 941145b49b1Seric if (tobuf[0] == '\0') 942c579ef51Seric { 943588cad61Seric define('g', (char *) NULL, e); 944145b49b1Seric return (0); 945c579ef51Seric } 946145b49b1Seric 9475dfc646bSeric /* print out messages as full list */ 94863780dbdSeric e->e_to = tobuf + 1; 9495dfc646bSeric 9505dfc646bSeric /* 9515dfc646bSeric ** Fill out any parameters after the $u parameter. 9525dfc646bSeric */ 9535dfc646bSeric 954c579ef51Seric while (!clever && *++mvp != NULL) 9555dfc646bSeric { 956b665faabSeric expand(*mvp, buf, sizeof buf, e); 9575dfc646bSeric *pvp++ = newstr(buf); 9585dfc646bSeric if (pvp >= &pv[MAXPV]) 95908b25121Seric syserr("554 deliver: pv overflow after $u for %s", pv[0]); 9605dfc646bSeric } 9615dfc646bSeric *pvp++ = NULL; 9625dfc646bSeric 96325a99e2eSeric /* 96425a99e2eSeric ** Call the mailer. 9656328bdf7Seric ** The argument vector gets built, pipes 96625a99e2eSeric ** are created as necessary, and we fork & exec as 9676328bdf7Seric ** appropriate. 968c579ef51Seric ** If we are running SMTP, we just need to clean up. 96925a99e2eSeric */ 97025a99e2eSeric 971960e665aSeric /*XXX this seems a bit wierd */ 9724899f6b5Seric if (ctladdr == NULL && m != ProgMailer && 9734899f6b5Seric bitset(QGOODUID, e->e_from.q_flags)) 974960e665aSeric ctladdr = &e->e_from; 975960e665aSeric 9769d4a8008Seric #if NAMED_BIND 9772bcc6d2dSeric if (ConfigLevel < 2) 978912a731aSbostic _res.options &= ~(RES_DEFNAMES | RES_DNSRCH); /* XXX */ 979134746fbSeric #endif 9809c9e68d9Seric 9819c9e68d9Seric if (tTd(11, 1)) 982134746fbSeric { 9839c9e68d9Seric printf("openmailer:"); 9849c9e68d9Seric printav(pv); 9859c9e68d9Seric } 9869c9e68d9Seric errno = 0; 987b665faabSeric #if NAMED_BIND 988b665faabSeric h_errno = 0; 989b665faabSeric #endif 9909c9e68d9Seric 991b665faabSeric CurHostName = NULL; 9929c9e68d9Seric 9939c9e68d9Seric /* 9949c9e68d9Seric ** Deal with the special case of mail handled through an IPC 9959c9e68d9Seric ** connection. 9969c9e68d9Seric ** In this case we don't actually fork. We must be 9979c9e68d9Seric ** running SMTP for this to work. We will return a 9989c9e68d9Seric ** zero pid to indicate that we are running IPC. 9999c9e68d9Seric ** We also handle a debug version that just talks to stdin/out. 10009c9e68d9Seric */ 10019c9e68d9Seric 10029c9e68d9Seric curhost = NULL; 1003c931b82bSeric SmtpPhase = NULL; 1004df106f0bSeric mci = NULL; 10059c9e68d9Seric 10067febfd66Seric #ifdef XDEBUG 10077febfd66Seric { 10087febfd66Seric char wbuf[MAXLINE]; 10097febfd66Seric 10107febfd66Seric /* make absolutely certain 0, 1, and 2 are in use */ 10117febfd66Seric sprintf(wbuf, "%s... openmailer(%s)", e->e_to, m->m_name); 10127febfd66Seric checkfd012(wbuf); 10137febfd66Seric } 10147febfd66Seric #endif 10157febfd66Seric 1016b665faabSeric /* check for 8-bit available */ 1017b665faabSeric if (bitset(EF_HAS8BIT, e->e_flags) && 1018b665faabSeric bitnset(M_7BITS, m->m_flags) && 1019b665faabSeric !bitset(MM_MIME8BIT, MimeMode)) 1020b665faabSeric { 1021b665faabSeric usrerr("554 Cannot send 8-bit data to 7-bit destination"); 1022b665faabSeric rcode = EX_DATAERR; 10235b068d51Seric e->e_status = "5.6.3"; 1024b665faabSeric goto give_up; 1025b665faabSeric } 1026b665faabSeric 10279c9e68d9Seric /* check for Local Person Communication -- not for mortals!!! */ 10289c9e68d9Seric if (strcmp(m->m_mailer, "[LPC]") == 0) 10299c9e68d9Seric { 10309c9e68d9Seric mci = (MCI *) xalloc(sizeof *mci); 10319c9e68d9Seric bzero((char *) mci, sizeof *mci); 10329c9e68d9Seric mci->mci_in = stdin; 10339c9e68d9Seric mci->mci_out = stdout; 10349c9e68d9Seric mci->mci_state = clever ? MCIS_OPENING : MCIS_OPEN; 10359c9e68d9Seric mci->mci_mailer = m; 10369c9e68d9Seric } 10379c9e68d9Seric else if (strcmp(m->m_mailer, "[IPC]") == 0 || 10389c9e68d9Seric strcmp(m->m_mailer, "[TCP]") == 0) 10399c9e68d9Seric { 10409c9e68d9Seric #ifdef DAEMON 10419c9e68d9Seric register int i; 1042b665faabSeric register u_short port = 0; 10439c9e68d9Seric 1044a5d44642Seric if (pv[0] == NULL || pv[1] == NULL || pv[1][0] == '\0') 1045a5d44642Seric { 1046a5d44642Seric syserr("null host name for %s mailer", m->m_mailer); 1047a5d44642Seric rcode = EX_CONFIG; 1048a5d44642Seric goto give_up; 1049a5d44642Seric } 1050a5d44642Seric 10519c9e68d9Seric CurHostName = pv[1]; 10529c9e68d9Seric curhost = hostsignature(m, pv[1], e); 10539c9e68d9Seric 10549c9e68d9Seric if (curhost == NULL || curhost[0] == '\0') 10559c9e68d9Seric { 1056a5d44642Seric syserr("null host signature for %s", pv[1]); 1057dfebe401Seric rcode = EX_CONFIG; 1058b31e7f2bSeric goto give_up; 1059b31e7f2bSeric } 10609c9e68d9Seric 10619c9e68d9Seric if (!clever) 10629c9e68d9Seric { 10639c9e68d9Seric syserr("554 non-clever IPC"); 1064df106f0bSeric rcode = EX_CONFIG; 10659c9e68d9Seric goto give_up; 10669c9e68d9Seric } 10679c9e68d9Seric if (pv[2] != NULL) 10689c9e68d9Seric port = atoi(pv[2]); 10699c9e68d9Seric tryhost: 10709c9e68d9Seric while (*curhost != '\0') 10719c9e68d9Seric { 10729c9e68d9Seric register char *p; 1073b665faabSeric static char hostbuf[MAXNAME + 1]; 10749c9e68d9Seric 10759c9e68d9Seric /* pull the next host from the signature */ 10769c9e68d9Seric p = strchr(curhost, ':'); 10779c9e68d9Seric if (p == NULL) 10789c9e68d9Seric p = &curhost[strlen(curhost)]; 1079df106f0bSeric if (p == curhost) 1080df106f0bSeric { 1081df106f0bSeric syserr("deliver: null host name in signature"); 10828087428aSeric curhost++; 1083df106f0bSeric continue; 1084df106f0bSeric } 10859c9e68d9Seric strncpy(hostbuf, curhost, p - curhost); 10869c9e68d9Seric hostbuf[p - curhost] = '\0'; 10879c9e68d9Seric if (*p != '\0') 10889c9e68d9Seric p++; 10899c9e68d9Seric curhost = p; 10909c9e68d9Seric 10919c9e68d9Seric /* see if we already know that this host is fried */ 10929c9e68d9Seric CurHostName = hostbuf; 10939c9e68d9Seric mci = mci_get(hostbuf, m); 10949c9e68d9Seric if (mci->mci_state != MCIS_CLOSED) 10959c9e68d9Seric { 10969c9e68d9Seric if (tTd(11, 1)) 10979c9e68d9Seric { 10989c9e68d9Seric printf("openmailer: "); 10994052916eSeric mci_dump(mci, FALSE); 11009c9e68d9Seric } 11019c9e68d9Seric CurHostName = mci->mci_host; 1102b665faabSeric message("Using cached connection to %s via %s...", 1103b665faabSeric hostbuf, m->m_name); 11049c9e68d9Seric break; 11059c9e68d9Seric } 11069c9e68d9Seric mci->mci_mailer = m; 11079c9e68d9Seric if (mci->mci_exitstat != EX_OK) 11089c9e68d9Seric continue; 11099c9e68d9Seric 11109c9e68d9Seric /* try the connection */ 11119c9e68d9Seric setproctitle("%s %s: %s", e->e_id, hostbuf, "user open"); 1112b665faabSeric message("Connecting to %s via %s...", 11139c9e68d9Seric hostbuf, m->m_name); 11149c9e68d9Seric i = makeconnection(hostbuf, port, mci, 11159c9e68d9Seric bitnset(M_SECURE_PORT, m->m_flags)); 11169c9e68d9Seric mci->mci_exitstat = i; 11179c9e68d9Seric mci->mci_errno = errno; 11189d4a8008Seric #if NAMED_BIND 1119f170942cSeric mci->mci_herrno = h_errno; 1120f170942cSeric #endif 11219c9e68d9Seric if (i == EX_OK) 11229c9e68d9Seric { 11239c9e68d9Seric mci->mci_state = MCIS_OPENING; 11249c9e68d9Seric mci_cache(mci); 1125f170942cSeric if (TrafficLogFile != NULL) 1126f170942cSeric fprintf(TrafficLogFile, "%05d == CONNECT %s\n", 1127f170942cSeric getpid(), hostbuf); 11289c9e68d9Seric break; 11299c9e68d9Seric } 11309c9e68d9Seric else if (tTd(11, 1)) 11319c9e68d9Seric printf("openmailer: makeconnection => stat=%d, errno=%d\n", 11329c9e68d9Seric i, errno); 11339c9e68d9Seric 11349c9e68d9Seric /* enter status of this host */ 11359c9e68d9Seric setstat(i); 1136df106f0bSeric 1137df106f0bSeric /* should print some message here for -v mode */ 1138df106f0bSeric } 1139df106f0bSeric if (mci == NULL) 1140df106f0bSeric { 1141df106f0bSeric syserr("deliver: no host name"); 1142df106f0bSeric rcode = EX_OSERR; 1143df106f0bSeric goto give_up; 11449c9e68d9Seric } 11459c9e68d9Seric mci->mci_pid = 0; 11469c9e68d9Seric #else /* no DAEMON */ 11479c9e68d9Seric syserr("554 openmailer: no IPC"); 11489c9e68d9Seric if (tTd(11, 1)) 11499c9e68d9Seric printf("openmailer: NULL\n"); 1150df106f0bSeric rcode = EX_UNAVAILABLE; 1151df106f0bSeric goto give_up; 11529c9e68d9Seric #endif /* DAEMON */ 11539c9e68d9Seric } 11549c9e68d9Seric else 11559c9e68d9Seric { 1156b665faabSeric /* flush any expired connections */ 1157b665faabSeric (void) mci_scan(NULL); 1158b665faabSeric 1159b665faabSeric /* announce the connection to verbose listeners */ 1160b665faabSeric if (host == NULL || host[0] == '\0') 1161b665faabSeric message("Connecting to %s...", m->m_name); 1162b665faabSeric else 1163b665faabSeric message("Connecting to %s via %s...", host, m->m_name); 1164f170942cSeric if (TrafficLogFile != NULL) 11650e3bfef5Seric { 1166f170942cSeric char **av; 1167f170942cSeric 1168f170942cSeric fprintf(TrafficLogFile, "%05d === EXEC", getpid()); 1169f170942cSeric for (av = pv; *av != NULL; av++) 1170f170942cSeric fprintf(TrafficLogFile, " %s", *av); 1171f170942cSeric fprintf(TrafficLogFile, "\n"); 11726fe8c3bcSeric } 11736fe8c3bcSeric 11749c9e68d9Seric /* create a pipe to shove the mail through */ 11759c9e68d9Seric if (pipe(mpvect) < 0) 11769c9e68d9Seric { 11770e3bfef5Seric syserr("%s... openmailer(%s): pipe (to mailer)", 11780e3bfef5Seric e->e_to, m->m_name); 11799c9e68d9Seric if (tTd(11, 1)) 11809c9e68d9Seric printf("openmailer: NULL\n"); 11819c9e68d9Seric rcode = EX_OSERR; 11829c9e68d9Seric goto give_up; 11839c9e68d9Seric } 11849c9e68d9Seric 11859c9e68d9Seric /* if this mailer speaks smtp, create a return pipe */ 11869c9e68d9Seric if (clever && pipe(rpvect) < 0) 11879c9e68d9Seric { 11880e3bfef5Seric syserr("%s... openmailer(%s): pipe (from mailer)", 11890e3bfef5Seric e->e_to, m->m_name); 11909c9e68d9Seric (void) close(mpvect[0]); 11919c9e68d9Seric (void) close(mpvect[1]); 11929c9e68d9Seric if (tTd(11, 1)) 11939c9e68d9Seric printf("openmailer: NULL\n"); 11949c9e68d9Seric rcode = EX_OSERR; 11959c9e68d9Seric goto give_up; 11969c9e68d9Seric } 11979c9e68d9Seric 11989c9e68d9Seric /* 11999c9e68d9Seric ** Actually fork the mailer process. 12009c9e68d9Seric ** DOFORK is clever about retrying. 12019c9e68d9Seric ** 12029c9e68d9Seric ** Dispose of SIGCHLD signal catchers that may be laying 12039c9e68d9Seric ** around so that endmail will get it. 12049c9e68d9Seric */ 12059c9e68d9Seric 12069c9e68d9Seric if (e->e_xfp != NULL) 12079c9e68d9Seric (void) fflush(e->e_xfp); /* for debugging */ 12089c9e68d9Seric (void) fflush(stdout); 12099c9e68d9Seric # ifdef SIGCHLD 12102b9178d3Seric (void) setsignal(SIGCHLD, SIG_DFL); 12119c9e68d9Seric # endif /* SIGCHLD */ 12129c9e68d9Seric DOFORK(FORK); 12139c9e68d9Seric /* pid is set by DOFORK */ 12149c9e68d9Seric if (pid < 0) 12159c9e68d9Seric { 12169c9e68d9Seric /* failure */ 12170e3bfef5Seric syserr("%s... openmailer(%s): cannot fork", 12180e3bfef5Seric e->e_to, m->m_name); 12199c9e68d9Seric (void) close(mpvect[0]); 12209c9e68d9Seric (void) close(mpvect[1]); 12219c9e68d9Seric if (clever) 12229c9e68d9Seric { 12239c9e68d9Seric (void) close(rpvect[0]); 12249c9e68d9Seric (void) close(rpvect[1]); 12259c9e68d9Seric } 12269c9e68d9Seric if (tTd(11, 1)) 12279c9e68d9Seric printf("openmailer: NULL\n"); 12289c9e68d9Seric rcode = EX_OSERR; 12299c9e68d9Seric goto give_up; 12309c9e68d9Seric } 12319c9e68d9Seric else if (pid == 0) 12329c9e68d9Seric { 12339c9e68d9Seric int i; 12349c9e68d9Seric int saveerrno; 12359c9e68d9Seric char **ep; 12369c9e68d9Seric char *env[MAXUSERENVIRON]; 12379c9e68d9Seric extern char **environ; 12389c9e68d9Seric extern int DtableSize; 12399c9e68d9Seric 1240f2e4d5e8Seric if (e->e_lockfp != NULL) 1241ac5a49f9Seric (void) close(fileno(e->e_lockfp)); 1242f2e4d5e8Seric 12439c9e68d9Seric /* child -- set up input & exec mailer */ 12442b9178d3Seric (void) setsignal(SIGINT, SIG_IGN); 12452b9178d3Seric (void) setsignal(SIGHUP, SIG_IGN); 12462b9178d3Seric (void) setsignal(SIGTERM, SIG_DFL); 12479c9e68d9Seric 124835427e30Seric /* tweak niceness */ 124935427e30Seric if (m->m_nice != 0) 125035427e30Seric nice(m->m_nice); 125135427e30Seric 125244f2317fSeric /* reset user and group */ 1253b665faabSeric if (bitnset(M_SPECIFIC_UID, m->m_flags)) 1254acc57dbfSeric { 1255b665faabSeric (void) setgid(m->m_gid); 1256b665faabSeric (void) setuid(m->m_uid); 1257acc57dbfSeric } 1258b665faabSeric else if (ctladdr != NULL && ctladdr->q_uid != 0) 125944f2317fSeric { 126044f2317fSeric (void) initgroups(ctladdr->q_ruser? 126144f2317fSeric ctladdr->q_ruser: ctladdr->q_user, 126244f2317fSeric ctladdr->q_gid); 126351cfe111Seric (void) setgid(ctladdr->q_gid); 126444f2317fSeric (void) setuid(ctladdr->q_uid); 126544f2317fSeric } 1266b665faabSeric else 1267b665faabSeric { 1268b665faabSeric (void) initgroups(DefUser, DefGid); 1269b665faabSeric if (m->m_gid == 0) 1270b665faabSeric (void) setgid(DefGid); 1271b665faabSeric else 1272b665faabSeric (void) setgid(m->m_gid); 1273b665faabSeric if (m->m_uid == 0) 1274b665faabSeric (void) setuid(DefUid); 1275b665faabSeric else 1276b665faabSeric (void) setuid(m->m_uid); 127744f2317fSeric } 127844f2317fSeric 127944f2317fSeric if (tTd(11, 2)) 128044f2317fSeric printf("openmailer: running as r/euid=%d/%d\n", 128144f2317fSeric getuid(), geteuid()); 128244f2317fSeric 1283b986f6aaSeric /* move into some "safe" directory */ 1284b986f6aaSeric if (m->m_execdir != NULL) 1285b986f6aaSeric { 1286b986f6aaSeric char *p, *q; 1287b665faabSeric char buf[MAXLINE + 1]; 1288b986f6aaSeric 1289b986f6aaSeric for (p = m->m_execdir; p != NULL; p = q) 1290b986f6aaSeric { 1291b986f6aaSeric q = strchr(p, ':'); 1292b986f6aaSeric if (q != NULL) 1293b986f6aaSeric *q = '\0'; 1294b665faabSeric expand(p, buf, sizeof buf, e); 1295b986f6aaSeric if (q != NULL) 1296b986f6aaSeric *q++ = ':'; 1297b986f6aaSeric if (tTd(11, 20)) 1298b986f6aaSeric printf("openmailer: trydir %s\n", 1299b986f6aaSeric buf); 1300b986f6aaSeric if (buf[0] != '\0' && chdir(buf) >= 0) 1301b986f6aaSeric break; 1302b986f6aaSeric } 1303b986f6aaSeric } 1304b986f6aaSeric 13059c9e68d9Seric /* arrange to filter std & diag output of command */ 13069c9e68d9Seric if (clever) 13079c9e68d9Seric { 13089c9e68d9Seric (void) close(rpvect[0]); 13096fe8c3bcSeric if (dup2(rpvect[1], STDOUT_FILENO) < 0) 13106fe8c3bcSeric { 13110e3bfef5Seric syserr("%s... openmailer(%s): cannot dup pipe %d for stdout", 13120e3bfef5Seric e->e_to, m->m_name, rpvect[1]); 13136fe8c3bcSeric _exit(EX_OSERR); 13146fe8c3bcSeric } 13159c9e68d9Seric (void) close(rpvect[1]); 13169c9e68d9Seric } 13178b40b0a4Seric else if (OpMode == MD_SMTP || OpMode == MD_DAEMON || 13188b40b0a4Seric HoldErrs || DisConnected) 13199c9e68d9Seric { 13209c9e68d9Seric /* put mailer output in transcript */ 13216fe8c3bcSeric if (dup2(fileno(e->e_xfp), STDOUT_FILENO) < 0) 13226fe8c3bcSeric { 13230e3bfef5Seric syserr("%s... openmailer(%s): cannot dup xscript %d for stdout", 13240e3bfef5Seric e->e_to, m->m_name, 13256fe8c3bcSeric fileno(e->e_xfp)); 13266fe8c3bcSeric _exit(EX_OSERR); 13279c9e68d9Seric } 13286fe8c3bcSeric } 13296fe8c3bcSeric if (dup2(STDOUT_FILENO, STDERR_FILENO) < 0) 13306fe8c3bcSeric { 13310e3bfef5Seric syserr("%s... openmailer(%s): cannot dup stdout for stderr", 13320e3bfef5Seric e->e_to, m->m_name); 13336fe8c3bcSeric _exit(EX_OSERR); 13346fe8c3bcSeric } 13359c9e68d9Seric 13369c9e68d9Seric /* arrange to get standard input */ 13379c9e68d9Seric (void) close(mpvect[1]); 13389c9e68d9Seric if (dup2(mpvect[0], STDIN_FILENO) < 0) 13399c9e68d9Seric { 13400e3bfef5Seric syserr("%s... openmailer(%s): cannot dup pipe %d for stdin", 13410e3bfef5Seric e->e_to, m->m_name, mpvect[0]); 13429c9e68d9Seric _exit(EX_OSERR); 13439c9e68d9Seric } 13449c9e68d9Seric (void) close(mpvect[0]); 13459c9e68d9Seric 13469c9e68d9Seric /* arrange for all the files to be closed */ 13479c9e68d9Seric for (i = 3; i < DtableSize; i++) 13489c9e68d9Seric { 13499c9e68d9Seric register int j; 135044f2317fSeric 13519c9e68d9Seric if ((j = fcntl(i, F_GETFD, 0)) != -1) 13529c9e68d9Seric (void) fcntl(i, F_SETFD, j | 1); 13539c9e68d9Seric } 13549c9e68d9Seric 13559f9b003eSeric /* 13569f9b003eSeric ** Set up the mailer environment 1357b665faabSeric ** _FORCE_MAIL_LOCAL_ is DG-UX equiv of -d flag. 13589f9b003eSeric ** TZ is timezone information. 13599f9b003eSeric ** SYSTYPE is Apollo software sys type (required). 13609f9b003eSeric ** ISP is Apollo hardware system type (required). 13619f9b003eSeric */ 13629f9b003eSeric 13639c9e68d9Seric i = 0; 13649c9e68d9Seric env[i++] = "AGENT=sendmail"; 1365b665faabSeric env[i++] = "_FORCE_MAIL_LOCAL_=yes"; 13669c9e68d9Seric for (ep = environ; *ep != NULL; ep++) 13679c9e68d9Seric { 13689f9b003eSeric if (strncmp(*ep, "TZ=", 3) == 0 || 13699f9b003eSeric strncmp(*ep, "ISP=", 4) == 0 || 13709f9b003eSeric strncmp(*ep, "SYSTYPE=", 8) == 0) 13719c9e68d9Seric env[i++] = *ep; 13729c9e68d9Seric } 1373b665faabSeric env[i] = NULL; 13749c9e68d9Seric 1375929277f2Seric /* run disconnected from terminal */ 1376929277f2Seric (void) setsid(); 1377929277f2Seric 13789c9e68d9Seric /* try to execute the mailer */ 13793f11fd05Seric execve(m->m_mailer, (ARGV_T) pv, (ARGV_T) env); 13809c9e68d9Seric saveerrno = errno; 13819c9e68d9Seric syserr("Cannot exec %s", m->m_mailer); 1382b665faabSeric if (bitnset(M_LOCALMAILER, m->m_flags) || 1383b665faabSeric transienterror(saveerrno)) 13847c941fd2Seric _exit(EX_OSERR); 13859c9e68d9Seric _exit(EX_UNAVAILABLE); 13869c9e68d9Seric } 13879c9e68d9Seric 13889c9e68d9Seric /* 13899c9e68d9Seric ** Set up return value. 13909c9e68d9Seric */ 13919c9e68d9Seric 13929c9e68d9Seric mci = (MCI *) xalloc(sizeof *mci); 13939c9e68d9Seric bzero((char *) mci, sizeof *mci); 13949c9e68d9Seric mci->mci_mailer = m; 13959c9e68d9Seric mci->mci_state = clever ? MCIS_OPENING : MCIS_OPEN; 13969c9e68d9Seric mci->mci_pid = pid; 13979c9e68d9Seric (void) close(mpvect[0]); 13989c9e68d9Seric mci->mci_out = fdopen(mpvect[1], "w"); 1399335eae58Seric if (mci->mci_out == NULL) 1400335eae58Seric { 1401335eae58Seric syserr("deliver: cannot create mailer output channel, fd=%d", 1402335eae58Seric mpvect[1]); 1403335eae58Seric (void) close(mpvect[1]); 1404335eae58Seric if (clever) 1405335eae58Seric { 1406335eae58Seric (void) close(rpvect[0]); 1407335eae58Seric (void) close(rpvect[1]); 1408335eae58Seric } 1409335eae58Seric rcode = EX_OSERR; 1410335eae58Seric goto give_up; 1411335eae58Seric } 14129c9e68d9Seric if (clever) 14139c9e68d9Seric { 14149c9e68d9Seric (void) close(rpvect[1]); 14159c9e68d9Seric mci->mci_in = fdopen(rpvect[0], "r"); 1416335eae58Seric if (mci->mci_in == NULL) 1417335eae58Seric { 1418335eae58Seric syserr("deliver: cannot create mailer input channel, fd=%d", 1419335eae58Seric mpvect[1]); 1420335eae58Seric (void) close(rpvect[0]); 1421335eae58Seric fclose(mci->mci_out); 1422335eae58Seric mci->mci_out = NULL; 1423335eae58Seric rcode = EX_OSERR; 1424335eae58Seric goto give_up; 1425335eae58Seric } 14269c9e68d9Seric } 14279c9e68d9Seric else 14289c9e68d9Seric { 14299c9e68d9Seric mci->mci_flags |= MCIF_TEMP; 14309c9e68d9Seric mci->mci_in = NULL; 14319c9e68d9Seric } 14329c9e68d9Seric } 14339c9e68d9Seric 14349c9e68d9Seric /* 14359c9e68d9Seric ** If we are in SMTP opening state, send initial protocol. 14369c9e68d9Seric */ 14379c9e68d9Seric 14389c9e68d9Seric if (clever && mci->mci_state != MCIS_CLOSED) 14399c9e68d9Seric { 14409c9e68d9Seric smtpinit(m, mci, e); 14419c9e68d9Seric } 1442b665faabSeric 1443b665faabSeric if (bitset(EF_HAS8BIT, e->e_flags) && bitnset(M_7BITS, m->m_flags)) 1444b665faabSeric mci->mci_flags |= MCIF_CVT8TO7; 1445b665faabSeric else 1446b665faabSeric mci->mci_flags &= ~MCIF_CVT8TO7; 1447b665faabSeric 14489c9e68d9Seric if (tTd(11, 1)) 14499c9e68d9Seric { 14509c9e68d9Seric printf("openmailer: "); 14514052916eSeric mci_dump(mci, FALSE); 14529c9e68d9Seric } 14539c9e68d9Seric 14549c9e68d9Seric if (mci->mci_state != MCIS_OPEN) 1455b31e7f2bSeric { 1456b31e7f2bSeric /* couldn't open the mailer */ 1457b31e7f2bSeric rcode = mci->mci_exitstat; 14582a6bc25bSeric errno = mci->mci_errno; 14599d4a8008Seric #if NAMED_BIND 1460f170942cSeric h_errno = mci->mci_herrno; 1461f170942cSeric #endif 1462b31e7f2bSeric if (rcode == EX_OK) 1463b31e7f2bSeric { 1464b31e7f2bSeric /* shouldn't happen */ 146508b25121Seric syserr("554 deliver: rcode=%d, mci_state=%d, sig=%s", 14666b0f339dSeric rcode, mci->mci_state, firstsig); 1467b31e7f2bSeric rcode = EX_SOFTWARE; 1468b31e7f2bSeric } 1469b665faabSeric else if (curhost != NULL && *curhost != '\0') 147090891494Seric { 147190891494Seric /* try next MX site */ 147290891494Seric goto tryhost; 147390891494Seric } 1474b31e7f2bSeric } 1475b31e7f2bSeric else if (!clever) 1476b31e7f2bSeric { 1477b31e7f2bSeric /* 1478b31e7f2bSeric ** Format and send message. 1479b31e7f2bSeric */ 148015d084d5Seric 14815aa0f353Seric putfromline(mci, e); 1482b665faabSeric (*e->e_puthdr)(mci, e->e_header, e); 14836ffc2dd1Seric (*e->e_putbody)(mci, e, NULL); 1484b31e7f2bSeric 1485b31e7f2bSeric /* get the exit status */ 1486c9be6216Seric rcode = endmailer(mci, e, pv); 1487134746fbSeric } 1488134746fbSeric else 1489b31e7f2bSeric #ifdef SMTP 1490134746fbSeric { 1491b31e7f2bSeric /* 1492b31e7f2bSeric ** Send the MAIL FROM: protocol 1493b31e7f2bSeric */ 149415d084d5Seric 1495b31e7f2bSeric rcode = smtpmailfrom(m, mci, e); 1496b31e7f2bSeric if (rcode == EX_OK) 149775889e88Seric { 1498ded0d3daSkarels register char *t = tobuf; 1499ded0d3daSkarels register int i; 1500ded0d3daSkarels 1501588cad61Seric /* send the recipient list */ 150263780dbdSeric tobuf[0] = '\0'; 150375889e88Seric for (to = tochain; to != NULL; to = to->q_tchain) 150475889e88Seric { 150563780dbdSeric e->e_to = to->q_paddr; 150615d084d5Seric if ((i = smtprcpt(to, m, mci, e)) != EX_OK) 150775889e88Seric { 1508b665faabSeric markfailure(e, to, mci, i); 1509b665faabSeric giveresponse(i, m, mci, ctladdr, xstart, e); 151063780dbdSeric } 151175889e88Seric else 151275889e88Seric { 1513911693bfSbostic *t++ = ','; 1514b31e7f2bSeric for (p = to->q_paddr; *p; *t++ = *p++) 1515b31e7f2bSeric continue; 1516ee39df61Seric *t = '\0'; 1517588cad61Seric } 1518588cad61Seric } 1519588cad61Seric 152063780dbdSeric /* now send the data */ 152163780dbdSeric if (tobuf[0] == '\0') 1522b31e7f2bSeric { 15239c9e68d9Seric rcode = EX_OK; 152463780dbdSeric e->e_to = NULL; 1525b31e7f2bSeric if (bitset(MCIF_CACHED, mci->mci_flags)) 1526b31e7f2bSeric smtprset(m, mci, e); 1527b31e7f2bSeric } 152875889e88Seric else 152975889e88Seric { 153063780dbdSeric e->e_to = tobuf + 1; 153175889e88Seric rcode = smtpdata(m, mci, e); 153263780dbdSeric } 153363780dbdSeric 153463780dbdSeric /* now close the connection */ 1535b31e7f2bSeric if (!bitset(MCIF_CACHED, mci->mci_flags)) 153615d084d5Seric smtpquit(m, mci, e); 153763780dbdSeric } 1538cb082c5bSeric if (rcode != EX_OK && curhost != NULL && *curhost != '\0') 15399c9e68d9Seric { 15409c9e68d9Seric /* try next MX site */ 15419c9e68d9Seric goto tryhost; 15429c9e68d9Seric } 1543c579ef51Seric } 1544b31e7f2bSeric #else /* not SMTP */ 1545a05b3449Sbostic { 154608b25121Seric syserr("554 deliver: need SMTP compiled to use clever mailer"); 1547845e533cSeric rcode = EX_CONFIG; 1548b31e7f2bSeric goto give_up; 1549a05b3449Sbostic } 1550b31e7f2bSeric #endif /* SMTP */ 15519d4a8008Seric #if NAMED_BIND 15522bcc6d2dSeric if (ConfigLevel < 2) 1553912a731aSbostic _res.options |= RES_DEFNAMES | RES_DNSRCH; /* XXX */ 1554134746fbSeric #endif 15555dfc646bSeric 1556b31e7f2bSeric /* arrange a return receipt if requested */ 1557df106f0bSeric if (rcode == EX_OK && e->e_receiptto != NULL && 1558df106f0bSeric bitnset(M_LOCALMAILER, m->m_flags)) 1559b31e7f2bSeric { 1560b31e7f2bSeric e->e_flags |= EF_SENDRECEIPT; 1561b31e7f2bSeric /* do we want to send back more info? */ 1562b31e7f2bSeric } 1563b31e7f2bSeric 1564c77d1c25Seric /* 156563780dbdSeric ** Do final status disposal. 156663780dbdSeric ** We check for something in tobuf for the SMTP case. 1567c77d1c25Seric ** If we got a temporary failure, arrange to queue the 1568c77d1c25Seric ** addressees. 1569c77d1c25Seric */ 1570c77d1c25Seric 1571b31e7f2bSeric give_up: 157263780dbdSeric if (tobuf[0] != '\0') 1573b665faabSeric giveresponse(rcode, m, mci, ctladdr, xstart, e); 1574772e6e50Seric for (to = tochain; to != NULL; to = to->q_tchain) 1575b31e7f2bSeric { 1576dde5acadSeric if (rcode != EX_OK) 1577b665faabSeric markfailure(e, to, mci, rcode); 1578b665faabSeric else if (!bitset(QBADADDR|QQUEUEUP, to->q_flags)) 1579655518ecSeric { 1580dde5acadSeric to->q_flags |= QSENT; 1581b665faabSeric to->q_statdate = curtime(); 1582655518ecSeric e->e_nsent++; 1583b665faabSeric if (bitnset(M_LOCALMAILER, m->m_flags) && 1584b665faabSeric (e->e_receiptto != NULL || 1585b665faabSeric bitset(QPINGONSUCCESS, to->q_flags))) 1586df106f0bSeric { 15879070d157Seric to->q_flags |= QDELIVERED; 1588d95dad3eSeric to->q_status = "2.1.5"; 1589df106f0bSeric fprintf(e->e_xfp, "%s... Successfully delivered\n", 1590df106f0bSeric to->q_paddr); 1591df106f0bSeric } 1592b665faabSeric else if (bitset(QPINGONSUCCESS, to->q_flags) && 1593b665faabSeric bitset(QPRIMARY, to->q_flags) && 1594b665faabSeric !bitset(MCIF_DSN, mci->mci_flags)) 1595b665faabSeric { 1596b665faabSeric to->q_flags |= QRELAYED; 1597b665faabSeric fprintf(e->e_xfp, "%s... relayed; expect no further notifications\n", 1598b665faabSeric to->q_paddr); 1599b665faabSeric } 1600655518ecSeric } 1601b31e7f2bSeric } 1602b31e7f2bSeric 1603b31e7f2bSeric /* 1604b31e7f2bSeric ** Restore state and return. 1605b31e7f2bSeric */ 1606c77d1c25Seric 16077febfd66Seric #ifdef XDEBUG 16087febfd66Seric { 16097febfd66Seric char wbuf[MAXLINE]; 16107febfd66Seric 16117febfd66Seric /* make absolutely certain 0, 1, and 2 are in use */ 161244622ea3Seric sprintf(wbuf, "%s... end of deliver(%s)", 161344622ea3Seric e->e_to == NULL ? "NO-TO-LIST" : e->e_to, 161444622ea3Seric m->m_name); 16157febfd66Seric checkfd012(wbuf); 16167febfd66Seric } 16177febfd66Seric #endif 16187febfd66Seric 161935490626Seric errno = 0; 1620588cad61Seric define('g', (char *) NULL, e); 16215826d9d3Seric return (rcode); 162225a99e2eSeric } 16235dfc646bSeric /* 162483b7ddc9Seric ** MARKFAILURE -- mark a failure on a specific address. 162583b7ddc9Seric ** 162683b7ddc9Seric ** Parameters: 162783b7ddc9Seric ** e -- the envelope we are sending. 162883b7ddc9Seric ** q -- the address to mark. 1629b665faabSeric ** mci -- mailer connection information. 163083b7ddc9Seric ** rcode -- the code signifying the particular failure. 163183b7ddc9Seric ** 163283b7ddc9Seric ** Returns: 163383b7ddc9Seric ** none. 163483b7ddc9Seric ** 163583b7ddc9Seric ** Side Effects: 163683b7ddc9Seric ** marks the address (and possibly the envelope) with the 163783b7ddc9Seric ** failure so that an error will be returned or 163883b7ddc9Seric ** the message will be queued, as appropriate. 163983b7ddc9Seric */ 164083b7ddc9Seric 1641b665faabSeric markfailure(e, q, mci, rcode) 164283b7ddc9Seric register ENVELOPE *e; 164383b7ddc9Seric register ADDRESS *q; 1644b665faabSeric register MCI *mci; 164583b7ddc9Seric int rcode; 164683b7ddc9Seric { 1647b665faabSeric char *stat = NULL; 164819c47125Seric 1649d5aafa3cSeric switch (rcode) 1650d5aafa3cSeric { 1651d5aafa3cSeric case EX_OK: 1652d5aafa3cSeric break; 1653d5aafa3cSeric 1654d5aafa3cSeric case EX_TEMPFAIL: 1655d5aafa3cSeric case EX_IOERR: 1656d5aafa3cSeric case EX_OSERR: 165783b7ddc9Seric q->q_flags |= QQUEUEUP; 1658d5aafa3cSeric break; 1659d5aafa3cSeric 1660d5aafa3cSeric default: 1661f170942cSeric q->q_flags |= QBADADDR; 1662d5aafa3cSeric break; 1663d5aafa3cSeric } 1664b665faabSeric 16655b068d51Seric /* find most specific error code possible */ 1666b665faabSeric if (q->q_status == NULL && mci != NULL) 1667b665faabSeric q->q_status = mci->mci_status; 16685b068d51Seric if (q->q_status == NULL) 16695b068d51Seric q->q_status = e->e_status; 16705b068d51Seric if (q->q_status == NULL) 16715b068d51Seric { 1672b665faabSeric switch (rcode) 1673b665faabSeric { 1674b665faabSeric case EX_USAGE: 1675b665faabSeric stat = "5.5.4"; 1676b665faabSeric break; 1677b665faabSeric 1678b665faabSeric case EX_DATAERR: 1679b665faabSeric stat = "5.5.2"; 1680b665faabSeric break; 1681b665faabSeric 1682b665faabSeric case EX_NOUSER: 1683b665faabSeric stat = "5.1.1"; 1684b665faabSeric break; 1685b665faabSeric 16865b068d51Seric case EX_NOHOST: 16875b068d51Seric stat = "5.1.2"; 16885b068d51Seric break; 16895b068d51Seric 1690b665faabSeric case EX_NOINPUT: 1691b665faabSeric case EX_CANTCREAT: 1692b665faabSeric case EX_NOPERM: 1693b665faabSeric stat = "5.3.0"; 1694b665faabSeric break; 1695b665faabSeric 1696b665faabSeric case EX_UNAVAILABLE: 1697b665faabSeric case EX_SOFTWARE: 1698b665faabSeric case EX_OSFILE: 1699b665faabSeric case EX_PROTOCOL: 1700b665faabSeric case EX_CONFIG: 1701b665faabSeric stat = "5.5.0"; 1702b665faabSeric break; 1703b665faabSeric 1704b665faabSeric case EX_OSERR: 1705b665faabSeric case EX_IOERR: 1706b665faabSeric stat = "4.5.0"; 1707b665faabSeric break; 1708b665faabSeric 1709b665faabSeric case EX_TEMPFAIL: 1710b665faabSeric stat = "4.2.0"; 1711b665faabSeric break; 1712b665faabSeric } 1713d95dad3eSeric if (stat != NULL) 1714b665faabSeric q->q_status = stat; 17155b068d51Seric } 1716b665faabSeric 1717b665faabSeric q->q_statdate = curtime(); 1718b665faabSeric if (CurHostName != NULL && CurHostName[0] != '\0') 1719b665faabSeric q->q_statmta = newstr(CurHostName); 1720b665faabSeric if (rcode != EX_OK && q->q_rstatus == NULL) 1721b665faabSeric { 1722b665faabSeric char buf[30]; 1723b665faabSeric 1724b665faabSeric (void) sprintf(buf, "%d", rcode); 1725b665faabSeric q->q_rstatus = newstr(buf); 1726b665faabSeric } 172783b7ddc9Seric } 172883b7ddc9Seric /* 1729c579ef51Seric ** ENDMAILER -- Wait for mailer to terminate. 1730c579ef51Seric ** 1731c579ef51Seric ** We should never get fatal errors (e.g., segmentation 1732c579ef51Seric ** violation), so we report those specially. For other 1733c579ef51Seric ** errors, we choose a status message (into statmsg), 1734c579ef51Seric ** and if it represents an error, we print it. 1735c579ef51Seric ** 1736c579ef51Seric ** Parameters: 1737c579ef51Seric ** pid -- pid of mailer. 1738c9be6216Seric ** e -- the current envelope. 1739c9be6216Seric ** pv -- the parameter vector that invoked the mailer 1740c9be6216Seric ** (for error messages). 1741c579ef51Seric ** 1742c579ef51Seric ** Returns: 1743c579ef51Seric ** exit code of mailer. 1744c579ef51Seric ** 1745c579ef51Seric ** Side Effects: 1746c579ef51Seric ** none. 1747c579ef51Seric */ 1748c579ef51Seric 1749c9be6216Seric endmailer(mci, e, pv) 1750b31e7f2bSeric register MCI *mci; 1751c9be6216Seric register ENVELOPE *e; 1752c9be6216Seric char **pv; 1753c579ef51Seric { 1754588cad61Seric int st; 1755c579ef51Seric 175675889e88Seric /* close any connections */ 175775889e88Seric if (mci->mci_in != NULL) 175876f3d53fSeric (void) xfclose(mci->mci_in, mci->mci_mailer->m_name, "mci_in"); 175975889e88Seric if (mci->mci_out != NULL) 176076f3d53fSeric (void) xfclose(mci->mci_out, mci->mci_mailer->m_name, "mci_out"); 176175889e88Seric mci->mci_in = mci->mci_out = NULL; 176275889e88Seric mci->mci_state = MCIS_CLOSED; 176375889e88Seric 176433db8731Seric /* in the IPC case there is nothing to wait for */ 176575889e88Seric if (mci->mci_pid == 0) 176633db8731Seric return (EX_OK); 176733db8731Seric 176833db8731Seric /* wait for the mailer process to die and collect status */ 176975889e88Seric st = waitfor(mci->mci_pid); 1770588cad61Seric if (st == -1) 177178de67c1Seric { 1772c9be6216Seric syserr("endmailer %s: wait", pv[0]); 1773588cad61Seric return (EX_SOFTWARE); 1774c579ef51Seric } 177533db8731Seric 1776bf9bc890Seric if (WIFEXITED(st)) 1777c579ef51Seric { 1778bf9bc890Seric /* normal death -- return status */ 1779bf9bc890Seric return (WEXITSTATUS(st)); 1780bf9bc890Seric } 1781bf9bc890Seric 1782bf9bc890Seric /* it died a horrid death */ 1783550092c3Seric syserr("451 mailer %s died with signal %o", 1784550092c3Seric mci->mci_mailer->m_name, st); 1785c9be6216Seric 1786c9be6216Seric /* log the arguments */ 17873c930db3Seric if (pv != NULL && e->e_xfp != NULL) 1788c9be6216Seric { 1789c9be6216Seric register char **av; 1790c9be6216Seric 1791c9be6216Seric fprintf(e->e_xfp, "Arguments:"); 1792c9be6216Seric for (av = pv; *av != NULL; av++) 1793c9be6216Seric fprintf(e->e_xfp, " %s", *av); 1794c9be6216Seric fprintf(e->e_xfp, "\n"); 1795c9be6216Seric } 1796c9be6216Seric 17975f73204aSeric ExitStat = EX_TEMPFAIL; 17985f73204aSeric return (EX_TEMPFAIL); 1799c579ef51Seric } 1800c579ef51Seric /* 180125a99e2eSeric ** GIVERESPONSE -- Interpret an error response from a mailer 180225a99e2eSeric ** 180325a99e2eSeric ** Parameters: 180425a99e2eSeric ** stat -- the status code from the mailer (high byte 180525a99e2eSeric ** only; core dumps must have been taken care of 180625a99e2eSeric ** already). 180781161401Seric ** m -- the mailer info for this mailer. 180881161401Seric ** mci -- the mailer connection info -- can be NULL if the 180981161401Seric ** response is given before the connection is made. 18104dee0003Seric ** ctladdr -- the controlling address for the recipient 18114dee0003Seric ** address(es). 1812b665faabSeric ** xstart -- the transaction start time, for computing 1813b665faabSeric ** transaction delays. 181481161401Seric ** e -- the current envelope. 181525a99e2eSeric ** 181625a99e2eSeric ** Returns: 1817db8841e9Seric ** none. 181825a99e2eSeric ** 181925a99e2eSeric ** Side Effects: 1820c1f9df2cSeric ** Errors may be incremented. 182125a99e2eSeric ** ExitStat may be set. 182225a99e2eSeric */ 182325a99e2eSeric 1824b665faabSeric giveresponse(stat, m, mci, ctladdr, xstart, e) 182525a99e2eSeric int stat; 1826588cad61Seric register MAILER *m; 182781161401Seric register MCI *mci; 18284dee0003Seric ADDRESS *ctladdr; 1829b665faabSeric time_t xstart; 1830198d9be0Seric ENVELOPE *e; 183125a99e2eSeric { 18329c16475dSeric register const char *statmsg; 183325a99e2eSeric extern char *SysExMsg[]; 183425a99e2eSeric register int i; 1835d4bd8f0eSbostic extern int N_SysEx; 1836198d9be0Seric char buf[MAXLINE]; 183725a99e2eSeric 183813bbc08cSeric /* 183913bbc08cSeric ** Compute status message from code. 184013bbc08cSeric */ 184113bbc08cSeric 184225a99e2eSeric i = stat - EX__BASE; 1843588cad61Seric if (stat == 0) 18446fe8c3bcSeric { 1845588cad61Seric statmsg = "250 Sent"; 1846ce5531bdSeric if (e->e_statmsg != NULL) 18476fe8c3bcSeric { 1848ce5531bdSeric (void) sprintf(buf, "%s (%s)", statmsg, e->e_statmsg); 18496fe8c3bcSeric statmsg = buf; 18506fe8c3bcSeric } 18516fe8c3bcSeric } 1852588cad61Seric else if (i < 0 || i > N_SysEx) 1853588cad61Seric { 1854588cad61Seric (void) sprintf(buf, "554 unknown mailer error %d", stat); 1855588cad61Seric stat = EX_UNAVAILABLE; 1856588cad61Seric statmsg = buf; 1857588cad61Seric } 1858198d9be0Seric else if (stat == EX_TEMPFAIL) 1859198d9be0Seric { 18607d55540cSeric (void) strcpy(buf, SysExMsg[i] + 1); 18619d4a8008Seric #if NAMED_BIND 1862f28da541Smiriam if (h_errno == TRY_AGAIN) 18634d50702aSeric statmsg = errstring(h_errno+E_DNSBASE); 1864f28da541Smiriam else 1865d4bd8f0eSbostic #endif 1866f28da541Smiriam { 18678557d168Seric if (errno != 0) 1868d87e85f3Seric statmsg = errstring(errno); 1869d87e85f3Seric else 1870d87e85f3Seric { 1871d87e85f3Seric #ifdef SMTP 1872d87e85f3Seric statmsg = SmtpError; 18736c2c3107Seric #else /* SMTP */ 1874d87e85f3Seric statmsg = NULL; 18756c2c3107Seric #endif /* SMTP */ 1876d87e85f3Seric } 1877f28da541Smiriam } 1878d87e85f3Seric if (statmsg != NULL && statmsg[0] != '\0') 1879d87e85f3Seric { 188087c9b3e7Seric (void) strcat(buf, ": "); 1881d87e85f3Seric (void) strcat(buf, statmsg); 18828557d168Seric } 1883198d9be0Seric statmsg = buf; 1884198d9be0Seric } 18859d4a8008Seric #if NAMED_BIND 1886f170942cSeric else if (stat == EX_NOHOST && h_errno != 0) 1887f170942cSeric { 18884d50702aSeric statmsg = errstring(h_errno + E_DNSBASE); 1889862934b2Seric (void) sprintf(buf, "%s (%s)", SysExMsg[i] + 1, statmsg); 1890f170942cSeric statmsg = buf; 1891f170942cSeric } 1892f170942cSeric #endif 189325a99e2eSeric else 1894d87e85f3Seric { 189525a99e2eSeric statmsg = SysExMsg[i]; 18967d55540cSeric if (*statmsg++ == ':') 18977d55540cSeric { 18987d55540cSeric (void) sprintf(buf, "%s: %s", statmsg, errstring(errno)); 18997d55540cSeric statmsg = buf; 19007d55540cSeric } 1901d87e85f3Seric } 1902588cad61Seric 1903588cad61Seric /* 1904588cad61Seric ** Print the message as appropriate 1905588cad61Seric */ 1906588cad61Seric 1907198d9be0Seric if (stat == EX_OK || stat == EX_TEMPFAIL) 1908df106f0bSeric { 1909df106f0bSeric extern char MsgBuf[]; 1910df106f0bSeric 19111f96bd0bSeric message("%s", &statmsg[4]); 1912df106f0bSeric if (stat == EX_TEMPFAIL && e->e_xfp != NULL) 1913df106f0bSeric fprintf(e->e_xfp, "%s\n", &MsgBuf[4]); 1914df106f0bSeric } 191525a99e2eSeric else 191625a99e2eSeric { 1917862934b2Seric char mbuf[8]; 1918862934b2Seric 1919c1f9df2cSeric Errors++; 1920862934b2Seric sprintf(mbuf, "%.3s %%s", statmsg); 1921862934b2Seric usrerr(mbuf, &statmsg[4]); 192225a99e2eSeric } 192325a99e2eSeric 192425a99e2eSeric /* 192525a99e2eSeric ** Final cleanup. 192625a99e2eSeric ** Log a record of the transaction. Compute the new 192725a99e2eSeric ** ExitStat -- if we already had an error, stick with 192825a99e2eSeric ** that. 192925a99e2eSeric */ 193025a99e2eSeric 19312f624c86Seric if (LogLevel > ((stat == EX_TEMPFAIL) ? 8 : (stat == EX_OK) ? 7 : 6)) 1932b665faabSeric logdelivery(m, mci, &statmsg[4], ctladdr, xstart, e); 1933eb238f8cSeric 19345d3f0ed4Seric if (tTd(11, 2)) 19355d3f0ed4Seric printf("giveresponse: stat=%d, e->e_message=%s\n", 19362c8ac7e0Seric stat, e->e_message == NULL ? "<NULL>" : e->e_message); 19375d3f0ed4Seric 1938eb238f8cSeric if (stat != EX_TEMPFAIL) 1939eb238f8cSeric setstat(stat); 19401097d4c9Seric if (stat != EX_OK && (stat != EX_TEMPFAIL || e->e_message == NULL)) 1941198d9be0Seric { 1942198d9be0Seric if (e->e_message != NULL) 1943198d9be0Seric free(e->e_message); 1944198d9be0Seric e->e_message = newstr(&statmsg[4]); 1945198d9be0Seric } 19468557d168Seric errno = 0; 19479d4a8008Seric #if NAMED_BIND 1948f28da541Smiriam h_errno = 0; 1949d4bd8f0eSbostic #endif 1950eb238f8cSeric } 1951eb238f8cSeric /* 1952eb238f8cSeric ** LOGDELIVERY -- log the delivery in the system log 1953eb238f8cSeric ** 19542c9b4f99Seric ** Care is taken to avoid logging lines that are too long, because 19552c9b4f99Seric ** some versions of syslog have an unfortunate proclivity for core 19562c9b4f99Seric ** dumping. This is a hack, to be sure, that is at best empirical. 19572c9b4f99Seric ** 1958eb238f8cSeric ** Parameters: 195981161401Seric ** m -- the mailer info. Can be NULL for initial queue. 196081161401Seric ** mci -- the mailer connection info -- can be NULL if the 196181161401Seric ** log is occuring when no connection is active. 196281161401Seric ** stat -- the message to print for the status. 19634dee0003Seric ** ctladdr -- the controlling address for the to list. 1964b665faabSeric ** xstart -- the transaction start time, used for 1965b665faabSeric ** computing transaction delay. 196681161401Seric ** e -- the current envelope. 1967eb238f8cSeric ** 1968eb238f8cSeric ** Returns: 1969eb238f8cSeric ** none 1970eb238f8cSeric ** 1971eb238f8cSeric ** Side Effects: 1972eb238f8cSeric ** none 1973eb238f8cSeric */ 1974eb238f8cSeric 1975b665faabSeric logdelivery(m, mci, stat, ctladdr, xstart, e) 197681161401Seric MAILER *m; 197781161401Seric register MCI *mci; 1978eb238f8cSeric char *stat; 19794dee0003Seric ADDRESS *ctladdr; 1980b665faabSeric time_t xstart; 1981b31e7f2bSeric register ENVELOPE *e; 19825cf56be3Seric { 1983eb238f8cSeric # ifdef LOG 19844dee0003Seric register char *bp; 19852c9b4f99Seric register char *p; 19862c9b4f99Seric int l; 1987d6acf3eeSeric char buf[512]; 19889507d1f9Seric 19893a100e8bSeric # if (SYSLOG_BUFSIZE) >= 256 19904dee0003Seric bp = buf; 19914dee0003Seric if (ctladdr != NULL) 19924dee0003Seric { 19934dee0003Seric strcpy(bp, ", ctladdr="); 1994f62f08c7Seric strcat(bp, shortenstring(ctladdr->q_paddr, 83)); 19954dee0003Seric bp += strlen(bp); 19964dee0003Seric if (bitset(QGOODUID, ctladdr->q_flags)) 19974dee0003Seric { 19984dee0003Seric (void) sprintf(bp, " (%d/%d)", 19994dee0003Seric ctladdr->q_uid, ctladdr->q_gid); 20004dee0003Seric bp += strlen(bp); 20014dee0003Seric } 20024dee0003Seric } 20034dee0003Seric 2004b665faabSeric sprintf(bp, ", delay=%s", pintvl(curtime() - e->e_ctime, TRUE)); 20054dee0003Seric bp += strlen(bp); 200681161401Seric 2007b665faabSeric if (xstart != (time_t) 0) 2008b665faabSeric { 2009b665faabSeric sprintf(bp, ", xdelay=%s", pintvl(curtime() - xstart, TRUE)); 2010b665faabSeric bp += strlen(bp); 2011b665faabSeric } 2012b665faabSeric 201348ed5d33Seric if (m != NULL) 201471ff6caaSeric { 20154dee0003Seric (void) strcpy(bp, ", mailer="); 20164dee0003Seric (void) strcat(bp, m->m_name); 20174dee0003Seric bp += strlen(bp); 201871ff6caaSeric } 201948ed5d33Seric 202048ed5d33Seric if (mci != NULL && mci->mci_host != NULL) 202171ff6caaSeric { 202271ff6caaSeric # ifdef DAEMON 2023e2f2f828Seric extern SOCKADDR CurHostAddr; 202448ed5d33Seric # endif 202571ff6caaSeric 20264dee0003Seric (void) strcpy(bp, ", relay="); 20274dee0003Seric (void) strcat(bp, mci->mci_host); 202848ed5d33Seric 202948ed5d33Seric # ifdef DAEMON 20302bdfc6b9Seric (void) strcat(bp, " ["); 20314dee0003Seric (void) strcat(bp, anynet_ntoa(&CurHostAddr)); 20322bdfc6b9Seric (void) strcat(bp, "]"); 203371ff6caaSeric # endif 203471ff6caaSeric } 2035bcb9b028Seric else if (strcmp(stat, "queued") != 0) 203648ed5d33Seric { 203748ed5d33Seric char *p = macvalue('h', e); 20389507d1f9Seric 203948ed5d33Seric if (p != NULL && p[0] != '\0') 204048ed5d33Seric { 20414dee0003Seric (void) strcpy(bp, ", relay="); 20424dee0003Seric (void) strcat(bp, p); 204348ed5d33Seric } 204448ed5d33Seric } 2045cb082c5bSeric bp += strlen(bp); 2046d6acf3eeSeric 20473a100e8bSeric #define STATLEN (((SYSLOG_BUFSIZE) - 100) / 4) 20483a100e8bSeric #if (STATLEN) < 63 20493a100e8bSeric # undef STATLEN 20503a100e8bSeric # define STATLEN 63 20513a100e8bSeric #endif 20523a100e8bSeric #if (STATLEN) > 203 20533a100e8bSeric # undef STATLEN 20543a100e8bSeric # define STATLEN 203 20553a100e8bSeric #endif 20563a100e8bSeric 20573a100e8bSeric if ((bp - buf) > (sizeof buf - ((STATLEN) + 20))) 20582c9b4f99Seric { 20592c9b4f99Seric /* desperation move -- truncate data */ 20603a100e8bSeric bp = buf + sizeof buf - ((STATLEN) + 17); 20612c9b4f99Seric strcpy(bp, "..."); 20622c9b4f99Seric bp += 3; 20632c9b4f99Seric } 20642c9b4f99Seric 20652c9b4f99Seric (void) strcpy(bp, ", stat="); 20662c9b4f99Seric bp += strlen(bp); 20673a100e8bSeric 20683a100e8bSeric (void) strcpy(bp, shortenstring(stat, (STATLEN))); 20692c9b4f99Seric 20702c9b4f99Seric l = SYSLOG_BUFSIZE - 100 - strlen(buf); 20712c9b4f99Seric p = e->e_to; 2072972b1942Seric while (strlen(p) >= (SIZE_T) l) 20732c9b4f99Seric { 20742c9b4f99Seric register char *q = strchr(p + l, ','); 20752c9b4f99Seric 20762a1b6b73Seric if (q == NULL) 20772c9b4f99Seric break; 20782c9b4f99Seric syslog(LOG_INFO, "%s: to=%.*s [more]%s", 20792c9b4f99Seric e->e_id, ++q - p, p, buf); 20802c9b4f99Seric p = q; 20812c9b4f99Seric } 20822c9b4f99Seric syslog(LOG_INFO, "%s: to=%s%s", e->e_id, p, buf); 20833a100e8bSeric 20843a100e8bSeric # else /* we have a very short log buffer size */ 20853a100e8bSeric 208627607809Seric l = SYSLOG_BUFSIZE - 85; 20873a100e8bSeric p = e->e_to; 20883a100e8bSeric while (strlen(p) >= l) 20893a100e8bSeric { 20903a100e8bSeric register char *q = strchr(p + l, ','); 20913a100e8bSeric 20923a100e8bSeric if (q == NULL) 20933a100e8bSeric break; 20943a100e8bSeric syslog(LOG_INFO, "%s: to=%.*s [more]", 20953a100e8bSeric e->e_id, ++q - p, p); 20963a100e8bSeric p = q; 20973a100e8bSeric } 20983a100e8bSeric syslog(LOG_INFO, "%s: to=%s", e->e_id, p); 20993a100e8bSeric 21003a100e8bSeric if (ctladdr != NULL) 21013a100e8bSeric { 21023a100e8bSeric bp = buf; 21033a100e8bSeric strcpy(buf, "ctladdr="); 21043a100e8bSeric bp += strlen(buf); 21053a100e8bSeric strcpy(bp, shortenstring(ctladdr->q_paddr, 83)); 21063a100e8bSeric bp += strlen(buf); 21073a100e8bSeric if (bitset(QGOODUID, ctladdr->q_flags)) 21083a100e8bSeric { 21093a100e8bSeric (void) sprintf(bp, " (%d/%d)", 21103a100e8bSeric ctladdr->q_uid, ctladdr->q_gid); 21113a100e8bSeric bp += strlen(bp); 21123a100e8bSeric } 21133a100e8bSeric syslog(LOG_INFO, "%s: %s", e->e_id, buf); 21143a100e8bSeric } 21154e797715Seric bp = buf; 21164e797715Seric sprintf(bp, "delay=%s", pintvl(curtime() - e->e_ctime, TRUE)); 21174e797715Seric bp += strlen(bp); 2118b665faabSeric if (xstart != (time_t) 0) 2119b665faabSeric { 2120b665faabSeric sprintf(bp, ", xdelay=%s", pintvl(curtime() - xstart, TRUE)); 2121b665faabSeric bp += strlen(bp); 2122b665faabSeric } 21233a100e8bSeric 21243a100e8bSeric if (m != NULL) 21254e797715Seric { 21264e797715Seric sprintf(bp, ", mailer=%s", m->m_name); 21274e797715Seric bp += strlen(bp); 21284e797715Seric } 2129b056abd0Seric syslog(LOG_INFO, "%s: %s", e->e_id, buf); 21303a100e8bSeric 2131b056abd0Seric buf[0] = '\0'; 21323a100e8bSeric if (mci != NULL && mci->mci_host != NULL) 21333a100e8bSeric { 21343a100e8bSeric # ifdef DAEMON 21353a100e8bSeric extern SOCKADDR CurHostAddr; 21363a100e8bSeric # endif 21373a100e8bSeric 2138d2ece200Seric sprintf(buf, "relay=%s", mci->mci_host); 21393a100e8bSeric 21403a100e8bSeric # ifdef DAEMON 2141b056abd0Seric (void) strcat(buf, " ["); 2142b056abd0Seric (void) strcat(buf, anynet_ntoa(&CurHostAddr)); 2143b056abd0Seric (void) strcat(buf, "]"); 21443a100e8bSeric # endif 21453a100e8bSeric } 2146bcb9b028Seric else if (strcmp(stat, "queued") != 0) 21473a100e8bSeric { 21483a100e8bSeric char *p = macvalue('h', e); 21493a100e8bSeric 21503a100e8bSeric if (p != NULL && p[0] != '\0') 2151d2ece200Seric sprintf(buf, "relay=%s", p); 21523a100e8bSeric } 2153b056abd0Seric if (buf[0] != '\0') 21544e797715Seric syslog(LOG_INFO, "%s: %s", e->e_id, buf); 21553a100e8bSeric 21563a100e8bSeric syslog(LOG_INFO, "%s: stat=%s", e->e_id, shortenstring(stat, 63)); 21573a100e8bSeric # endif /* short log buffer */ 21586c2c3107Seric # endif /* LOG */ 215925a99e2eSeric } 216025a99e2eSeric /* 216151552439Seric ** PUTFROMLINE -- output a UNIX-style from line (or whatever) 216225a99e2eSeric ** 216351552439Seric ** This can be made an arbitrary message separator by changing $l 216451552439Seric ** 21659b6c17a6Seric ** One of the ugliest hacks seen by human eyes is contained herein: 21669b6c17a6Seric ** UUCP wants those stupid "remote from <host>" lines. Why oh why 21679b6c17a6Seric ** does a well-meaning programmer such as myself have to deal with 21689b6c17a6Seric ** this kind of antique garbage???? 216925a99e2eSeric ** 217025a99e2eSeric ** Parameters: 21715aa0f353Seric ** mci -- the connection information. 21725aa0f353Seric ** e -- the envelope. 217325a99e2eSeric ** 217425a99e2eSeric ** Returns: 217551552439Seric ** none 217625a99e2eSeric ** 217725a99e2eSeric ** Side Effects: 217851552439Seric ** outputs some text to fp. 217925a99e2eSeric */ 218025a99e2eSeric 21815aa0f353Seric putfromline(mci, e) 21825aa0f353Seric register MCI *mci; 2183b31e7f2bSeric ENVELOPE *e; 218425a99e2eSeric { 21852bc47524Seric char *template = "\201l\n"; 218651552439Seric char buf[MAXLINE]; 218725a99e2eSeric 21885aa0f353Seric if (bitnset(M_NHDR, mci->mci_mailer->m_flags)) 218951552439Seric return; 219013bbc08cSeric 21912c7e1b8dSeric # ifdef UGLYUUCP 21925aa0f353Seric if (bitnset(M_UGLYUUCP, mci->mci_mailer->m_flags)) 219374b6e67bSeric { 2194ea09d6edSeric char *bang; 2195ea09d6edSeric char xbuf[MAXLINE]; 219674b6e67bSeric 2197b665faabSeric expand("\201g", buf, sizeof buf, e); 21986c2c3107Seric bang = strchr(buf, '!'); 219974b6e67bSeric if (bang == NULL) 220034fcca25Seric { 220134fcca25Seric errno = 0; 220234fcca25Seric syserr("554 No ! in UUCP From address! (%s given)", buf); 220334fcca25Seric } 220474b6e67bSeric else 2205588cad61Seric { 2206ea09d6edSeric *bang++ = '\0'; 22072bc47524Seric (void) sprintf(xbuf, "From %s \201d remote from %s\n", bang, buf); 2208ea09d6edSeric template = xbuf; 220974b6e67bSeric } 2210588cad61Seric } 22116c2c3107Seric # endif /* UGLYUUCP */ 2212b665faabSeric expand(template, buf, sizeof buf, e); 2213d95dad3eSeric putxline(buf, mci, PXLF_NOTHINGSPECIAL); 2214bc6e2962Seric } 2215bc6e2962Seric /* 221651552439Seric ** PUTBODY -- put the body of a message. 221751552439Seric ** 221851552439Seric ** Parameters: 22195aa0f353Seric ** mci -- the connection information. 22209a6a5f55Seric ** e -- the envelope to put out. 222103c02fdeSeric ** separator -- if non-NULL, a message separator that must 222203c02fdeSeric ** not be permitted in the resulting message. 222351552439Seric ** 222451552439Seric ** Returns: 222551552439Seric ** none. 222651552439Seric ** 222751552439Seric ** Side Effects: 222851552439Seric ** The message is written onto fp. 222951552439Seric */ 223051552439Seric 2231b665faabSeric /* values for output state variable */ 2232b665faabSeric #define OS_HEAD 0 /* at beginning of line */ 2233b665faabSeric #define OS_CR 1 /* read a carriage return */ 2234b665faabSeric #define OS_INLINE 2 /* putting rest of line */ 2235b665faabSeric 22366ffc2dd1Seric putbody(mci, e, separator) 22375aa0f353Seric register MCI *mci; 22389a6a5f55Seric register ENVELOPE *e; 223903c02fdeSeric char *separator; 224051552439Seric { 224177b52738Seric char buf[MAXLINE]; 224251552439Seric 224351552439Seric /* 224451552439Seric ** Output the body of the message 224551552439Seric */ 224651552439Seric 2247b665faabSeric if (e->e_dfp == NULL && bitset(EF_HAS_DF, e->e_flags)) 22489a6a5f55Seric { 2249b665faabSeric char *df = queuename(e, 'd'); 2250b665faabSeric 2251b665faabSeric e->e_dfp = fopen(df, "r"); 22529a6a5f55Seric if (e->e_dfp == NULL) 22538f9146b0Srick syserr("putbody: Cannot open %s for %s from %s", 2254b665faabSeric df, e->e_to, e->e_from.q_paddr); 2255b665faabSeric } 2256b665faabSeric if (e->e_dfp == NULL) 2257b665faabSeric { 2258b665faabSeric if (bitset(MCIF_INHEADER, mci->mci_flags)) 2259b665faabSeric { 2260b665faabSeric putline("", mci); 2261b665faabSeric mci->mci_flags &= ~MCIF_INHEADER; 2262b665faabSeric } 2263b665faabSeric putline("<<< No Message Collected >>>", mci); 2264b665faabSeric goto endofmessage; 2265b665faabSeric } 2266b665faabSeric if (e->e_dfino == (ino_t) 0) 2267b665faabSeric { 2268b665faabSeric struct stat stbuf; 2269b665faabSeric 2270b665faabSeric if (fstat(fileno(e->e_dfp), &stbuf) < 0) 2271b665faabSeric e->e_dfino = -1; 2272b665faabSeric else 2273b665faabSeric { 2274b665faabSeric e->e_dfdev = stbuf.st_dev; 2275b665faabSeric e->e_dfino = stbuf.st_ino; 2276b665faabSeric } 2277b665faabSeric } 2278b665faabSeric rewind(e->e_dfp); 2279b665faabSeric 2280b665faabSeric if (bitset(MCIF_CVT8TO7, mci->mci_flags)) 2281b665faabSeric { 2282b665faabSeric char *boundaries[MAXMIMENESTING + 1]; 2283b665faabSeric 2284b665faabSeric /* 2285b665faabSeric ** Do 8 to 7 bit MIME conversion. 2286b665faabSeric */ 2287b665faabSeric 2288b665faabSeric /* make sure it looks like a MIME message */ 2289b665faabSeric if (hvalue("MIME-Version", e->e_header) == NULL) 2290b665faabSeric putline("MIME-Version: 1.0", mci); 2291b665faabSeric 2292b665faabSeric if (hvalue("Content-Type", e->e_header) == NULL) 2293b665faabSeric { 2294b665faabSeric sprintf(buf, "Content-Type: text/plain; charset=%s", 2295b665faabSeric defcharset(e)); 2296b665faabSeric putline(buf, mci); 2297b665faabSeric } 2298b665faabSeric 2299b665faabSeric /* now do the hard work */ 2300b665faabSeric boundaries[0] = NULL; 2301b665faabSeric mime8to7(mci, e->e_header, e, boundaries, M87F_OUTER); 23029a6a5f55Seric } 2303bd4e74cdSeric else 2304b665faabSeric { 2305b665faabSeric int ostate; 2306b665faabSeric register char *bp; 2307b665faabSeric register char *pbp; 2308b665faabSeric register int c; 2309b665faabSeric int padc; 2310b665faabSeric char *buflim; 2311b665faabSeric int pos = 0; 2312b665faabSeric char peekbuf[10]; 2313b665faabSeric 2314b665faabSeric /* we can pass it through unmodified */ 2315b665faabSeric if (bitset(MCIF_INHEADER, mci->mci_flags)) 2316b665faabSeric { 2317b665faabSeric putline("", mci); 2318b665faabSeric mci->mci_flags &= ~MCIF_INHEADER; 231964187506Seric } 2320b665faabSeric 2321b665faabSeric /* determine end of buffer; allow for short mailer lines */ 2322b665faabSeric buflim = &buf[sizeof buf - 1]; 2323b665faabSeric if (mci->mci_mailer->m_linelimit > 0 && 2324b665faabSeric mci->mci_mailer->m_linelimit < sizeof buf - 1) 2325b665faabSeric buflim = &buf[mci->mci_mailer->m_linelimit - 1]; 2326b665faabSeric 2327b665faabSeric /* copy temp file to output with mapping */ 2328b665faabSeric ostate = OS_HEAD; 2329b665faabSeric bp = buf; 2330b665faabSeric pbp = peekbuf; 2331b665faabSeric while (!ferror(mci->mci_out)) 2332519e7d80Seric { 2333b665faabSeric register char *xp; 2334b665faabSeric 2335b665faabSeric if (pbp > peekbuf) 2336b665faabSeric c = *--pbp; 23374ff9b170Seric else if ((c = getc(e->e_dfp)) == EOF) 2338b665faabSeric break; 2339b665faabSeric if (bitset(MCIF_7BIT, mci->mci_flags)) 2340b665faabSeric c &= 0x7f; 2341b665faabSeric switch (ostate) 2342a6ce3008Seric { 2343b665faabSeric case OS_HEAD: 2344b665faabSeric if (c != '\r' && c != '\n' && bp < buflim) 2345b665faabSeric { 2346b665faabSeric *bp++ = c; 2347b665faabSeric break; 2348b665faabSeric } 2349b665faabSeric 2350b665faabSeric /* check beginning of line for special cases */ 2351b665faabSeric *bp = '\0'; 2352b665faabSeric pos = 0; 2353b665faabSeric padc = EOF; 23545aa0f353Seric if (buf[0] == 'F' && 23555aa0f353Seric bitnset(M_ESCFROM, mci->mci_mailer->m_flags) && 2356d6fa2b58Sbostic strncmp(buf, "From ", 5) == 0) 2357b665faabSeric { 2358b665faabSeric padc = '>'; 2359b665faabSeric } 2360b665faabSeric if (buf[0] == '-' && buf[1] == '-' && 2361b665faabSeric separator != NULL) 236203c02fdeSeric { 236303c02fdeSeric /* possible separator */ 236403c02fdeSeric int sl = strlen(separator); 236503c02fdeSeric 236603c02fdeSeric if (strncmp(&buf[2], separator, sl) == 0) 2367b665faabSeric padc = ' '; 236803c02fdeSeric } 2369b665faabSeric if (buf[0] == '.' && 2370b665faabSeric bitnset(M_XDOT, mci->mci_mailer->m_flags)) 2371b665faabSeric { 2372b665faabSeric padc = '.'; 2373b665faabSeric } 2374b665faabSeric 2375b665faabSeric /* now copy out saved line */ 2376b665faabSeric if (TrafficLogFile != NULL) 2377b665faabSeric { 2378b665faabSeric fprintf(TrafficLogFile, "%05d >>> ", getpid()); 2379b665faabSeric if (padc != EOF) 23804ff9b170Seric putc(padc, TrafficLogFile); 2381b665faabSeric for (xp = buf; xp < bp; xp++) 23824ff9b170Seric putc(*xp, TrafficLogFile); 2383b665faabSeric if (c == '\n') 2384b665faabSeric fputs(mci->mci_mailer->m_eol, 2385b665faabSeric TrafficLogFile); 2386b665faabSeric } 2387b665faabSeric if (padc != EOF) 2388b665faabSeric { 23894ff9b170Seric putc(padc, mci->mci_out); 2390b665faabSeric pos++; 2391b665faabSeric } 2392b665faabSeric for (xp = buf; xp < bp; xp++) 23934ff9b170Seric putc(*xp, mci->mci_out); 2394b665faabSeric if (c == '\n') 2395b665faabSeric { 2396b665faabSeric fputs(mci->mci_mailer->m_eol, 2397b665faabSeric mci->mci_out); 2398b665faabSeric pos = 0; 2399b665faabSeric } 2400b665faabSeric else 2401b665faabSeric { 2402b665faabSeric pos += bp - buf; 2403b665faabSeric if (c != '\r') 2404b665faabSeric *pbp++ = c; 2405b665faabSeric } 2406b665faabSeric bp = buf; 2407b665faabSeric 2408b665faabSeric /* determine next state */ 2409b665faabSeric if (c == '\n') 2410b665faabSeric ostate = OS_HEAD; 2411b665faabSeric else if (c == '\r') 2412b665faabSeric ostate = OS_CR; 2413b665faabSeric else 2414b665faabSeric ostate = OS_INLINE; 2415b665faabSeric continue; 2416b665faabSeric 2417b665faabSeric case OS_CR: 2418b665faabSeric if (c == '\n') 2419b665faabSeric { 2420b665faabSeric /* got CRLF */ 2421b665faabSeric fputs(mci->mci_mailer->m_eol, mci->mci_out); 2422b665faabSeric if (TrafficLogFile != NULL) 2423b665faabSeric { 2424b665faabSeric fputs(mci->mci_mailer->m_eol, 2425b665faabSeric TrafficLogFile); 2426b665faabSeric } 2427b665faabSeric ostate = OS_HEAD; 2428b665faabSeric continue; 2429b665faabSeric } 2430b665faabSeric 2431b665faabSeric /* had a naked carriage return */ 2432b665faabSeric *pbp++ = c; 2433b665faabSeric c = '\r'; 2434b665faabSeric goto putch; 2435b665faabSeric 2436b665faabSeric case OS_INLINE: 2437b665faabSeric if (c == '\r') 2438b665faabSeric { 2439b665faabSeric ostate = OS_CR; 2440b665faabSeric continue; 2441b665faabSeric } 2442b665faabSeric putch: 2443b665faabSeric if (mci->mci_mailer->m_linelimit > 0 && 2444b665faabSeric pos > mci->mci_mailer->m_linelimit && 2445b665faabSeric c != '\n') 2446b665faabSeric { 2447b665faabSeric putc('!', mci->mci_out); 2448b665faabSeric fputs(mci->mci_mailer->m_eol, mci->mci_out); 2449b665faabSeric if (TrafficLogFile != NULL) 2450b665faabSeric { 2451b665faabSeric fprintf(TrafficLogFile, "!%s", 2452b665faabSeric mci->mci_mailer->m_eol); 2453b665faabSeric } 2454b665faabSeric ostate = OS_HEAD; 2455b665faabSeric *pbp++ = c; 2456b665faabSeric continue; 2457b665faabSeric } 2458b665faabSeric if (TrafficLogFile != NULL) 24594ff9b170Seric putc(c, TrafficLogFile); 2460b665faabSeric putc(c, mci->mci_out); 2461b665faabSeric pos++; 2462b665faabSeric ostate = c == '\n' ? OS_HEAD : OS_INLINE; 2463b665faabSeric break; 2464b665faabSeric } 2465b665faabSeric } 2466a6ce3008Seric } 246751552439Seric 24689a6a5f55Seric if (ferror(e->e_dfp)) 246951552439Seric { 2470b665faabSeric syserr("putbody: df%s: read error", e->e_id); 247151552439Seric ExitStat = EX_IOERR; 247251552439Seric } 247351552439Seric 2474b665faabSeric endofmessage: 24750890ba1fSeric /* some mailers want extra blank line at end of message */ 24765aa0f353Seric if (bitnset(M_BLANKEND, mci->mci_mailer->m_flags) && 24775aa0f353Seric buf[0] != '\0' && buf[0] != '\n') 24785aa0f353Seric putline("", mci); 24790890ba1fSeric 24805aa0f353Seric (void) fflush(mci->mci_out); 24815aa0f353Seric if (ferror(mci->mci_out) && errno != EPIPE) 248251552439Seric { 248351552439Seric syserr("putbody: write error"); 248451552439Seric ExitStat = EX_IOERR; 248551552439Seric } 248651552439Seric errno = 0; 248725a99e2eSeric } 248825a99e2eSeric /* 248925a99e2eSeric ** MAILFILE -- Send a message to a file. 249025a99e2eSeric ** 2491f129ec7dSeric ** If the file has the setuid/setgid bits set, but NO execute 2492f129ec7dSeric ** bits, sendmail will try to become the owner of that file 2493f129ec7dSeric ** rather than the real user. Obviously, this only works if 2494f129ec7dSeric ** sendmail runs as root. 2495f129ec7dSeric ** 2496588cad61Seric ** This could be done as a subordinate mailer, except that it 2497588cad61Seric ** is used implicitly to save messages in ~/dead.letter. We 2498588cad61Seric ** view this as being sufficiently important as to include it 2499588cad61Seric ** here. For example, if the system is dying, we shouldn't have 2500588cad61Seric ** to create another process plus some pipes to save the message. 2501588cad61Seric ** 250225a99e2eSeric ** Parameters: 250325a99e2eSeric ** filename -- the name of the file to send to. 25046259796dSeric ** ctladdr -- the controlling address header -- includes 25056259796dSeric ** the userid/groupid to be when sending. 250625a99e2eSeric ** 250725a99e2eSeric ** Returns: 250825a99e2eSeric ** The exit code associated with the operation. 250925a99e2eSeric ** 251025a99e2eSeric ** Side Effects: 251125a99e2eSeric ** none. 251225a99e2eSeric */ 251325a99e2eSeric 2514b31e7f2bSeric mailfile(filename, ctladdr, e) 251525a99e2eSeric char *filename; 25166259796dSeric ADDRESS *ctladdr; 2517b31e7f2bSeric register ENVELOPE *e; 251825a99e2eSeric { 251925a99e2eSeric register FILE *f; 2520b665faabSeric register int pid = -1; 252115d084d5Seric int mode; 252225a99e2eSeric 2523671745f3Seric if (tTd(11, 1)) 2524671745f3Seric { 2525671745f3Seric printf("mailfile %s\n ctladdr=", filename); 2526671745f3Seric printaddr(ctladdr, FALSE); 2527671745f3Seric } 2528671745f3Seric 2529f170942cSeric if (e->e_xfp != NULL) 2530f170942cSeric fflush(e->e_xfp); 2531f170942cSeric 253232d19d43Seric /* 253332d19d43Seric ** Fork so we can change permissions here. 253432d19d43Seric ** Note that we MUST use fork, not vfork, because of 253532d19d43Seric ** the complications of calling subroutines, etc. 253632d19d43Seric */ 253732d19d43Seric 253832d19d43Seric DOFORK(fork); 253932d19d43Seric 254032d19d43Seric if (pid < 0) 254132d19d43Seric return (EX_OSERR); 254232d19d43Seric else if (pid == 0) 254332d19d43Seric { 254432d19d43Seric /* child -- actually write to file */ 2545f129ec7dSeric struct stat stb; 2546f2e4d5e8Seric struct stat fsb; 25475aa0f353Seric MCI mcibuf; 25484ef13b77Seric int oflags = O_WRONLY|O_APPEND; 2549f129ec7dSeric 2550f2e4d5e8Seric if (e->e_lockfp != NULL) 255152099264Seric (void) close(fileno(e->e_lockfp)); 2552f2e4d5e8Seric 25532b9178d3Seric (void) setsignal(SIGINT, SIG_DFL); 25542b9178d3Seric (void) setsignal(SIGHUP, SIG_DFL); 25552b9178d3Seric (void) setsignal(SIGTERM, SIG_DFL); 25563462ad9eSeric (void) umask(OldUmask); 255795f16dc0Seric 2558b665faabSeric #ifdef HASLSTAT 2559b665faabSeric if ((SafeFileEnv != NULL ? lstat(filename, &stb) 2560b665faabSeric : stat(filename, &stb)) < 0) 2561b665faabSeric #else 2562f129ec7dSeric if (stat(filename, &stb) < 0) 2563b665faabSeric #endif 25644ef13b77Seric { 25653a98e7eaSeric stb.st_mode = FileMode; 25664ef13b77Seric oflags |= O_CREAT|O_EXCL; 25674ef13b77Seric } 2568b665faabSeric else if (bitset(0111, stb.st_mode) || stb.st_nlink != 1 || 2569b665faabSeric (SafeFileEnv != NULL && !S_ISREG(stb.st_mode))) 2570f2e4d5e8Seric exit(EX_CANTCREAT); 257115d084d5Seric mode = stb.st_mode; 257295f16dc0Seric 257395f16dc0Seric /* limit the errors to those actually caused in the child */ 257495f16dc0Seric errno = 0; 257595f16dc0Seric ExitStat = EX_OK; 257695f16dc0Seric 257719428781Seric if (ctladdr != NULL) 257815d084d5Seric { 257915d084d5Seric /* ignore setuid and setgid bits */ 258015d084d5Seric mode &= ~(S_ISGID|S_ISUID); 258115d084d5Seric } 258215d084d5Seric 25838f9146b0Srick /* we have to open the dfile BEFORE setuid */ 2584b665faabSeric if (e->e_dfp == NULL && bitset(EF_HAS_DF, e->e_flags)) 25858f9146b0Srick { 2586b665faabSeric char *df = queuename(e, 'd'); 2587b665faabSeric 2588b665faabSeric e->e_dfp = fopen(df, "r"); 258995f16dc0Seric if (e->e_dfp == NULL) 259095f16dc0Seric { 25918f9146b0Srick syserr("mailfile: Cannot open %s for %s from %s", 2592b665faabSeric df, e->e_to, e->e_from.q_paddr); 25938f9146b0Srick } 25948f9146b0Srick } 25958f9146b0Srick 2596b665faabSeric if (SafeFileEnv != NULL && SafeFileEnv[0] != '\0') 2597b665faabSeric { 2598b665faabSeric int i; 2599b665faabSeric 2600b665faabSeric if (chroot(SafeFileEnv) < 0) 2601b665faabSeric { 2602b665faabSeric syserr("mailfile: Cannot chroot(%s)", 2603b665faabSeric SafeFileEnv); 2604b665faabSeric exit(EX_CANTCREAT); 2605b665faabSeric } 2606b665faabSeric i = strlen(SafeFileEnv); 2607b665faabSeric if (strncmp(SafeFileEnv, filename, i) == 0) 2608b665faabSeric filename += i; 2609b665faabSeric } 2610b665faabSeric if (chdir("/") < 0) 2611b665faabSeric syserr("mailfile: cannot chdir(/)"); 2612b665faabSeric 261315d084d5Seric if (!bitset(S_ISGID, mode) || setgid(stb.st_gid) < 0) 2614e36b99e2Seric { 2615b665faabSeric if (ctladdr != NULL && ctladdr->q_uid != 0) 2616898a126bSbostic (void) initgroups(ctladdr->q_ruser ? 2617898a126bSbostic ctladdr->q_ruser : ctladdr->q_user, 2618898a126bSbostic ctladdr->q_gid); 2619b665faabSeric else if (FileMailer != NULL && FileMailer->m_gid != 0) 2620b665faabSeric (void) initgroups(DefUser, FileMailer->m_gid); 2621b665faabSeric else 2622b665faabSeric (void) initgroups(DefUser, DefGid); 2623e36b99e2Seric } 262415d084d5Seric if (!bitset(S_ISUID, mode) || setuid(stb.st_uid) < 0) 2625e36b99e2Seric { 2626b665faabSeric if (ctladdr != NULL && ctladdr->q_uid != 0) 2627bd4e74cdSeric (void) setuid(ctladdr->q_uid); 2628b665faabSeric else if (FileMailer != NULL && FileMailer->m_uid != 0) 2629b665faabSeric (void) setuid(FileMailer->m_uid); 2630b665faabSeric else 2631b665faabSeric (void) setuid(DefUid); 2632e36b99e2Seric } 263395f16dc0Seric FileName = filename; 263495f16dc0Seric LineNumber = 0; 26354ef13b77Seric f = dfopen(filename, oflags, FileMode); 263625a99e2eSeric if (f == NULL) 263795f16dc0Seric { 2638b6a0de9dSeric message("554 cannot open: %s", errstring(errno)); 263932d19d43Seric exit(EX_CANTCREAT); 264095f16dc0Seric } 2641f2e4d5e8Seric if (fstat(fileno(f), &fsb) < 0 || 2642b665faabSeric (!bitset(O_CREAT, oflags) && 26434ef13b77Seric (stb.st_nlink != fsb.st_nlink || 2644f2e4d5e8Seric stb.st_dev != fsb.st_dev || 2645f2e4d5e8Seric stb.st_ino != fsb.st_ino || 2646b665faabSeric stb.st_uid != fsb.st_uid))) 2647f2e4d5e8Seric { 2648f2e4d5e8Seric message("554 cannot write: file changed after open"); 2649f2e4d5e8Seric exit(EX_CANTCREAT); 2650f2e4d5e8Seric } 265125a99e2eSeric 26525aa0f353Seric bzero(&mcibuf, sizeof mcibuf); 26535aa0f353Seric mcibuf.mci_mailer = FileMailer; 26545aa0f353Seric mcibuf.mci_out = f; 26555aa0f353Seric if (bitnset(M_7BITS, FileMailer->m_flags)) 26565aa0f353Seric mcibuf.mci_flags |= MCIF_7BIT; 26575aa0f353Seric 26585aa0f353Seric putfromline(&mcibuf, e); 2659b665faabSeric (*e->e_puthdr)(&mcibuf, e->e_header, e); 26606ffc2dd1Seric (*e->e_putbody)(&mcibuf, e, NULL); 26615aa0f353Seric putline("\n", &mcibuf); 266295f16dc0Seric if (ferror(f)) 266395f16dc0Seric { 2664b6a0de9dSeric message("451 I/O error: %s", errstring(errno)); 266595f16dc0Seric setstat(EX_IOERR); 266695f16dc0Seric } 2667ee4b0922Seric (void) xfclose(f, "mailfile", filename); 266832d19d43Seric (void) fflush(stdout); 2669e36b99e2Seric 267027628d59Seric /* reset ISUID & ISGID bits for paranoid systems */ 2671c77d1c25Seric (void) chmod(filename, (int) stb.st_mode); 267295f16dc0Seric exit(ExitStat); 267313bbc08cSeric /*NOTREACHED*/ 267432d19d43Seric } 267532d19d43Seric else 267632d19d43Seric { 267732d19d43Seric /* parent -- wait for exit status */ 2678588cad61Seric int st; 267932d19d43Seric 2680588cad61Seric st = waitfor(pid); 2681bf9bc890Seric if (WIFEXITED(st)) 2682bf9bc890Seric return (WEXITSTATUS(st)); 2683588cad61Seric else 2684b6a0de9dSeric { 2685b6a0de9dSeric syserr("child died on signal %d", st); 2686bf9bc890Seric return (EX_UNAVAILABLE); 2687b6a0de9dSeric } 26888f9146b0Srick /*NOTREACHED*/ 268932d19d43Seric } 269025a99e2eSeric } 2691ea4dc939Seric /* 2692e103b48fSeric ** HOSTSIGNATURE -- return the "signature" for a host. 2693e103b48fSeric ** 2694e103b48fSeric ** The signature describes how we are going to send this -- it 2695e103b48fSeric ** can be just the hostname (for non-Internet hosts) or can be 2696e103b48fSeric ** an ordered list of MX hosts. 2697e103b48fSeric ** 2698e103b48fSeric ** Parameters: 2699e103b48fSeric ** m -- the mailer describing this host. 2700e103b48fSeric ** host -- the host name. 2701e103b48fSeric ** e -- the current envelope. 2702e103b48fSeric ** 2703e103b48fSeric ** Returns: 2704e103b48fSeric ** The signature for this host. 2705e103b48fSeric ** 2706e103b48fSeric ** Side Effects: 2707e103b48fSeric ** Can tweak the symbol table. 2708e103b48fSeric */ 2709e103b48fSeric 2710e103b48fSeric char * 2711e103b48fSeric hostsignature(m, host, e) 2712e103b48fSeric register MAILER *m; 2713e103b48fSeric char *host; 2714e103b48fSeric ENVELOPE *e; 2715e103b48fSeric { 2716e103b48fSeric register char *p; 2717e103b48fSeric register STAB *s; 2718e103b48fSeric int i; 2719e103b48fSeric int len; 27209d4a8008Seric #if NAMED_BIND 2721e103b48fSeric int nmx; 2722e103b48fSeric auto int rcode; 2723bafdc4e5Seric char *hp; 2724bafdc4e5Seric char *endp; 2725b665faabSeric int oldoptions = _res.options; 2726e103b48fSeric char *mxhosts[MAXMXHOSTS + 1]; 2727e103b48fSeric #endif 2728e103b48fSeric 2729e103b48fSeric /* 2730e103b48fSeric ** Check to see if this uses IPC -- if not, it can't have MX records. 2731e103b48fSeric */ 2732e103b48fSeric 2733e103b48fSeric p = m->m_mailer; 2734e103b48fSeric if (strcmp(p, "[IPC]") != 0 && strcmp(p, "[TCP]") != 0) 2735e103b48fSeric { 2736e103b48fSeric /* just an ordinary mailer */ 2737e103b48fSeric return host; 2738e103b48fSeric } 2739e103b48fSeric 2740e103b48fSeric /* 2741e103b48fSeric ** Look it up in the symbol table. 2742e103b48fSeric */ 2743e103b48fSeric 2744e103b48fSeric s = stab(host, ST_HOSTSIG, ST_ENTER); 2745e103b48fSeric if (s->s_hostsig != NULL) 2746e103b48fSeric return s->s_hostsig; 2747e103b48fSeric 2748e103b48fSeric /* 2749e103b48fSeric ** Not already there -- create a signature. 2750e103b48fSeric */ 2751e103b48fSeric 27529d4a8008Seric #if NAMED_BIND 2753516782b4Seric if (ConfigLevel < 2) 2754516782b4Seric _res.options &= ~(RES_DEFNAMES | RES_DNSRCH); /* XXX */ 2755516782b4Seric 2756bafdc4e5Seric for (hp = host; hp != NULL; hp = endp) 2757bafdc4e5Seric { 2758bafdc4e5Seric endp = strchr(hp, ':'); 2759bafdc4e5Seric if (endp != NULL) 2760bafdc4e5Seric *endp = '\0'; 2761bafdc4e5Seric 27627bf809e6Seric nmx = getmxrr(hp, mxhosts, TRUE, &rcode); 27637d55540cSeric 2764e103b48fSeric if (nmx <= 0) 2765e103b48fSeric { 2766e103b48fSeric register MCI *mci; 2767e103b48fSeric 2768e103b48fSeric /* update the connection info for this host */ 2769bafdc4e5Seric mci = mci_get(hp, m); 2770e103b48fSeric mci->mci_exitstat = rcode; 2771e103b48fSeric mci->mci_errno = errno; 2772f170942cSeric mci->mci_herrno = h_errno; 2773e103b48fSeric 2774e103b48fSeric /* and return the original host name as the signature */ 2775bafdc4e5Seric nmx = 1; 2776bafdc4e5Seric mxhosts[0] = hp; 2777e103b48fSeric } 2778e103b48fSeric 2779e103b48fSeric len = 0; 2780e103b48fSeric for (i = 0; i < nmx; i++) 2781e103b48fSeric { 2782e103b48fSeric len += strlen(mxhosts[i]) + 1; 2783e103b48fSeric } 2784bafdc4e5Seric if (s->s_hostsig != NULL) 2785bafdc4e5Seric len += strlen(s->s_hostsig) + 1; 2786bafdc4e5Seric p = xalloc(len); 2787bafdc4e5Seric if (s->s_hostsig != NULL) 2788bafdc4e5Seric { 2789bafdc4e5Seric (void) strcpy(p, s->s_hostsig); 2790bafdc4e5Seric free(s->s_hostsig); 2791bafdc4e5Seric s->s_hostsig = p; 2792bafdc4e5Seric p += strlen(p); 2793bafdc4e5Seric *p++ = ':'; 2794bafdc4e5Seric } 2795bafdc4e5Seric else 2796bafdc4e5Seric s->s_hostsig = p; 2797e103b48fSeric for (i = 0; i < nmx; i++) 2798e103b48fSeric { 2799e103b48fSeric if (i != 0) 2800e103b48fSeric *p++ = ':'; 2801e103b48fSeric strcpy(p, mxhosts[i]); 2802e103b48fSeric p += strlen(p); 2803e103b48fSeric } 2804bafdc4e5Seric if (endp != NULL) 2805bafdc4e5Seric *endp++ = ':'; 2806bafdc4e5Seric } 2807e103b48fSeric makelower(s->s_hostsig); 2808516782b4Seric if (ConfigLevel < 2) 2809516782b4Seric _res.options = oldoptions; 2810e103b48fSeric #else 2811e103b48fSeric /* not using BIND -- the signature is just the host name */ 2812e103b48fSeric s->s_hostsig = host; 2813e103b48fSeric #endif 2814e103b48fSeric if (tTd(17, 1)) 2815e103b48fSeric printf("hostsignature(%s) = %s\n", host, s->s_hostsig); 2816e103b48fSeric return s->s_hostsig; 2817e103b48fSeric } 2818