14227346bSdist /* 2*759969d8Seric * 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*759969d8Seric static char sccsid[] = "@(#)deliver.c 8.144 (Berkeley) 04/21/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; 1064bb8b0fdSeric 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); 1109c9e68d9Seric return; 1119c9e68d9Seric } 1129c9e68d9Seric 113b8004690Seric /* 114b8004690Seric ** Do sender deletion. 115b8004690Seric ** 116b8004690Seric ** If the sender has the QQUEUEUP flag set, skip this. 117b8004690Seric ** This can happen if the name server is hosed when you 118b8004690Seric ** are trying to send mail. The result is that the sender 119b8004690Seric ** is instantiated in the queue as a recipient. 120b8004690Seric */ 121b8004690Seric 122e76a6a8fSeric if (!bitset(EF_METOO, e->e_flags) && 123e76a6a8fSeric !bitset(QQUEUEUP, e->e_from.q_flags)) 1249c9e68d9Seric { 1259c9e68d9Seric if (tTd(13, 5)) 1269c9e68d9Seric { 1279c9e68d9Seric printf("sendall: QDONTSEND "); 1289c9e68d9Seric printaddr(&e->e_from, FALSE); 1299c9e68d9Seric } 1309c9e68d9Seric e->e_from.q_flags |= QDONTSEND; 131b665faabSeric (void) recipient(&e->e_from, &e->e_sendqueue, 0, e); 1329c9e68d9Seric } 1339c9e68d9Seric 134ce5531bdSeric /* 135ce5531bdSeric ** Handle alias owners. 136ce5531bdSeric ** 137ce5531bdSeric ** We scan up the q_alias chain looking for owners. 138ce5531bdSeric ** We discard owners that are the same as the return path. 139ce5531bdSeric */ 140ce5531bdSeric 141ce5531bdSeric for (q = e->e_sendqueue; q != NULL; q = q->q_next) 142ce5531bdSeric { 143ce5531bdSeric register struct address *a; 144ce5531bdSeric 145ce5531bdSeric for (a = q; a != NULL && a->q_owner == NULL; a = a->q_alias) 146ce5531bdSeric continue; 147ce5531bdSeric if (a != NULL) 148ce5531bdSeric q->q_owner = a->q_owner; 149ce5531bdSeric 150ce5531bdSeric if (q->q_owner != NULL && 151ce5531bdSeric !bitset(QDONTSEND, q->q_flags) && 152ce5531bdSeric strcmp(q->q_owner, e->e_from.q_paddr) == 0) 153ce5531bdSeric q->q_owner = NULL; 154ce5531bdSeric } 155ce5531bdSeric 156ce5531bdSeric owner = ""; 157ce5531bdSeric otherowners = 1; 158ce5531bdSeric while (owner != NULL && otherowners > 0) 159ce5531bdSeric { 160ce5531bdSeric owner = NULL; 161ce5531bdSeric otherowners = 0; 162ce5531bdSeric 163ce5531bdSeric for (q = e->e_sendqueue; q != NULL; q = q->q_next) 164ce5531bdSeric { 165ce5531bdSeric if (bitset(QDONTSEND, q->q_flags)) 166ce5531bdSeric continue; 167ce5531bdSeric 168ce5531bdSeric if (q->q_owner != NULL) 169ce5531bdSeric { 170ce5531bdSeric if (owner == NULL) 171ce5531bdSeric owner = q->q_owner; 172ce5531bdSeric else if (owner != q->q_owner) 173ce5531bdSeric { 174ce5531bdSeric if (strcmp(owner, q->q_owner) == 0) 175ce5531bdSeric { 176ce5531bdSeric /* make future comparisons cheap */ 177ce5531bdSeric q->q_owner = owner; 178ce5531bdSeric } 179ce5531bdSeric else 180ce5531bdSeric { 181ce5531bdSeric otherowners++; 182ce5531bdSeric } 183ce5531bdSeric owner = q->q_owner; 184ce5531bdSeric } 185ce5531bdSeric } 186ce5531bdSeric else 187ce5531bdSeric { 188ce5531bdSeric otherowners++; 189ce5531bdSeric } 190b665faabSeric 191b665faabSeric /* 192b665faabSeric ** If this mailer is expensive, and if we don't 193b665faabSeric ** want to make connections now, just mark these 194b665faabSeric ** addresses and return. This is useful if we 195b665faabSeric ** want to batch connections to reduce load. This 196b665faabSeric ** will cause the messages to be queued up, and a 197b665faabSeric ** daemon will come along to send the messages later. 198b665faabSeric */ 199b665faabSeric 200b665faabSeric if (bitset(QBADADDR|QQUEUEUP, q->q_flags)) 201b665faabSeric continue; 202b665faabSeric if (NoConnect && !Verbose && 203b665faabSeric bitnset(M_EXPENSIVE, q->q_mailer->m_flags)) 204b665faabSeric { 205b665faabSeric q->q_flags |= QQUEUEUP; 206b665faabSeric e->e_to = q->q_paddr; 207b665faabSeric message("queued"); 208b665faabSeric if (LogLevel > 8) 209b665faabSeric logdelivery(q->q_mailer, NULL, 210b665faabSeric "queued", NULL, 211b665faabSeric (time_t) 0, e); 212b665faabSeric e->e_to = NULL; 213b665faabSeric } 214b665faabSeric else 215b665faabSeric { 216b665faabSeric somedeliveries = TRUE; 217b665faabSeric } 218ce5531bdSeric } 219ce5531bdSeric 220ce5531bdSeric if (owner != NULL && otherowners > 0) 221ce5531bdSeric { 222ce5531bdSeric extern HDR *copyheader(); 223ce5531bdSeric extern ADDRESS *copyqueue(); 224ce5531bdSeric 225ce5531bdSeric /* 226ce5531bdSeric ** Split this envelope into two. 227ce5531bdSeric */ 228ce5531bdSeric 229ce5531bdSeric ee = (ENVELOPE *) xalloc(sizeof(ENVELOPE)); 230ce5531bdSeric *ee = *e; 231ce5531bdSeric ee->e_id = NULL; 232ce5531bdSeric (void) queuename(ee, '\0'); 233ce5531bdSeric 234ce5531bdSeric if (tTd(13, 1)) 235ce5531bdSeric printf("sendall: split %s into %s\n", 236ce5531bdSeric e->e_id, ee->e_id); 237ce5531bdSeric 238ce5531bdSeric ee->e_header = copyheader(e->e_header); 239ce5531bdSeric ee->e_sendqueue = copyqueue(e->e_sendqueue); 240ce5531bdSeric ee->e_errorqueue = copyqueue(e->e_errorqueue); 241b665faabSeric ee->e_flags = e->e_flags & ~(EF_INQUEUE|EF_CLRQUEUE|EF_FATALERRS|EF_SENDRECEIPT|EF_RET_PARAM); 242fce3c07bSeric ee->e_flags |= EF_NORECEIPT; 243ce5531bdSeric setsender(owner, ee, NULL, TRUE); 244ce5531bdSeric if (tTd(13, 5)) 245ce5531bdSeric { 246ce5531bdSeric printf("sendall(split): QDONTSEND "); 247ce5531bdSeric printaddr(&ee->e_from, FALSE); 248ce5531bdSeric } 249ce5531bdSeric ee->e_from.q_flags |= QDONTSEND; 250ce5531bdSeric ee->e_dfp = NULL; 251ce5531bdSeric ee->e_xfp = NULL; 252ce5531bdSeric ee->e_errormode = EM_MAIL; 253b056abd0Seric ee->e_sibling = splitenv; 254b056abd0Seric splitenv = ee; 255ce5531bdSeric 256ce5531bdSeric for (q = e->e_sendqueue; q != NULL; q = q->q_next) 257b665faabSeric { 258ce5531bdSeric if (q->q_owner == owner) 259de1a6b1bSeric { 260ce5531bdSeric q->q_flags |= QDONTSEND; 261de1a6b1bSeric q->q_flags &= ~QQUEUEUP; 262de1a6b1bSeric } 263b665faabSeric } 264ce5531bdSeric for (q = ee->e_sendqueue; q != NULL; q = q->q_next) 265b665faabSeric { 266ce5531bdSeric if (q->q_owner != owner) 267de1a6b1bSeric { 268ce5531bdSeric q->q_flags |= QDONTSEND; 269de1a6b1bSeric q->q_flags &= ~QQUEUEUP; 270de1a6b1bSeric } 271b665faabSeric else 272ce5531bdSeric { 273b665faabSeric /* clear DSN parameters */ 274b665faabSeric q->q_flags &= ~(QHASNOTIFY|QPINGONSUCCESS); 275b665faabSeric q->q_flags |= QPINGONFAILURE|QPINGONDELAY; 276b665faabSeric } 277b665faabSeric } 278b665faabSeric 279b665faabSeric if (mode != SM_VERIFY && bitset(EF_HAS_DF, e->e_flags)) 280b665faabSeric { 281b665faabSeric char df1buf[20], df2buf[20]; 282b665faabSeric 283ce5531bdSeric ee->e_dfp = NULL; 284b665faabSeric strcpy(df1buf, queuename(e, 'd')); 285b665faabSeric strcpy(df2buf, queuename(ee, 'd')); 286b665faabSeric if (link(df1buf, df2buf) < 0) 287ce5531bdSeric { 288ce5531bdSeric syserr("sendall: link(%s, %s)", 289b665faabSeric df1buf, df2buf); 290ce5531bdSeric } 291ce5531bdSeric } 292ce5531bdSeric #ifdef LOG 293ce5531bdSeric if (LogLevel > 4) 294c8b70947Seric syslog(LOG_INFO, "%s: clone %s, owner=%s", 295c8b70947Seric ee->e_id, e->e_id, owner); 296ce5531bdSeric #endif 297ce5531bdSeric } 298ce5531bdSeric } 299ce5531bdSeric 300ce5531bdSeric if (owner != NULL) 301ce5531bdSeric { 302ce5531bdSeric setsender(owner, e, NULL, TRUE); 303ce5531bdSeric if (tTd(13, 5)) 304ce5531bdSeric { 305ce5531bdSeric printf("sendall(owner): QDONTSEND "); 306ce5531bdSeric printaddr(&e->e_from, FALSE); 307ce5531bdSeric } 308ce5531bdSeric e->e_from.q_flags |= QDONTSEND; 309ce5531bdSeric e->e_errormode = EM_MAIL; 310fce3c07bSeric e->e_flags |= EF_NORECEIPT; 311ce5531bdSeric } 312ce5531bdSeric 313b665faabSeric /* if nothing to be delivered, just queue up everything */ 314b665faabSeric if (!somedeliveries && mode != SM_QUEUE && mode != SM_VERIFY) 315b665faabSeric mode = SM_QUEUE; 316b665faabSeric 317c1ac89b1Seric # ifdef QUEUE 318c1ac89b1Seric if ((mode == SM_QUEUE || mode == SM_FORK || 319c1ac89b1Seric (mode != SM_VERIFY && SuperSafe)) && 320c1ac89b1Seric !bitset(EF_INQUEUE, e->e_flags)) 321c1ac89b1Seric { 322c1ac89b1Seric /* be sure everything is instantiated in the queue */ 323b665faabSeric queueup(e, TRUE, mode == SM_QUEUE); 324b056abd0Seric for (ee = splitenv; ee != NULL; ee = ee->e_sibling) 325b665faabSeric queueup(ee, TRUE, mode == SM_QUEUE); 326c1ac89b1Seric } 327c1ac89b1Seric #endif /* QUEUE */ 328c1ac89b1Seric 3297880f3e4Seric /* 330b665faabSeric ** If we belong in background, fork now. 3317880f3e4Seric */ 3327880f3e4Seric 333c1ac89b1Seric switch (mode) 334c1ac89b1Seric { 335c1ac89b1Seric case SM_VERIFY: 336c1ac89b1Seric Verbose = TRUE; 337c1ac89b1Seric break; 338c1ac89b1Seric 339c1ac89b1Seric case SM_QUEUE: 340c1ac89b1Seric queueonly: 341b665faabSeric if (e->e_nrcpts > 0) 342c1ac89b1Seric e->e_flags |= EF_INQUEUE|EF_KEEPQUEUE; 343c1ac89b1Seric return; 344c1ac89b1Seric 345c1ac89b1Seric case SM_FORK: 346c1ac89b1Seric if (e->e_xfp != NULL) 347c1ac89b1Seric (void) fflush(e->e_xfp); 348c1ac89b1Seric 349b269aa8eSeric # if !HASFLOCK 350c1ac89b1Seric /* 3516b2765c6Seric ** Since fcntl locking has the interesting semantic that 3526b2765c6Seric ** the lock is owned by a process, not by an open file 3536b2765c6Seric ** descriptor, we have to flush this to the queue, and 3546b2765c6Seric ** then restart from scratch in the child. 355c1ac89b1Seric */ 356c1ac89b1Seric 357b665faabSeric { 3586b2765c6Seric /* save id for future use */ 359b665faabSeric char *qid = e->e_id; 3606b2765c6Seric 3616b2765c6Seric /* now drop the envelope in the parent */ 3626b2765c6Seric e->e_flags |= EF_INQUEUE|EF_KEEPQUEUE; 3636b2765c6Seric dropenvelope(e); 3646b2765c6Seric 3656b2765c6Seric /* and reacquire in the child */ 366b665faabSeric (void) dowork(qid, TRUE, FALSE, e); 367b665faabSeric } 3686b2765c6Seric 3696b2765c6Seric return; 3706b2765c6Seric 3716b2765c6Seric # else /* HASFLOCK */ 372c1ac89b1Seric 373c1ac89b1Seric pid = fork(); 374c1ac89b1Seric if (pid < 0) 375c1ac89b1Seric { 376c1ac89b1Seric goto queueonly; 377c1ac89b1Seric } 378c1ac89b1Seric else if (pid > 0) 379c1ac89b1Seric { 3800e484fe5Seric /* be sure we leave the temp files to our child */ 3810e484fe5Seric /* can't call unlockqueue to avoid unlink of xfp */ 3820e484fe5Seric if (e->e_lockfp != NULL) 383b665faabSeric (void) xfclose(e->e_lockfp, "sendenvelope lockfp", e->e_id); 3840e484fe5Seric e->e_lockfp = NULL; 3850e484fe5Seric 3860e484fe5Seric /* close any random open files in the envelope */ 3870e484fe5Seric closexscript(e); 3880e484fe5Seric if (e->e_dfp != NULL) 389b665faabSeric (void) xfclose(e->e_dfp, "sendenvelope dfp", e->e_id); 3900e484fe5Seric e->e_dfp = NULL; 391b665faabSeric e->e_id = NULL; 392b665faabSeric e->e_flags &= ~EF_HAS_DF; 3939f9b003eSeric 3949f9b003eSeric /* catch intermediate zombie */ 3959f9b003eSeric (void) waitfor(pid); 396c1ac89b1Seric return; 397c1ac89b1Seric } 398c1ac89b1Seric 399c1ac89b1Seric /* double fork to avoid zombies */ 4009f9b003eSeric pid = fork(); 4019f9b003eSeric if (pid > 0) 402c1ac89b1Seric exit(EX_OK); 403c1ac89b1Seric 404c1ac89b1Seric /* be sure we are immune from the terminal */ 4057880f3e4Seric disconnect(1, e); 406c1ac89b1Seric 4079f9b003eSeric /* prevent parent from waiting if there was an error */ 4089f9b003eSeric if (pid < 0) 4099f9b003eSeric { 4109f9b003eSeric e->e_flags |= EF_INQUEUE|EF_KEEPQUEUE; 4119f9b003eSeric finis(); 4129f9b003eSeric } 4139f9b003eSeric 414c1ac89b1Seric /* 415c1ac89b1Seric ** Close any cached connections. 416c1ac89b1Seric ** 417c1ac89b1Seric ** We don't send the QUIT protocol because the parent 418c1ac89b1Seric ** still knows about the connection. 419c1ac89b1Seric ** 420c1ac89b1Seric ** This should only happen when delivering an error 421c1ac89b1Seric ** message. 422c1ac89b1Seric */ 423c1ac89b1Seric 424c1ac89b1Seric mci_flush(FALSE, NULL); 425c1ac89b1Seric 4266b2765c6Seric # endif /* HASFLOCK */ 4276b2765c6Seric 428c1ac89b1Seric break; 429c1ac89b1Seric } 430c1ac89b1Seric 431b665faabSeric if (splitenv != NULL) 432b665faabSeric { 433b665faabSeric if (tTd(13, 1)) 434b665faabSeric { 435b665faabSeric printf("\nsendall: Split queue; remaining queue:\n"); 436b665faabSeric printaddr(e->e_sendqueue, TRUE); 437b665faabSeric } 438b665faabSeric 439b665faabSeric for (ee = splitenv; ee != NULL; ee = ee->e_sibling) 440b665faabSeric { 441b665faabSeric CurEnv = ee; 442b665faabSeric if (mode != SM_VERIFY) 443b665faabSeric openxscript(ee); 444b665faabSeric sendenvelope(ee, mode); 445b665faabSeric dropenvelope(ee); 446b665faabSeric } 447b665faabSeric 448b665faabSeric CurEnv = e; 449b665faabSeric } 450b665faabSeric sendenvelope(e, mode); 451b665faabSeric Verbose = oldverbose; 452b665faabSeric } 453b665faabSeric 454b665faabSeric void 455b665faabSeric sendenvelope(e, mode) 456b665faabSeric register ENVELOPE *e; 457b665faabSeric char mode; 458b665faabSeric { 459b665faabSeric register ADDRESS *q; 460b665faabSeric bool didany; 461b665faabSeric 462b665faabSeric /* 463b665faabSeric ** If we have had global, fatal errors, don't bother sending 464b665faabSeric ** the message at all if we are in SMTP mode. Local errors 465b665faabSeric ** (e.g., a single address failing) will still cause the other 466b665faabSeric ** addresses to be sent. 467b665faabSeric */ 468b665faabSeric 469b665faabSeric if (bitset(EF_FATALERRS, e->e_flags) && 470b665faabSeric (OpMode == MD_SMTP || OpMode == MD_DAEMON)) 471b665faabSeric { 472b665faabSeric e->e_flags |= EF_CLRQUEUE; 473b665faabSeric return; 474b665faabSeric } 475b665faabSeric 476c1ac89b1Seric /* 4779c9e68d9Seric ** Run through the list and send everything. 4785288e21aSeric ** 4795288e21aSeric ** Set EF_GLOBALERRS so that error messages during delivery 4805288e21aSeric ** result in returned mail. 4819c9e68d9Seric */ 4829c9e68d9Seric 4839c9e68d9Seric e->e_nsent = 0; 4845288e21aSeric e->e_flags |= EF_GLOBALERRS; 485b665faabSeric didany = FALSE; 486faad2b16Seric 487faad2b16Seric /* now run through the queue */ 4889c9e68d9Seric for (q = e->e_sendqueue; q != NULL; q = q->q_next) 4899c9e68d9Seric { 490fdc75a0fSeric #ifdef XDEBUG 491fdc75a0fSeric char wbuf[MAXNAME + 20]; 492fdc75a0fSeric 493fdc75a0fSeric (void) sprintf(wbuf, "sendall(%s)", q->q_paddr); 494fdc75a0fSeric checkfd012(wbuf); 495fdc75a0fSeric #endif 4969c9e68d9Seric if (mode == SM_VERIFY) 4979c9e68d9Seric { 4989c9e68d9Seric e->e_to = q->q_paddr; 4999c9e68d9Seric if (!bitset(QDONTSEND|QBADADDR, q->q_flags)) 5008dfca105Seric { 501fafe46e1Seric if (q->q_host != NULL && q->q_host[0] != '\0') 5028dfca105Seric message("deliverable: mailer %s, host %s, user %s", 5038dfca105Seric q->q_mailer->m_name, 5048dfca105Seric q->q_host, 5058dfca105Seric q->q_user); 506fafe46e1Seric else 507fafe46e1Seric message("deliverable: mailer %s, user %s", 508fafe46e1Seric q->q_mailer->m_name, 509fafe46e1Seric q->q_user); 5108dfca105Seric } 5119c9e68d9Seric } 5129c9e68d9Seric else if (!bitset(QDONTSEND|QBADADDR, q->q_flags)) 5139c9e68d9Seric { 5149c9e68d9Seric # ifdef QUEUE 5159c9e68d9Seric /* 5169c9e68d9Seric ** Checkpoint the send list every few addresses 5179c9e68d9Seric */ 5189c9e68d9Seric 5199c9e68d9Seric if (e->e_nsent >= CheckpointInterval) 5209c9e68d9Seric { 5219c9e68d9Seric queueup(e, TRUE, FALSE); 5229c9e68d9Seric e->e_nsent = 0; 5239c9e68d9Seric } 5249c9e68d9Seric # endif /* QUEUE */ 5259c9e68d9Seric (void) deliver(e, q); 526b665faabSeric didany = TRUE; 5279c9e68d9Seric } 5289c9e68d9Seric } 529b665faabSeric if (didany) 530b665faabSeric { 531b665faabSeric e->e_dtime = curtime(); 532b665faabSeric e->e_ntries++; 533b665faabSeric } 5349c9e68d9Seric 535fdc75a0fSeric #ifdef XDEBUG 536fdc75a0fSeric checkfd012("end of sendenvelope"); 537fdc75a0fSeric #endif 538fdc75a0fSeric 5399c9e68d9Seric if (mode == SM_FORK) 5409c9e68d9Seric finis(); 5419c9e68d9Seric } 5429c9e68d9Seric /* 5439c9e68d9Seric ** DOFORK -- do a fork, retrying a couple of times on failure. 5449c9e68d9Seric ** 5459c9e68d9Seric ** This MUST be a macro, since after a vfork we are running 5469c9e68d9Seric ** two processes on the same stack!!! 5479c9e68d9Seric ** 5489c9e68d9Seric ** Parameters: 5499c9e68d9Seric ** none. 5509c9e68d9Seric ** 5519c9e68d9Seric ** Returns: 5529c9e68d9Seric ** From a macro??? You've got to be kidding! 5539c9e68d9Seric ** 5549c9e68d9Seric ** Side Effects: 5559c9e68d9Seric ** Modifies the ==> LOCAL <== variable 'pid', leaving: 5569c9e68d9Seric ** pid of child in parent, zero in child. 5579c9e68d9Seric ** -1 on unrecoverable error. 5589c9e68d9Seric ** 5599c9e68d9Seric ** Notes: 5609c9e68d9Seric ** I'm awfully sorry this looks so awful. That's 5619c9e68d9Seric ** vfork for you..... 5629c9e68d9Seric */ 5639c9e68d9Seric 5649c9e68d9Seric # define NFORKTRIES 5 5659c9e68d9Seric 5669c9e68d9Seric # ifndef FORK 5679c9e68d9Seric # define FORK fork 5689c9e68d9Seric # endif 5699c9e68d9Seric 5709c9e68d9Seric # define DOFORK(fORKfN) \ 5719c9e68d9Seric {\ 5729c9e68d9Seric register int i;\ 5739c9e68d9Seric \ 5749c9e68d9Seric for (i = NFORKTRIES; --i >= 0; )\ 5759c9e68d9Seric {\ 5769c9e68d9Seric pid = fORKfN();\ 5779c9e68d9Seric if (pid >= 0)\ 5789c9e68d9Seric break;\ 5799c9e68d9Seric if (i > 0)\ 5809c9e68d9Seric sleep((unsigned) NFORKTRIES - i);\ 5819c9e68d9Seric }\ 5829c9e68d9Seric } 5839c9e68d9Seric /* 5849c9e68d9Seric ** DOFORK -- simple fork interface to DOFORK. 5859c9e68d9Seric ** 5869c9e68d9Seric ** Parameters: 5879c9e68d9Seric ** none. 5889c9e68d9Seric ** 5899c9e68d9Seric ** Returns: 5909c9e68d9Seric ** pid of child in parent. 5919c9e68d9Seric ** zero in child. 5929c9e68d9Seric ** -1 on error. 5939c9e68d9Seric ** 5949c9e68d9Seric ** Side Effects: 5959c9e68d9Seric ** returns twice, once in parent and once in child. 5969c9e68d9Seric */ 5979c9e68d9Seric 5989c9e68d9Seric dofork() 5999c9e68d9Seric { 600b665faabSeric register int pid = -1; 6019c9e68d9Seric 6029c9e68d9Seric DOFORK(fork); 6039c9e68d9Seric return (pid); 6049c9e68d9Seric } 6059c9e68d9Seric /* 60613bbc08cSeric ** DELIVER -- Deliver a message to a list of addresses. 60713bbc08cSeric ** 60813bbc08cSeric ** This routine delivers to everyone on the same host as the 60913bbc08cSeric ** user on the head of the list. It is clever about mailers 61013bbc08cSeric ** that don't handle multiple users. It is NOT guaranteed 61113bbc08cSeric ** that it will deliver to all these addresses however -- so 61213bbc08cSeric ** deliver should be called once for each address on the 61313bbc08cSeric ** list. 61425a99e2eSeric ** 61525a99e2eSeric ** Parameters: 616588cad61Seric ** e -- the envelope to deliver. 617c77d1c25Seric ** firstto -- head of the address list to deliver to. 61825a99e2eSeric ** 61925a99e2eSeric ** Returns: 62025a99e2eSeric ** zero -- successfully delivered. 62125a99e2eSeric ** else -- some failure, see ExitStat for more info. 62225a99e2eSeric ** 62325a99e2eSeric ** Side Effects: 62425a99e2eSeric ** The standard input is passed off to someone. 62525a99e2eSeric */ 62625a99e2eSeric 627b665faabSeric int 628588cad61Seric deliver(e, firstto) 629588cad61Seric register ENVELOPE *e; 630c77d1c25Seric ADDRESS *firstto; 63125a99e2eSeric { 63278442df3Seric char *host; /* host being sent to */ 63378442df3Seric char *user; /* user being sent to */ 63425a99e2eSeric char **pvp; 6355dfc646bSeric register char **mvp; 63625a99e2eSeric register char *p; 637588cad61Seric register MAILER *m; /* mailer for this recipient */ 6386259796dSeric ADDRESS *ctladdr; 639b31e7f2bSeric register MCI *mci; 640c77d1c25Seric register ADDRESS *to = firstto; 641c579ef51Seric bool clever = FALSE; /* running user smtp to this mailer */ 642b665faabSeric ADDRESS *tochain = NULL; /* users chain in this mailer call */ 643911693bfSbostic int rcode; /* response code */ 644e103b48fSeric char *firstsig; /* signature of firstto */ 645b665faabSeric int pid = -1; 6469c9e68d9Seric char *curhost; 647b665faabSeric time_t xstart; 6489c9e68d9Seric int mpvect[2]; 6499c9e68d9Seric int rpvect[2]; 650ee6bf8dfSeric char *pv[MAXPV+1]; 651579ef0ddSeric char tobuf[TOBUFSIZE]; /* text line of to people */ 652b665faabSeric char buf[MAXNAME + 1]; 653b665faabSeric char rpathbuf[MAXNAME + 1]; /* translated return path */ 654fabb3bd4Seric extern int checkcompat(); 65525a99e2eSeric 65635490626Seric errno = 0; 657ee4b0922Seric if (bitset(QDONTSEND|QBADADDR|QQUEUEUP, to->q_flags)) 6585dfc646bSeric return (0); 65925a99e2eSeric 6609d4a8008Seric #if NAMED_BIND 661912a731aSbostic /* unless interactive, try twice, over a minute */ 6628d19a23dSeric if (OpMode == MD_DAEMON || OpMode == MD_SMTP) 6638d19a23dSeric { 664912a731aSbostic _res.retrans = 30; 665912a731aSbostic _res.retry = 2; 666912a731aSbostic } 667d4bd8f0eSbostic #endif 668912a731aSbostic 66951552439Seric m = to->q_mailer; 67051552439Seric host = to->q_host; 671c9be6216Seric CurEnv = e; /* just in case */ 6724384d521Seric e->e_statmsg = NULL; 673df106f0bSeric SmtpError[0] = '\0'; 674b665faabSeric xstart = curtime(); 67551552439Seric 6766ef48975Seric if (tTd(10, 1)) 677562ec147Seric printf("\n--deliver, id=%s, mailer=%s, host=`%s', first user=`%s'\n", 678562ec147Seric e->e_id, m->m_name, host, to->q_user); 679ab81ee53Seric if (tTd(10, 100)) 680ab81ee53Seric printopenfds(FALSE); 681f3dbc832Seric 682f3dbc832Seric /* 6835dfc646bSeric ** Do initial argv setup. 6845dfc646bSeric ** Insert the mailer name. Notice that $x expansion is 6855dfc646bSeric ** NOT done on the mailer name. Then, if the mailer has 6865dfc646bSeric ** a picky -f flag, we insert it as appropriate. This 6875dfc646bSeric ** code does not check for 'pv' overflow; this places a 6885dfc646bSeric ** manifest lower limit of 4 for MAXPV. 6893bea8136Seric ** The from address rewrite is expected to make 6903bea8136Seric ** the address relative to the other end. 6915dfc646bSeric */ 6925dfc646bSeric 69378442df3Seric /* rewrite from address, using rewriting rules */ 694efe54562Seric rcode = EX_OK; 695b665faabSeric if (bitnset(M_UDBENVELOPE, e->e_from.q_mailer->m_flags)) 696b665faabSeric p = e->e_sender; 697b665faabSeric else 698b665faabSeric p = e->e_from.q_paddr; 699b665faabSeric (void) strcpy(rpathbuf, remotename(p, m, 700efe54562Seric RF_SENDERADDR|RF_CANONICAL, 701efe54562Seric &rcode, e)); 702ee4b0922Seric define('g', rpathbuf, e); /* translated return path */ 703588cad61Seric define('h', host, e); /* to host */ 7045dfc646bSeric Errors = 0; 7055dfc646bSeric pvp = pv; 7065dfc646bSeric *pvp++ = m->m_argv[0]; 7075dfc646bSeric 7085dfc646bSeric /* insert -f or -r flag as appropriate */ 70957fc6f17Seric if (FromFlag && (bitnset(M_FOPT, m->m_flags) || bitnset(M_ROPT, m->m_flags))) 7105dfc646bSeric { 71157fc6f17Seric if (bitnset(M_FOPT, m->m_flags)) 7125dfc646bSeric *pvp++ = "-f"; 7135dfc646bSeric else 7145dfc646bSeric *pvp++ = "-r"; 715c23ed322Seric *pvp++ = newstr(rpathbuf); 7165dfc646bSeric } 7175dfc646bSeric 7185dfc646bSeric /* 7195dfc646bSeric ** Append the other fixed parts of the argv. These run 7205dfc646bSeric ** up to the first entry containing "$u". There can only 7215dfc646bSeric ** be one of these, and there are only a few more slots 7225dfc646bSeric ** in the pv after it. 7235dfc646bSeric */ 7245dfc646bSeric 7255dfc646bSeric for (mvp = m->m_argv; (p = *++mvp) != NULL; ) 7265dfc646bSeric { 7272bc47524Seric /* can't use strchr here because of sign extension problems */ 7282bc47524Seric while (*p != '\0') 7292bc47524Seric { 7302bc47524Seric if ((*p++ & 0377) == MACROEXPAND) 7312bc47524Seric { 7322bc47524Seric if (*p == 'u') 7335dfc646bSeric break; 7342bc47524Seric } 7352bc47524Seric } 7362bc47524Seric 7372bc47524Seric if (*p != '\0') 7385dfc646bSeric break; 7395dfc646bSeric 7405dfc646bSeric /* this entry is safe -- go ahead and process it */ 741b665faabSeric expand(*mvp, buf, sizeof buf, e); 7425dfc646bSeric *pvp++ = newstr(buf); 7435dfc646bSeric if (pvp >= &pv[MAXPV - 3]) 7445dfc646bSeric { 74508b25121Seric syserr("554 Too many parameters to %s before $u", pv[0]); 7465dfc646bSeric return (-1); 7475dfc646bSeric } 7485dfc646bSeric } 749c579ef51Seric 75033db8731Seric /* 75133db8731Seric ** If we have no substitution for the user name in the argument 75233db8731Seric ** list, we know that we must supply the names otherwise -- and 75333db8731Seric ** SMTP is the answer!! 75433db8731Seric */ 75533db8731Seric 7565dfc646bSeric if (*mvp == NULL) 757c579ef51Seric { 758c579ef51Seric /* running SMTP */ 7592c7e1b8dSeric # ifdef SMTP 760c579ef51Seric clever = TRUE; 761c579ef51Seric *pvp = NULL; 7626c2c3107Seric # else /* SMTP */ 76333db8731Seric /* oops! we don't implement SMTP */ 764df106f0bSeric syserr("554 SMTP style mailer not implemented"); 7652c7e1b8dSeric return (EX_SOFTWARE); 7666c2c3107Seric # endif /* SMTP */ 767c579ef51Seric } 7685dfc646bSeric 7695dfc646bSeric /* 7705dfc646bSeric ** At this point *mvp points to the argument with $u. We 7715dfc646bSeric ** run through our address list and append all the addresses 7725dfc646bSeric ** we can. If we run out of space, do not fret! We can 7735dfc646bSeric ** always send another copy later. 7745dfc646bSeric */ 7755dfc646bSeric 7765dfc646bSeric tobuf[0] = '\0'; 777588cad61Seric e->e_to = tobuf; 7786259796dSeric ctladdr = NULL; 779e103b48fSeric firstsig = hostsignature(firstto->q_mailer, firstto->q_host, e); 7805dfc646bSeric for (; to != NULL; to = to->q_next) 7815dfc646bSeric { 7825dfc646bSeric /* avoid sending multiple recipients to dumb mailers */ 78357fc6f17Seric if (tobuf[0] != '\0' && !bitnset(M_MUSER, m->m_flags)) 7845dfc646bSeric break; 7855dfc646bSeric 7865dfc646bSeric /* if already sent or not for this host, don't send */ 787ee4b0922Seric if (bitset(QDONTSEND|QBADADDR|QQUEUEUP, to->q_flags) || 788e103b48fSeric to->q_mailer != firstto->q_mailer || 789e103b48fSeric strcmp(hostsignature(to->q_mailer, to->q_host, e), firstsig) != 0) 7905dfc646bSeric continue; 7916259796dSeric 7924b22ea87Seric /* avoid overflowing tobuf */ 793aa50a568Sbostic if (sizeof tobuf < (strlen(to->q_paddr) + strlen(tobuf) + 2)) 7944b22ea87Seric break; 7954b22ea87Seric 7966ef48975Seric if (tTd(10, 1)) 797772e6e50Seric { 798772e6e50Seric printf("\nsend to "); 799772e6e50Seric printaddr(to, FALSE); 800772e6e50Seric } 801772e6e50Seric 8026259796dSeric /* compute effective uid/gid when sending */ 803b665faabSeric if (bitnset(M_RUNASRCPT, to->q_mailer->m_flags)) 8046259796dSeric ctladdr = getctladdr(to); 8056259796dSeric 806b665faabSeric if (tTd(10, 2)) 807b665faabSeric { 808b665faabSeric printf("ctladdr="); 809b665faabSeric printaddr(ctladdr, FALSE); 810b665faabSeric } 811b665faabSeric 8125dfc646bSeric user = to->q_user; 813588cad61Seric e->e_to = to->q_paddr; 81475f1ade9Seric if (tTd(10, 5)) 81575f1ade9Seric { 81675f1ade9Seric printf("deliver: QDONTSEND "); 81775f1ade9Seric printaddr(to, FALSE); 81875f1ade9Seric } 819ee4b0922Seric to->q_flags |= QDONTSEND; 8205dfc646bSeric 8215dfc646bSeric /* 8225dfc646bSeric ** Check to see that these people are allowed to 8235dfc646bSeric ** talk to each other. 8242a6e0786Seric */ 8252a6e0786Seric 82669582d2fSeric if (m->m_maxsize != 0 && e->e_msgsize > m->m_maxsize) 82769582d2fSeric { 828b665faabSeric e->e_flags |= EF_NO_BODY_RETN; 82908b25121Seric usrerr("552 Message is too large; %ld bytes max", m->m_maxsize); 830b665faabSeric giveresponse(EX_UNAVAILABLE, m, NULL, ctladdr, xstart, e); 83169582d2fSeric continue; 83269582d2fSeric } 833b665faabSeric #if NAMED_BIND 834b665faabSeric h_errno = 0; 835b665faabSeric #endif 836fabb3bd4Seric rcode = checkcompat(to, e); 8371793c9c5Seric if (rcode != EX_OK) 8385dfc646bSeric { 839b665faabSeric markfailure(e, to, NULL, rcode); 840b665faabSeric giveresponse(rcode, m, NULL, ctladdr, xstart, e); 8415dfc646bSeric continue; 8425dfc646bSeric } 8432a6e0786Seric 8442a6e0786Seric /* 8459ec9501bSeric ** Strip quote bits from names if the mailer is dumb 8469ec9501bSeric ** about them. 84725a99e2eSeric */ 84825a99e2eSeric 84957fc6f17Seric if (bitnset(M_STRIPQ, m->m_flags)) 85025a99e2eSeric { 8511d8f1806Seric stripquotes(user); 8521d8f1806Seric stripquotes(host); 85325a99e2eSeric } 85425a99e2eSeric 855cdb828c5Seric /* hack attack -- delivermail compatibility */ 856cdb828c5Seric if (m == ProgMailer && *user == '|') 857cdb828c5Seric user++; 858cdb828c5Seric 85925a99e2eSeric /* 8603efaed6eSeric ** If an error message has already been given, don't 8613efaed6eSeric ** bother to send to this address. 8623efaed6eSeric ** 8633efaed6eSeric ** >>>>>>>>>> This clause assumes that the local mailer 8643efaed6eSeric ** >> NOTE >> cannot do any further aliasing; that 8653efaed6eSeric ** >>>>>>>>>> function is subsumed by sendmail. 8663efaed6eSeric */ 8673efaed6eSeric 8686cae517dSeric if (bitset(QBADADDR|QQUEUEUP, to->q_flags)) 8693efaed6eSeric continue; 8703efaed6eSeric 871f2fec898Seric /* save statistics.... */ 872588cad61Seric markstats(e, to); 873f2fec898Seric 8743efaed6eSeric /* 87525a99e2eSeric ** See if this user name is "special". 87625a99e2eSeric ** If the user name has a slash in it, assume that this 87751552439Seric ** is a file -- send it off without further ado. Note 87851552439Seric ** that this type of addresses is not processed along 87951552439Seric ** with the others, so we fudge on the To person. 88025a99e2eSeric */ 88125a99e2eSeric 8822c017f8dSeric if (m == FileMailer) 88325a99e2eSeric { 88403463a75Seric rcode = mailfile(user, ctladdr, e); 885b665faabSeric giveresponse(rcode, m, NULL, ctladdr, xstart, e); 886b665faabSeric e->e_nsent++; 887dde5acadSeric if (rcode == EX_OK) 888b665faabSeric { 889dde5acadSeric to->q_flags |= QSENT; 890b665faabSeric if (bitnset(M_LOCALMAILER, m->m_flags) && 891b665faabSeric (e->e_receiptto != NULL || 892b665faabSeric bitset(QPINGONSUCCESS, to->q_flags))) 893b665faabSeric { 894b665faabSeric to->q_flags |= QREPORT; 895b665faabSeric fprintf(e->e_xfp, "%s... Successfully delivered\n", 896b665faabSeric to->q_paddr); 897b665faabSeric } 898b665faabSeric } 899b665faabSeric to->q_statdate = curtime(); 9005dfc646bSeric continue; 90125a99e2eSeric } 90225a99e2eSeric 90313bbc08cSeric /* 90413bbc08cSeric ** Address is verified -- add this user to mailer 90513bbc08cSeric ** argv, and add it to the print list of recipients. 90613bbc08cSeric */ 90713bbc08cSeric 908508daeccSeric /* link together the chain of recipients */ 909508daeccSeric to->q_tchain = tochain; 910508daeccSeric tochain = to; 911508daeccSeric 9125dfc646bSeric /* create list of users for error messages */ 913db8841e9Seric (void) strcat(tobuf, ","); 914db8841e9Seric (void) strcat(tobuf, to->q_paddr); 915588cad61Seric define('u', user, e); /* to user */ 916b6f89e6eSeric p = to->q_home; 917b6f89e6eSeric if (p == NULL && ctladdr != NULL) 918b6f89e6eSeric p = ctladdr->q_home; 919b6f89e6eSeric define('z', p, e); /* user's home */ 9205dfc646bSeric 921c579ef51Seric /* 922508daeccSeric ** Expand out this user into argument list. 923c579ef51Seric */ 924c579ef51Seric 925508daeccSeric if (!clever) 926c579ef51Seric { 927b665faabSeric expand(*mvp, buf, sizeof buf, e); 9285dfc646bSeric *pvp++ = newstr(buf); 9295dfc646bSeric if (pvp >= &pv[MAXPV - 2]) 9305dfc646bSeric { 9315dfc646bSeric /* allow some space for trailing parms */ 9325dfc646bSeric break; 9335dfc646bSeric } 9345dfc646bSeric } 935c579ef51Seric } 9365dfc646bSeric 937145b49b1Seric /* see if any addresses still exist */ 938145b49b1Seric if (tobuf[0] == '\0') 939c579ef51Seric { 940588cad61Seric define('g', (char *) NULL, e); 941145b49b1Seric return (0); 942c579ef51Seric } 943145b49b1Seric 9445dfc646bSeric /* print out messages as full list */ 94563780dbdSeric e->e_to = tobuf + 1; 9465dfc646bSeric 9475dfc646bSeric /* 9485dfc646bSeric ** Fill out any parameters after the $u parameter. 9495dfc646bSeric */ 9505dfc646bSeric 951c579ef51Seric while (!clever && *++mvp != NULL) 9525dfc646bSeric { 953b665faabSeric expand(*mvp, buf, sizeof buf, e); 9545dfc646bSeric *pvp++ = newstr(buf); 9555dfc646bSeric if (pvp >= &pv[MAXPV]) 95608b25121Seric syserr("554 deliver: pv overflow after $u for %s", pv[0]); 9575dfc646bSeric } 9585dfc646bSeric *pvp++ = NULL; 9595dfc646bSeric 96025a99e2eSeric /* 96125a99e2eSeric ** Call the mailer. 9626328bdf7Seric ** The argument vector gets built, pipes 96325a99e2eSeric ** are created as necessary, and we fork & exec as 9646328bdf7Seric ** appropriate. 965c579ef51Seric ** If we are running SMTP, we just need to clean up. 96625a99e2eSeric */ 96725a99e2eSeric 968960e665aSeric /*XXX this seems a bit wierd */ 9694899f6b5Seric if (ctladdr == NULL && m != ProgMailer && 9704899f6b5Seric bitset(QGOODUID, e->e_from.q_flags)) 971960e665aSeric ctladdr = &e->e_from; 972960e665aSeric 9739d4a8008Seric #if NAMED_BIND 9742bcc6d2dSeric if (ConfigLevel < 2) 975912a731aSbostic _res.options &= ~(RES_DEFNAMES | RES_DNSRCH); /* XXX */ 976134746fbSeric #endif 9779c9e68d9Seric 9789c9e68d9Seric if (tTd(11, 1)) 979134746fbSeric { 9809c9e68d9Seric printf("openmailer:"); 9819c9e68d9Seric printav(pv); 9829c9e68d9Seric } 9839c9e68d9Seric errno = 0; 984b665faabSeric #if NAMED_BIND 985b665faabSeric h_errno = 0; 986b665faabSeric #endif 9879c9e68d9Seric 988b665faabSeric CurHostName = NULL; 9899c9e68d9Seric 9909c9e68d9Seric /* 9919c9e68d9Seric ** Deal with the special case of mail handled through an IPC 9929c9e68d9Seric ** connection. 9939c9e68d9Seric ** In this case we don't actually fork. We must be 9949c9e68d9Seric ** running SMTP for this to work. We will return a 9959c9e68d9Seric ** zero pid to indicate that we are running IPC. 9969c9e68d9Seric ** We also handle a debug version that just talks to stdin/out. 9979c9e68d9Seric */ 9989c9e68d9Seric 9999c9e68d9Seric curhost = NULL; 1000c931b82bSeric SmtpPhase = NULL; 1001df106f0bSeric mci = NULL; 10029c9e68d9Seric 10037febfd66Seric #ifdef XDEBUG 10047febfd66Seric { 10057febfd66Seric char wbuf[MAXLINE]; 10067febfd66Seric 10077febfd66Seric /* make absolutely certain 0, 1, and 2 are in use */ 10087febfd66Seric sprintf(wbuf, "%s... openmailer(%s)", e->e_to, m->m_name); 10097febfd66Seric checkfd012(wbuf); 10107febfd66Seric } 10117febfd66Seric #endif 10127febfd66Seric 1013b665faabSeric /* check for 8-bit available */ 1014b665faabSeric if (bitset(EF_HAS8BIT, e->e_flags) && 1015b665faabSeric bitnset(M_7BITS, m->m_flags) && 1016b665faabSeric !bitset(MM_MIME8BIT, MimeMode)) 1017b665faabSeric { 1018b665faabSeric usrerr("554 Cannot send 8-bit data to 7-bit destination"); 1019b665faabSeric rcode = EX_DATAERR; 1020b665faabSeric goto give_up; 1021b665faabSeric } 1022b665faabSeric 10239c9e68d9Seric /* check for Local Person Communication -- not for mortals!!! */ 10249c9e68d9Seric if (strcmp(m->m_mailer, "[LPC]") == 0) 10259c9e68d9Seric { 10269c9e68d9Seric mci = (MCI *) xalloc(sizeof *mci); 10279c9e68d9Seric bzero((char *) mci, sizeof *mci); 10289c9e68d9Seric mci->mci_in = stdin; 10299c9e68d9Seric mci->mci_out = stdout; 10309c9e68d9Seric mci->mci_state = clever ? MCIS_OPENING : MCIS_OPEN; 10319c9e68d9Seric mci->mci_mailer = m; 10329c9e68d9Seric } 10339c9e68d9Seric else if (strcmp(m->m_mailer, "[IPC]") == 0 || 10349c9e68d9Seric strcmp(m->m_mailer, "[TCP]") == 0) 10359c9e68d9Seric { 10369c9e68d9Seric #ifdef DAEMON 10379c9e68d9Seric register int i; 1038b665faabSeric register u_short port = 0; 10399c9e68d9Seric 1040a5d44642Seric if (pv[0] == NULL || pv[1] == NULL || pv[1][0] == '\0') 1041a5d44642Seric { 1042a5d44642Seric syserr("null host name for %s mailer", m->m_mailer); 1043a5d44642Seric rcode = EX_CONFIG; 1044a5d44642Seric goto give_up; 1045a5d44642Seric } 1046a5d44642Seric 10479c9e68d9Seric CurHostName = pv[1]; 10489c9e68d9Seric curhost = hostsignature(m, pv[1], e); 10499c9e68d9Seric 10509c9e68d9Seric if (curhost == NULL || curhost[0] == '\0') 10519c9e68d9Seric { 1052a5d44642Seric syserr("null host signature for %s", pv[1]); 1053dfebe401Seric rcode = EX_CONFIG; 1054b31e7f2bSeric goto give_up; 1055b31e7f2bSeric } 10569c9e68d9Seric 10579c9e68d9Seric if (!clever) 10589c9e68d9Seric { 10599c9e68d9Seric syserr("554 non-clever IPC"); 1060df106f0bSeric rcode = EX_CONFIG; 10619c9e68d9Seric goto give_up; 10629c9e68d9Seric } 10639c9e68d9Seric if (pv[2] != NULL) 10649c9e68d9Seric port = atoi(pv[2]); 10659c9e68d9Seric tryhost: 10669c9e68d9Seric while (*curhost != '\0') 10679c9e68d9Seric { 10689c9e68d9Seric register char *p; 1069b665faabSeric static char hostbuf[MAXNAME + 1]; 10709c9e68d9Seric 10719c9e68d9Seric /* pull the next host from the signature */ 10729c9e68d9Seric p = strchr(curhost, ':'); 10739c9e68d9Seric if (p == NULL) 10749c9e68d9Seric p = &curhost[strlen(curhost)]; 1075df106f0bSeric if (p == curhost) 1076df106f0bSeric { 1077df106f0bSeric syserr("deliver: null host name in signature"); 10788087428aSeric curhost++; 1079df106f0bSeric continue; 1080df106f0bSeric } 10819c9e68d9Seric strncpy(hostbuf, curhost, p - curhost); 10829c9e68d9Seric hostbuf[p - curhost] = '\0'; 10839c9e68d9Seric if (*p != '\0') 10849c9e68d9Seric p++; 10859c9e68d9Seric curhost = p; 10869c9e68d9Seric 10879c9e68d9Seric /* see if we already know that this host is fried */ 10889c9e68d9Seric CurHostName = hostbuf; 10899c9e68d9Seric mci = mci_get(hostbuf, m); 10909c9e68d9Seric if (mci->mci_state != MCIS_CLOSED) 10919c9e68d9Seric { 10929c9e68d9Seric if (tTd(11, 1)) 10939c9e68d9Seric { 10949c9e68d9Seric printf("openmailer: "); 10954052916eSeric mci_dump(mci, FALSE); 10969c9e68d9Seric } 10979c9e68d9Seric CurHostName = mci->mci_host; 1098b665faabSeric message("Using cached connection to %s via %s...", 1099b665faabSeric hostbuf, m->m_name); 11009c9e68d9Seric break; 11019c9e68d9Seric } 11029c9e68d9Seric mci->mci_mailer = m; 11039c9e68d9Seric if (mci->mci_exitstat != EX_OK) 11049c9e68d9Seric continue; 11059c9e68d9Seric 11069c9e68d9Seric /* try the connection */ 11079c9e68d9Seric setproctitle("%s %s: %s", e->e_id, hostbuf, "user open"); 1108b665faabSeric message("Connecting to %s via %s...", 11099c9e68d9Seric hostbuf, m->m_name); 11109c9e68d9Seric i = makeconnection(hostbuf, port, mci, 11119c9e68d9Seric bitnset(M_SECURE_PORT, m->m_flags)); 11129c9e68d9Seric mci->mci_exitstat = i; 11139c9e68d9Seric mci->mci_errno = errno; 11149d4a8008Seric #if NAMED_BIND 1115f170942cSeric mci->mci_herrno = h_errno; 1116f170942cSeric #endif 11179c9e68d9Seric if (i == EX_OK) 11189c9e68d9Seric { 11199c9e68d9Seric mci->mci_state = MCIS_OPENING; 11209c9e68d9Seric mci_cache(mci); 1121f170942cSeric if (TrafficLogFile != NULL) 1122f170942cSeric fprintf(TrafficLogFile, "%05d == CONNECT %s\n", 1123f170942cSeric getpid(), hostbuf); 11249c9e68d9Seric break; 11259c9e68d9Seric } 11269c9e68d9Seric else if (tTd(11, 1)) 11279c9e68d9Seric printf("openmailer: makeconnection => stat=%d, errno=%d\n", 11289c9e68d9Seric i, errno); 11299c9e68d9Seric 11309c9e68d9Seric /* enter status of this host */ 11319c9e68d9Seric setstat(i); 1132df106f0bSeric 1133df106f0bSeric /* should print some message here for -v mode */ 1134df106f0bSeric } 1135df106f0bSeric if (mci == NULL) 1136df106f0bSeric { 1137df106f0bSeric syserr("deliver: no host name"); 1138df106f0bSeric rcode = EX_OSERR; 1139df106f0bSeric goto give_up; 11409c9e68d9Seric } 11419c9e68d9Seric mci->mci_pid = 0; 11429c9e68d9Seric #else /* no DAEMON */ 11439c9e68d9Seric syserr("554 openmailer: no IPC"); 11449c9e68d9Seric if (tTd(11, 1)) 11459c9e68d9Seric printf("openmailer: NULL\n"); 1146df106f0bSeric rcode = EX_UNAVAILABLE; 1147df106f0bSeric goto give_up; 11489c9e68d9Seric #endif /* DAEMON */ 11499c9e68d9Seric } 11509c9e68d9Seric else 11519c9e68d9Seric { 1152b665faabSeric /* flush any expired connections */ 1153b665faabSeric (void) mci_scan(NULL); 1154b665faabSeric 1155b665faabSeric /* announce the connection to verbose listeners */ 1156b665faabSeric if (host == NULL || host[0] == '\0') 1157b665faabSeric message("Connecting to %s...", m->m_name); 1158b665faabSeric else 1159b665faabSeric message("Connecting to %s via %s...", host, m->m_name); 1160f170942cSeric if (TrafficLogFile != NULL) 11610e3bfef5Seric { 1162f170942cSeric char **av; 1163f170942cSeric 1164f170942cSeric fprintf(TrafficLogFile, "%05d === EXEC", getpid()); 1165f170942cSeric for (av = pv; *av != NULL; av++) 1166f170942cSeric fprintf(TrafficLogFile, " %s", *av); 1167f170942cSeric fprintf(TrafficLogFile, "\n"); 11686fe8c3bcSeric } 11696fe8c3bcSeric 11709c9e68d9Seric /* create a pipe to shove the mail through */ 11719c9e68d9Seric if (pipe(mpvect) < 0) 11729c9e68d9Seric { 11730e3bfef5Seric syserr("%s... openmailer(%s): pipe (to mailer)", 11740e3bfef5Seric e->e_to, m->m_name); 11759c9e68d9Seric if (tTd(11, 1)) 11769c9e68d9Seric printf("openmailer: NULL\n"); 11779c9e68d9Seric rcode = EX_OSERR; 11789c9e68d9Seric goto give_up; 11799c9e68d9Seric } 11809c9e68d9Seric 11819c9e68d9Seric /* if this mailer speaks smtp, create a return pipe */ 11829c9e68d9Seric if (clever && pipe(rpvect) < 0) 11839c9e68d9Seric { 11840e3bfef5Seric syserr("%s... openmailer(%s): pipe (from mailer)", 11850e3bfef5Seric e->e_to, m->m_name); 11869c9e68d9Seric (void) close(mpvect[0]); 11879c9e68d9Seric (void) close(mpvect[1]); 11889c9e68d9Seric if (tTd(11, 1)) 11899c9e68d9Seric printf("openmailer: NULL\n"); 11909c9e68d9Seric rcode = EX_OSERR; 11919c9e68d9Seric goto give_up; 11929c9e68d9Seric } 11939c9e68d9Seric 11949c9e68d9Seric /* 11959c9e68d9Seric ** Actually fork the mailer process. 11969c9e68d9Seric ** DOFORK is clever about retrying. 11979c9e68d9Seric ** 11989c9e68d9Seric ** Dispose of SIGCHLD signal catchers that may be laying 11999c9e68d9Seric ** around so that endmail will get it. 12009c9e68d9Seric */ 12019c9e68d9Seric 12029c9e68d9Seric if (e->e_xfp != NULL) 12039c9e68d9Seric (void) fflush(e->e_xfp); /* for debugging */ 12049c9e68d9Seric (void) fflush(stdout); 12059c9e68d9Seric # ifdef SIGCHLD 12062b9178d3Seric (void) setsignal(SIGCHLD, SIG_DFL); 12079c9e68d9Seric # endif /* SIGCHLD */ 12089c9e68d9Seric DOFORK(FORK); 12099c9e68d9Seric /* pid is set by DOFORK */ 12109c9e68d9Seric if (pid < 0) 12119c9e68d9Seric { 12129c9e68d9Seric /* failure */ 12130e3bfef5Seric syserr("%s... openmailer(%s): cannot fork", 12140e3bfef5Seric e->e_to, m->m_name); 12159c9e68d9Seric (void) close(mpvect[0]); 12169c9e68d9Seric (void) close(mpvect[1]); 12179c9e68d9Seric if (clever) 12189c9e68d9Seric { 12199c9e68d9Seric (void) close(rpvect[0]); 12209c9e68d9Seric (void) close(rpvect[1]); 12219c9e68d9Seric } 12229c9e68d9Seric if (tTd(11, 1)) 12239c9e68d9Seric printf("openmailer: NULL\n"); 12249c9e68d9Seric rcode = EX_OSERR; 12259c9e68d9Seric goto give_up; 12269c9e68d9Seric } 12279c9e68d9Seric else if (pid == 0) 12289c9e68d9Seric { 12299c9e68d9Seric int i; 12309c9e68d9Seric int saveerrno; 12319c9e68d9Seric char **ep; 12329c9e68d9Seric char *env[MAXUSERENVIRON]; 12339c9e68d9Seric extern char **environ; 12349c9e68d9Seric extern int DtableSize; 12359c9e68d9Seric 1236f2e4d5e8Seric if (e->e_lockfp != NULL) 1237ac5a49f9Seric (void) close(fileno(e->e_lockfp)); 1238f2e4d5e8Seric 12399c9e68d9Seric /* child -- set up input & exec mailer */ 12402b9178d3Seric (void) setsignal(SIGINT, SIG_IGN); 12412b9178d3Seric (void) setsignal(SIGHUP, SIG_IGN); 12422b9178d3Seric (void) setsignal(SIGTERM, SIG_DFL); 12439c9e68d9Seric 124435427e30Seric /* tweak niceness */ 124535427e30Seric if (m->m_nice != 0) 124635427e30Seric nice(m->m_nice); 124735427e30Seric 124844f2317fSeric /* reset user and group */ 1249b665faabSeric if (bitnset(M_SPECIFIC_UID, m->m_flags)) 1250acc57dbfSeric { 1251b665faabSeric (void) setgid(m->m_gid); 1252b665faabSeric (void) setuid(m->m_uid); 1253acc57dbfSeric } 1254b665faabSeric else if (ctladdr != NULL && ctladdr->q_uid != 0) 125544f2317fSeric { 125644f2317fSeric (void) initgroups(ctladdr->q_ruser? 125744f2317fSeric ctladdr->q_ruser: ctladdr->q_user, 125844f2317fSeric ctladdr->q_gid); 125951cfe111Seric (void) setgid(ctladdr->q_gid); 126044f2317fSeric (void) setuid(ctladdr->q_uid); 126144f2317fSeric } 1262b665faabSeric else 1263b665faabSeric { 1264b665faabSeric (void) initgroups(DefUser, DefGid); 1265b665faabSeric if (m->m_gid == 0) 1266b665faabSeric (void) setgid(DefGid); 1267b665faabSeric else 1268b665faabSeric (void) setgid(m->m_gid); 1269b665faabSeric if (m->m_uid == 0) 1270b665faabSeric (void) setuid(DefUid); 1271b665faabSeric else 1272b665faabSeric (void) setuid(m->m_uid); 127344f2317fSeric } 127444f2317fSeric 127544f2317fSeric if (tTd(11, 2)) 127644f2317fSeric printf("openmailer: running as r/euid=%d/%d\n", 127744f2317fSeric getuid(), geteuid()); 127844f2317fSeric 1279b986f6aaSeric /* move into some "safe" directory */ 1280b986f6aaSeric if (m->m_execdir != NULL) 1281b986f6aaSeric { 1282b986f6aaSeric char *p, *q; 1283b665faabSeric char buf[MAXLINE + 1]; 1284b986f6aaSeric 1285b986f6aaSeric for (p = m->m_execdir; p != NULL; p = q) 1286b986f6aaSeric { 1287b986f6aaSeric q = strchr(p, ':'); 1288b986f6aaSeric if (q != NULL) 1289b986f6aaSeric *q = '\0'; 1290b665faabSeric expand(p, buf, sizeof buf, e); 1291b986f6aaSeric if (q != NULL) 1292b986f6aaSeric *q++ = ':'; 1293b986f6aaSeric if (tTd(11, 20)) 1294b986f6aaSeric printf("openmailer: trydir %s\n", 1295b986f6aaSeric buf); 1296b986f6aaSeric if (buf[0] != '\0' && chdir(buf) >= 0) 1297b986f6aaSeric break; 1298b986f6aaSeric } 1299b986f6aaSeric } 1300b986f6aaSeric 13019c9e68d9Seric /* arrange to filter std & diag output of command */ 13029c9e68d9Seric if (clever) 13039c9e68d9Seric { 13049c9e68d9Seric (void) close(rpvect[0]); 13056fe8c3bcSeric if (dup2(rpvect[1], STDOUT_FILENO) < 0) 13066fe8c3bcSeric { 13070e3bfef5Seric syserr("%s... openmailer(%s): cannot dup pipe %d for stdout", 13080e3bfef5Seric e->e_to, m->m_name, rpvect[1]); 13096fe8c3bcSeric _exit(EX_OSERR); 13106fe8c3bcSeric } 13119c9e68d9Seric (void) close(rpvect[1]); 13129c9e68d9Seric } 13138b40b0a4Seric else if (OpMode == MD_SMTP || OpMode == MD_DAEMON || 13148b40b0a4Seric HoldErrs || DisConnected) 13159c9e68d9Seric { 13169c9e68d9Seric /* put mailer output in transcript */ 13176fe8c3bcSeric if (dup2(fileno(e->e_xfp), STDOUT_FILENO) < 0) 13186fe8c3bcSeric { 13190e3bfef5Seric syserr("%s... openmailer(%s): cannot dup xscript %d for stdout", 13200e3bfef5Seric e->e_to, m->m_name, 13216fe8c3bcSeric fileno(e->e_xfp)); 13226fe8c3bcSeric _exit(EX_OSERR); 13239c9e68d9Seric } 13246fe8c3bcSeric } 13256fe8c3bcSeric if (dup2(STDOUT_FILENO, STDERR_FILENO) < 0) 13266fe8c3bcSeric { 13270e3bfef5Seric syserr("%s... openmailer(%s): cannot dup stdout for stderr", 13280e3bfef5Seric e->e_to, m->m_name); 13296fe8c3bcSeric _exit(EX_OSERR); 13306fe8c3bcSeric } 13319c9e68d9Seric 13329c9e68d9Seric /* arrange to get standard input */ 13339c9e68d9Seric (void) close(mpvect[1]); 13349c9e68d9Seric if (dup2(mpvect[0], STDIN_FILENO) < 0) 13359c9e68d9Seric { 13360e3bfef5Seric syserr("%s... openmailer(%s): cannot dup pipe %d for stdin", 13370e3bfef5Seric e->e_to, m->m_name, mpvect[0]); 13389c9e68d9Seric _exit(EX_OSERR); 13399c9e68d9Seric } 13409c9e68d9Seric (void) close(mpvect[0]); 13419c9e68d9Seric 13429c9e68d9Seric /* arrange for all the files to be closed */ 13439c9e68d9Seric for (i = 3; i < DtableSize; i++) 13449c9e68d9Seric { 13459c9e68d9Seric register int j; 134644f2317fSeric 13479c9e68d9Seric if ((j = fcntl(i, F_GETFD, 0)) != -1) 13489c9e68d9Seric (void) fcntl(i, F_SETFD, j | 1); 13499c9e68d9Seric } 13509c9e68d9Seric 13519f9b003eSeric /* 13529f9b003eSeric ** Set up the mailer environment 1353b665faabSeric ** _FORCE_MAIL_LOCAL_ is DG-UX equiv of -d flag. 13549f9b003eSeric ** TZ is timezone information. 13559f9b003eSeric ** SYSTYPE is Apollo software sys type (required). 13569f9b003eSeric ** ISP is Apollo hardware system type (required). 13579f9b003eSeric */ 13589f9b003eSeric 13599c9e68d9Seric i = 0; 13609c9e68d9Seric env[i++] = "AGENT=sendmail"; 1361b665faabSeric env[i++] = "_FORCE_MAIL_LOCAL_=yes"; 13629c9e68d9Seric for (ep = environ; *ep != NULL; ep++) 13639c9e68d9Seric { 13649f9b003eSeric if (strncmp(*ep, "TZ=", 3) == 0 || 13659f9b003eSeric strncmp(*ep, "ISP=", 4) == 0 || 13669f9b003eSeric strncmp(*ep, "SYSTYPE=", 8) == 0) 13679c9e68d9Seric env[i++] = *ep; 13689c9e68d9Seric } 1369b665faabSeric env[i] = NULL; 13709c9e68d9Seric 1371929277f2Seric /* run disconnected from terminal */ 1372929277f2Seric (void) setsid(); 1373929277f2Seric 13749c9e68d9Seric /* try to execute the mailer */ 13753f11fd05Seric execve(m->m_mailer, (ARGV_T) pv, (ARGV_T) env); 13769c9e68d9Seric saveerrno = errno; 13779c9e68d9Seric syserr("Cannot exec %s", m->m_mailer); 1378b665faabSeric if (bitnset(M_LOCALMAILER, m->m_flags) || 1379b665faabSeric transienterror(saveerrno)) 13807c941fd2Seric _exit(EX_OSERR); 13819c9e68d9Seric _exit(EX_UNAVAILABLE); 13829c9e68d9Seric } 13839c9e68d9Seric 13849c9e68d9Seric /* 13859c9e68d9Seric ** Set up return value. 13869c9e68d9Seric */ 13879c9e68d9Seric 13889c9e68d9Seric mci = (MCI *) xalloc(sizeof *mci); 13899c9e68d9Seric bzero((char *) mci, sizeof *mci); 13909c9e68d9Seric mci->mci_mailer = m; 13919c9e68d9Seric mci->mci_state = clever ? MCIS_OPENING : MCIS_OPEN; 13929c9e68d9Seric mci->mci_pid = pid; 13939c9e68d9Seric (void) close(mpvect[0]); 13949c9e68d9Seric mci->mci_out = fdopen(mpvect[1], "w"); 1395335eae58Seric if (mci->mci_out == NULL) 1396335eae58Seric { 1397335eae58Seric syserr("deliver: cannot create mailer output channel, fd=%d", 1398335eae58Seric mpvect[1]); 1399335eae58Seric (void) close(mpvect[1]); 1400335eae58Seric if (clever) 1401335eae58Seric { 1402335eae58Seric (void) close(rpvect[0]); 1403335eae58Seric (void) close(rpvect[1]); 1404335eae58Seric } 1405335eae58Seric rcode = EX_OSERR; 1406335eae58Seric goto give_up; 1407335eae58Seric } 14089c9e68d9Seric if (clever) 14099c9e68d9Seric { 14109c9e68d9Seric (void) close(rpvect[1]); 14119c9e68d9Seric mci->mci_in = fdopen(rpvect[0], "r"); 1412335eae58Seric if (mci->mci_in == NULL) 1413335eae58Seric { 1414335eae58Seric syserr("deliver: cannot create mailer input channel, fd=%d", 1415335eae58Seric mpvect[1]); 1416335eae58Seric (void) close(rpvect[0]); 1417335eae58Seric fclose(mci->mci_out); 1418335eae58Seric mci->mci_out = NULL; 1419335eae58Seric rcode = EX_OSERR; 1420335eae58Seric goto give_up; 1421335eae58Seric } 14229c9e68d9Seric } 14239c9e68d9Seric else 14249c9e68d9Seric { 14259c9e68d9Seric mci->mci_flags |= MCIF_TEMP; 14269c9e68d9Seric mci->mci_in = NULL; 14279c9e68d9Seric } 14289c9e68d9Seric } 14299c9e68d9Seric 14309c9e68d9Seric /* 14319c9e68d9Seric ** If we are in SMTP opening state, send initial protocol. 14329c9e68d9Seric */ 14339c9e68d9Seric 14349c9e68d9Seric if (clever && mci->mci_state != MCIS_CLOSED) 14359c9e68d9Seric { 14369c9e68d9Seric smtpinit(m, mci, e); 14379c9e68d9Seric } 1438b665faabSeric 1439b665faabSeric if (bitset(EF_HAS8BIT, e->e_flags) && bitnset(M_7BITS, m->m_flags)) 1440b665faabSeric mci->mci_flags |= MCIF_CVT8TO7; 1441b665faabSeric else 1442b665faabSeric mci->mci_flags &= ~MCIF_CVT8TO7; 1443b665faabSeric 14449c9e68d9Seric if (tTd(11, 1)) 14459c9e68d9Seric { 14469c9e68d9Seric printf("openmailer: "); 14474052916eSeric mci_dump(mci, FALSE); 14489c9e68d9Seric } 14499c9e68d9Seric 14509c9e68d9Seric if (mci->mci_state != MCIS_OPEN) 1451b31e7f2bSeric { 1452b31e7f2bSeric /* couldn't open the mailer */ 1453b31e7f2bSeric rcode = mci->mci_exitstat; 14542a6bc25bSeric errno = mci->mci_errno; 14559d4a8008Seric #if NAMED_BIND 1456f170942cSeric h_errno = mci->mci_herrno; 1457f170942cSeric #endif 1458b31e7f2bSeric if (rcode == EX_OK) 1459b31e7f2bSeric { 1460b31e7f2bSeric /* shouldn't happen */ 146108b25121Seric syserr("554 deliver: rcode=%d, mci_state=%d, sig=%s", 14626b0f339dSeric rcode, mci->mci_state, firstsig); 1463b31e7f2bSeric rcode = EX_SOFTWARE; 1464b31e7f2bSeric } 1465b665faabSeric else if (curhost != NULL && *curhost != '\0') 146690891494Seric { 146790891494Seric /* try next MX site */ 146890891494Seric goto tryhost; 146990891494Seric } 1470b31e7f2bSeric } 1471b31e7f2bSeric else if (!clever) 1472b31e7f2bSeric { 1473b31e7f2bSeric /* 1474b31e7f2bSeric ** Format and send message. 1475b31e7f2bSeric */ 147615d084d5Seric 14775aa0f353Seric putfromline(mci, e); 1478b665faabSeric (*e->e_puthdr)(mci, e->e_header, e); 14796ffc2dd1Seric (*e->e_putbody)(mci, e, NULL); 1480b31e7f2bSeric 1481b31e7f2bSeric /* get the exit status */ 1482c9be6216Seric rcode = endmailer(mci, e, pv); 1483134746fbSeric } 1484134746fbSeric else 1485b31e7f2bSeric #ifdef SMTP 1486134746fbSeric { 1487b31e7f2bSeric /* 1488b31e7f2bSeric ** Send the MAIL FROM: protocol 1489b31e7f2bSeric */ 149015d084d5Seric 1491b31e7f2bSeric rcode = smtpmailfrom(m, mci, e); 1492b31e7f2bSeric if (rcode == EX_OK) 149375889e88Seric { 1494ded0d3daSkarels register char *t = tobuf; 1495ded0d3daSkarels register int i; 1496ded0d3daSkarels 1497588cad61Seric /* send the recipient list */ 149863780dbdSeric tobuf[0] = '\0'; 149975889e88Seric for (to = tochain; to != NULL; to = to->q_tchain) 150075889e88Seric { 150163780dbdSeric e->e_to = to->q_paddr; 150215d084d5Seric if ((i = smtprcpt(to, m, mci, e)) != EX_OK) 150375889e88Seric { 1504b665faabSeric markfailure(e, to, mci, i); 1505b665faabSeric giveresponse(i, m, mci, ctladdr, xstart, e); 150663780dbdSeric } 150775889e88Seric else 150875889e88Seric { 1509911693bfSbostic *t++ = ','; 1510b31e7f2bSeric for (p = to->q_paddr; *p; *t++ = *p++) 1511b31e7f2bSeric continue; 1512ee39df61Seric *t = '\0'; 1513588cad61Seric } 1514588cad61Seric } 1515588cad61Seric 151663780dbdSeric /* now send the data */ 151763780dbdSeric if (tobuf[0] == '\0') 1518b31e7f2bSeric { 15199c9e68d9Seric rcode = EX_OK; 152063780dbdSeric e->e_to = NULL; 1521b31e7f2bSeric if (bitset(MCIF_CACHED, mci->mci_flags)) 1522b31e7f2bSeric smtprset(m, mci, e); 1523b31e7f2bSeric } 152475889e88Seric else 152575889e88Seric { 152663780dbdSeric e->e_to = tobuf + 1; 152775889e88Seric rcode = smtpdata(m, mci, e); 152863780dbdSeric } 152963780dbdSeric 153063780dbdSeric /* now close the connection */ 1531b31e7f2bSeric if (!bitset(MCIF_CACHED, mci->mci_flags)) 153215d084d5Seric smtpquit(m, mci, e); 153363780dbdSeric } 1534cb082c5bSeric if (rcode != EX_OK && curhost != NULL && *curhost != '\0') 15359c9e68d9Seric { 15369c9e68d9Seric /* try next MX site */ 15379c9e68d9Seric goto tryhost; 15389c9e68d9Seric } 1539c579ef51Seric } 1540b31e7f2bSeric #else /* not SMTP */ 1541a05b3449Sbostic { 154208b25121Seric syserr("554 deliver: need SMTP compiled to use clever mailer"); 1543845e533cSeric rcode = EX_CONFIG; 1544b31e7f2bSeric goto give_up; 1545a05b3449Sbostic } 1546b31e7f2bSeric #endif /* SMTP */ 15479d4a8008Seric #if NAMED_BIND 15482bcc6d2dSeric if (ConfigLevel < 2) 1549912a731aSbostic _res.options |= RES_DEFNAMES | RES_DNSRCH; /* XXX */ 1550134746fbSeric #endif 15515dfc646bSeric 1552b31e7f2bSeric /* arrange a return receipt if requested */ 1553df106f0bSeric if (rcode == EX_OK && e->e_receiptto != NULL && 1554df106f0bSeric bitnset(M_LOCALMAILER, m->m_flags)) 1555b31e7f2bSeric { 1556b31e7f2bSeric e->e_flags |= EF_SENDRECEIPT; 1557b31e7f2bSeric /* do we want to send back more info? */ 1558b31e7f2bSeric } 1559b31e7f2bSeric 1560c77d1c25Seric /* 156163780dbdSeric ** Do final status disposal. 156263780dbdSeric ** We check for something in tobuf for the SMTP case. 1563c77d1c25Seric ** If we got a temporary failure, arrange to queue the 1564c77d1c25Seric ** addressees. 1565c77d1c25Seric */ 1566c77d1c25Seric 1567b31e7f2bSeric give_up: 156863780dbdSeric if (tobuf[0] != '\0') 1569b665faabSeric giveresponse(rcode, m, mci, ctladdr, xstart, e); 1570772e6e50Seric for (to = tochain; to != NULL; to = to->q_tchain) 1571b31e7f2bSeric { 1572dde5acadSeric if (rcode != EX_OK) 1573b665faabSeric markfailure(e, to, mci, rcode); 1574b665faabSeric else if (!bitset(QBADADDR|QQUEUEUP, to->q_flags)) 1575655518ecSeric { 1576dde5acadSeric to->q_flags |= QSENT; 1577b665faabSeric to->q_statdate = curtime(); 1578655518ecSeric e->e_nsent++; 1579b665faabSeric if (bitnset(M_LOCALMAILER, m->m_flags) && 1580b665faabSeric (e->e_receiptto != NULL || 1581b665faabSeric bitset(QPINGONSUCCESS, to->q_flags))) 1582df106f0bSeric { 1583b665faabSeric to->q_flags |= QREPORT; 1584df106f0bSeric fprintf(e->e_xfp, "%s... Successfully delivered\n", 1585df106f0bSeric to->q_paddr); 1586df106f0bSeric } 1587b665faabSeric else if (bitset(QPINGONSUCCESS, to->q_flags) && 1588b665faabSeric bitset(QPRIMARY, to->q_flags) && 1589b665faabSeric !bitset(MCIF_DSN, mci->mci_flags)) 1590b665faabSeric { 1591b665faabSeric to->q_flags |= QRELAYED; 1592b665faabSeric fprintf(e->e_xfp, "%s... relayed; expect no further notifications\n", 1593b665faabSeric to->q_paddr); 1594b665faabSeric } 1595655518ecSeric } 1596b31e7f2bSeric } 1597b31e7f2bSeric 1598b31e7f2bSeric /* 1599b31e7f2bSeric ** Restore state and return. 1600b31e7f2bSeric */ 1601c77d1c25Seric 16027febfd66Seric #ifdef XDEBUG 16037febfd66Seric { 16047febfd66Seric char wbuf[MAXLINE]; 16057febfd66Seric 16067febfd66Seric /* make absolutely certain 0, 1, and 2 are in use */ 160744622ea3Seric sprintf(wbuf, "%s... end of deliver(%s)", 160844622ea3Seric e->e_to == NULL ? "NO-TO-LIST" : e->e_to, 160944622ea3Seric m->m_name); 16107febfd66Seric checkfd012(wbuf); 16117febfd66Seric } 16127febfd66Seric #endif 16137febfd66Seric 161435490626Seric errno = 0; 1615588cad61Seric define('g', (char *) NULL, e); 16165826d9d3Seric return (rcode); 161725a99e2eSeric } 16185dfc646bSeric /* 161983b7ddc9Seric ** MARKFAILURE -- mark a failure on a specific address. 162083b7ddc9Seric ** 162183b7ddc9Seric ** Parameters: 162283b7ddc9Seric ** e -- the envelope we are sending. 162383b7ddc9Seric ** q -- the address to mark. 1624b665faabSeric ** mci -- mailer connection information. 162583b7ddc9Seric ** rcode -- the code signifying the particular failure. 162683b7ddc9Seric ** 162783b7ddc9Seric ** Returns: 162883b7ddc9Seric ** none. 162983b7ddc9Seric ** 163083b7ddc9Seric ** Side Effects: 163183b7ddc9Seric ** marks the address (and possibly the envelope) with the 163283b7ddc9Seric ** failure so that an error will be returned or 163383b7ddc9Seric ** the message will be queued, as appropriate. 163483b7ddc9Seric */ 163583b7ddc9Seric 1636b665faabSeric markfailure(e, q, mci, rcode) 163783b7ddc9Seric register ENVELOPE *e; 163883b7ddc9Seric register ADDRESS *q; 1639b665faabSeric register MCI *mci; 164083b7ddc9Seric int rcode; 164183b7ddc9Seric { 1642b665faabSeric char *stat = NULL; 164319c47125Seric 1644d5aafa3cSeric switch (rcode) 1645d5aafa3cSeric { 1646d5aafa3cSeric case EX_OK: 1647d5aafa3cSeric break; 1648d5aafa3cSeric 1649d5aafa3cSeric case EX_TEMPFAIL: 1650d5aafa3cSeric case EX_IOERR: 1651d5aafa3cSeric case EX_OSERR: 165283b7ddc9Seric q->q_flags |= QQUEUEUP; 1653d5aafa3cSeric break; 1654d5aafa3cSeric 1655d5aafa3cSeric default: 1656f170942cSeric q->q_flags |= QBADADDR; 1657d5aafa3cSeric break; 1658d5aafa3cSeric } 1659b665faabSeric 1660b665faabSeric if (q->q_status == NULL && mci != NULL) 1661b665faabSeric q->q_status = mci->mci_status; 1662b665faabSeric switch (rcode) 1663b665faabSeric { 1664b665faabSeric case EX_USAGE: 1665b665faabSeric stat = "5.5.4"; 1666b665faabSeric break; 1667b665faabSeric 1668b665faabSeric case EX_DATAERR: 1669b665faabSeric stat = "5.5.2"; 1670b665faabSeric break; 1671b665faabSeric 1672b665faabSeric case EX_NOUSER: 1673b665faabSeric case EX_NOHOST: 1674b665faabSeric stat = "5.1.1"; 1675b665faabSeric break; 1676b665faabSeric 1677b665faabSeric case EX_NOINPUT: 1678b665faabSeric case EX_CANTCREAT: 1679b665faabSeric case EX_NOPERM: 1680b665faabSeric stat = "5.3.0"; 1681b665faabSeric break; 1682b665faabSeric 1683b665faabSeric case EX_UNAVAILABLE: 1684b665faabSeric case EX_SOFTWARE: 1685b665faabSeric case EX_OSFILE: 1686b665faabSeric case EX_PROTOCOL: 1687b665faabSeric case EX_CONFIG: 1688b665faabSeric stat = "5.5.0"; 1689b665faabSeric break; 1690b665faabSeric 1691b665faabSeric case EX_OSERR: 1692b665faabSeric case EX_IOERR: 1693b665faabSeric stat = "4.5.0"; 1694b665faabSeric break; 1695b665faabSeric 1696b665faabSeric case EX_TEMPFAIL: 1697b665faabSeric stat = "4.2.0"; 1698b665faabSeric break; 1699b665faabSeric } 1700b665faabSeric if (stat != NULL && q->q_status == NULL) 1701b665faabSeric q->q_status = stat; 1702b665faabSeric 1703b665faabSeric q->q_statdate = curtime(); 1704b665faabSeric if (CurHostName != NULL && CurHostName[0] != '\0') 1705b665faabSeric q->q_statmta = newstr(CurHostName); 1706b665faabSeric if (rcode != EX_OK && q->q_rstatus == NULL) 1707b665faabSeric { 1708b665faabSeric char buf[30]; 1709b665faabSeric 1710b665faabSeric (void) sprintf(buf, "%d", rcode); 1711b665faabSeric q->q_rstatus = newstr(buf); 1712b665faabSeric } 171383b7ddc9Seric } 171483b7ddc9Seric /* 1715c579ef51Seric ** ENDMAILER -- Wait for mailer to terminate. 1716c579ef51Seric ** 1717c579ef51Seric ** We should never get fatal errors (e.g., segmentation 1718c579ef51Seric ** violation), so we report those specially. For other 1719c579ef51Seric ** errors, we choose a status message (into statmsg), 1720c579ef51Seric ** and if it represents an error, we print it. 1721c579ef51Seric ** 1722c579ef51Seric ** Parameters: 1723c579ef51Seric ** pid -- pid of mailer. 1724c9be6216Seric ** e -- the current envelope. 1725c9be6216Seric ** pv -- the parameter vector that invoked the mailer 1726c9be6216Seric ** (for error messages). 1727c579ef51Seric ** 1728c579ef51Seric ** Returns: 1729c579ef51Seric ** exit code of mailer. 1730c579ef51Seric ** 1731c579ef51Seric ** Side Effects: 1732c579ef51Seric ** none. 1733c579ef51Seric */ 1734c579ef51Seric 1735c9be6216Seric endmailer(mci, e, pv) 1736b31e7f2bSeric register MCI *mci; 1737c9be6216Seric register ENVELOPE *e; 1738c9be6216Seric char **pv; 1739c579ef51Seric { 1740588cad61Seric int st; 1741c579ef51Seric 174275889e88Seric /* close any connections */ 174375889e88Seric if (mci->mci_in != NULL) 174476f3d53fSeric (void) xfclose(mci->mci_in, mci->mci_mailer->m_name, "mci_in"); 174575889e88Seric if (mci->mci_out != NULL) 174676f3d53fSeric (void) xfclose(mci->mci_out, mci->mci_mailer->m_name, "mci_out"); 174775889e88Seric mci->mci_in = mci->mci_out = NULL; 174875889e88Seric mci->mci_state = MCIS_CLOSED; 174975889e88Seric 175033db8731Seric /* in the IPC case there is nothing to wait for */ 175175889e88Seric if (mci->mci_pid == 0) 175233db8731Seric return (EX_OK); 175333db8731Seric 175433db8731Seric /* wait for the mailer process to die and collect status */ 175575889e88Seric st = waitfor(mci->mci_pid); 1756588cad61Seric if (st == -1) 175778de67c1Seric { 1758c9be6216Seric syserr("endmailer %s: wait", pv[0]); 1759588cad61Seric return (EX_SOFTWARE); 1760c579ef51Seric } 176133db8731Seric 1762bf9bc890Seric if (WIFEXITED(st)) 1763c579ef51Seric { 1764bf9bc890Seric /* normal death -- return status */ 1765bf9bc890Seric return (WEXITSTATUS(st)); 1766bf9bc890Seric } 1767bf9bc890Seric 1768bf9bc890Seric /* it died a horrid death */ 1769550092c3Seric syserr("451 mailer %s died with signal %o", 1770550092c3Seric mci->mci_mailer->m_name, st); 1771c9be6216Seric 1772c9be6216Seric /* log the arguments */ 17733c930db3Seric if (pv != NULL && e->e_xfp != NULL) 1774c9be6216Seric { 1775c9be6216Seric register char **av; 1776c9be6216Seric 1777c9be6216Seric fprintf(e->e_xfp, "Arguments:"); 1778c9be6216Seric for (av = pv; *av != NULL; av++) 1779c9be6216Seric fprintf(e->e_xfp, " %s", *av); 1780c9be6216Seric fprintf(e->e_xfp, "\n"); 1781c9be6216Seric } 1782c9be6216Seric 17835f73204aSeric ExitStat = EX_TEMPFAIL; 17845f73204aSeric return (EX_TEMPFAIL); 1785c579ef51Seric } 1786c579ef51Seric /* 178725a99e2eSeric ** GIVERESPONSE -- Interpret an error response from a mailer 178825a99e2eSeric ** 178925a99e2eSeric ** Parameters: 179025a99e2eSeric ** stat -- the status code from the mailer (high byte 179125a99e2eSeric ** only; core dumps must have been taken care of 179225a99e2eSeric ** already). 179381161401Seric ** m -- the mailer info for this mailer. 179481161401Seric ** mci -- the mailer connection info -- can be NULL if the 179581161401Seric ** response is given before the connection is made. 17964dee0003Seric ** ctladdr -- the controlling address for the recipient 17974dee0003Seric ** address(es). 1798b665faabSeric ** xstart -- the transaction start time, for computing 1799b665faabSeric ** transaction delays. 180081161401Seric ** e -- the current envelope. 180125a99e2eSeric ** 180225a99e2eSeric ** Returns: 1803db8841e9Seric ** none. 180425a99e2eSeric ** 180525a99e2eSeric ** Side Effects: 1806c1f9df2cSeric ** Errors may be incremented. 180725a99e2eSeric ** ExitStat may be set. 180825a99e2eSeric */ 180925a99e2eSeric 1810b665faabSeric giveresponse(stat, m, mci, ctladdr, xstart, e) 181125a99e2eSeric int stat; 1812588cad61Seric register MAILER *m; 181381161401Seric register MCI *mci; 18144dee0003Seric ADDRESS *ctladdr; 1815b665faabSeric time_t xstart; 1816198d9be0Seric ENVELOPE *e; 181725a99e2eSeric { 18189c16475dSeric register const char *statmsg; 181925a99e2eSeric extern char *SysExMsg[]; 182025a99e2eSeric register int i; 1821d4bd8f0eSbostic extern int N_SysEx; 1822198d9be0Seric char buf[MAXLINE]; 182325a99e2eSeric 182413bbc08cSeric /* 182513bbc08cSeric ** Compute status message from code. 182613bbc08cSeric */ 182713bbc08cSeric 182825a99e2eSeric i = stat - EX__BASE; 1829588cad61Seric if (stat == 0) 18306fe8c3bcSeric { 1831588cad61Seric statmsg = "250 Sent"; 1832ce5531bdSeric if (e->e_statmsg != NULL) 18336fe8c3bcSeric { 1834ce5531bdSeric (void) sprintf(buf, "%s (%s)", statmsg, e->e_statmsg); 18356fe8c3bcSeric statmsg = buf; 18366fe8c3bcSeric } 18376fe8c3bcSeric } 1838588cad61Seric else if (i < 0 || i > N_SysEx) 1839588cad61Seric { 1840588cad61Seric (void) sprintf(buf, "554 unknown mailer error %d", stat); 1841588cad61Seric stat = EX_UNAVAILABLE; 1842588cad61Seric statmsg = buf; 1843588cad61Seric } 1844198d9be0Seric else if (stat == EX_TEMPFAIL) 1845198d9be0Seric { 18467d55540cSeric (void) strcpy(buf, SysExMsg[i] + 1); 18479d4a8008Seric #if NAMED_BIND 1848f28da541Smiriam if (h_errno == TRY_AGAIN) 18494d50702aSeric statmsg = errstring(h_errno+E_DNSBASE); 1850f28da541Smiriam else 1851d4bd8f0eSbostic #endif 1852f28da541Smiriam { 18538557d168Seric if (errno != 0) 1854d87e85f3Seric statmsg = errstring(errno); 1855d87e85f3Seric else 1856d87e85f3Seric { 1857d87e85f3Seric #ifdef SMTP 1858d87e85f3Seric statmsg = SmtpError; 18596c2c3107Seric #else /* SMTP */ 1860d87e85f3Seric statmsg = NULL; 18616c2c3107Seric #endif /* SMTP */ 1862d87e85f3Seric } 1863f28da541Smiriam } 1864d87e85f3Seric if (statmsg != NULL && statmsg[0] != '\0') 1865d87e85f3Seric { 186687c9b3e7Seric (void) strcat(buf, ": "); 1867d87e85f3Seric (void) strcat(buf, statmsg); 18688557d168Seric } 1869198d9be0Seric statmsg = buf; 1870198d9be0Seric } 18719d4a8008Seric #if NAMED_BIND 1872f170942cSeric else if (stat == EX_NOHOST && h_errno != 0) 1873f170942cSeric { 18744d50702aSeric statmsg = errstring(h_errno + E_DNSBASE); 1875862934b2Seric (void) sprintf(buf, "%s (%s)", SysExMsg[i] + 1, statmsg); 1876f170942cSeric statmsg = buf; 1877f170942cSeric } 1878f170942cSeric #endif 187925a99e2eSeric else 1880d87e85f3Seric { 188125a99e2eSeric statmsg = SysExMsg[i]; 18827d55540cSeric if (*statmsg++ == ':') 18837d55540cSeric { 18847d55540cSeric (void) sprintf(buf, "%s: %s", statmsg, errstring(errno)); 18857d55540cSeric statmsg = buf; 18867d55540cSeric } 1887d87e85f3Seric } 1888588cad61Seric 1889588cad61Seric /* 1890588cad61Seric ** Print the message as appropriate 1891588cad61Seric */ 1892588cad61Seric 1893198d9be0Seric if (stat == EX_OK || stat == EX_TEMPFAIL) 1894df106f0bSeric { 1895df106f0bSeric extern char MsgBuf[]; 1896df106f0bSeric 18971f96bd0bSeric message("%s", &statmsg[4]); 1898df106f0bSeric if (stat == EX_TEMPFAIL && e->e_xfp != NULL) 1899df106f0bSeric fprintf(e->e_xfp, "%s\n", &MsgBuf[4]); 1900df106f0bSeric } 190125a99e2eSeric else 190225a99e2eSeric { 1903862934b2Seric char mbuf[8]; 1904862934b2Seric 1905c1f9df2cSeric Errors++; 1906862934b2Seric sprintf(mbuf, "%.3s %%s", statmsg); 1907862934b2Seric usrerr(mbuf, &statmsg[4]); 190825a99e2eSeric } 190925a99e2eSeric 191025a99e2eSeric /* 191125a99e2eSeric ** Final cleanup. 191225a99e2eSeric ** Log a record of the transaction. Compute the new 191325a99e2eSeric ** ExitStat -- if we already had an error, stick with 191425a99e2eSeric ** that. 191525a99e2eSeric */ 191625a99e2eSeric 19172f624c86Seric if (LogLevel > ((stat == EX_TEMPFAIL) ? 8 : (stat == EX_OK) ? 7 : 6)) 1918b665faabSeric logdelivery(m, mci, &statmsg[4], ctladdr, xstart, e); 1919eb238f8cSeric 19205d3f0ed4Seric if (tTd(11, 2)) 19215d3f0ed4Seric printf("giveresponse: stat=%d, e->e_message=%s\n", 19222c8ac7e0Seric stat, e->e_message == NULL ? "<NULL>" : e->e_message); 19235d3f0ed4Seric 1924eb238f8cSeric if (stat != EX_TEMPFAIL) 1925eb238f8cSeric setstat(stat); 19261097d4c9Seric if (stat != EX_OK && (stat != EX_TEMPFAIL || e->e_message == NULL)) 1927198d9be0Seric { 1928198d9be0Seric if (e->e_message != NULL) 1929198d9be0Seric free(e->e_message); 1930198d9be0Seric e->e_message = newstr(&statmsg[4]); 1931198d9be0Seric } 19328557d168Seric errno = 0; 19339d4a8008Seric #if NAMED_BIND 1934f28da541Smiriam h_errno = 0; 1935d4bd8f0eSbostic #endif 1936eb238f8cSeric } 1937eb238f8cSeric /* 1938eb238f8cSeric ** LOGDELIVERY -- log the delivery in the system log 1939eb238f8cSeric ** 19402c9b4f99Seric ** Care is taken to avoid logging lines that are too long, because 19412c9b4f99Seric ** some versions of syslog have an unfortunate proclivity for core 19422c9b4f99Seric ** dumping. This is a hack, to be sure, that is at best empirical. 19432c9b4f99Seric ** 1944eb238f8cSeric ** Parameters: 194581161401Seric ** m -- the mailer info. Can be NULL for initial queue. 194681161401Seric ** mci -- the mailer connection info -- can be NULL if the 194781161401Seric ** log is occuring when no connection is active. 194881161401Seric ** stat -- the message to print for the status. 19494dee0003Seric ** ctladdr -- the controlling address for the to list. 1950b665faabSeric ** xstart -- the transaction start time, used for 1951b665faabSeric ** computing transaction delay. 195281161401Seric ** e -- the current envelope. 1953eb238f8cSeric ** 1954eb238f8cSeric ** Returns: 1955eb238f8cSeric ** none 1956eb238f8cSeric ** 1957eb238f8cSeric ** Side Effects: 1958eb238f8cSeric ** none 1959eb238f8cSeric */ 1960eb238f8cSeric 1961b665faabSeric logdelivery(m, mci, stat, ctladdr, xstart, e) 196281161401Seric MAILER *m; 196381161401Seric register MCI *mci; 1964eb238f8cSeric char *stat; 19654dee0003Seric ADDRESS *ctladdr; 1966b665faabSeric time_t xstart; 1967b31e7f2bSeric register ENVELOPE *e; 19685cf56be3Seric { 1969eb238f8cSeric # ifdef LOG 19704dee0003Seric register char *bp; 19712c9b4f99Seric register char *p; 19722c9b4f99Seric int l; 1973d6acf3eeSeric char buf[512]; 19749507d1f9Seric 19753a100e8bSeric # if (SYSLOG_BUFSIZE) >= 256 19764dee0003Seric bp = buf; 19774dee0003Seric if (ctladdr != NULL) 19784dee0003Seric { 19794dee0003Seric strcpy(bp, ", ctladdr="); 1980f62f08c7Seric strcat(bp, shortenstring(ctladdr->q_paddr, 83)); 19814dee0003Seric bp += strlen(bp); 19824dee0003Seric if (bitset(QGOODUID, ctladdr->q_flags)) 19834dee0003Seric { 19844dee0003Seric (void) sprintf(bp, " (%d/%d)", 19854dee0003Seric ctladdr->q_uid, ctladdr->q_gid); 19864dee0003Seric bp += strlen(bp); 19874dee0003Seric } 19884dee0003Seric } 19894dee0003Seric 1990b665faabSeric sprintf(bp, ", delay=%s", pintvl(curtime() - e->e_ctime, TRUE)); 19914dee0003Seric bp += strlen(bp); 199281161401Seric 1993b665faabSeric if (xstart != (time_t) 0) 1994b665faabSeric { 1995b665faabSeric sprintf(bp, ", xdelay=%s", pintvl(curtime() - xstart, TRUE)); 1996b665faabSeric bp += strlen(bp); 1997b665faabSeric } 1998b665faabSeric 199948ed5d33Seric if (m != NULL) 200071ff6caaSeric { 20014dee0003Seric (void) strcpy(bp, ", mailer="); 20024dee0003Seric (void) strcat(bp, m->m_name); 20034dee0003Seric bp += strlen(bp); 200471ff6caaSeric } 200548ed5d33Seric 200648ed5d33Seric if (mci != NULL && mci->mci_host != NULL) 200771ff6caaSeric { 200871ff6caaSeric # ifdef DAEMON 2009e2f2f828Seric extern SOCKADDR CurHostAddr; 201048ed5d33Seric # endif 201171ff6caaSeric 20124dee0003Seric (void) strcpy(bp, ", relay="); 20134dee0003Seric (void) strcat(bp, mci->mci_host); 201448ed5d33Seric 201548ed5d33Seric # ifdef DAEMON 20162bdfc6b9Seric (void) strcat(bp, " ["); 20174dee0003Seric (void) strcat(bp, anynet_ntoa(&CurHostAddr)); 20182bdfc6b9Seric (void) strcat(bp, "]"); 201971ff6caaSeric # endif 202071ff6caaSeric } 2021bcb9b028Seric else if (strcmp(stat, "queued") != 0) 202248ed5d33Seric { 202348ed5d33Seric char *p = macvalue('h', e); 20249507d1f9Seric 202548ed5d33Seric if (p != NULL && p[0] != '\0') 202648ed5d33Seric { 20274dee0003Seric (void) strcpy(bp, ", relay="); 20284dee0003Seric (void) strcat(bp, p); 202948ed5d33Seric } 203048ed5d33Seric } 2031cb082c5bSeric bp += strlen(bp); 2032d6acf3eeSeric 20333a100e8bSeric #define STATLEN (((SYSLOG_BUFSIZE) - 100) / 4) 20343a100e8bSeric #if (STATLEN) < 63 20353a100e8bSeric # undef STATLEN 20363a100e8bSeric # define STATLEN 63 20373a100e8bSeric #endif 20383a100e8bSeric #if (STATLEN) > 203 20393a100e8bSeric # undef STATLEN 20403a100e8bSeric # define STATLEN 203 20413a100e8bSeric #endif 20423a100e8bSeric 20433a100e8bSeric if ((bp - buf) > (sizeof buf - ((STATLEN) + 20))) 20442c9b4f99Seric { 20452c9b4f99Seric /* desperation move -- truncate data */ 20463a100e8bSeric bp = buf + sizeof buf - ((STATLEN) + 17); 20472c9b4f99Seric strcpy(bp, "..."); 20482c9b4f99Seric bp += 3; 20492c9b4f99Seric } 20502c9b4f99Seric 20512c9b4f99Seric (void) strcpy(bp, ", stat="); 20522c9b4f99Seric bp += strlen(bp); 20533a100e8bSeric 20543a100e8bSeric (void) strcpy(bp, shortenstring(stat, (STATLEN))); 20552c9b4f99Seric 20562c9b4f99Seric l = SYSLOG_BUFSIZE - 100 - strlen(buf); 20572c9b4f99Seric p = e->e_to; 2058972b1942Seric while (strlen(p) >= (SIZE_T) l) 20592c9b4f99Seric { 20602c9b4f99Seric register char *q = strchr(p + l, ','); 20612c9b4f99Seric 20622a1b6b73Seric if (q == NULL) 20632c9b4f99Seric break; 20642c9b4f99Seric syslog(LOG_INFO, "%s: to=%.*s [more]%s", 20652c9b4f99Seric e->e_id, ++q - p, p, buf); 20662c9b4f99Seric p = q; 20672c9b4f99Seric } 20682c9b4f99Seric syslog(LOG_INFO, "%s: to=%s%s", e->e_id, p, buf); 20693a100e8bSeric 20703a100e8bSeric # else /* we have a very short log buffer size */ 20713a100e8bSeric 207227607809Seric l = SYSLOG_BUFSIZE - 85; 20733a100e8bSeric p = e->e_to; 20743a100e8bSeric while (strlen(p) >= l) 20753a100e8bSeric { 20763a100e8bSeric register char *q = strchr(p + l, ','); 20773a100e8bSeric 20783a100e8bSeric if (q == NULL) 20793a100e8bSeric break; 20803a100e8bSeric syslog(LOG_INFO, "%s: to=%.*s [more]", 20813a100e8bSeric e->e_id, ++q - p, p); 20823a100e8bSeric p = q; 20833a100e8bSeric } 20843a100e8bSeric syslog(LOG_INFO, "%s: to=%s", e->e_id, p); 20853a100e8bSeric 20863a100e8bSeric if (ctladdr != NULL) 20873a100e8bSeric { 20883a100e8bSeric bp = buf; 20893a100e8bSeric strcpy(buf, "ctladdr="); 20903a100e8bSeric bp += strlen(buf); 20913a100e8bSeric strcpy(bp, shortenstring(ctladdr->q_paddr, 83)); 20923a100e8bSeric bp += strlen(buf); 20933a100e8bSeric if (bitset(QGOODUID, ctladdr->q_flags)) 20943a100e8bSeric { 20953a100e8bSeric (void) sprintf(bp, " (%d/%d)", 20963a100e8bSeric ctladdr->q_uid, ctladdr->q_gid); 20973a100e8bSeric bp += strlen(bp); 20983a100e8bSeric } 20993a100e8bSeric syslog(LOG_INFO, "%s: %s", e->e_id, buf); 21003a100e8bSeric } 21014e797715Seric bp = buf; 21024e797715Seric sprintf(bp, "delay=%s", pintvl(curtime() - e->e_ctime, TRUE)); 21034e797715Seric bp += strlen(bp); 2104b665faabSeric if (xstart != (time_t) 0) 2105b665faabSeric { 2106b665faabSeric sprintf(bp, ", xdelay=%s", pintvl(curtime() - xstart, TRUE)); 2107b665faabSeric bp += strlen(bp); 2108b665faabSeric } 21093a100e8bSeric 21103a100e8bSeric if (m != NULL) 21114e797715Seric { 21124e797715Seric sprintf(bp, ", mailer=%s", m->m_name); 21134e797715Seric bp += strlen(bp); 21144e797715Seric } 2115b056abd0Seric syslog(LOG_INFO, "%s: %s", e->e_id, buf); 21163a100e8bSeric 2117b056abd0Seric buf[0] = '\0'; 21183a100e8bSeric if (mci != NULL && mci->mci_host != NULL) 21193a100e8bSeric { 21203a100e8bSeric # ifdef DAEMON 21213a100e8bSeric extern SOCKADDR CurHostAddr; 21223a100e8bSeric # endif 21233a100e8bSeric 2124d2ece200Seric sprintf(buf, "relay=%s", mci->mci_host); 21253a100e8bSeric 21263a100e8bSeric # ifdef DAEMON 2127b056abd0Seric (void) strcat(buf, " ["); 2128b056abd0Seric (void) strcat(buf, anynet_ntoa(&CurHostAddr)); 2129b056abd0Seric (void) strcat(buf, "]"); 21303a100e8bSeric # endif 21313a100e8bSeric } 2132bcb9b028Seric else if (strcmp(stat, "queued") != 0) 21333a100e8bSeric { 21343a100e8bSeric char *p = macvalue('h', e); 21353a100e8bSeric 21363a100e8bSeric if (p != NULL && p[0] != '\0') 2137d2ece200Seric sprintf(buf, "relay=%s", p); 21383a100e8bSeric } 2139b056abd0Seric if (buf[0] != '\0') 21404e797715Seric syslog(LOG_INFO, "%s: %s", e->e_id, buf); 21413a100e8bSeric 21423a100e8bSeric syslog(LOG_INFO, "%s: stat=%s", e->e_id, shortenstring(stat, 63)); 21433a100e8bSeric # endif /* short log buffer */ 21446c2c3107Seric # endif /* LOG */ 214525a99e2eSeric } 214625a99e2eSeric /* 214751552439Seric ** PUTFROMLINE -- output a UNIX-style from line (or whatever) 214825a99e2eSeric ** 214951552439Seric ** This can be made an arbitrary message separator by changing $l 215051552439Seric ** 21519b6c17a6Seric ** One of the ugliest hacks seen by human eyes is contained herein: 21529b6c17a6Seric ** UUCP wants those stupid "remote from <host>" lines. Why oh why 21539b6c17a6Seric ** does a well-meaning programmer such as myself have to deal with 21549b6c17a6Seric ** this kind of antique garbage???? 215525a99e2eSeric ** 215625a99e2eSeric ** Parameters: 21575aa0f353Seric ** mci -- the connection information. 21585aa0f353Seric ** e -- the envelope. 215925a99e2eSeric ** 216025a99e2eSeric ** Returns: 216151552439Seric ** none 216225a99e2eSeric ** 216325a99e2eSeric ** Side Effects: 216451552439Seric ** outputs some text to fp. 216525a99e2eSeric */ 216625a99e2eSeric 21675aa0f353Seric putfromline(mci, e) 21685aa0f353Seric register MCI *mci; 2169b31e7f2bSeric ENVELOPE *e; 217025a99e2eSeric { 21712bc47524Seric char *template = "\201l\n"; 217251552439Seric char buf[MAXLINE]; 217325a99e2eSeric 21745aa0f353Seric if (bitnset(M_NHDR, mci->mci_mailer->m_flags)) 217551552439Seric return; 217613bbc08cSeric 21772c7e1b8dSeric # ifdef UGLYUUCP 21785aa0f353Seric if (bitnset(M_UGLYUUCP, mci->mci_mailer->m_flags)) 217974b6e67bSeric { 2180ea09d6edSeric char *bang; 2181ea09d6edSeric char xbuf[MAXLINE]; 218274b6e67bSeric 2183b665faabSeric expand("\201g", buf, sizeof buf, e); 21846c2c3107Seric bang = strchr(buf, '!'); 218574b6e67bSeric if (bang == NULL) 218634fcca25Seric { 218734fcca25Seric errno = 0; 218834fcca25Seric syserr("554 No ! in UUCP From address! (%s given)", buf); 218934fcca25Seric } 219074b6e67bSeric else 2191588cad61Seric { 2192ea09d6edSeric *bang++ = '\0'; 21932bc47524Seric (void) sprintf(xbuf, "From %s \201d remote from %s\n", bang, buf); 2194ea09d6edSeric template = xbuf; 219574b6e67bSeric } 2196588cad61Seric } 21976c2c3107Seric # endif /* UGLYUUCP */ 2198b665faabSeric expand(template, buf, sizeof buf, e); 2199b665faabSeric putxline(buf, mci, FALSE); 2200bc6e2962Seric } 2201bc6e2962Seric /* 220251552439Seric ** PUTBODY -- put the body of a message. 220351552439Seric ** 220451552439Seric ** Parameters: 22055aa0f353Seric ** mci -- the connection information. 22069a6a5f55Seric ** e -- the envelope to put out. 220703c02fdeSeric ** separator -- if non-NULL, a message separator that must 220803c02fdeSeric ** not be permitted in the resulting message. 220951552439Seric ** 221051552439Seric ** Returns: 221151552439Seric ** none. 221251552439Seric ** 221351552439Seric ** Side Effects: 221451552439Seric ** The message is written onto fp. 221551552439Seric */ 221651552439Seric 2217b665faabSeric /* values for output state variable */ 2218b665faabSeric #define OS_HEAD 0 /* at beginning of line */ 2219b665faabSeric #define OS_CR 1 /* read a carriage return */ 2220b665faabSeric #define OS_INLINE 2 /* putting rest of line */ 2221b665faabSeric 22226ffc2dd1Seric putbody(mci, e, separator) 22235aa0f353Seric register MCI *mci; 22249a6a5f55Seric register ENVELOPE *e; 222503c02fdeSeric char *separator; 222651552439Seric { 222777b52738Seric char buf[MAXLINE]; 222851552439Seric 222951552439Seric /* 223051552439Seric ** Output the body of the message 223151552439Seric */ 223251552439Seric 2233b665faabSeric if (e->e_dfp == NULL && bitset(EF_HAS_DF, e->e_flags)) 22349a6a5f55Seric { 2235b665faabSeric char *df = queuename(e, 'd'); 2236b665faabSeric 2237b665faabSeric e->e_dfp = fopen(df, "r"); 22389a6a5f55Seric if (e->e_dfp == NULL) 22398f9146b0Srick syserr("putbody: Cannot open %s for %s from %s", 2240b665faabSeric df, e->e_to, e->e_from.q_paddr); 2241b665faabSeric } 2242b665faabSeric if (e->e_dfp == NULL) 2243b665faabSeric { 2244b665faabSeric if (bitset(MCIF_INHEADER, mci->mci_flags)) 2245b665faabSeric { 2246b665faabSeric putline("", mci); 2247b665faabSeric mci->mci_flags &= ~MCIF_INHEADER; 2248b665faabSeric } 2249b665faabSeric putline("<<< No Message Collected >>>", mci); 2250b665faabSeric goto endofmessage; 2251b665faabSeric } 2252b665faabSeric if (e->e_dfino == (ino_t) 0) 2253b665faabSeric { 2254b665faabSeric struct stat stbuf; 2255b665faabSeric 2256b665faabSeric if (fstat(fileno(e->e_dfp), &stbuf) < 0) 2257b665faabSeric e->e_dfino = -1; 2258b665faabSeric else 2259b665faabSeric { 2260b665faabSeric e->e_dfdev = stbuf.st_dev; 2261b665faabSeric e->e_dfino = stbuf.st_ino; 2262b665faabSeric } 2263b665faabSeric } 2264b665faabSeric rewind(e->e_dfp); 2265b665faabSeric 2266b665faabSeric if (bitset(MCIF_CVT8TO7, mci->mci_flags)) 2267b665faabSeric { 2268b665faabSeric char *boundaries[MAXMIMENESTING + 1]; 2269b665faabSeric 2270b665faabSeric /* 2271b665faabSeric ** Do 8 to 7 bit MIME conversion. 2272b665faabSeric */ 2273b665faabSeric 2274b665faabSeric /* make sure it looks like a MIME message */ 2275b665faabSeric if (hvalue("MIME-Version", e->e_header) == NULL) 2276b665faabSeric putline("MIME-Version: 1.0", mci); 2277b665faabSeric 2278b665faabSeric if (hvalue("Content-Type", e->e_header) == NULL) 2279b665faabSeric { 2280b665faabSeric sprintf(buf, "Content-Type: text/plain; charset=%s", 2281b665faabSeric defcharset(e)); 2282b665faabSeric putline(buf, mci); 2283b665faabSeric } 2284b665faabSeric 2285b665faabSeric /* now do the hard work */ 2286b665faabSeric boundaries[0] = NULL; 2287b665faabSeric mime8to7(mci, e->e_header, e, boundaries, M87F_OUTER); 22889a6a5f55Seric } 2289bd4e74cdSeric else 2290b665faabSeric { 2291b665faabSeric int ostate; 2292b665faabSeric register char *bp; 2293b665faabSeric register char *pbp; 2294b665faabSeric register int c; 2295b665faabSeric int padc; 2296b665faabSeric char *buflim; 2297b665faabSeric int pos = 0; 2298b665faabSeric char peekbuf[10]; 2299b665faabSeric 2300b665faabSeric /* we can pass it through unmodified */ 2301b665faabSeric if (bitset(MCIF_INHEADER, mci->mci_flags)) 2302b665faabSeric { 2303b665faabSeric putline("", mci); 2304b665faabSeric mci->mci_flags &= ~MCIF_INHEADER; 230564187506Seric } 2306b665faabSeric 2307b665faabSeric /* determine end of buffer; allow for short mailer lines */ 2308b665faabSeric buflim = &buf[sizeof buf - 1]; 2309b665faabSeric if (mci->mci_mailer->m_linelimit > 0 && 2310b665faabSeric mci->mci_mailer->m_linelimit < sizeof buf - 1) 2311b665faabSeric buflim = &buf[mci->mci_mailer->m_linelimit - 1]; 2312b665faabSeric 2313b665faabSeric /* copy temp file to output with mapping */ 2314b665faabSeric ostate = OS_HEAD; 2315b665faabSeric bp = buf; 2316b665faabSeric pbp = peekbuf; 2317b665faabSeric while (!ferror(mci->mci_out)) 2318519e7d80Seric { 2319b665faabSeric register char *xp; 2320b665faabSeric 2321b665faabSeric if (pbp > peekbuf) 2322b665faabSeric c = *--pbp; 2323b665faabSeric else if ((c = fgetc(e->e_dfp)) == EOF) 2324b665faabSeric break; 2325b665faabSeric if (bitset(MCIF_7BIT, mci->mci_flags)) 2326b665faabSeric c &= 0x7f; 2327b665faabSeric switch (ostate) 2328a6ce3008Seric { 2329b665faabSeric case OS_HEAD: 2330b665faabSeric if (c != '\r' && c != '\n' && bp < buflim) 2331b665faabSeric { 2332b665faabSeric *bp++ = c; 2333b665faabSeric break; 2334b665faabSeric } 2335b665faabSeric 2336b665faabSeric /* check beginning of line for special cases */ 2337b665faabSeric *bp = '\0'; 2338b665faabSeric pos = 0; 2339b665faabSeric padc = EOF; 23405aa0f353Seric if (buf[0] == 'F' && 23415aa0f353Seric bitnset(M_ESCFROM, mci->mci_mailer->m_flags) && 2342d6fa2b58Sbostic strncmp(buf, "From ", 5) == 0) 2343b665faabSeric { 2344b665faabSeric padc = '>'; 2345b665faabSeric } 2346b665faabSeric if (buf[0] == '-' && buf[1] == '-' && 2347b665faabSeric separator != NULL) 234803c02fdeSeric { 234903c02fdeSeric /* possible separator */ 235003c02fdeSeric int sl = strlen(separator); 235103c02fdeSeric 235203c02fdeSeric if (strncmp(&buf[2], separator, sl) == 0) 2353b665faabSeric padc = ' '; 235403c02fdeSeric } 2355b665faabSeric if (buf[0] == '.' && 2356b665faabSeric bitnset(M_XDOT, mci->mci_mailer->m_flags)) 2357b665faabSeric { 2358b665faabSeric padc = '.'; 2359b665faabSeric } 2360b665faabSeric 2361b665faabSeric /* now copy out saved line */ 2362b665faabSeric if (TrafficLogFile != NULL) 2363b665faabSeric { 2364b665faabSeric fprintf(TrafficLogFile, "%05d >>> ", getpid()); 2365b665faabSeric if (padc != EOF) 2366b665faabSeric fputc(padc, TrafficLogFile); 2367b665faabSeric for (xp = buf; xp < bp; xp++) 2368b665faabSeric fputc(*xp, TrafficLogFile); 2369b665faabSeric if (c == '\n') 2370b665faabSeric fputs(mci->mci_mailer->m_eol, 2371b665faabSeric TrafficLogFile); 2372b665faabSeric } 2373b665faabSeric if (padc != EOF) 2374b665faabSeric { 2375b665faabSeric fputc(padc, mci->mci_out); 2376b665faabSeric pos++; 2377b665faabSeric } 2378b665faabSeric for (xp = buf; xp < bp; xp++) 2379b665faabSeric fputc(*xp, mci->mci_out); 2380b665faabSeric if (c == '\n') 2381b665faabSeric { 2382b665faabSeric fputs(mci->mci_mailer->m_eol, 2383b665faabSeric mci->mci_out); 2384b665faabSeric pos = 0; 2385b665faabSeric } 2386b665faabSeric else 2387b665faabSeric { 2388b665faabSeric pos += bp - buf; 2389b665faabSeric if (c != '\r') 2390b665faabSeric *pbp++ = c; 2391b665faabSeric } 2392b665faabSeric bp = buf; 2393b665faabSeric 2394b665faabSeric /* determine next state */ 2395b665faabSeric if (c == '\n') 2396b665faabSeric ostate = OS_HEAD; 2397b665faabSeric else if (c == '\r') 2398b665faabSeric ostate = OS_CR; 2399b665faabSeric else 2400b665faabSeric ostate = OS_INLINE; 2401b665faabSeric continue; 2402b665faabSeric 2403b665faabSeric case OS_CR: 2404b665faabSeric if (c == '\n') 2405b665faabSeric { 2406b665faabSeric /* got CRLF */ 2407b665faabSeric fputs(mci->mci_mailer->m_eol, mci->mci_out); 2408b665faabSeric if (TrafficLogFile != NULL) 2409b665faabSeric { 2410b665faabSeric fputs(mci->mci_mailer->m_eol, 2411b665faabSeric TrafficLogFile); 2412b665faabSeric } 2413b665faabSeric ostate = OS_HEAD; 2414b665faabSeric continue; 2415b665faabSeric } 2416b665faabSeric 2417b665faabSeric /* had a naked carriage return */ 2418b665faabSeric *pbp++ = c; 2419b665faabSeric c = '\r'; 2420b665faabSeric goto putch; 2421b665faabSeric 2422b665faabSeric case OS_INLINE: 2423b665faabSeric if (c == '\r') 2424b665faabSeric { 2425b665faabSeric ostate = OS_CR; 2426b665faabSeric continue; 2427b665faabSeric } 2428b665faabSeric putch: 2429b665faabSeric if (mci->mci_mailer->m_linelimit > 0 && 2430b665faabSeric pos > mci->mci_mailer->m_linelimit && 2431b665faabSeric c != '\n') 2432b665faabSeric { 2433b665faabSeric putc('!', mci->mci_out); 2434b665faabSeric fputs(mci->mci_mailer->m_eol, mci->mci_out); 2435b665faabSeric if (TrafficLogFile != NULL) 2436b665faabSeric { 2437b665faabSeric fprintf(TrafficLogFile, "!%s", 2438b665faabSeric mci->mci_mailer->m_eol); 2439b665faabSeric } 2440b665faabSeric ostate = OS_HEAD; 2441b665faabSeric *pbp++ = c; 2442b665faabSeric continue; 2443b665faabSeric } 2444b665faabSeric if (TrafficLogFile != NULL) 2445b665faabSeric fputc(c, TrafficLogFile); 2446b665faabSeric putc(c, mci->mci_out); 2447b665faabSeric pos++; 2448b665faabSeric ostate = c == '\n' ? OS_HEAD : OS_INLINE; 2449b665faabSeric break; 2450b665faabSeric } 2451b665faabSeric } 2452a6ce3008Seric } 245351552439Seric 24549a6a5f55Seric if (ferror(e->e_dfp)) 245551552439Seric { 2456b665faabSeric syserr("putbody: df%s: read error", e->e_id); 245751552439Seric ExitStat = EX_IOERR; 245851552439Seric } 245951552439Seric 2460b665faabSeric endofmessage: 24610890ba1fSeric /* some mailers want extra blank line at end of message */ 24625aa0f353Seric if (bitnset(M_BLANKEND, mci->mci_mailer->m_flags) && 24635aa0f353Seric buf[0] != '\0' && buf[0] != '\n') 24645aa0f353Seric putline("", mci); 24650890ba1fSeric 24665aa0f353Seric (void) fflush(mci->mci_out); 24675aa0f353Seric if (ferror(mci->mci_out) && errno != EPIPE) 246851552439Seric { 246951552439Seric syserr("putbody: write error"); 247051552439Seric ExitStat = EX_IOERR; 247151552439Seric } 247251552439Seric errno = 0; 247325a99e2eSeric } 247425a99e2eSeric /* 247525a99e2eSeric ** MAILFILE -- Send a message to a file. 247625a99e2eSeric ** 2477f129ec7dSeric ** If the file has the setuid/setgid bits set, but NO execute 2478f129ec7dSeric ** bits, sendmail will try to become the owner of that file 2479f129ec7dSeric ** rather than the real user. Obviously, this only works if 2480f129ec7dSeric ** sendmail runs as root. 2481f129ec7dSeric ** 2482588cad61Seric ** This could be done as a subordinate mailer, except that it 2483588cad61Seric ** is used implicitly to save messages in ~/dead.letter. We 2484588cad61Seric ** view this as being sufficiently important as to include it 2485588cad61Seric ** here. For example, if the system is dying, we shouldn't have 2486588cad61Seric ** to create another process plus some pipes to save the message. 2487588cad61Seric ** 248825a99e2eSeric ** Parameters: 248925a99e2eSeric ** filename -- the name of the file to send to. 24906259796dSeric ** ctladdr -- the controlling address header -- includes 24916259796dSeric ** the userid/groupid to be when sending. 249225a99e2eSeric ** 249325a99e2eSeric ** Returns: 249425a99e2eSeric ** The exit code associated with the operation. 249525a99e2eSeric ** 249625a99e2eSeric ** Side Effects: 249725a99e2eSeric ** none. 249825a99e2eSeric */ 249925a99e2eSeric 2500b31e7f2bSeric mailfile(filename, ctladdr, e) 250125a99e2eSeric char *filename; 25026259796dSeric ADDRESS *ctladdr; 2503b31e7f2bSeric register ENVELOPE *e; 250425a99e2eSeric { 250525a99e2eSeric register FILE *f; 2506b665faabSeric register int pid = -1; 250715d084d5Seric int mode; 250825a99e2eSeric 2509671745f3Seric if (tTd(11, 1)) 2510671745f3Seric { 2511671745f3Seric printf("mailfile %s\n ctladdr=", filename); 2512671745f3Seric printaddr(ctladdr, FALSE); 2513671745f3Seric } 2514671745f3Seric 2515f170942cSeric if (e->e_xfp != NULL) 2516f170942cSeric fflush(e->e_xfp); 2517f170942cSeric 251832d19d43Seric /* 251932d19d43Seric ** Fork so we can change permissions here. 252032d19d43Seric ** Note that we MUST use fork, not vfork, because of 252132d19d43Seric ** the complications of calling subroutines, etc. 252232d19d43Seric */ 252332d19d43Seric 252432d19d43Seric DOFORK(fork); 252532d19d43Seric 252632d19d43Seric if (pid < 0) 252732d19d43Seric return (EX_OSERR); 252832d19d43Seric else if (pid == 0) 252932d19d43Seric { 253032d19d43Seric /* child -- actually write to file */ 2531f129ec7dSeric struct stat stb; 2532f2e4d5e8Seric struct stat fsb; 25335aa0f353Seric MCI mcibuf; 25344ef13b77Seric int oflags = O_WRONLY|O_APPEND; 2535f129ec7dSeric 2536f2e4d5e8Seric if (e->e_lockfp != NULL) 253752099264Seric (void) close(fileno(e->e_lockfp)); 2538f2e4d5e8Seric 25392b9178d3Seric (void) setsignal(SIGINT, SIG_DFL); 25402b9178d3Seric (void) setsignal(SIGHUP, SIG_DFL); 25412b9178d3Seric (void) setsignal(SIGTERM, SIG_DFL); 25423462ad9eSeric (void) umask(OldUmask); 254395f16dc0Seric 2544b665faabSeric #ifdef HASLSTAT 2545b665faabSeric if ((SafeFileEnv != NULL ? lstat(filename, &stb) 2546b665faabSeric : stat(filename, &stb)) < 0) 2547b665faabSeric #else 2548f129ec7dSeric if (stat(filename, &stb) < 0) 2549b665faabSeric #endif 25504ef13b77Seric { 25513a98e7eaSeric stb.st_mode = FileMode; 25524ef13b77Seric oflags |= O_CREAT|O_EXCL; 25534ef13b77Seric } 2554b665faabSeric else if (bitset(0111, stb.st_mode) || stb.st_nlink != 1 || 2555b665faabSeric (SafeFileEnv != NULL && !S_ISREG(stb.st_mode))) 2556f2e4d5e8Seric exit(EX_CANTCREAT); 255715d084d5Seric mode = stb.st_mode; 255895f16dc0Seric 255995f16dc0Seric /* limit the errors to those actually caused in the child */ 256095f16dc0Seric errno = 0; 256195f16dc0Seric ExitStat = EX_OK; 256295f16dc0Seric 256319428781Seric if (ctladdr != NULL) 256415d084d5Seric { 256515d084d5Seric /* ignore setuid and setgid bits */ 256615d084d5Seric mode &= ~(S_ISGID|S_ISUID); 256715d084d5Seric } 256815d084d5Seric 25698f9146b0Srick /* we have to open the dfile BEFORE setuid */ 2570b665faabSeric if (e->e_dfp == NULL && bitset(EF_HAS_DF, e->e_flags)) 25718f9146b0Srick { 2572b665faabSeric char *df = queuename(e, 'd'); 2573b665faabSeric 2574b665faabSeric e->e_dfp = fopen(df, "r"); 257595f16dc0Seric if (e->e_dfp == NULL) 257695f16dc0Seric { 25778f9146b0Srick syserr("mailfile: Cannot open %s for %s from %s", 2578b665faabSeric df, e->e_to, e->e_from.q_paddr); 25798f9146b0Srick } 25808f9146b0Srick } 25818f9146b0Srick 2582b665faabSeric if (SafeFileEnv != NULL && SafeFileEnv[0] != '\0') 2583b665faabSeric { 2584b665faabSeric int i; 2585b665faabSeric 2586b665faabSeric if (chroot(SafeFileEnv) < 0) 2587b665faabSeric { 2588b665faabSeric syserr("mailfile: Cannot chroot(%s)", 2589b665faabSeric SafeFileEnv); 2590b665faabSeric exit(EX_CANTCREAT); 2591b665faabSeric } 2592b665faabSeric i = strlen(SafeFileEnv); 2593b665faabSeric if (strncmp(SafeFileEnv, filename, i) == 0) 2594b665faabSeric filename += i; 2595b665faabSeric } 2596b665faabSeric if (chdir("/") < 0) 2597b665faabSeric syserr("mailfile: cannot chdir(/)"); 2598b665faabSeric 259915d084d5Seric if (!bitset(S_ISGID, mode) || setgid(stb.st_gid) < 0) 2600e36b99e2Seric { 2601b665faabSeric if (ctladdr != NULL && ctladdr->q_uid != 0) 2602898a126bSbostic (void) initgroups(ctladdr->q_ruser ? 2603898a126bSbostic ctladdr->q_ruser : ctladdr->q_user, 2604898a126bSbostic ctladdr->q_gid); 2605b665faabSeric else if (FileMailer != NULL && FileMailer->m_gid != 0) 2606b665faabSeric (void) initgroups(DefUser, FileMailer->m_gid); 2607b665faabSeric else 2608b665faabSeric (void) initgroups(DefUser, DefGid); 2609e36b99e2Seric } 261015d084d5Seric if (!bitset(S_ISUID, mode) || setuid(stb.st_uid) < 0) 2611e36b99e2Seric { 2612b665faabSeric if (ctladdr != NULL && ctladdr->q_uid != 0) 2613bd4e74cdSeric (void) setuid(ctladdr->q_uid); 2614b665faabSeric else if (FileMailer != NULL && FileMailer->m_uid != 0) 2615b665faabSeric (void) setuid(FileMailer->m_uid); 2616b665faabSeric else 2617b665faabSeric (void) setuid(DefUid); 2618e36b99e2Seric } 261995f16dc0Seric FileName = filename; 262095f16dc0Seric LineNumber = 0; 26214ef13b77Seric f = dfopen(filename, oflags, FileMode); 262225a99e2eSeric if (f == NULL) 262395f16dc0Seric { 2624b6a0de9dSeric message("554 cannot open: %s", errstring(errno)); 262532d19d43Seric exit(EX_CANTCREAT); 262695f16dc0Seric } 2627f2e4d5e8Seric if (fstat(fileno(f), &fsb) < 0 || 2628b665faabSeric (!bitset(O_CREAT, oflags) && 26294ef13b77Seric (stb.st_nlink != fsb.st_nlink || 2630f2e4d5e8Seric stb.st_dev != fsb.st_dev || 2631f2e4d5e8Seric stb.st_ino != fsb.st_ino || 2632b665faabSeric stb.st_uid != fsb.st_uid))) 2633f2e4d5e8Seric { 2634f2e4d5e8Seric message("554 cannot write: file changed after open"); 2635f2e4d5e8Seric exit(EX_CANTCREAT); 2636f2e4d5e8Seric } 263725a99e2eSeric 26385aa0f353Seric bzero(&mcibuf, sizeof mcibuf); 26395aa0f353Seric mcibuf.mci_mailer = FileMailer; 26405aa0f353Seric mcibuf.mci_out = f; 26415aa0f353Seric if (bitnset(M_7BITS, FileMailer->m_flags)) 26425aa0f353Seric mcibuf.mci_flags |= MCIF_7BIT; 26435aa0f353Seric 26445aa0f353Seric putfromline(&mcibuf, e); 2645b665faabSeric (*e->e_puthdr)(&mcibuf, e->e_header, e); 26466ffc2dd1Seric (*e->e_putbody)(&mcibuf, e, NULL); 26475aa0f353Seric putline("\n", &mcibuf); 264895f16dc0Seric if (ferror(f)) 264995f16dc0Seric { 2650b6a0de9dSeric message("451 I/O error: %s", errstring(errno)); 265195f16dc0Seric setstat(EX_IOERR); 265295f16dc0Seric } 2653ee4b0922Seric (void) xfclose(f, "mailfile", filename); 265432d19d43Seric (void) fflush(stdout); 2655e36b99e2Seric 265627628d59Seric /* reset ISUID & ISGID bits for paranoid systems */ 2657c77d1c25Seric (void) chmod(filename, (int) stb.st_mode); 265895f16dc0Seric exit(ExitStat); 265913bbc08cSeric /*NOTREACHED*/ 266032d19d43Seric } 266132d19d43Seric else 266232d19d43Seric { 266332d19d43Seric /* parent -- wait for exit status */ 2664588cad61Seric int st; 266532d19d43Seric 2666588cad61Seric st = waitfor(pid); 2667bf9bc890Seric if (WIFEXITED(st)) 2668bf9bc890Seric return (WEXITSTATUS(st)); 2669588cad61Seric else 2670b6a0de9dSeric { 2671b6a0de9dSeric syserr("child died on signal %d", st); 2672bf9bc890Seric return (EX_UNAVAILABLE); 2673b6a0de9dSeric } 26748f9146b0Srick /*NOTREACHED*/ 267532d19d43Seric } 267625a99e2eSeric } 2677ea4dc939Seric /* 2678e103b48fSeric ** HOSTSIGNATURE -- return the "signature" for a host. 2679e103b48fSeric ** 2680e103b48fSeric ** The signature describes how we are going to send this -- it 2681e103b48fSeric ** can be just the hostname (for non-Internet hosts) or can be 2682e103b48fSeric ** an ordered list of MX hosts. 2683e103b48fSeric ** 2684e103b48fSeric ** Parameters: 2685e103b48fSeric ** m -- the mailer describing this host. 2686e103b48fSeric ** host -- the host name. 2687e103b48fSeric ** e -- the current envelope. 2688e103b48fSeric ** 2689e103b48fSeric ** Returns: 2690e103b48fSeric ** The signature for this host. 2691e103b48fSeric ** 2692e103b48fSeric ** Side Effects: 2693e103b48fSeric ** Can tweak the symbol table. 2694e103b48fSeric */ 2695e103b48fSeric 2696e103b48fSeric char * 2697e103b48fSeric hostsignature(m, host, e) 2698e103b48fSeric register MAILER *m; 2699e103b48fSeric char *host; 2700e103b48fSeric ENVELOPE *e; 2701e103b48fSeric { 2702e103b48fSeric register char *p; 2703e103b48fSeric register STAB *s; 2704e103b48fSeric int i; 2705e103b48fSeric int len; 27069d4a8008Seric #if NAMED_BIND 2707e103b48fSeric int nmx; 2708e103b48fSeric auto int rcode; 2709bafdc4e5Seric char *hp; 2710bafdc4e5Seric char *endp; 2711b665faabSeric int oldoptions = _res.options; 2712e103b48fSeric char *mxhosts[MAXMXHOSTS + 1]; 2713e103b48fSeric #endif 2714e103b48fSeric 2715e103b48fSeric /* 2716e103b48fSeric ** Check to see if this uses IPC -- if not, it can't have MX records. 2717e103b48fSeric */ 2718e103b48fSeric 2719e103b48fSeric p = m->m_mailer; 2720e103b48fSeric if (strcmp(p, "[IPC]") != 0 && strcmp(p, "[TCP]") != 0) 2721e103b48fSeric { 2722e103b48fSeric /* just an ordinary mailer */ 2723e103b48fSeric return host; 2724e103b48fSeric } 2725e103b48fSeric 2726e103b48fSeric /* 2727e103b48fSeric ** Look it up in the symbol table. 2728e103b48fSeric */ 2729e103b48fSeric 2730e103b48fSeric s = stab(host, ST_HOSTSIG, ST_ENTER); 2731e103b48fSeric if (s->s_hostsig != NULL) 2732e103b48fSeric return s->s_hostsig; 2733e103b48fSeric 2734e103b48fSeric /* 2735e103b48fSeric ** Not already there -- create a signature. 2736e103b48fSeric */ 2737e103b48fSeric 27389d4a8008Seric #if NAMED_BIND 2739516782b4Seric if (ConfigLevel < 2) 2740516782b4Seric _res.options &= ~(RES_DEFNAMES | RES_DNSRCH); /* XXX */ 2741516782b4Seric 2742bafdc4e5Seric for (hp = host; hp != NULL; hp = endp) 2743bafdc4e5Seric { 2744bafdc4e5Seric endp = strchr(hp, ':'); 2745bafdc4e5Seric if (endp != NULL) 2746bafdc4e5Seric *endp = '\0'; 2747bafdc4e5Seric 27487bf809e6Seric nmx = getmxrr(hp, mxhosts, TRUE, &rcode); 27497d55540cSeric 2750e103b48fSeric if (nmx <= 0) 2751e103b48fSeric { 2752e103b48fSeric register MCI *mci; 2753e103b48fSeric 2754e103b48fSeric /* update the connection info for this host */ 2755bafdc4e5Seric mci = mci_get(hp, m); 2756e103b48fSeric mci->mci_exitstat = rcode; 2757e103b48fSeric mci->mci_errno = errno; 2758f170942cSeric mci->mci_herrno = h_errno; 2759e103b48fSeric 2760e103b48fSeric /* and return the original host name as the signature */ 2761bafdc4e5Seric nmx = 1; 2762bafdc4e5Seric mxhosts[0] = hp; 2763e103b48fSeric } 2764e103b48fSeric 2765e103b48fSeric len = 0; 2766e103b48fSeric for (i = 0; i < nmx; i++) 2767e103b48fSeric { 2768e103b48fSeric len += strlen(mxhosts[i]) + 1; 2769e103b48fSeric } 2770bafdc4e5Seric if (s->s_hostsig != NULL) 2771bafdc4e5Seric len += strlen(s->s_hostsig) + 1; 2772bafdc4e5Seric p = xalloc(len); 2773bafdc4e5Seric if (s->s_hostsig != NULL) 2774bafdc4e5Seric { 2775bafdc4e5Seric (void) strcpy(p, s->s_hostsig); 2776bafdc4e5Seric free(s->s_hostsig); 2777bafdc4e5Seric s->s_hostsig = p; 2778bafdc4e5Seric p += strlen(p); 2779bafdc4e5Seric *p++ = ':'; 2780bafdc4e5Seric } 2781bafdc4e5Seric else 2782bafdc4e5Seric s->s_hostsig = p; 2783e103b48fSeric for (i = 0; i < nmx; i++) 2784e103b48fSeric { 2785e103b48fSeric if (i != 0) 2786e103b48fSeric *p++ = ':'; 2787e103b48fSeric strcpy(p, mxhosts[i]); 2788e103b48fSeric p += strlen(p); 2789e103b48fSeric } 2790bafdc4e5Seric if (endp != NULL) 2791bafdc4e5Seric *endp++ = ':'; 2792bafdc4e5Seric } 2793e103b48fSeric makelower(s->s_hostsig); 2794516782b4Seric if (ConfigLevel < 2) 2795516782b4Seric _res.options = oldoptions; 2796e103b48fSeric #else 2797e103b48fSeric /* not using BIND -- the signature is just the host name */ 2798e103b48fSeric s->s_hostsig = host; 2799e103b48fSeric #endif 2800e103b48fSeric if (tTd(17, 1)) 2801e103b48fSeric printf("hostsignature(%s) = %s\n", host, s->s_hostsig); 2802e103b48fSeric return s->s_hostsig; 2803e103b48fSeric } 2804b665faabSeric /* 2805b665faabSeric ** SETSTATUS -- set the address status for return messages 2806b665faabSeric ** 2807b665faabSeric ** Parameters: 2808b665faabSeric ** a -- the address to set. 2809b665faabSeric ** msg -- the text of the message, which must be in standard 2810b665faabSeric ** SMTP form (3 digits, a space, and a message). 2811b665faabSeric ** 2812b665faabSeric ** Returns: 2813b665faabSeric ** none. 2814b665faabSeric */ 2815b665faabSeric 2816b665faabSeric setstatus(a, msg) 2817b665faabSeric register ADDRESS *a; 2818b665faabSeric char *msg; 2819b665faabSeric { 2820b665faabSeric char buf[MAXLINE]; 2821b665faabSeric 2822b665faabSeric if (a->q_rstatus != NULL) 2823b665faabSeric free(a->q_rstatus); 2824972b1942Seric if (strlen(msg) > (SIZE_T) 4) 2825b665faabSeric { 2826b665faabSeric register char *p, *q; 2827b665faabSeric int parenlev = 0; 2828b665faabSeric 2829b665faabSeric strncpy(buf, msg, 4); 2830b665faabSeric p = &buf[4]; 2831b665faabSeric *p++ = '('; 2832b665faabSeric for (q = &msg[4]; *q != '\0'; q++) 2833b665faabSeric { 2834b665faabSeric switch (*q) 2835b665faabSeric { 2836b665faabSeric case '(': 2837b665faabSeric parenlev++; 2838b665faabSeric break; 2839b665faabSeric 2840b665faabSeric case ')': 2841b665faabSeric if (parenlev > 0) 2842b665faabSeric parenlev--; 2843b665faabSeric else 2844b665faabSeric *p++ = '\\'; 2845b665faabSeric break; 2846b665faabSeric } 2847b665faabSeric *p++ = *q; 2848b665faabSeric } 2849b665faabSeric while (parenlev-- >= 0) 2850b665faabSeric *p++ = ')'; 2851b665faabSeric *p++ = '\0'; 2852b665faabSeric msg = buf; 2853b665faabSeric } 2854b665faabSeric a->q_rstatus = newstr(msg); 2855b665faabSeric } 2856