14227346bSdist /* 20942ea6aSbostic * Copyright (c) 1983 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*6ffc2dd1Seric static char sccsid[] = "@(#)deliver.c 8.120 (Berkeley) 02/05/95"; 11e70a7521Sbostic #endif /* not lint */ 124227346bSdist 13fcde9cc8Sbostic #include "sendmail.h" 14f28da541Smiriam #include <netdb.h> 15911693bfSbostic #include <errno.h> 169d4a8008Seric #if NAMED_BIND 17912a731aSbostic #include <resolv.h> 18f170942cSeric 19f170942cSeric extern int h_errno; 20134746fbSeric #endif 2125a99e2eSeric 225d437c4dSeric extern char SmtpError[]; 235d437c4dSeric 2425a99e2eSeric /* 259c9e68d9Seric ** SENDALL -- actually send all the messages. 269c9e68d9Seric ** 279c9e68d9Seric ** Parameters: 289c9e68d9Seric ** e -- the envelope to send. 299c9e68d9Seric ** mode -- the delivery mode to use. If SM_DEFAULT, use 309c9e68d9Seric ** the current e->e_sendmode. 319c9e68d9Seric ** 329c9e68d9Seric ** Returns: 339c9e68d9Seric ** none. 349c9e68d9Seric ** 359c9e68d9Seric ** Side Effects: 369c9e68d9Seric ** Scans the send lists and sends everything it finds. 379c9e68d9Seric ** Delivers any appropriate error messages. 389c9e68d9Seric ** If we are running in a non-interactive mode, takes the 399c9e68d9Seric ** appropriate action. 409c9e68d9Seric */ 419c9e68d9Seric 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; 516103d9b4Seric bool announcequeueup; 520ae32ff4Seric bool oldverbose = Verbose; 530ae32ff4Seric int pid; 54bb07bf86Seric char *qid; 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; 786103d9b4Seric announcequeueup = mode == SM_QUEUE; 799c9e68d9Seric } 806103d9b4Seric else 816103d9b4Seric announcequeueup = FALSE; 829c9e68d9Seric 839c9e68d9Seric if (tTd(13, 1)) 849c9e68d9Seric { 850e484fe5Seric printf("\n===== SENDALL: mode %c, id %s, e_from ", 860e484fe5Seric mode, e->e_id); 879c9e68d9Seric printaddr(&e->e_from, FALSE); 889c9e68d9Seric printf("sendqueue:\n"); 899c9e68d9Seric printaddr(e->e_sendqueue, TRUE); 909c9e68d9Seric } 919c9e68d9Seric 929c9e68d9Seric /* 939c9e68d9Seric ** Do any preprocessing necessary for the mode we are running. 949c9e68d9Seric ** Check to make sure the hop count is reasonable. 959c9e68d9Seric ** Delete sends to the sender in mailing lists. 969c9e68d9Seric */ 979c9e68d9Seric 989c9e68d9Seric CurEnv = e; 999c9e68d9Seric 1009c9e68d9Seric if (e->e_hopcount > MaxHopCount) 1019c9e68d9Seric { 1029c9e68d9Seric errno = 0; 103f356687bSeric queueup(e, TRUE, announcequeueup); 10427607809Seric e->e_flags |= EF_FATALERRS|EF_PM_NOTIFY|EF_CLRQUEUE; 1054bb8b0fdSeric syserr("554 too many hops %d (%d max): from %s via %s, to %s", 1069c9e68d9Seric e->e_hopcount, MaxHopCount, e->e_from.q_paddr, 107f7869e68Seric RealHostName == NULL ? "localhost" : RealHostName, 108f7869e68Seric e->e_sendqueue->q_paddr); 1099c9e68d9Seric return; 1109c9e68d9Seric } 1119c9e68d9Seric 112b8004690Seric /* 113b8004690Seric ** Do sender deletion. 114b8004690Seric ** 115b8004690Seric ** If the sender has the QQUEUEUP flag set, skip this. 116b8004690Seric ** This can happen if the name server is hosed when you 117b8004690Seric ** are trying to send mail. The result is that the sender 118b8004690Seric ** is instantiated in the queue as a recipient. 119b8004690Seric */ 120b8004690Seric 121e76a6a8fSeric if (!bitset(EF_METOO, e->e_flags) && 122e76a6a8fSeric !bitset(QQUEUEUP, e->e_from.q_flags)) 1239c9e68d9Seric { 1249c9e68d9Seric if (tTd(13, 5)) 1259c9e68d9Seric { 1269c9e68d9Seric printf("sendall: QDONTSEND "); 1279c9e68d9Seric printaddr(&e->e_from, FALSE); 1289c9e68d9Seric } 1299c9e68d9Seric e->e_from.q_flags |= QDONTSEND; 1309ff40499Seric (void) recipient(&e->e_from, &e->e_sendqueue, 0, e); 1319c9e68d9Seric } 1329c9e68d9Seric 133ce5531bdSeric /* 134ce5531bdSeric ** Handle alias owners. 135ce5531bdSeric ** 136ce5531bdSeric ** We scan up the q_alias chain looking for owners. 137ce5531bdSeric ** We discard owners that are the same as the return path. 138ce5531bdSeric */ 139ce5531bdSeric 140ce5531bdSeric for (q = e->e_sendqueue; q != NULL; q = q->q_next) 141ce5531bdSeric { 142ce5531bdSeric register struct address *a; 143ce5531bdSeric 144ce5531bdSeric for (a = q; a != NULL && a->q_owner == NULL; a = a->q_alias) 145ce5531bdSeric continue; 146ce5531bdSeric if (a != NULL) 147ce5531bdSeric q->q_owner = a->q_owner; 148ce5531bdSeric 149ce5531bdSeric if (q->q_owner != NULL && 150ce5531bdSeric !bitset(QDONTSEND, q->q_flags) && 151ce5531bdSeric strcmp(q->q_owner, e->e_from.q_paddr) == 0) 152ce5531bdSeric q->q_owner = NULL; 153ce5531bdSeric } 154ce5531bdSeric 155ce5531bdSeric owner = ""; 156ce5531bdSeric otherowners = 1; 157ce5531bdSeric while (owner != NULL && otherowners > 0) 158ce5531bdSeric { 159ce5531bdSeric owner = NULL; 160ce5531bdSeric otherowners = 0; 161ce5531bdSeric 162ce5531bdSeric for (q = e->e_sendqueue; q != NULL; q = q->q_next) 163ce5531bdSeric { 164ce5531bdSeric if (bitset(QDONTSEND, q->q_flags)) 165ce5531bdSeric continue; 166ce5531bdSeric 167ce5531bdSeric if (q->q_owner != NULL) 168ce5531bdSeric { 169ce5531bdSeric if (owner == NULL) 170ce5531bdSeric owner = q->q_owner; 171ce5531bdSeric else if (owner != q->q_owner) 172ce5531bdSeric { 173ce5531bdSeric if (strcmp(owner, q->q_owner) == 0) 174ce5531bdSeric { 175ce5531bdSeric /* make future comparisons cheap */ 176ce5531bdSeric q->q_owner = owner; 177ce5531bdSeric } 178ce5531bdSeric else 179ce5531bdSeric { 180ce5531bdSeric otherowners++; 181ce5531bdSeric } 182ce5531bdSeric owner = q->q_owner; 183ce5531bdSeric } 184ce5531bdSeric } 185ce5531bdSeric else 186ce5531bdSeric { 187ce5531bdSeric otherowners++; 188ce5531bdSeric } 189ce5531bdSeric } 190ce5531bdSeric 191ce5531bdSeric if (owner != NULL && otherowners > 0) 192ce5531bdSeric { 193ce5531bdSeric extern HDR *copyheader(); 194ce5531bdSeric extern ADDRESS *copyqueue(); 195ce5531bdSeric 196ce5531bdSeric /* 197ce5531bdSeric ** Split this envelope into two. 198ce5531bdSeric */ 199ce5531bdSeric 200ce5531bdSeric ee = (ENVELOPE *) xalloc(sizeof(ENVELOPE)); 201ce5531bdSeric *ee = *e; 202ce5531bdSeric ee->e_id = NULL; 203ce5531bdSeric (void) queuename(ee, '\0'); 204ce5531bdSeric 205ce5531bdSeric if (tTd(13, 1)) 206ce5531bdSeric printf("sendall: split %s into %s\n", 207ce5531bdSeric e->e_id, ee->e_id); 208ce5531bdSeric 209ce5531bdSeric ee->e_header = copyheader(e->e_header); 210ce5531bdSeric ee->e_sendqueue = copyqueue(e->e_sendqueue); 211ce5531bdSeric ee->e_errorqueue = copyqueue(e->e_errorqueue); 212fce3c07bSeric ee->e_flags = e->e_flags & ~(EF_INQUEUE|EF_CLRQUEUE|EF_FATALERRS|EF_SENDRECEIPT); 213fce3c07bSeric ee->e_flags |= EF_NORECEIPT; 214ce5531bdSeric setsender(owner, ee, NULL, TRUE); 215ce5531bdSeric if (tTd(13, 5)) 216ce5531bdSeric { 217ce5531bdSeric printf("sendall(split): QDONTSEND "); 218ce5531bdSeric printaddr(&ee->e_from, FALSE); 219ce5531bdSeric } 220ce5531bdSeric ee->e_from.q_flags |= QDONTSEND; 221ce5531bdSeric ee->e_dfp = NULL; 222ce5531bdSeric ee->e_xfp = NULL; 223ce5531bdSeric ee->e_df = NULL; 224ce5531bdSeric ee->e_errormode = EM_MAIL; 225b056abd0Seric ee->e_sibling = splitenv; 226b056abd0Seric splitenv = ee; 227ce5531bdSeric 228ce5531bdSeric for (q = e->e_sendqueue; q != NULL; q = q->q_next) 229ce5531bdSeric if (q->q_owner == owner) 230de1a6b1bSeric { 231ce5531bdSeric q->q_flags |= QDONTSEND; 232de1a6b1bSeric q->q_flags &= ~QQUEUEUP; 233de1a6b1bSeric } 234ce5531bdSeric for (q = ee->e_sendqueue; q != NULL; q = q->q_next) 235ce5531bdSeric if (q->q_owner != owner) 236de1a6b1bSeric { 237ce5531bdSeric q->q_flags |= QDONTSEND; 238de1a6b1bSeric q->q_flags &= ~QQUEUEUP; 239de1a6b1bSeric } 240ce5531bdSeric 241ce5531bdSeric if (e->e_df != NULL && mode != SM_VERIFY) 242ce5531bdSeric { 243ce5531bdSeric ee->e_dfp = NULL; 244da662164Seric ee->e_df = queuename(ee, 'd'); 245da662164Seric ee->e_df = newstr(ee->e_df); 246ce5531bdSeric if (link(e->e_df, ee->e_df) < 0) 247ce5531bdSeric { 248ce5531bdSeric syserr("sendall: link(%s, %s)", 249ce5531bdSeric e->e_df, ee->e_df); 250ce5531bdSeric } 251ce5531bdSeric } 252ce5531bdSeric #ifdef LOG 253ce5531bdSeric if (LogLevel > 4) 254c8b70947Seric syslog(LOG_INFO, "%s: clone %s, owner=%s", 255c8b70947Seric ee->e_id, e->e_id, owner); 256ce5531bdSeric #endif 257ce5531bdSeric } 258ce5531bdSeric } 259ce5531bdSeric 260ce5531bdSeric if (owner != NULL) 261ce5531bdSeric { 262ce5531bdSeric setsender(owner, e, NULL, TRUE); 263ce5531bdSeric if (tTd(13, 5)) 264ce5531bdSeric { 265ce5531bdSeric printf("sendall(owner): QDONTSEND "); 266ce5531bdSeric printaddr(&e->e_from, FALSE); 267ce5531bdSeric } 268ce5531bdSeric e->e_from.q_flags |= QDONTSEND; 269ce5531bdSeric e->e_errormode = EM_MAIL; 270fce3c07bSeric e->e_flags |= EF_NORECEIPT; 271ce5531bdSeric } 272ce5531bdSeric 273c1ac89b1Seric # ifdef QUEUE 274c1ac89b1Seric if ((mode == SM_QUEUE || mode == SM_FORK || 275c1ac89b1Seric (mode != SM_VERIFY && SuperSafe)) && 276c1ac89b1Seric !bitset(EF_INQUEUE, e->e_flags)) 277c1ac89b1Seric { 278c1ac89b1Seric /* be sure everything is instantiated in the queue */ 2796103d9b4Seric queueup(e, TRUE, announcequeueup); 280b056abd0Seric for (ee = splitenv; ee != NULL; ee = ee->e_sibling) 281b056abd0Seric queueup(ee, TRUE, announcequeueup); 282c1ac89b1Seric } 283c1ac89b1Seric #endif /* QUEUE */ 284c1ac89b1Seric 2857880f3e4Seric /* 2860ae32ff4Seric ** If we belong in background, fork now. 2877880f3e4Seric */ 2887880f3e4Seric 289c1ac89b1Seric switch (mode) 290c1ac89b1Seric { 291c1ac89b1Seric case SM_VERIFY: 292c1ac89b1Seric Verbose = TRUE; 293c1ac89b1Seric break; 294c1ac89b1Seric 295c1ac89b1Seric case SM_QUEUE: 296c1ac89b1Seric queueonly: 297c1ac89b1Seric e->e_flags |= EF_INQUEUE|EF_KEEPQUEUE; 298c1ac89b1Seric return; 299c1ac89b1Seric 300c1ac89b1Seric case SM_FORK: 301c1ac89b1Seric if (e->e_xfp != NULL) 302c1ac89b1Seric (void) fflush(e->e_xfp); 303c1ac89b1Seric 304b269aa8eSeric # if !HASFLOCK 305c1ac89b1Seric /* 3066b2765c6Seric ** Since fcntl locking has the interesting semantic that 3076b2765c6Seric ** the lock is owned by a process, not by an open file 3086b2765c6Seric ** descriptor, we have to flush this to the queue, and 3096b2765c6Seric ** then restart from scratch in the child. 310c1ac89b1Seric */ 311c1ac89b1Seric 3126b2765c6Seric /* save id for future use */ 313bb07bf86Seric qid = e->e_id; 3146b2765c6Seric 3156b2765c6Seric /* now drop the envelope in the parent */ 3166b2765c6Seric e->e_flags |= EF_INQUEUE|EF_KEEPQUEUE; 3176b2765c6Seric dropenvelope(e); 3186b2765c6Seric 3196b2765c6Seric /* and reacquire in the child */ 320bb07bf86Seric (void) dowork(qid, TRUE, FALSE, e); 3216b2765c6Seric 3226b2765c6Seric return; 3236b2765c6Seric 3246b2765c6Seric # else /* HASFLOCK */ 325c1ac89b1Seric 326c1ac89b1Seric pid = fork(); 327c1ac89b1Seric if (pid < 0) 328c1ac89b1Seric { 329c1ac89b1Seric goto queueonly; 330c1ac89b1Seric } 331c1ac89b1Seric else if (pid > 0) 332c1ac89b1Seric { 3330e484fe5Seric /* be sure we leave the temp files to our child */ 3340e484fe5Seric /* can't call unlockqueue to avoid unlink of xfp */ 3350e484fe5Seric if (e->e_lockfp != NULL) 3360e484fe5Seric (void) xfclose(e->e_lockfp, "sendenvelope", "lockfp"); 3370e484fe5Seric e->e_lockfp = NULL; 3380e484fe5Seric 3390e484fe5Seric /* close any random open files in the envelope */ 3400e484fe5Seric closexscript(e); 3410e484fe5Seric if (e->e_dfp != NULL) 3420e484fe5Seric (void) xfclose(e->e_dfp, "sendenvelope", e->e_df); 3430e484fe5Seric e->e_dfp = NULL; 3440e484fe5Seric e->e_id = e->e_df = NULL; 3459f9b003eSeric 3469f9b003eSeric /* catch intermediate zombie */ 3479f9b003eSeric (void) waitfor(pid); 348c1ac89b1Seric return; 349c1ac89b1Seric } 350c1ac89b1Seric 351c1ac89b1Seric /* double fork to avoid zombies */ 3529f9b003eSeric pid = fork(); 3539f9b003eSeric if (pid > 0) 354c1ac89b1Seric exit(EX_OK); 355c1ac89b1Seric 356c1ac89b1Seric /* be sure we are immune from the terminal */ 3577880f3e4Seric disconnect(1, e); 358c1ac89b1Seric 3599f9b003eSeric /* prevent parent from waiting if there was an error */ 3609f9b003eSeric if (pid < 0) 3619f9b003eSeric { 3629f9b003eSeric e->e_flags |= EF_INQUEUE|EF_KEEPQUEUE; 3639f9b003eSeric finis(); 3649f9b003eSeric } 3659f9b003eSeric 366c1ac89b1Seric /* 367c1ac89b1Seric ** Close any cached connections. 368c1ac89b1Seric ** 369c1ac89b1Seric ** We don't send the QUIT protocol because the parent 370c1ac89b1Seric ** still knows about the connection. 371c1ac89b1Seric ** 372c1ac89b1Seric ** This should only happen when delivering an error 373c1ac89b1Seric ** message. 374c1ac89b1Seric */ 375c1ac89b1Seric 376c1ac89b1Seric mci_flush(FALSE, NULL); 377c1ac89b1Seric 3786b2765c6Seric # endif /* HASFLOCK */ 3796b2765c6Seric 380c1ac89b1Seric break; 381c1ac89b1Seric } 382c1ac89b1Seric 3830ae32ff4Seric if (splitenv != NULL) 3840ae32ff4Seric { 3850ae32ff4Seric if (tTd(13, 1)) 3860ae32ff4Seric { 3870ae32ff4Seric printf("\nsendall: Split queue; remaining queue:\n"); 3880ae32ff4Seric printaddr(e->e_sendqueue, TRUE); 3890ae32ff4Seric } 3900ae32ff4Seric 3910ae32ff4Seric for (ee = splitenv; ee != NULL; ee = ee->e_sibling) 3920ae32ff4Seric { 3930ae32ff4Seric CurEnv = ee; 3940ae32ff4Seric if (mode != SM_VERIFY) 3950ae32ff4Seric openxscript(ee); 3960ae32ff4Seric sendenvelope(ee, mode); 3970ae32ff4Seric dropenvelope(ee); 3980ae32ff4Seric } 3990ae32ff4Seric 4000ae32ff4Seric CurEnv = e; 4010ae32ff4Seric } 4020ae32ff4Seric sendenvelope(e, mode); 4030ae32ff4Seric Verbose = oldverbose; 4040ae32ff4Seric } 4050ae32ff4Seric 4060ae32ff4Seric sendenvelope(e, mode) 4070ae32ff4Seric register ENVELOPE *e; 4080ae32ff4Seric char mode; 4090ae32ff4Seric { 4100ae32ff4Seric register ADDRESS *q; 4110ae32ff4Seric char *qf; 4120ae32ff4Seric bool didany; 4130ae32ff4Seric 4140ae32ff4Seric /* 4150ae32ff4Seric ** If we have had global, fatal errors, don't bother sending 4160ae32ff4Seric ** the message at all if we are in SMTP mode. Local errors 4170ae32ff4Seric ** (e.g., a single address failing) will still cause the other 4180ae32ff4Seric ** addresses to be sent. 4190ae32ff4Seric */ 4200ae32ff4Seric 4210ae32ff4Seric if (bitset(EF_FATALERRS, e->e_flags) && 4220ae32ff4Seric (OpMode == MD_SMTP || OpMode == MD_DAEMON)) 4230ae32ff4Seric { 4240ae32ff4Seric e->e_flags |= EF_CLRQUEUE; 4250ae32ff4Seric return; 4260ae32ff4Seric } 4270ae32ff4Seric 428c1ac89b1Seric /* 4299c9e68d9Seric ** Run through the list and send everything. 4305288e21aSeric ** 4315288e21aSeric ** Set EF_GLOBALERRS so that error messages during delivery 4325288e21aSeric ** result in returned mail. 4339c9e68d9Seric */ 4349c9e68d9Seric 4359c9e68d9Seric e->e_nsent = 0; 4365288e21aSeric e->e_flags |= EF_GLOBALERRS; 437519e7d80Seric didany = FALSE; 438faad2b16Seric 439faad2b16Seric /* now run through the queue */ 4409c9e68d9Seric for (q = e->e_sendqueue; q != NULL; q = q->q_next) 4419c9e68d9Seric { 442fdc75a0fSeric #ifdef XDEBUG 443fdc75a0fSeric char wbuf[MAXNAME + 20]; 444fdc75a0fSeric 445fdc75a0fSeric (void) sprintf(wbuf, "sendall(%s)", q->q_paddr); 446fdc75a0fSeric checkfd012(wbuf); 447fdc75a0fSeric #endif 4489c9e68d9Seric if (mode == SM_VERIFY) 4499c9e68d9Seric { 4509c9e68d9Seric e->e_to = q->q_paddr; 4519c9e68d9Seric if (!bitset(QDONTSEND|QBADADDR, q->q_flags)) 4528dfca105Seric { 453fafe46e1Seric if (q->q_host != NULL && q->q_host[0] != '\0') 4548dfca105Seric message("deliverable: mailer %s, host %s, user %s", 4558dfca105Seric q->q_mailer->m_name, 4568dfca105Seric q->q_host, 4578dfca105Seric q->q_user); 458fafe46e1Seric else 459fafe46e1Seric message("deliverable: mailer %s, user %s", 460fafe46e1Seric q->q_mailer->m_name, 461fafe46e1Seric q->q_user); 4628dfca105Seric } 4639c9e68d9Seric } 4649c9e68d9Seric else if (!bitset(QDONTSEND|QBADADDR, q->q_flags)) 4659c9e68d9Seric { 4669c9e68d9Seric # ifdef QUEUE 4679c9e68d9Seric /* 4689c9e68d9Seric ** Checkpoint the send list every few addresses 4699c9e68d9Seric */ 4709c9e68d9Seric 4719c9e68d9Seric if (e->e_nsent >= CheckpointInterval) 4729c9e68d9Seric { 4739c9e68d9Seric queueup(e, TRUE, FALSE); 4749c9e68d9Seric e->e_nsent = 0; 4759c9e68d9Seric } 4769c9e68d9Seric # endif /* QUEUE */ 4779c9e68d9Seric (void) deliver(e, q); 478519e7d80Seric didany = TRUE; 4799c9e68d9Seric } 4809c9e68d9Seric } 481519e7d80Seric if (didany) 482519e7d80Seric { 483519e7d80Seric e->e_dtime = curtime(); 484519e7d80Seric e->e_ntries++; 485519e7d80Seric } 4869c9e68d9Seric 487fdc75a0fSeric #ifdef XDEBUG 488fdc75a0fSeric checkfd012("end of sendenvelope"); 489fdc75a0fSeric #endif 490fdc75a0fSeric 4919c9e68d9Seric if (mode == SM_FORK) 4929c9e68d9Seric finis(); 4939c9e68d9Seric } 4949c9e68d9Seric /* 4959c9e68d9Seric ** DOFORK -- do a fork, retrying a couple of times on failure. 4969c9e68d9Seric ** 4979c9e68d9Seric ** This MUST be a macro, since after a vfork we are running 4989c9e68d9Seric ** two processes on the same stack!!! 4999c9e68d9Seric ** 5009c9e68d9Seric ** Parameters: 5019c9e68d9Seric ** none. 5029c9e68d9Seric ** 5039c9e68d9Seric ** Returns: 5049c9e68d9Seric ** From a macro??? You've got to be kidding! 5059c9e68d9Seric ** 5069c9e68d9Seric ** Side Effects: 5079c9e68d9Seric ** Modifies the ==> LOCAL <== variable 'pid', leaving: 5089c9e68d9Seric ** pid of child in parent, zero in child. 5099c9e68d9Seric ** -1 on unrecoverable error. 5109c9e68d9Seric ** 5119c9e68d9Seric ** Notes: 5129c9e68d9Seric ** I'm awfully sorry this looks so awful. That's 5139c9e68d9Seric ** vfork for you..... 5149c9e68d9Seric */ 5159c9e68d9Seric 5169c9e68d9Seric # define NFORKTRIES 5 5179c9e68d9Seric 5189c9e68d9Seric # ifndef FORK 5199c9e68d9Seric # define FORK fork 5209c9e68d9Seric # endif 5219c9e68d9Seric 5229c9e68d9Seric # define DOFORK(fORKfN) \ 5239c9e68d9Seric {\ 5249c9e68d9Seric register int i;\ 5259c9e68d9Seric \ 5269c9e68d9Seric for (i = NFORKTRIES; --i >= 0; )\ 5279c9e68d9Seric {\ 5289c9e68d9Seric pid = fORKfN();\ 5299c9e68d9Seric if (pid >= 0)\ 5309c9e68d9Seric break;\ 5319c9e68d9Seric if (i > 0)\ 5329c9e68d9Seric sleep((unsigned) NFORKTRIES - i);\ 5339c9e68d9Seric }\ 5349c9e68d9Seric } 5359c9e68d9Seric /* 5369c9e68d9Seric ** DOFORK -- simple fork interface to DOFORK. 5379c9e68d9Seric ** 5389c9e68d9Seric ** Parameters: 5399c9e68d9Seric ** none. 5409c9e68d9Seric ** 5419c9e68d9Seric ** Returns: 5429c9e68d9Seric ** pid of child in parent. 5439c9e68d9Seric ** zero in child. 5449c9e68d9Seric ** -1 on error. 5459c9e68d9Seric ** 5469c9e68d9Seric ** Side Effects: 5479c9e68d9Seric ** returns twice, once in parent and once in child. 5489c9e68d9Seric */ 5499c9e68d9Seric 5509c9e68d9Seric dofork() 5519c9e68d9Seric { 5529c9e68d9Seric register int pid; 5539c9e68d9Seric 5549c9e68d9Seric DOFORK(fork); 5559c9e68d9Seric return (pid); 5569c9e68d9Seric } 5579c9e68d9Seric /* 55813bbc08cSeric ** DELIVER -- Deliver a message to a list of addresses. 55913bbc08cSeric ** 56013bbc08cSeric ** This routine delivers to everyone on the same host as the 56113bbc08cSeric ** user on the head of the list. It is clever about mailers 56213bbc08cSeric ** that don't handle multiple users. It is NOT guaranteed 56313bbc08cSeric ** that it will deliver to all these addresses however -- so 56413bbc08cSeric ** deliver should be called once for each address on the 56513bbc08cSeric ** list. 56625a99e2eSeric ** 56725a99e2eSeric ** Parameters: 568588cad61Seric ** e -- the envelope to deliver. 569c77d1c25Seric ** firstto -- head of the address list to deliver to. 57025a99e2eSeric ** 57125a99e2eSeric ** Returns: 57225a99e2eSeric ** zero -- successfully delivered. 57325a99e2eSeric ** else -- some failure, see ExitStat for more info. 57425a99e2eSeric ** 57525a99e2eSeric ** Side Effects: 57625a99e2eSeric ** The standard input is passed off to someone. 57725a99e2eSeric */ 57825a99e2eSeric 579588cad61Seric deliver(e, firstto) 580588cad61Seric register ENVELOPE *e; 581c77d1c25Seric ADDRESS *firstto; 58225a99e2eSeric { 58378442df3Seric char *host; /* host being sent to */ 58478442df3Seric char *user; /* user being sent to */ 58525a99e2eSeric char **pvp; 5865dfc646bSeric register char **mvp; 58725a99e2eSeric register char *p; 588588cad61Seric register MAILER *m; /* mailer for this recipient */ 5896259796dSeric ADDRESS *ctladdr; 590b31e7f2bSeric register MCI *mci; 591c77d1c25Seric register ADDRESS *to = firstto; 592c579ef51Seric bool clever = FALSE; /* running user smtp to this mailer */ 593772e6e50Seric ADDRESS *tochain = NULL; /* chain of users in this mailer call */ 594911693bfSbostic int rcode; /* response code */ 595e103b48fSeric char *firstsig; /* signature of firstto */ 5969c9e68d9Seric int pid; 5979c9e68d9Seric char *curhost; 598c4e9ac32Seric time_t xstart; 5999c9e68d9Seric int mpvect[2]; 6009c9e68d9Seric int rpvect[2]; 601ee6bf8dfSeric char *pv[MAXPV+1]; 602579ef0ddSeric char tobuf[TOBUFSIZE]; /* text line of to people */ 603ee6bf8dfSeric char buf[MAXNAME]; 604c23ed322Seric char rpathbuf[MAXNAME]; /* translated return path */ 605fabb3bd4Seric extern int checkcompat(); 60625a99e2eSeric 60735490626Seric errno = 0; 608ee4b0922Seric if (bitset(QDONTSEND|QBADADDR|QQUEUEUP, to->q_flags)) 6095dfc646bSeric return (0); 61025a99e2eSeric 6119d4a8008Seric #if NAMED_BIND 612912a731aSbostic /* unless interactive, try twice, over a minute */ 6138d19a23dSeric if (OpMode == MD_DAEMON || OpMode == MD_SMTP) 6148d19a23dSeric { 615912a731aSbostic _res.retrans = 30; 616912a731aSbostic _res.retry = 2; 617912a731aSbostic } 618d4bd8f0eSbostic #endif 619912a731aSbostic 62051552439Seric m = to->q_mailer; 62151552439Seric host = to->q_host; 622c9be6216Seric CurEnv = e; /* just in case */ 6234384d521Seric e->e_statmsg = NULL; 624df106f0bSeric SmtpError[0] = '\0'; 62551552439Seric 6266ef48975Seric if (tTd(10, 1)) 627562ec147Seric printf("\n--deliver, id=%s, mailer=%s, host=`%s', first user=`%s'\n", 628562ec147Seric e->e_id, m->m_name, host, to->q_user); 629ab81ee53Seric if (tTd(10, 100)) 630ab81ee53Seric printopenfds(FALSE); 631f3dbc832Seric 632f3dbc832Seric /* 633f3dbc832Seric ** If this mailer is expensive, and if we don't want to make 634f3dbc832Seric ** connections now, just mark these addresses and return. 635f3dbc832Seric ** This is useful if we want to batch connections to 636f3dbc832Seric ** reduce load. This will cause the messages to be 637f3dbc832Seric ** queued up, and a daemon will come along to send the 638f3dbc832Seric ** messages later. 639f3dbc832Seric ** This should be on a per-mailer basis. 640f3dbc832Seric */ 641f3dbc832Seric 64279aa5155Seric if (NoConnect && bitnset(M_EXPENSIVE, m->m_flags) && !Verbose) 643f3dbc832Seric { 644f3dbc832Seric for (; to != NULL; to = to->q_next) 645f4560e80Seric { 646ee4b0922Seric if (bitset(QDONTSEND|QBADADDR|QQUEUEUP, to->q_flags) || 647c6e18ac5Seric to->q_mailer != m) 648f4560e80Seric continue; 649268a25e1Seric to->q_flags |= QQUEUEUP; 650588cad61Seric e->e_to = to->q_paddr; 65108b25121Seric message("queued"); 6522f624c86Seric if (LogLevel > 8) 653c4e9ac32Seric logdelivery(m, NULL, "queued", NULL, xstart, e); 654f4560e80Seric } 655588cad61Seric e->e_to = NULL; 656f3dbc832Seric return (0); 657f3dbc832Seric } 658f3dbc832Seric 65925a99e2eSeric /* 6605dfc646bSeric ** Do initial argv setup. 6615dfc646bSeric ** Insert the mailer name. Notice that $x expansion is 6625dfc646bSeric ** NOT done on the mailer name. Then, if the mailer has 6635dfc646bSeric ** a picky -f flag, we insert it as appropriate. This 6645dfc646bSeric ** code does not check for 'pv' overflow; this places a 6655dfc646bSeric ** manifest lower limit of 4 for MAXPV. 6663bea8136Seric ** The from address rewrite is expected to make 6673bea8136Seric ** the address relative to the other end. 6685dfc646bSeric */ 6695dfc646bSeric 67078442df3Seric /* rewrite from address, using rewriting rules */ 671efe54562Seric rcode = EX_OK; 672badf36fdSeric if (bitnset(M_UDBENVELOPE, e->e_from.q_mailer->m_flags)) 673badf36fdSeric p = e->e_sender; 674badf36fdSeric else 675badf36fdSeric p = e->e_from.q_paddr; 676badf36fdSeric (void) strcpy(rpathbuf, remotename(p, m, 677efe54562Seric RF_SENDERADDR|RF_CANONICAL, 678efe54562Seric &rcode, e)); 679ee4b0922Seric define('g', rpathbuf, e); /* translated return path */ 680588cad61Seric define('h', host, e); /* to host */ 6815dfc646bSeric Errors = 0; 6825dfc646bSeric pvp = pv; 6835dfc646bSeric *pvp++ = m->m_argv[0]; 6845dfc646bSeric 6855dfc646bSeric /* insert -f or -r flag as appropriate */ 68657fc6f17Seric if (FromFlag && (bitnset(M_FOPT, m->m_flags) || bitnset(M_ROPT, m->m_flags))) 6875dfc646bSeric { 68857fc6f17Seric if (bitnset(M_FOPT, m->m_flags)) 6895dfc646bSeric *pvp++ = "-f"; 6905dfc646bSeric else 6915dfc646bSeric *pvp++ = "-r"; 692c23ed322Seric *pvp++ = newstr(rpathbuf); 6935dfc646bSeric } 6945dfc646bSeric 6955dfc646bSeric /* 6965dfc646bSeric ** Append the other fixed parts of the argv. These run 6975dfc646bSeric ** up to the first entry containing "$u". There can only 6985dfc646bSeric ** be one of these, and there are only a few more slots 6995dfc646bSeric ** in the pv after it. 7005dfc646bSeric */ 7015dfc646bSeric 7025dfc646bSeric for (mvp = m->m_argv; (p = *++mvp) != NULL; ) 7035dfc646bSeric { 7042bc47524Seric /* can't use strchr here because of sign extension problems */ 7052bc47524Seric while (*p != '\0') 7062bc47524Seric { 7072bc47524Seric if ((*p++ & 0377) == MACROEXPAND) 7082bc47524Seric { 7092bc47524Seric if (*p == 'u') 7105dfc646bSeric break; 7112bc47524Seric } 7122bc47524Seric } 7132bc47524Seric 7142bc47524Seric if (*p != '\0') 7155dfc646bSeric break; 7165dfc646bSeric 7175dfc646bSeric /* this entry is safe -- go ahead and process it */ 718588cad61Seric expand(*mvp, buf, &buf[sizeof buf - 1], e); 7195dfc646bSeric *pvp++ = newstr(buf); 7205dfc646bSeric if (pvp >= &pv[MAXPV - 3]) 7215dfc646bSeric { 72208b25121Seric syserr("554 Too many parameters to %s before $u", pv[0]); 7235dfc646bSeric return (-1); 7245dfc646bSeric } 7255dfc646bSeric } 726c579ef51Seric 72733db8731Seric /* 72833db8731Seric ** If we have no substitution for the user name in the argument 72933db8731Seric ** list, we know that we must supply the names otherwise -- and 73033db8731Seric ** SMTP is the answer!! 73133db8731Seric */ 73233db8731Seric 7335dfc646bSeric if (*mvp == NULL) 734c579ef51Seric { 735c579ef51Seric /* running SMTP */ 7362c7e1b8dSeric # ifdef SMTP 737c579ef51Seric clever = TRUE; 738c579ef51Seric *pvp = NULL; 7396c2c3107Seric # else /* SMTP */ 74033db8731Seric /* oops! we don't implement SMTP */ 741df106f0bSeric syserr("554 SMTP style mailer not implemented"); 7422c7e1b8dSeric return (EX_SOFTWARE); 7436c2c3107Seric # endif /* SMTP */ 744c579ef51Seric } 7455dfc646bSeric 7465dfc646bSeric /* 7475dfc646bSeric ** At this point *mvp points to the argument with $u. We 7485dfc646bSeric ** run through our address list and append all the addresses 7495dfc646bSeric ** we can. If we run out of space, do not fret! We can 7505dfc646bSeric ** always send another copy later. 7515dfc646bSeric */ 7525dfc646bSeric 7535dfc646bSeric tobuf[0] = '\0'; 754588cad61Seric e->e_to = tobuf; 7556259796dSeric ctladdr = NULL; 756c4e9ac32Seric xstart = curtime(); 757e103b48fSeric firstsig = hostsignature(firstto->q_mailer, firstto->q_host, e); 7585dfc646bSeric for (; to != NULL; to = to->q_next) 7595dfc646bSeric { 7605dfc646bSeric /* avoid sending multiple recipients to dumb mailers */ 76157fc6f17Seric if (tobuf[0] != '\0' && !bitnset(M_MUSER, m->m_flags)) 7625dfc646bSeric break; 7635dfc646bSeric 7645dfc646bSeric /* if already sent or not for this host, don't send */ 765ee4b0922Seric if (bitset(QDONTSEND|QBADADDR|QQUEUEUP, to->q_flags) || 766e103b48fSeric to->q_mailer != firstto->q_mailer || 767e103b48fSeric strcmp(hostsignature(to->q_mailer, to->q_host, e), firstsig) != 0) 7685dfc646bSeric continue; 7696259796dSeric 7704b22ea87Seric /* avoid overflowing tobuf */ 771aa50a568Sbostic if (sizeof tobuf < (strlen(to->q_paddr) + strlen(tobuf) + 2)) 7724b22ea87Seric break; 7734b22ea87Seric 7746ef48975Seric if (tTd(10, 1)) 775772e6e50Seric { 776772e6e50Seric printf("\nsend to "); 777772e6e50Seric printaddr(to, FALSE); 778772e6e50Seric } 779772e6e50Seric 7806259796dSeric /* compute effective uid/gid when sending */ 7810ed512e3Seric if (bitnset(M_RUNASRCPT, to->q_mailer->m_flags)) 7826259796dSeric ctladdr = getctladdr(to); 7836259796dSeric 78488bd8d39Seric if (tTd(10, 2)) 78588bd8d39Seric { 78688bd8d39Seric printf("ctladdr="); 78788bd8d39Seric printaddr(ctladdr, FALSE); 78888bd8d39Seric } 78988bd8d39Seric 7905dfc646bSeric user = to->q_user; 791588cad61Seric e->e_to = to->q_paddr; 79275f1ade9Seric if (tTd(10, 5)) 79375f1ade9Seric { 79475f1ade9Seric printf("deliver: QDONTSEND "); 79575f1ade9Seric printaddr(to, FALSE); 79675f1ade9Seric } 797ee4b0922Seric to->q_flags |= QDONTSEND; 7985dfc646bSeric 7995dfc646bSeric /* 8005dfc646bSeric ** Check to see that these people are allowed to 8015dfc646bSeric ** talk to each other. 8022a6e0786Seric */ 8032a6e0786Seric 80469582d2fSeric if (m->m_maxsize != 0 && e->e_msgsize > m->m_maxsize) 80569582d2fSeric { 8060ed512e3Seric e->e_flags |= EF_NORETURN; 80708b25121Seric usrerr("552 Message is too large; %ld bytes max", m->m_maxsize); 808c4e9ac32Seric giveresponse(EX_UNAVAILABLE, m, NULL, ctladdr, xstart, e); 80969582d2fSeric continue; 81069582d2fSeric } 8119bfcea71Seric #if NAMED_BIND 8129bfcea71Seric h_errno = 0; 8139bfcea71Seric #endif 814fabb3bd4Seric rcode = checkcompat(to, e); 8151793c9c5Seric if (rcode != EX_OK) 8165dfc646bSeric { 817dee32bf2Seric markfailure(e, to, NULL, rcode); 818c4e9ac32Seric giveresponse(rcode, m, NULL, ctladdr, xstart, e); 8195dfc646bSeric continue; 8205dfc646bSeric } 8212a6e0786Seric 8222a6e0786Seric /* 8239ec9501bSeric ** Strip quote bits from names if the mailer is dumb 8249ec9501bSeric ** about them. 82525a99e2eSeric */ 82625a99e2eSeric 82757fc6f17Seric if (bitnset(M_STRIPQ, m->m_flags)) 82825a99e2eSeric { 8291d8f1806Seric stripquotes(user); 8301d8f1806Seric stripquotes(host); 83125a99e2eSeric } 83225a99e2eSeric 833cdb828c5Seric /* hack attack -- delivermail compatibility */ 834cdb828c5Seric if (m == ProgMailer && *user == '|') 835cdb828c5Seric user++; 836cdb828c5Seric 83725a99e2eSeric /* 8383efaed6eSeric ** If an error message has already been given, don't 8393efaed6eSeric ** bother to send to this address. 8403efaed6eSeric ** 8413efaed6eSeric ** >>>>>>>>>> This clause assumes that the local mailer 8423efaed6eSeric ** >> NOTE >> cannot do any further aliasing; that 8433efaed6eSeric ** >>>>>>>>>> function is subsumed by sendmail. 8443efaed6eSeric */ 8453efaed6eSeric 8466cae517dSeric if (bitset(QBADADDR|QQUEUEUP, to->q_flags)) 8473efaed6eSeric continue; 8483efaed6eSeric 849f2fec898Seric /* save statistics.... */ 850588cad61Seric markstats(e, to); 851f2fec898Seric 8523efaed6eSeric /* 85325a99e2eSeric ** See if this user name is "special". 85425a99e2eSeric ** If the user name has a slash in it, assume that this 85551552439Seric ** is a file -- send it off without further ado. Note 85651552439Seric ** that this type of addresses is not processed along 85751552439Seric ** with the others, so we fudge on the To person. 85825a99e2eSeric */ 85925a99e2eSeric 8602c017f8dSeric if (m == FileMailer) 86125a99e2eSeric { 86203463a75Seric rcode = mailfile(user, ctladdr, e); 863c4e9ac32Seric giveresponse(rcode, m, NULL, ctladdr, xstart, e); 8649ff40499Seric e->e_nsent++; 865dde5acadSeric if (rcode == EX_OK) 8669ff40499Seric { 867dde5acadSeric to->q_flags |= QSENT; 8689ff40499Seric if (bitnset(M_LOCALMAILER, m->m_flags) && 8699ff40499Seric (e->e_receiptto != NULL || 8709ff40499Seric bitset(QPINGONSUCCESS, to->q_flags))) 8719ff40499Seric { 8729ff40499Seric to->q_flags |= QREPORT; 8739ff40499Seric fprintf(e->e_xfp, "%s... Successfully delivered\n", 8749ff40499Seric to->q_paddr); 8759ff40499Seric } 8769ff40499Seric } 8779447f5ceSeric to->q_statdate = curtime(); 8785dfc646bSeric continue; 87925a99e2eSeric } 88025a99e2eSeric 88113bbc08cSeric /* 88213bbc08cSeric ** Address is verified -- add this user to mailer 88313bbc08cSeric ** argv, and add it to the print list of recipients. 88413bbc08cSeric */ 88513bbc08cSeric 886508daeccSeric /* link together the chain of recipients */ 887508daeccSeric to->q_tchain = tochain; 888508daeccSeric tochain = to; 889508daeccSeric 8905dfc646bSeric /* create list of users for error messages */ 891db8841e9Seric (void) strcat(tobuf, ","); 892db8841e9Seric (void) strcat(tobuf, to->q_paddr); 893588cad61Seric define('u', user, e); /* to user */ 894b6f89e6eSeric p = to->q_home; 895b6f89e6eSeric if (p == NULL && ctladdr != NULL) 896b6f89e6eSeric p = ctladdr->q_home; 897b6f89e6eSeric define('z', p, e); /* user's home */ 8985dfc646bSeric 899c579ef51Seric /* 900508daeccSeric ** Expand out this user into argument list. 901c579ef51Seric */ 902c579ef51Seric 903508daeccSeric if (!clever) 904c579ef51Seric { 905588cad61Seric expand(*mvp, buf, &buf[sizeof buf - 1], e); 9065dfc646bSeric *pvp++ = newstr(buf); 9075dfc646bSeric if (pvp >= &pv[MAXPV - 2]) 9085dfc646bSeric { 9095dfc646bSeric /* allow some space for trailing parms */ 9105dfc646bSeric break; 9115dfc646bSeric } 9125dfc646bSeric } 913c579ef51Seric } 9145dfc646bSeric 915145b49b1Seric /* see if any addresses still exist */ 916145b49b1Seric if (tobuf[0] == '\0') 917c579ef51Seric { 918588cad61Seric define('g', (char *) NULL, e); 919145b49b1Seric return (0); 920c579ef51Seric } 921145b49b1Seric 9225dfc646bSeric /* print out messages as full list */ 92363780dbdSeric e->e_to = tobuf + 1; 9245dfc646bSeric 9255dfc646bSeric /* 9265dfc646bSeric ** Fill out any parameters after the $u parameter. 9275dfc646bSeric */ 9285dfc646bSeric 929c579ef51Seric while (!clever && *++mvp != NULL) 9305dfc646bSeric { 931588cad61Seric expand(*mvp, buf, &buf[sizeof buf - 1], e); 9325dfc646bSeric *pvp++ = newstr(buf); 9335dfc646bSeric if (pvp >= &pv[MAXPV]) 93408b25121Seric syserr("554 deliver: pv overflow after $u for %s", pv[0]); 9355dfc646bSeric } 9365dfc646bSeric *pvp++ = NULL; 9375dfc646bSeric 93825a99e2eSeric /* 93925a99e2eSeric ** Call the mailer. 9406328bdf7Seric ** The argument vector gets built, pipes 94125a99e2eSeric ** are created as necessary, and we fork & exec as 9426328bdf7Seric ** appropriate. 943c579ef51Seric ** If we are running SMTP, we just need to clean up. 94425a99e2eSeric */ 94525a99e2eSeric 946960e665aSeric /*XXX this seems a bit wierd */ 9474899f6b5Seric if (ctladdr == NULL && m != ProgMailer && 9484899f6b5Seric bitset(QGOODUID, e->e_from.q_flags)) 949960e665aSeric ctladdr = &e->e_from; 950960e665aSeric 9519d4a8008Seric #if NAMED_BIND 9522bcc6d2dSeric if (ConfigLevel < 2) 953912a731aSbostic _res.options &= ~(RES_DEFNAMES | RES_DNSRCH); /* XXX */ 954134746fbSeric #endif 9559c9e68d9Seric 9569c9e68d9Seric if (tTd(11, 1)) 957134746fbSeric { 9589c9e68d9Seric printf("openmailer:"); 9599c9e68d9Seric printav(pv); 9609c9e68d9Seric } 9619c9e68d9Seric errno = 0; 9629bfcea71Seric #if NAMED_BIND 9639bfcea71Seric h_errno = 0; 9649bfcea71Seric #endif 9659c9e68d9Seric 966dee32bf2Seric CurHostName = NULL; 9679c9e68d9Seric 9689c9e68d9Seric /* 9699c9e68d9Seric ** Deal with the special case of mail handled through an IPC 9709c9e68d9Seric ** connection. 9719c9e68d9Seric ** In this case we don't actually fork. We must be 9729c9e68d9Seric ** running SMTP for this to work. We will return a 9739c9e68d9Seric ** zero pid to indicate that we are running IPC. 9749c9e68d9Seric ** We also handle a debug version that just talks to stdin/out. 9759c9e68d9Seric */ 9769c9e68d9Seric 9779c9e68d9Seric curhost = NULL; 978c931b82bSeric SmtpPhase = NULL; 979df106f0bSeric mci = NULL; 9809c9e68d9Seric 9817febfd66Seric #ifdef XDEBUG 9827febfd66Seric { 9837febfd66Seric char wbuf[MAXLINE]; 9847febfd66Seric 9857febfd66Seric /* make absolutely certain 0, 1, and 2 are in use */ 9867febfd66Seric sprintf(wbuf, "%s... openmailer(%s)", e->e_to, m->m_name); 9877febfd66Seric checkfd012(wbuf); 9887febfd66Seric } 9897febfd66Seric #endif 9907febfd66Seric 991cc7496f5Seric /* check for 8-bit available */ 992cc7496f5Seric if (bitset(EF_HAS8BIT, e->e_flags) && 993cc7496f5Seric bitnset(M_7BITS, m->m_flags) && 994cc7496f5Seric !bitset(MM_MIME8BIT, MimeMode)) 995cc7496f5Seric { 996cc7496f5Seric usrerr("554 Cannot send 8-bit data to 7-bit destination"); 997cc7496f5Seric rcode = EX_DATAERR; 998cc7496f5Seric goto give_up; 999cc7496f5Seric } 1000cc7496f5Seric 10019c9e68d9Seric /* check for Local Person Communication -- not for mortals!!! */ 10029c9e68d9Seric if (strcmp(m->m_mailer, "[LPC]") == 0) 10039c9e68d9Seric { 10049c9e68d9Seric mci = (MCI *) xalloc(sizeof *mci); 10059c9e68d9Seric bzero((char *) mci, sizeof *mci); 10069c9e68d9Seric mci->mci_in = stdin; 10079c9e68d9Seric mci->mci_out = stdout; 10089c9e68d9Seric mci->mci_state = clever ? MCIS_OPENING : MCIS_OPEN; 10099c9e68d9Seric mci->mci_mailer = m; 10109c9e68d9Seric } 10119c9e68d9Seric else if (strcmp(m->m_mailer, "[IPC]") == 0 || 10129c9e68d9Seric strcmp(m->m_mailer, "[TCP]") == 0) 10139c9e68d9Seric { 10149c9e68d9Seric #ifdef DAEMON 10159c9e68d9Seric register int i; 10169c9e68d9Seric register u_short port; 10179c9e68d9Seric 1018a5d44642Seric if (pv[0] == NULL || pv[1] == NULL || pv[1][0] == '\0') 1019a5d44642Seric { 1020a5d44642Seric syserr("null host name for %s mailer", m->m_mailer); 1021a5d44642Seric rcode = EX_CONFIG; 1022a5d44642Seric goto give_up; 1023a5d44642Seric } 1024a5d44642Seric 10259c9e68d9Seric CurHostName = pv[1]; 10269c9e68d9Seric curhost = hostsignature(m, pv[1], e); 10279c9e68d9Seric 10289c9e68d9Seric if (curhost == NULL || curhost[0] == '\0') 10299c9e68d9Seric { 1030a5d44642Seric syserr("null host signature for %s", pv[1]); 1031dfebe401Seric rcode = EX_CONFIG; 1032b31e7f2bSeric goto give_up; 1033b31e7f2bSeric } 10349c9e68d9Seric 10359c9e68d9Seric if (!clever) 10369c9e68d9Seric { 10379c9e68d9Seric syserr("554 non-clever IPC"); 1038df106f0bSeric rcode = EX_CONFIG; 10399c9e68d9Seric goto give_up; 10409c9e68d9Seric } 10419c9e68d9Seric if (pv[2] != NULL) 10429c9e68d9Seric port = atoi(pv[2]); 10439c9e68d9Seric else 10449c9e68d9Seric port = 0; 10459c9e68d9Seric tryhost: 10469c9e68d9Seric while (*curhost != '\0') 10479c9e68d9Seric { 10489c9e68d9Seric register char *p; 10499c9e68d9Seric static char hostbuf[MAXNAME]; 10509c9e68d9Seric 10519c9e68d9Seric /* pull the next host from the signature */ 10529c9e68d9Seric p = strchr(curhost, ':'); 10539c9e68d9Seric if (p == NULL) 10549c9e68d9Seric p = &curhost[strlen(curhost)]; 1055df106f0bSeric if (p == curhost) 1056df106f0bSeric { 1057df106f0bSeric syserr("deliver: null host name in signature"); 10588087428aSeric curhost++; 1059df106f0bSeric continue; 1060df106f0bSeric } 10619c9e68d9Seric strncpy(hostbuf, curhost, p - curhost); 10629c9e68d9Seric hostbuf[p - curhost] = '\0'; 10639c9e68d9Seric if (*p != '\0') 10649c9e68d9Seric p++; 10659c9e68d9Seric curhost = p; 10669c9e68d9Seric 10679c9e68d9Seric /* see if we already know that this host is fried */ 10689c9e68d9Seric CurHostName = hostbuf; 10699c9e68d9Seric mci = mci_get(hostbuf, m); 10709c9e68d9Seric if (mci->mci_state != MCIS_CLOSED) 10719c9e68d9Seric { 10729c9e68d9Seric if (tTd(11, 1)) 10739c9e68d9Seric { 10749c9e68d9Seric printf("openmailer: "); 10754052916eSeric mci_dump(mci, FALSE); 10769c9e68d9Seric } 10779c9e68d9Seric CurHostName = mci->mci_host; 10780bde8488Seric message("Using cached connection to %s via %s...", 10790bde8488Seric hostbuf, m->m_name); 10809c9e68d9Seric break; 10819c9e68d9Seric } 10829c9e68d9Seric mci->mci_mailer = m; 10839c9e68d9Seric if (mci->mci_exitstat != EX_OK) 10849c9e68d9Seric continue; 10859c9e68d9Seric 10869c9e68d9Seric /* try the connection */ 10879c9e68d9Seric setproctitle("%s %s: %s", e->e_id, hostbuf, "user open"); 10880bde8488Seric message("Connecting to %s via %s...", 10899c9e68d9Seric hostbuf, m->m_name); 10909c9e68d9Seric i = makeconnection(hostbuf, port, mci, 10919c9e68d9Seric bitnset(M_SECURE_PORT, m->m_flags)); 10929c9e68d9Seric mci->mci_exitstat = i; 10939c9e68d9Seric mci->mci_errno = errno; 10949d4a8008Seric #if NAMED_BIND 1095f170942cSeric mci->mci_herrno = h_errno; 1096f170942cSeric #endif 10979c9e68d9Seric if (i == EX_OK) 10989c9e68d9Seric { 10999c9e68d9Seric mci->mci_state = MCIS_OPENING; 11009c9e68d9Seric mci_cache(mci); 1101f170942cSeric if (TrafficLogFile != NULL) 1102f170942cSeric fprintf(TrafficLogFile, "%05d == CONNECT %s\n", 1103f170942cSeric getpid(), hostbuf); 11049c9e68d9Seric break; 11059c9e68d9Seric } 11069c9e68d9Seric else if (tTd(11, 1)) 11079c9e68d9Seric printf("openmailer: makeconnection => stat=%d, errno=%d\n", 11089c9e68d9Seric i, errno); 11099c9e68d9Seric 11109c9e68d9Seric /* enter status of this host */ 11119c9e68d9Seric setstat(i); 1112df106f0bSeric 1113df106f0bSeric /* should print some message here for -v mode */ 1114df106f0bSeric } 1115df106f0bSeric if (mci == NULL) 1116df106f0bSeric { 1117df106f0bSeric syserr("deliver: no host name"); 1118df106f0bSeric rcode = EX_OSERR; 1119df106f0bSeric goto give_up; 11209c9e68d9Seric } 11219c9e68d9Seric mci->mci_pid = 0; 11229c9e68d9Seric #else /* no DAEMON */ 11239c9e68d9Seric syserr("554 openmailer: no IPC"); 11249c9e68d9Seric if (tTd(11, 1)) 11259c9e68d9Seric printf("openmailer: NULL\n"); 1126df106f0bSeric rcode = EX_UNAVAILABLE; 1127df106f0bSeric goto give_up; 11289c9e68d9Seric #endif /* DAEMON */ 11299c9e68d9Seric } 11309c9e68d9Seric else 11319c9e68d9Seric { 11328b1fa71dSeric /* flush any expired connections */ 11338b1fa71dSeric (void) mci_scan(NULL); 11348b1fa71dSeric 11358b1fa71dSeric /* announce the connection to verbose listeners */ 11360bde8488Seric if (host == NULL || host[0] == '\0') 11370bde8488Seric message("Connecting to %s...", m->m_name); 11380bde8488Seric else 11390bde8488Seric message("Connecting to %s via %s...", host, m->m_name); 1140f170942cSeric if (TrafficLogFile != NULL) 11410e3bfef5Seric { 1142f170942cSeric char **av; 1143f170942cSeric 1144f170942cSeric fprintf(TrafficLogFile, "%05d === EXEC", getpid()); 1145f170942cSeric for (av = pv; *av != NULL; av++) 1146f170942cSeric fprintf(TrafficLogFile, " %s", *av); 1147f170942cSeric fprintf(TrafficLogFile, "\n"); 11486fe8c3bcSeric } 11496fe8c3bcSeric 11509c9e68d9Seric /* create a pipe to shove the mail through */ 11519c9e68d9Seric if (pipe(mpvect) < 0) 11529c9e68d9Seric { 11530e3bfef5Seric syserr("%s... openmailer(%s): pipe (to mailer)", 11540e3bfef5Seric e->e_to, m->m_name); 11559c9e68d9Seric if (tTd(11, 1)) 11569c9e68d9Seric printf("openmailer: NULL\n"); 11579c9e68d9Seric rcode = EX_OSERR; 11589c9e68d9Seric goto give_up; 11599c9e68d9Seric } 11609c9e68d9Seric 11619c9e68d9Seric /* if this mailer speaks smtp, create a return pipe */ 11629c9e68d9Seric if (clever && pipe(rpvect) < 0) 11639c9e68d9Seric { 11640e3bfef5Seric syserr("%s... openmailer(%s): pipe (from mailer)", 11650e3bfef5Seric e->e_to, m->m_name); 11669c9e68d9Seric (void) close(mpvect[0]); 11679c9e68d9Seric (void) close(mpvect[1]); 11689c9e68d9Seric if (tTd(11, 1)) 11699c9e68d9Seric printf("openmailer: NULL\n"); 11709c9e68d9Seric rcode = EX_OSERR; 11719c9e68d9Seric goto give_up; 11729c9e68d9Seric } 11739c9e68d9Seric 11749c9e68d9Seric /* 11759c9e68d9Seric ** Actually fork the mailer process. 11769c9e68d9Seric ** DOFORK is clever about retrying. 11779c9e68d9Seric ** 11789c9e68d9Seric ** Dispose of SIGCHLD signal catchers that may be laying 11799c9e68d9Seric ** around so that endmail will get it. 11809c9e68d9Seric */ 11819c9e68d9Seric 11829c9e68d9Seric if (e->e_xfp != NULL) 11839c9e68d9Seric (void) fflush(e->e_xfp); /* for debugging */ 11849c9e68d9Seric (void) fflush(stdout); 11859c9e68d9Seric # ifdef SIGCHLD 11862b9178d3Seric (void) setsignal(SIGCHLD, SIG_DFL); 11879c9e68d9Seric # endif /* SIGCHLD */ 11889c9e68d9Seric DOFORK(FORK); 11899c9e68d9Seric /* pid is set by DOFORK */ 11909c9e68d9Seric if (pid < 0) 11919c9e68d9Seric { 11929c9e68d9Seric /* failure */ 11930e3bfef5Seric syserr("%s... openmailer(%s): cannot fork", 11940e3bfef5Seric e->e_to, m->m_name); 11959c9e68d9Seric (void) close(mpvect[0]); 11969c9e68d9Seric (void) close(mpvect[1]); 11979c9e68d9Seric if (clever) 11989c9e68d9Seric { 11999c9e68d9Seric (void) close(rpvect[0]); 12009c9e68d9Seric (void) close(rpvect[1]); 12019c9e68d9Seric } 12029c9e68d9Seric if (tTd(11, 1)) 12039c9e68d9Seric printf("openmailer: NULL\n"); 12049c9e68d9Seric rcode = EX_OSERR; 12059c9e68d9Seric goto give_up; 12069c9e68d9Seric } 12079c9e68d9Seric else if (pid == 0) 12089c9e68d9Seric { 12099c9e68d9Seric int i; 12109c9e68d9Seric int saveerrno; 12119c9e68d9Seric char **ep; 12129c9e68d9Seric char *env[MAXUSERENVIRON]; 12139c9e68d9Seric extern char **environ; 12149c9e68d9Seric extern int DtableSize; 12159c9e68d9Seric 12169c9e68d9Seric /* child -- set up input & exec mailer */ 12172b9178d3Seric (void) setsignal(SIGINT, SIG_IGN); 12182b9178d3Seric (void) setsignal(SIGHUP, SIG_IGN); 12192b9178d3Seric (void) setsignal(SIGTERM, SIG_DFL); 12209c9e68d9Seric 122144f2317fSeric /* reset user and group */ 1222acc57dbfSeric if (bitnset(M_SPECIFIC_UID, m->m_flags)) 1223acc57dbfSeric { 1224acc57dbfSeric (void) setgid(m->m_gid); 1225acc57dbfSeric (void) setuid(m->m_uid); 1226acc57dbfSeric } 1227ab9cdf66Seric else if (ctladdr != NULL && ctladdr->q_uid != 0) 122844f2317fSeric { 122944f2317fSeric (void) initgroups(ctladdr->q_ruser? 123044f2317fSeric ctladdr->q_ruser: ctladdr->q_user, 123144f2317fSeric ctladdr->q_gid); 123251cfe111Seric (void) setgid(ctladdr->q_gid); 123344f2317fSeric (void) setuid(ctladdr->q_uid); 123444f2317fSeric } 1235ab9cdf66Seric else 1236ab9cdf66Seric { 1237ab9cdf66Seric (void) initgroups(DefUser, DefGid); 1238ab9cdf66Seric if (m->m_gid == 0) 1239ab9cdf66Seric (void) setgid(DefGid); 1240ab9cdf66Seric else 1241ab9cdf66Seric (void) setgid(m->m_gid); 1242ab9cdf66Seric if (m->m_uid == 0) 1243ab9cdf66Seric (void) setuid(DefUid); 1244ab9cdf66Seric else 1245ab9cdf66Seric (void) setuid(m->m_uid); 124644f2317fSeric } 124744f2317fSeric 124844f2317fSeric if (tTd(11, 2)) 124944f2317fSeric printf("openmailer: running as r/euid=%d/%d\n", 125044f2317fSeric getuid(), geteuid()); 125144f2317fSeric 1252b986f6aaSeric /* move into some "safe" directory */ 1253b986f6aaSeric if (m->m_execdir != NULL) 1254b986f6aaSeric { 1255b986f6aaSeric char *p, *q; 1256b986f6aaSeric char buf[MAXLINE]; 1257b986f6aaSeric 1258b986f6aaSeric for (p = m->m_execdir; p != NULL; p = q) 1259b986f6aaSeric { 1260b986f6aaSeric q = strchr(p, ':'); 1261b986f6aaSeric if (q != NULL) 1262b986f6aaSeric *q = '\0'; 1263b986f6aaSeric expand(p, buf, &buf[sizeof buf] - 1, e); 1264b986f6aaSeric if (q != NULL) 1265b986f6aaSeric *q++ = ':'; 1266b986f6aaSeric if (tTd(11, 20)) 1267b986f6aaSeric printf("openmailer: trydir %s\n", 1268b986f6aaSeric buf); 1269b986f6aaSeric if (buf[0] != '\0' && chdir(buf) >= 0) 1270b986f6aaSeric break; 1271b986f6aaSeric } 1272b986f6aaSeric } 1273b986f6aaSeric 12749c9e68d9Seric /* arrange to filter std & diag output of command */ 12759c9e68d9Seric if (clever) 12769c9e68d9Seric { 12779c9e68d9Seric (void) close(rpvect[0]); 12786fe8c3bcSeric if (dup2(rpvect[1], STDOUT_FILENO) < 0) 12796fe8c3bcSeric { 12800e3bfef5Seric syserr("%s... openmailer(%s): cannot dup pipe %d for stdout", 12810e3bfef5Seric e->e_to, m->m_name, rpvect[1]); 12826fe8c3bcSeric _exit(EX_OSERR); 12836fe8c3bcSeric } 12849c9e68d9Seric (void) close(rpvect[1]); 12859c9e68d9Seric } 12868b40b0a4Seric else if (OpMode == MD_SMTP || OpMode == MD_DAEMON || 12878b40b0a4Seric HoldErrs || DisConnected) 12889c9e68d9Seric { 12899c9e68d9Seric /* put mailer output in transcript */ 12906fe8c3bcSeric if (dup2(fileno(e->e_xfp), STDOUT_FILENO) < 0) 12916fe8c3bcSeric { 12920e3bfef5Seric syserr("%s... openmailer(%s): cannot dup xscript %d for stdout", 12930e3bfef5Seric e->e_to, m->m_name, 12946fe8c3bcSeric fileno(e->e_xfp)); 12956fe8c3bcSeric _exit(EX_OSERR); 12969c9e68d9Seric } 12976fe8c3bcSeric } 12986fe8c3bcSeric if (dup2(STDOUT_FILENO, STDERR_FILENO) < 0) 12996fe8c3bcSeric { 13000e3bfef5Seric syserr("%s... openmailer(%s): cannot dup stdout for stderr", 13010e3bfef5Seric e->e_to, m->m_name); 13026fe8c3bcSeric _exit(EX_OSERR); 13036fe8c3bcSeric } 13049c9e68d9Seric 13059c9e68d9Seric /* arrange to get standard input */ 13069c9e68d9Seric (void) close(mpvect[1]); 13079c9e68d9Seric if (dup2(mpvect[0], STDIN_FILENO) < 0) 13089c9e68d9Seric { 13090e3bfef5Seric syserr("%s... openmailer(%s): cannot dup pipe %d for stdin", 13100e3bfef5Seric e->e_to, m->m_name, mpvect[0]); 13119c9e68d9Seric _exit(EX_OSERR); 13129c9e68d9Seric } 13139c9e68d9Seric (void) close(mpvect[0]); 13149c9e68d9Seric 13159c9e68d9Seric /* arrange for all the files to be closed */ 13169c9e68d9Seric for (i = 3; i < DtableSize; i++) 13179c9e68d9Seric { 13189c9e68d9Seric register int j; 131944f2317fSeric 13209c9e68d9Seric if ((j = fcntl(i, F_GETFD, 0)) != -1) 13219c9e68d9Seric (void) fcntl(i, F_SETFD, j | 1); 13229c9e68d9Seric } 13239c9e68d9Seric 13249f9b003eSeric /* 13259f9b003eSeric ** Set up the mailer environment 132676c572d2Seric ** _FORCE_MAIL_LOCAL_ is DG-UX equiv of -d flag. 13279f9b003eSeric ** TZ is timezone information. 13289f9b003eSeric ** SYSTYPE is Apollo software sys type (required). 13299f9b003eSeric ** ISP is Apollo hardware system type (required). 13309f9b003eSeric */ 13319f9b003eSeric 13329c9e68d9Seric i = 0; 13339c9e68d9Seric env[i++] = "AGENT=sendmail"; 133476c572d2Seric env[i++] = "_FORCE_MAIL_LOCAL_=yes"; 13359c9e68d9Seric for (ep = environ; *ep != NULL; ep++) 13369c9e68d9Seric { 13379f9b003eSeric if (strncmp(*ep, "TZ=", 3) == 0 || 13389f9b003eSeric strncmp(*ep, "ISP=", 4) == 0 || 13399f9b003eSeric strncmp(*ep, "SYSTYPE=", 8) == 0) 13409c9e68d9Seric env[i++] = *ep; 13419c9e68d9Seric } 134276c572d2Seric env[i] = NULL; 13439c9e68d9Seric 1344929277f2Seric /* run disconnected from terminal */ 1345929277f2Seric (void) setsid(); 1346929277f2Seric 13479c9e68d9Seric /* try to execute the mailer */ 13489c9e68d9Seric execve(m->m_mailer, pv, env); 13499c9e68d9Seric saveerrno = errno; 13509c9e68d9Seric syserr("Cannot exec %s", m->m_mailer); 13510ed512e3Seric if (bitnset(M_LOCALMAILER, m->m_flags) || 13520ed512e3Seric transienterror(saveerrno)) 13537c941fd2Seric _exit(EX_OSERR); 13549c9e68d9Seric _exit(EX_UNAVAILABLE); 13559c9e68d9Seric } 13569c9e68d9Seric 13579c9e68d9Seric /* 13589c9e68d9Seric ** Set up return value. 13599c9e68d9Seric */ 13609c9e68d9Seric 13619c9e68d9Seric mci = (MCI *) xalloc(sizeof *mci); 13629c9e68d9Seric bzero((char *) mci, sizeof *mci); 13639c9e68d9Seric mci->mci_mailer = m; 13649c9e68d9Seric mci->mci_state = clever ? MCIS_OPENING : MCIS_OPEN; 13659c9e68d9Seric mci->mci_pid = pid; 13669c9e68d9Seric (void) close(mpvect[0]); 13679c9e68d9Seric mci->mci_out = fdopen(mpvect[1], "w"); 1368335eae58Seric if (mci->mci_out == NULL) 1369335eae58Seric { 1370335eae58Seric syserr("deliver: cannot create mailer output channel, fd=%d", 1371335eae58Seric mpvect[1]); 1372335eae58Seric (void) close(mpvect[1]); 1373335eae58Seric if (clever) 1374335eae58Seric { 1375335eae58Seric (void) close(rpvect[0]); 1376335eae58Seric (void) close(rpvect[1]); 1377335eae58Seric } 1378335eae58Seric rcode = EX_OSERR; 1379335eae58Seric goto give_up; 1380335eae58Seric } 13819c9e68d9Seric if (clever) 13829c9e68d9Seric { 13839c9e68d9Seric (void) close(rpvect[1]); 13849c9e68d9Seric mci->mci_in = fdopen(rpvect[0], "r"); 1385335eae58Seric if (mci->mci_in == NULL) 1386335eae58Seric { 1387335eae58Seric syserr("deliver: cannot create mailer input channel, fd=%d", 1388335eae58Seric mpvect[1]); 1389335eae58Seric (void) close(rpvect[0]); 1390335eae58Seric fclose(mci->mci_out); 1391335eae58Seric mci->mci_out = NULL; 1392335eae58Seric rcode = EX_OSERR; 1393335eae58Seric goto give_up; 1394335eae58Seric } 13959c9e68d9Seric } 13969c9e68d9Seric else 13979c9e68d9Seric { 13989c9e68d9Seric mci->mci_flags |= MCIF_TEMP; 13999c9e68d9Seric mci->mci_in = NULL; 14009c9e68d9Seric } 14019c9e68d9Seric } 14029c9e68d9Seric 14039c9e68d9Seric /* 14049c9e68d9Seric ** If we are in SMTP opening state, send initial protocol. 14059c9e68d9Seric */ 14069c9e68d9Seric 14079c9e68d9Seric if (clever && mci->mci_state != MCIS_CLOSED) 14089c9e68d9Seric { 14099c9e68d9Seric smtpinit(m, mci, e); 14109c9e68d9Seric } 14117b14973fSeric 14127b14973fSeric if (bitset(EF_HAS8BIT, e->e_flags) && bitnset(M_7BITS, m->m_flags)) 14137b14973fSeric mci->mci_flags |= MCIF_CVT8TO7; 14147b14973fSeric else 14157b14973fSeric mci->mci_flags &= ~MCIF_CVT8TO7; 14167b14973fSeric 14179c9e68d9Seric if (tTd(11, 1)) 14189c9e68d9Seric { 14199c9e68d9Seric printf("openmailer: "); 14204052916eSeric mci_dump(mci, FALSE); 14219c9e68d9Seric } 14229c9e68d9Seric 14239c9e68d9Seric if (mci->mci_state != MCIS_OPEN) 1424b31e7f2bSeric { 1425b31e7f2bSeric /* couldn't open the mailer */ 1426b31e7f2bSeric rcode = mci->mci_exitstat; 14272a6bc25bSeric errno = mci->mci_errno; 14289d4a8008Seric #if NAMED_BIND 1429f170942cSeric h_errno = mci->mci_herrno; 1430f170942cSeric #endif 1431b31e7f2bSeric if (rcode == EX_OK) 1432b31e7f2bSeric { 1433b31e7f2bSeric /* shouldn't happen */ 143408b25121Seric syserr("554 deliver: rcode=%d, mci_state=%d, sig=%s", 14356b0f339dSeric rcode, mci->mci_state, firstsig); 1436b31e7f2bSeric rcode = EX_SOFTWARE; 1437b31e7f2bSeric } 1438cb082c5bSeric else if (rcode == EX_TEMPFAIL && curhost != NULL && *curhost != '\0') 143990891494Seric { 144090891494Seric /* try next MX site */ 144190891494Seric goto tryhost; 144290891494Seric } 1443b31e7f2bSeric } 1444b31e7f2bSeric else if (!clever) 1445b31e7f2bSeric { 1446b31e7f2bSeric /* 1447b31e7f2bSeric ** Format and send message. 1448b31e7f2bSeric */ 144915d084d5Seric 14505aa0f353Seric putfromline(mci, e); 1451*6ffc2dd1Seric (*e->e_puthdr)(mci, e->e_header, e); 1452*6ffc2dd1Seric (*e->e_putbody)(mci, e, NULL); 1453b31e7f2bSeric 1454b31e7f2bSeric /* get the exit status */ 1455c9be6216Seric rcode = endmailer(mci, e, pv); 1456134746fbSeric } 1457134746fbSeric else 1458b31e7f2bSeric #ifdef SMTP 1459134746fbSeric { 1460b31e7f2bSeric /* 1461b31e7f2bSeric ** Send the MAIL FROM: protocol 1462b31e7f2bSeric */ 146315d084d5Seric 1464b31e7f2bSeric rcode = smtpmailfrom(m, mci, e); 1465b31e7f2bSeric if (rcode == EX_OK) 146675889e88Seric { 1467ded0d3daSkarels register char *t = tobuf; 1468ded0d3daSkarels register int i; 1469ded0d3daSkarels 1470588cad61Seric /* send the recipient list */ 147163780dbdSeric tobuf[0] = '\0'; 147275889e88Seric for (to = tochain; to != NULL; to = to->q_tchain) 147375889e88Seric { 147463780dbdSeric e->e_to = to->q_paddr; 147515d084d5Seric if ((i = smtprcpt(to, m, mci, e)) != EX_OK) 147675889e88Seric { 1477dee32bf2Seric markfailure(e, to, mci, i); 1478c4e9ac32Seric giveresponse(i, m, mci, ctladdr, xstart, e); 147963780dbdSeric } 148075889e88Seric else 148175889e88Seric { 1482911693bfSbostic *t++ = ','; 1483b31e7f2bSeric for (p = to->q_paddr; *p; *t++ = *p++) 1484b31e7f2bSeric continue; 1485ee39df61Seric *t = '\0'; 1486588cad61Seric } 1487588cad61Seric } 1488588cad61Seric 148963780dbdSeric /* now send the data */ 149063780dbdSeric if (tobuf[0] == '\0') 1491b31e7f2bSeric { 14929c9e68d9Seric rcode = EX_OK; 149363780dbdSeric e->e_to = NULL; 1494b31e7f2bSeric if (bitset(MCIF_CACHED, mci->mci_flags)) 1495b31e7f2bSeric smtprset(m, mci, e); 1496b31e7f2bSeric } 149775889e88Seric else 149875889e88Seric { 149963780dbdSeric e->e_to = tobuf + 1; 150075889e88Seric rcode = smtpdata(m, mci, e); 150163780dbdSeric } 150263780dbdSeric 150363780dbdSeric /* now close the connection */ 1504b31e7f2bSeric if (!bitset(MCIF_CACHED, mci->mci_flags)) 150515d084d5Seric smtpquit(m, mci, e); 150663780dbdSeric } 1507cb082c5bSeric if (rcode != EX_OK && curhost != NULL && *curhost != '\0') 15089c9e68d9Seric { 15099c9e68d9Seric /* try next MX site */ 15109c9e68d9Seric goto tryhost; 15119c9e68d9Seric } 1512c579ef51Seric } 1513b31e7f2bSeric #else /* not SMTP */ 1514a05b3449Sbostic { 151508b25121Seric syserr("554 deliver: need SMTP compiled to use clever mailer"); 1516845e533cSeric rcode = EX_CONFIG; 1517b31e7f2bSeric goto give_up; 1518a05b3449Sbostic } 1519b31e7f2bSeric #endif /* SMTP */ 15209d4a8008Seric #if NAMED_BIND 15212bcc6d2dSeric if (ConfigLevel < 2) 1522912a731aSbostic _res.options |= RES_DEFNAMES | RES_DNSRCH; /* XXX */ 1523134746fbSeric #endif 15245dfc646bSeric 1525b31e7f2bSeric /* arrange a return receipt if requested */ 1526df106f0bSeric if (rcode == EX_OK && e->e_receiptto != NULL && 1527df106f0bSeric bitnset(M_LOCALMAILER, m->m_flags)) 1528b31e7f2bSeric { 1529b31e7f2bSeric e->e_flags |= EF_SENDRECEIPT; 1530b31e7f2bSeric /* do we want to send back more info? */ 1531b31e7f2bSeric } 1532b31e7f2bSeric 1533c77d1c25Seric /* 153463780dbdSeric ** Do final status disposal. 153563780dbdSeric ** We check for something in tobuf for the SMTP case. 1536c77d1c25Seric ** If we got a temporary failure, arrange to queue the 1537c77d1c25Seric ** addressees. 1538c77d1c25Seric */ 1539c77d1c25Seric 1540b31e7f2bSeric give_up: 154163780dbdSeric if (tobuf[0] != '\0') 1542c4e9ac32Seric giveresponse(rcode, m, mci, ctladdr, xstart, e); 1543772e6e50Seric for (to = tochain; to != NULL; to = to->q_tchain) 1544b31e7f2bSeric { 1545dde5acadSeric if (rcode != EX_OK) 1546dee32bf2Seric markfailure(e, to, mci, rcode); 1547dde5acadSeric else 1548655518ecSeric { 1549dde5acadSeric to->q_flags |= QSENT; 15509ff40499Seric to->q_statdate = curtime(); 1551655518ecSeric e->e_nsent++; 15529447f5ceSeric if (bitnset(M_LOCALMAILER, m->m_flags) && 15539447f5ceSeric (e->e_receiptto != NULL || 15549447f5ceSeric bitset(QPINGONSUCCESS, to->q_flags))) 1555df106f0bSeric { 15569447f5ceSeric to->q_flags |= QREPORT; 1557df106f0bSeric fprintf(e->e_xfp, "%s... Successfully delivered\n", 1558df106f0bSeric to->q_paddr); 1559df106f0bSeric } 1560655518ecSeric } 1561b31e7f2bSeric } 1562b31e7f2bSeric 1563b31e7f2bSeric /* 1564b31e7f2bSeric ** Restore state and return. 1565b31e7f2bSeric */ 1566c77d1c25Seric 15677febfd66Seric #ifdef XDEBUG 15687febfd66Seric { 15697febfd66Seric char wbuf[MAXLINE]; 15707febfd66Seric 15717febfd66Seric /* make absolutely certain 0, 1, and 2 are in use */ 157244622ea3Seric sprintf(wbuf, "%s... end of deliver(%s)", 157344622ea3Seric e->e_to == NULL ? "NO-TO-LIST" : e->e_to, 157444622ea3Seric m->m_name); 15757febfd66Seric checkfd012(wbuf); 15767febfd66Seric } 15777febfd66Seric #endif 15787febfd66Seric 157935490626Seric errno = 0; 1580588cad61Seric define('g', (char *) NULL, e); 15815826d9d3Seric return (rcode); 158225a99e2eSeric } 15835dfc646bSeric /* 158483b7ddc9Seric ** MARKFAILURE -- mark a failure on a specific address. 158583b7ddc9Seric ** 158683b7ddc9Seric ** Parameters: 158783b7ddc9Seric ** e -- the envelope we are sending. 158883b7ddc9Seric ** q -- the address to mark. 1589dee32bf2Seric ** mci -- mailer connection information. 159083b7ddc9Seric ** rcode -- the code signifying the particular failure. 159183b7ddc9Seric ** 159283b7ddc9Seric ** Returns: 159383b7ddc9Seric ** none. 159483b7ddc9Seric ** 159583b7ddc9Seric ** Side Effects: 159683b7ddc9Seric ** marks the address (and possibly the envelope) with the 159783b7ddc9Seric ** failure so that an error will be returned or 159883b7ddc9Seric ** the message will be queued, as appropriate. 159983b7ddc9Seric */ 160083b7ddc9Seric 1601dee32bf2Seric markfailure(e, q, mci, rcode) 160283b7ddc9Seric register ENVELOPE *e; 160383b7ddc9Seric register ADDRESS *q; 1604dee32bf2Seric register MCI *mci; 160583b7ddc9Seric int rcode; 160683b7ddc9Seric { 1607dee32bf2Seric char *stat = NULL; 160819c47125Seric 1609d5aafa3cSeric switch (rcode) 1610d5aafa3cSeric { 1611d5aafa3cSeric case EX_OK: 1612d5aafa3cSeric break; 1613d5aafa3cSeric 1614d5aafa3cSeric case EX_TEMPFAIL: 1615d5aafa3cSeric case EX_IOERR: 1616d5aafa3cSeric case EX_OSERR: 161783b7ddc9Seric q->q_flags |= QQUEUEUP; 1618d5aafa3cSeric break; 1619d5aafa3cSeric 1620d5aafa3cSeric default: 1621f170942cSeric q->q_flags |= QBADADDR; 1622d5aafa3cSeric break; 1623d5aafa3cSeric } 1624dee32bf2Seric 1625dee32bf2Seric if (q->q_status == NULL && mci != NULL) 1626dee32bf2Seric q->q_status = mci->mci_status; 1627dee32bf2Seric switch (rcode) 1628dee32bf2Seric { 1629dee32bf2Seric case EX_USAGE: 1630dee32bf2Seric stat = "550"; 1631dee32bf2Seric break; 1632dee32bf2Seric 1633dee32bf2Seric case EX_DATAERR: 1634dee32bf2Seric stat = "501"; 1635dee32bf2Seric break; 1636dee32bf2Seric 1637dee32bf2Seric case EX_NOINPUT: 1638dee32bf2Seric case EX_NOUSER: 1639dee32bf2Seric case EX_NOHOST: 1640dee32bf2Seric case EX_CANTCREAT: 1641dee32bf2Seric case EX_NOPERM: 1642dee32bf2Seric stat = "550"; 1643dee32bf2Seric break; 1644dee32bf2Seric 1645dee32bf2Seric case EX_UNAVAILABLE: 1646dee32bf2Seric case EX_SOFTWARE: 1647dee32bf2Seric case EX_OSFILE: 1648dee32bf2Seric case EX_PROTOCOL: 1649dee32bf2Seric case EX_CONFIG: 1650dee32bf2Seric stat = "554"; 1651dee32bf2Seric break; 1652dee32bf2Seric 1653dee32bf2Seric case EX_OSERR: 1654dee32bf2Seric case EX_IOERR: 1655dee32bf2Seric stat = "451"; 1656dee32bf2Seric break; 1657dee32bf2Seric 1658dee32bf2Seric case EX_TEMPFAIL: 1659dee32bf2Seric stat = "426"; 1660dee32bf2Seric break; 1661dee32bf2Seric } 1662dee32bf2Seric if (stat != NULL && q->q_status == NULL) 1663dee32bf2Seric q->q_status = stat; 1664dee32bf2Seric 16659447f5ceSeric q->q_statdate = curtime(); 166617877c49Seric if (CurHostName != NULL && CurHostName[0] != '\0') 16679447f5ceSeric q->q_statmta = newstr(CurHostName); 1668dee32bf2Seric if (rcode != EX_OK && q->q_rstatus == NULL) 1669dee32bf2Seric { 1670dee32bf2Seric char buf[30]; 1671dee32bf2Seric 1672dee32bf2Seric (void) sprintf(buf, "%d", rcode); 1673dee32bf2Seric q->q_rstatus = newstr(buf); 1674dee32bf2Seric } 167583b7ddc9Seric } 167683b7ddc9Seric /* 1677c579ef51Seric ** ENDMAILER -- Wait for mailer to terminate. 1678c579ef51Seric ** 1679c579ef51Seric ** We should never get fatal errors (e.g., segmentation 1680c579ef51Seric ** violation), so we report those specially. For other 1681c579ef51Seric ** errors, we choose a status message (into statmsg), 1682c579ef51Seric ** and if it represents an error, we print it. 1683c579ef51Seric ** 1684c579ef51Seric ** Parameters: 1685c579ef51Seric ** pid -- pid of mailer. 1686c9be6216Seric ** e -- the current envelope. 1687c9be6216Seric ** pv -- the parameter vector that invoked the mailer 1688c9be6216Seric ** (for error messages). 1689c579ef51Seric ** 1690c579ef51Seric ** Returns: 1691c579ef51Seric ** exit code of mailer. 1692c579ef51Seric ** 1693c579ef51Seric ** Side Effects: 1694c579ef51Seric ** none. 1695c579ef51Seric */ 1696c579ef51Seric 1697c9be6216Seric endmailer(mci, e, pv) 1698b31e7f2bSeric register MCI *mci; 1699c9be6216Seric register ENVELOPE *e; 1700c9be6216Seric char **pv; 1701c579ef51Seric { 1702588cad61Seric int st; 1703c579ef51Seric 170475889e88Seric /* close any connections */ 170575889e88Seric if (mci->mci_in != NULL) 170676f3d53fSeric (void) xfclose(mci->mci_in, mci->mci_mailer->m_name, "mci_in"); 170775889e88Seric if (mci->mci_out != NULL) 170876f3d53fSeric (void) xfclose(mci->mci_out, mci->mci_mailer->m_name, "mci_out"); 170975889e88Seric mci->mci_in = mci->mci_out = NULL; 171075889e88Seric mci->mci_state = MCIS_CLOSED; 171175889e88Seric 171233db8731Seric /* in the IPC case there is nothing to wait for */ 171375889e88Seric if (mci->mci_pid == 0) 171433db8731Seric return (EX_OK); 171533db8731Seric 171633db8731Seric /* wait for the mailer process to die and collect status */ 171775889e88Seric st = waitfor(mci->mci_pid); 1718588cad61Seric if (st == -1) 171978de67c1Seric { 1720c9be6216Seric syserr("endmailer %s: wait", pv[0]); 1721588cad61Seric return (EX_SOFTWARE); 1722c579ef51Seric } 172333db8731Seric 1724bf9bc890Seric if (WIFEXITED(st)) 1725c579ef51Seric { 1726bf9bc890Seric /* normal death -- return status */ 1727bf9bc890Seric return (WEXITSTATUS(st)); 1728bf9bc890Seric } 1729bf9bc890Seric 1730bf9bc890Seric /* it died a horrid death */ 1731550092c3Seric syserr("451 mailer %s died with signal %o", 1732550092c3Seric mci->mci_mailer->m_name, st); 1733c9be6216Seric 1734c9be6216Seric /* log the arguments */ 17353c930db3Seric if (pv != NULL && e->e_xfp != NULL) 1736c9be6216Seric { 1737c9be6216Seric register char **av; 1738c9be6216Seric 1739c9be6216Seric fprintf(e->e_xfp, "Arguments:"); 1740c9be6216Seric for (av = pv; *av != NULL; av++) 1741c9be6216Seric fprintf(e->e_xfp, " %s", *av); 1742c9be6216Seric fprintf(e->e_xfp, "\n"); 1743c9be6216Seric } 1744c9be6216Seric 17455f73204aSeric ExitStat = EX_TEMPFAIL; 17465f73204aSeric return (EX_TEMPFAIL); 1747c579ef51Seric } 1748c579ef51Seric /* 174925a99e2eSeric ** GIVERESPONSE -- Interpret an error response from a mailer 175025a99e2eSeric ** 175125a99e2eSeric ** Parameters: 175225a99e2eSeric ** stat -- the status code from the mailer (high byte 175325a99e2eSeric ** only; core dumps must have been taken care of 175425a99e2eSeric ** already). 175581161401Seric ** m -- the mailer info for this mailer. 175681161401Seric ** mci -- the mailer connection info -- can be NULL if the 175781161401Seric ** response is given before the connection is made. 17584dee0003Seric ** ctladdr -- the controlling address for the recipient 17594dee0003Seric ** address(es). 1760c4e9ac32Seric ** xstart -- the transaction start time, for computing 1761c4e9ac32Seric ** transaction delays. 176281161401Seric ** e -- the current envelope. 176325a99e2eSeric ** 176425a99e2eSeric ** Returns: 1765db8841e9Seric ** none. 176625a99e2eSeric ** 176725a99e2eSeric ** Side Effects: 1768c1f9df2cSeric ** Errors may be incremented. 176925a99e2eSeric ** ExitStat may be set. 177025a99e2eSeric */ 177125a99e2eSeric 1772c4e9ac32Seric giveresponse(stat, m, mci, ctladdr, xstart, e) 177325a99e2eSeric int stat; 1774588cad61Seric register MAILER *m; 177581161401Seric register MCI *mci; 17764dee0003Seric ADDRESS *ctladdr; 1777c4e9ac32Seric time_t xstart; 1778198d9be0Seric ENVELOPE *e; 177925a99e2eSeric { 17809c16475dSeric register const char *statmsg; 178125a99e2eSeric extern char *SysExMsg[]; 178225a99e2eSeric register int i; 1783d4bd8f0eSbostic extern int N_SysEx; 1784198d9be0Seric char buf[MAXLINE]; 178525a99e2eSeric 178613bbc08cSeric /* 178713bbc08cSeric ** Compute status message from code. 178813bbc08cSeric */ 178913bbc08cSeric 179025a99e2eSeric i = stat - EX__BASE; 1791588cad61Seric if (stat == 0) 17926fe8c3bcSeric { 1793588cad61Seric statmsg = "250 Sent"; 1794ce5531bdSeric if (e->e_statmsg != NULL) 17956fe8c3bcSeric { 1796ce5531bdSeric (void) sprintf(buf, "%s (%s)", statmsg, e->e_statmsg); 17976fe8c3bcSeric statmsg = buf; 17986fe8c3bcSeric } 17996fe8c3bcSeric } 1800588cad61Seric else if (i < 0 || i > N_SysEx) 1801588cad61Seric { 1802588cad61Seric (void) sprintf(buf, "554 unknown mailer error %d", stat); 1803588cad61Seric stat = EX_UNAVAILABLE; 1804588cad61Seric statmsg = buf; 1805588cad61Seric } 1806198d9be0Seric else if (stat == EX_TEMPFAIL) 1807198d9be0Seric { 18087d55540cSeric (void) strcpy(buf, SysExMsg[i] + 1); 18099d4a8008Seric #if NAMED_BIND 1810f28da541Smiriam if (h_errno == TRY_AGAIN) 18114d50702aSeric statmsg = errstring(h_errno+E_DNSBASE); 1812f28da541Smiriam else 1813d4bd8f0eSbostic #endif 1814f28da541Smiriam { 18158557d168Seric if (errno != 0) 1816d87e85f3Seric statmsg = errstring(errno); 1817d87e85f3Seric else 1818d87e85f3Seric { 1819d87e85f3Seric #ifdef SMTP 1820d87e85f3Seric statmsg = SmtpError; 18216c2c3107Seric #else /* SMTP */ 1822d87e85f3Seric statmsg = NULL; 18236c2c3107Seric #endif /* SMTP */ 1824d87e85f3Seric } 1825f28da541Smiriam } 1826d87e85f3Seric if (statmsg != NULL && statmsg[0] != '\0') 1827d87e85f3Seric { 182887c9b3e7Seric (void) strcat(buf, ": "); 1829d87e85f3Seric (void) strcat(buf, statmsg); 18308557d168Seric } 1831198d9be0Seric statmsg = buf; 1832198d9be0Seric } 18339d4a8008Seric #if NAMED_BIND 1834f170942cSeric else if (stat == EX_NOHOST && h_errno != 0) 1835f170942cSeric { 18364d50702aSeric statmsg = errstring(h_errno + E_DNSBASE); 1837862934b2Seric (void) sprintf(buf, "%s (%s)", SysExMsg[i] + 1, statmsg); 1838f170942cSeric statmsg = buf; 1839f170942cSeric } 1840f170942cSeric #endif 184125a99e2eSeric else 1842d87e85f3Seric { 184325a99e2eSeric statmsg = SysExMsg[i]; 18447d55540cSeric if (*statmsg++ == ':') 18457d55540cSeric { 18467d55540cSeric (void) sprintf(buf, "%s: %s", statmsg, errstring(errno)); 18477d55540cSeric statmsg = buf; 18487d55540cSeric } 1849d87e85f3Seric } 1850588cad61Seric 1851588cad61Seric /* 1852588cad61Seric ** Print the message as appropriate 1853588cad61Seric */ 1854588cad61Seric 1855198d9be0Seric if (stat == EX_OK || stat == EX_TEMPFAIL) 1856df106f0bSeric { 1857df106f0bSeric extern char MsgBuf[]; 1858df106f0bSeric 18591f96bd0bSeric message("%s", &statmsg[4]); 1860df106f0bSeric if (stat == EX_TEMPFAIL && e->e_xfp != NULL) 1861df106f0bSeric fprintf(e->e_xfp, "%s\n", &MsgBuf[4]); 1862df106f0bSeric } 186325a99e2eSeric else 186425a99e2eSeric { 1865862934b2Seric char mbuf[8]; 1866862934b2Seric 1867c1f9df2cSeric Errors++; 1868862934b2Seric sprintf(mbuf, "%.3s %%s", statmsg); 1869862934b2Seric usrerr(mbuf, &statmsg[4]); 187025a99e2eSeric } 187125a99e2eSeric 187225a99e2eSeric /* 187325a99e2eSeric ** Final cleanup. 187425a99e2eSeric ** Log a record of the transaction. Compute the new 187525a99e2eSeric ** ExitStat -- if we already had an error, stick with 187625a99e2eSeric ** that. 187725a99e2eSeric */ 187825a99e2eSeric 18792f624c86Seric if (LogLevel > ((stat == EX_TEMPFAIL) ? 8 : (stat == EX_OK) ? 7 : 6)) 1880c4e9ac32Seric logdelivery(m, mci, &statmsg[4], ctladdr, xstart, e); 1881eb238f8cSeric 18825d3f0ed4Seric if (tTd(11, 2)) 18835d3f0ed4Seric printf("giveresponse: stat=%d, e->e_message=%s\n", 18842c8ac7e0Seric stat, e->e_message == NULL ? "<NULL>" : e->e_message); 18855d3f0ed4Seric 1886eb238f8cSeric if (stat != EX_TEMPFAIL) 1887eb238f8cSeric setstat(stat); 18881097d4c9Seric if (stat != EX_OK && (stat != EX_TEMPFAIL || e->e_message == NULL)) 1889198d9be0Seric { 1890198d9be0Seric if (e->e_message != NULL) 1891198d9be0Seric free(e->e_message); 1892198d9be0Seric e->e_message = newstr(&statmsg[4]); 1893198d9be0Seric } 18948557d168Seric errno = 0; 18959d4a8008Seric #if NAMED_BIND 1896f28da541Smiriam h_errno = 0; 1897d4bd8f0eSbostic #endif 1898eb238f8cSeric } 1899eb238f8cSeric /* 1900eb238f8cSeric ** LOGDELIVERY -- log the delivery in the system log 1901eb238f8cSeric ** 19022c9b4f99Seric ** Care is taken to avoid logging lines that are too long, because 19032c9b4f99Seric ** some versions of syslog have an unfortunate proclivity for core 19042c9b4f99Seric ** dumping. This is a hack, to be sure, that is at best empirical. 19052c9b4f99Seric ** 1906eb238f8cSeric ** Parameters: 190781161401Seric ** m -- the mailer info. Can be NULL for initial queue. 190881161401Seric ** mci -- the mailer connection info -- can be NULL if the 190981161401Seric ** log is occuring when no connection is active. 191081161401Seric ** stat -- the message to print for the status. 19114dee0003Seric ** ctladdr -- the controlling address for the to list. 1912c4e9ac32Seric ** xstart -- the transaction start time, used for 1913c4e9ac32Seric ** computing transaction delay. 191481161401Seric ** e -- the current envelope. 1915eb238f8cSeric ** 1916eb238f8cSeric ** Returns: 1917eb238f8cSeric ** none 1918eb238f8cSeric ** 1919eb238f8cSeric ** Side Effects: 1920eb238f8cSeric ** none 1921eb238f8cSeric */ 1922eb238f8cSeric 1923c4e9ac32Seric logdelivery(m, mci, stat, ctladdr, xstart, e) 192481161401Seric MAILER *m; 192581161401Seric register MCI *mci; 1926eb238f8cSeric char *stat; 19274dee0003Seric ADDRESS *ctladdr; 1928c4e9ac32Seric time_t xstart; 1929b31e7f2bSeric register ENVELOPE *e; 19305cf56be3Seric { 1931eb238f8cSeric # ifdef LOG 19324dee0003Seric register char *bp; 19332c9b4f99Seric register char *p; 19342c9b4f99Seric int l; 1935d6acf3eeSeric char buf[512]; 19369507d1f9Seric 19373a100e8bSeric # if (SYSLOG_BUFSIZE) >= 256 19384dee0003Seric bp = buf; 19394dee0003Seric if (ctladdr != NULL) 19404dee0003Seric { 19414dee0003Seric strcpy(bp, ", ctladdr="); 1942f62f08c7Seric strcat(bp, shortenstring(ctladdr->q_paddr, 83)); 19434dee0003Seric bp += strlen(bp); 19444dee0003Seric if (bitset(QGOODUID, ctladdr->q_flags)) 19454dee0003Seric { 19464dee0003Seric (void) sprintf(bp, " (%d/%d)", 19474dee0003Seric ctladdr->q_uid, ctladdr->q_gid); 19484dee0003Seric bp += strlen(bp); 19494dee0003Seric } 19504dee0003Seric } 19514dee0003Seric 1952c4e9ac32Seric sprintf(bp, ", delay=%s", pintvl(curtime() - e->e_ctime, TRUE)); 19534dee0003Seric bp += strlen(bp); 195481161401Seric 1955c4e9ac32Seric if (xstart != (time_t) 0) 1956c4e9ac32Seric { 1957c4e9ac32Seric sprintf(bp, ", xdelay=%s", pintvl(curtime() - xstart, TRUE)); 1958c4e9ac32Seric bp += strlen(bp); 1959c4e9ac32Seric } 1960c4e9ac32Seric 196148ed5d33Seric if (m != NULL) 196271ff6caaSeric { 19634dee0003Seric (void) strcpy(bp, ", mailer="); 19644dee0003Seric (void) strcat(bp, m->m_name); 19654dee0003Seric bp += strlen(bp); 196671ff6caaSeric } 196748ed5d33Seric 196848ed5d33Seric if (mci != NULL && mci->mci_host != NULL) 196971ff6caaSeric { 197071ff6caaSeric # ifdef DAEMON 1971e2f2f828Seric extern SOCKADDR CurHostAddr; 197248ed5d33Seric # endif 197371ff6caaSeric 19744dee0003Seric (void) strcpy(bp, ", relay="); 19754dee0003Seric (void) strcat(bp, mci->mci_host); 197648ed5d33Seric 197748ed5d33Seric # ifdef DAEMON 19782bdfc6b9Seric (void) strcat(bp, " ["); 19794dee0003Seric (void) strcat(bp, anynet_ntoa(&CurHostAddr)); 19802bdfc6b9Seric (void) strcat(bp, "]"); 198171ff6caaSeric # endif 198271ff6caaSeric } 1983bcb9b028Seric else if (strcmp(stat, "queued") != 0) 198448ed5d33Seric { 198548ed5d33Seric char *p = macvalue('h', e); 19869507d1f9Seric 198748ed5d33Seric if (p != NULL && p[0] != '\0') 198848ed5d33Seric { 19894dee0003Seric (void) strcpy(bp, ", relay="); 19904dee0003Seric (void) strcat(bp, p); 199148ed5d33Seric } 199248ed5d33Seric } 1993cb082c5bSeric bp += strlen(bp); 1994d6acf3eeSeric 19953a100e8bSeric #define STATLEN (((SYSLOG_BUFSIZE) - 100) / 4) 19963a100e8bSeric #if (STATLEN) < 63 19973a100e8bSeric # undef STATLEN 19983a100e8bSeric # define STATLEN 63 19993a100e8bSeric #endif 20003a100e8bSeric #if (STATLEN) > 203 20013a100e8bSeric # undef STATLEN 20023a100e8bSeric # define STATLEN 203 20033a100e8bSeric #endif 20043a100e8bSeric 20053a100e8bSeric if ((bp - buf) > (sizeof buf - ((STATLEN) + 20))) 20062c9b4f99Seric { 20072c9b4f99Seric /* desperation move -- truncate data */ 20083a100e8bSeric bp = buf + sizeof buf - ((STATLEN) + 17); 20092c9b4f99Seric strcpy(bp, "..."); 20102c9b4f99Seric bp += 3; 20112c9b4f99Seric } 20122c9b4f99Seric 20132c9b4f99Seric (void) strcpy(bp, ", stat="); 20142c9b4f99Seric bp += strlen(bp); 20153a100e8bSeric 20163a100e8bSeric (void) strcpy(bp, shortenstring(stat, (STATLEN))); 20172c9b4f99Seric 20182c9b4f99Seric l = SYSLOG_BUFSIZE - 100 - strlen(buf); 20192c9b4f99Seric p = e->e_to; 20202c9b4f99Seric while (strlen(p) >= l) 20212c9b4f99Seric { 20222c9b4f99Seric register char *q = strchr(p + l, ','); 20232c9b4f99Seric 20242a1b6b73Seric if (q == NULL) 20252c9b4f99Seric break; 20262c9b4f99Seric syslog(LOG_INFO, "%s: to=%.*s [more]%s", 20272c9b4f99Seric e->e_id, ++q - p, p, buf); 20282c9b4f99Seric p = q; 20292c9b4f99Seric } 20302c9b4f99Seric syslog(LOG_INFO, "%s: to=%s%s", e->e_id, p, buf); 20313a100e8bSeric 20323a100e8bSeric # else /* we have a very short log buffer size */ 20333a100e8bSeric 203427607809Seric l = SYSLOG_BUFSIZE - 85; 20353a100e8bSeric p = e->e_to; 20363a100e8bSeric while (strlen(p) >= l) 20373a100e8bSeric { 20383a100e8bSeric register char *q = strchr(p + l, ','); 20393a100e8bSeric 20403a100e8bSeric if (q == NULL) 20413a100e8bSeric break; 20423a100e8bSeric syslog(LOG_INFO, "%s: to=%.*s [more]", 20433a100e8bSeric e->e_id, ++q - p, p); 20443a100e8bSeric p = q; 20453a100e8bSeric } 20463a100e8bSeric syslog(LOG_INFO, "%s: to=%s", e->e_id, p); 20473a100e8bSeric 20483a100e8bSeric if (ctladdr != NULL) 20493a100e8bSeric { 20503a100e8bSeric bp = buf; 20513a100e8bSeric strcpy(buf, "ctladdr="); 20523a100e8bSeric bp += strlen(buf); 20533a100e8bSeric strcpy(bp, shortenstring(ctladdr->q_paddr, 83)); 20543a100e8bSeric bp += strlen(buf); 20553a100e8bSeric if (bitset(QGOODUID, ctladdr->q_flags)) 20563a100e8bSeric { 20573a100e8bSeric (void) sprintf(bp, " (%d/%d)", 20583a100e8bSeric ctladdr->q_uid, ctladdr->q_gid); 20593a100e8bSeric bp += strlen(bp); 20603a100e8bSeric } 20613a100e8bSeric syslog(LOG_INFO, "%s: %s", e->e_id, buf); 20623a100e8bSeric } 20634e797715Seric bp = buf; 20644e797715Seric sprintf(bp, "delay=%s", pintvl(curtime() - e->e_ctime, TRUE)); 20654e797715Seric bp += strlen(bp); 2066c4e9ac32Seric if (xstart != (time_t) 0) 2067c4e9ac32Seric { 2068c4e9ac32Seric sprintf(bp, ", xdelay=%s", pintvl(curtime() - xstart, TRUE)); 2069c4e9ac32Seric bp += strlen(bp); 2070c4e9ac32Seric } 20713a100e8bSeric 20723a100e8bSeric if (m != NULL) 20734e797715Seric { 20744e797715Seric sprintf(bp, ", mailer=%s", m->m_name); 20754e797715Seric bp += strlen(bp); 20764e797715Seric } 2077b056abd0Seric syslog(LOG_INFO, "%s: %s", e->e_id, buf); 20783a100e8bSeric 2079b056abd0Seric buf[0] = '\0'; 20803a100e8bSeric if (mci != NULL && mci->mci_host != NULL) 20813a100e8bSeric { 20823a100e8bSeric # ifdef DAEMON 20833a100e8bSeric extern SOCKADDR CurHostAddr; 20843a100e8bSeric # endif 20853a100e8bSeric 2086d2ece200Seric sprintf(buf, "relay=%s", mci->mci_host); 20873a100e8bSeric 20883a100e8bSeric # ifdef DAEMON 2089b056abd0Seric (void) strcat(buf, " ["); 2090b056abd0Seric (void) strcat(buf, anynet_ntoa(&CurHostAddr)); 2091b056abd0Seric (void) strcat(buf, "]"); 20923a100e8bSeric # endif 20933a100e8bSeric } 2094bcb9b028Seric else if (strcmp(stat, "queued") != 0) 20953a100e8bSeric { 20963a100e8bSeric char *p = macvalue('h', e); 20973a100e8bSeric 20983a100e8bSeric if (p != NULL && p[0] != '\0') 2099d2ece200Seric sprintf(buf, "relay=%s", p); 21003a100e8bSeric } 2101b056abd0Seric if (buf[0] != '\0') 21024e797715Seric syslog(LOG_INFO, "%s: %s", e->e_id, buf); 21033a100e8bSeric 21043a100e8bSeric syslog(LOG_INFO, "%s: stat=%s", e->e_id, shortenstring(stat, 63)); 21053a100e8bSeric # endif /* short log buffer */ 21066c2c3107Seric # endif /* LOG */ 210725a99e2eSeric } 210825a99e2eSeric /* 210951552439Seric ** PUTFROMLINE -- output a UNIX-style from line (or whatever) 211025a99e2eSeric ** 211151552439Seric ** This can be made an arbitrary message separator by changing $l 211251552439Seric ** 21139b6c17a6Seric ** One of the ugliest hacks seen by human eyes is contained herein: 21149b6c17a6Seric ** UUCP wants those stupid "remote from <host>" lines. Why oh why 21159b6c17a6Seric ** does a well-meaning programmer such as myself have to deal with 21169b6c17a6Seric ** this kind of antique garbage???? 211725a99e2eSeric ** 211825a99e2eSeric ** Parameters: 21195aa0f353Seric ** mci -- the connection information. 21205aa0f353Seric ** e -- the envelope. 212125a99e2eSeric ** 212225a99e2eSeric ** Returns: 212351552439Seric ** none 212425a99e2eSeric ** 212525a99e2eSeric ** Side Effects: 212651552439Seric ** outputs some text to fp. 212725a99e2eSeric */ 212825a99e2eSeric 21295aa0f353Seric putfromline(mci, e) 21305aa0f353Seric register MCI *mci; 2131b31e7f2bSeric ENVELOPE *e; 213225a99e2eSeric { 21332bc47524Seric char *template = "\201l\n"; 213451552439Seric char buf[MAXLINE]; 213525a99e2eSeric 21365aa0f353Seric if (bitnset(M_NHDR, mci->mci_mailer->m_flags)) 213751552439Seric return; 213813bbc08cSeric 21392c7e1b8dSeric # ifdef UGLYUUCP 21405aa0f353Seric if (bitnset(M_UGLYUUCP, mci->mci_mailer->m_flags)) 214174b6e67bSeric { 2142ea09d6edSeric char *bang; 2143ea09d6edSeric char xbuf[MAXLINE]; 214474b6e67bSeric 2145ee4b0922Seric expand("\201g", buf, &buf[sizeof buf - 1], e); 21466c2c3107Seric bang = strchr(buf, '!'); 214774b6e67bSeric if (bang == NULL) 214834fcca25Seric { 214934fcca25Seric errno = 0; 215034fcca25Seric syserr("554 No ! in UUCP From address! (%s given)", buf); 215134fcca25Seric } 215274b6e67bSeric else 2153588cad61Seric { 2154ea09d6edSeric *bang++ = '\0'; 21552bc47524Seric (void) sprintf(xbuf, "From %s \201d remote from %s\n", bang, buf); 2156ea09d6edSeric template = xbuf; 215774b6e67bSeric } 2158588cad61Seric } 21596c2c3107Seric # endif /* UGLYUUCP */ 2160b31e7f2bSeric expand(template, buf, &buf[sizeof buf - 1], e); 21615aa0f353Seric putline(buf, mci); 2162bc6e2962Seric } 2163bc6e2962Seric /* 216451552439Seric ** PUTBODY -- put the body of a message. 216551552439Seric ** 216651552439Seric ** Parameters: 21675aa0f353Seric ** mci -- the connection information. 21689a6a5f55Seric ** e -- the envelope to put out. 216903c02fdeSeric ** separator -- if non-NULL, a message separator that must 217003c02fdeSeric ** not be permitted in the resulting message. 217151552439Seric ** 217251552439Seric ** Returns: 217351552439Seric ** none. 217451552439Seric ** 217551552439Seric ** Side Effects: 217651552439Seric ** The message is written onto fp. 217751552439Seric */ 217851552439Seric 21798d0f8cdfSeric /* values for output state variable */ 21808d0f8cdfSeric #define OS_HEAD 0 /* at beginning of line */ 21818d0f8cdfSeric #define OS_CR 1 /* read a carriage return */ 21828d0f8cdfSeric #define OS_INLINE 2 /* putting rest of line */ 21838d0f8cdfSeric 2184*6ffc2dd1Seric putbody(mci, e, separator) 21855aa0f353Seric register MCI *mci; 21869a6a5f55Seric register ENVELOPE *e; 218703c02fdeSeric char *separator; 218851552439Seric { 218977b52738Seric char buf[MAXLINE]; 219051552439Seric 219151552439Seric /* 219251552439Seric ** Output the body of the message 219351552439Seric */ 219451552439Seric 21955737cedfSeric if (e->e_dfp == NULL && e->e_df != NULL) 21969a6a5f55Seric { 21979a6a5f55Seric e->e_dfp = fopen(e->e_df, "r"); 21989a6a5f55Seric if (e->e_dfp == NULL) 21998f9146b0Srick syserr("putbody: Cannot open %s for %s from %s", 2200e76a6a8fSeric e->e_df, e->e_to, e->e_from.q_paddr); 22019a6a5f55Seric } 22025737cedfSeric if (e->e_dfp == NULL) 2203a6ce3008Seric { 2204a6ce3008Seric if (bitset(MCIF_INHEADER, mci->mci_flags)) 2205a6ce3008Seric { 2206a6ce3008Seric putline("", mci); 2207a6ce3008Seric mci->mci_flags &= ~MCIF_INHEADER; 2208a6ce3008Seric } 22095aa0f353Seric putline("<<< No Message Collected >>>", mci); 22108d0f8cdfSeric goto endofmessage; 22119a6a5f55Seric } 22125737cedfSeric if (e->e_dfino == (ino_t) 0) 2213519e7d80Seric { 2214519e7d80Seric struct stat stbuf; 2215519e7d80Seric 2216519e7d80Seric if (fstat(fileno(e->e_dfp), &stbuf) < 0) 2217519e7d80Seric e->e_dfino = -1; 2218519e7d80Seric else 2219e2ea87bcSeric { 2220e2ea87bcSeric e->e_dfdev = stbuf.st_dev; 2221519e7d80Seric e->e_dfino = stbuf.st_ino; 2222519e7d80Seric } 2223e2ea87bcSeric } 22249a6a5f55Seric rewind(e->e_dfp); 2225a6ce3008Seric 2226a6ce3008Seric if (bitset(MCIF_CVT8TO7, mci->mci_flags)) 2227a6ce3008Seric { 2228e2ea87bcSeric /* 2229e2ea87bcSeric ** Do 8 to 7 bit MIME conversion. 2230e2ea87bcSeric */ 2231e2ea87bcSeric 2232e2ea87bcSeric /* make sure it looks like a MIME message */ 2233a6ce3008Seric if (hvalue("MIME-Version", e->e_header) == NULL) 2234a6ce3008Seric putline("MIME-Version: 1.0", mci); 2235e2ea87bcSeric 2236e2ea87bcSeric if (hvalue("Content-Type", e->e_header) == NULL) 2237ec51840eSeric { 2238ec51840eSeric sprintf(buf, "Content-Type: text/plain; charset=%s", 2239dac402a4Seric defcharset(e)); 2240ec51840eSeric putline(buf, mci); 2241ec51840eSeric } 2242e2ea87bcSeric 2243e2ea87bcSeric /* now do the hard work */ 2244a6ce3008Seric mime8to7(mci, e->e_header, e, NULL); 2245a6ce3008Seric } 2246a6ce3008Seric else 2247a6ce3008Seric { 22488d0f8cdfSeric int ostate; 22498d0f8cdfSeric register char *bp; 22508d0f8cdfSeric register char *pbp; 22518d0f8cdfSeric register int c; 22528d0f8cdfSeric int padc; 22538d0f8cdfSeric char *buflim; 22548d0f8cdfSeric int pos; 22558d0f8cdfSeric char peekbuf[10]; 22568d0f8cdfSeric 2257a6ce3008Seric /* we can pass it through unmodified */ 2258a6ce3008Seric if (bitset(MCIF_INHEADER, mci->mci_flags)) 2259a6ce3008Seric { 2260a6ce3008Seric putline("", mci); 2261a6ce3008Seric mci->mci_flags &= ~MCIF_INHEADER; 2262a6ce3008Seric } 22638d0f8cdfSeric 22648d0f8cdfSeric /* determine end of buffer; allow for short mailer lines */ 22658d0f8cdfSeric buflim = &buf[sizeof buf - 1]; 2266a1112e6cSeric if (mci->mci_mailer->m_linelimit > 0 && 2267a1112e6cSeric mci->mci_mailer->m_linelimit < sizeof buf - 1) 22688d0f8cdfSeric buflim = &buf[mci->mci_mailer->m_linelimit - 1]; 22698d0f8cdfSeric 22708d0f8cdfSeric /* copy temp file to output with mapping */ 22718d0f8cdfSeric ostate = OS_HEAD; 22728d0f8cdfSeric bp = buf; 22738d0f8cdfSeric pbp = peekbuf; 22748d0f8cdfSeric while (!ferror(mci->mci_out)) 227524fc8aeeSeric { 22768d0f8cdfSeric register char *xp; 22778d0f8cdfSeric 22788d0f8cdfSeric if (pbp > peekbuf) 22798d0f8cdfSeric c = *--pbp; 22808d0f8cdfSeric else if ((c = fgetc(e->e_dfp)) == EOF) 22818d0f8cdfSeric break; 22828d0f8cdfSeric if (bitset(MCIF_7BIT, mci->mci_flags)) 22838d0f8cdfSeric c &= 0x7f; 22848d0f8cdfSeric switch (ostate) 22858d0f8cdfSeric { 22868d0f8cdfSeric case OS_HEAD: 22878d0f8cdfSeric if (c != '\r' && c != '\n' && bp < buflim) 22888d0f8cdfSeric { 22898d0f8cdfSeric *bp++ = c; 22908d0f8cdfSeric break; 22918d0f8cdfSeric } 22928d0f8cdfSeric 22938d0f8cdfSeric /* check beginning of line for special cases */ 22948d0f8cdfSeric *bp = '\0'; 22958d0f8cdfSeric pos = 0; 22968d0f8cdfSeric padc = EOF; 22975aa0f353Seric if (buf[0] == 'F' && 22985aa0f353Seric bitnset(M_ESCFROM, mci->mci_mailer->m_flags) && 2299d6fa2b58Sbostic strncmp(buf, "From ", 5) == 0) 23008d0f8cdfSeric { 23018d0f8cdfSeric padc = '>'; 23028d0f8cdfSeric } 2303a6ce3008Seric if (buf[0] == '-' && buf[1] == '-' && 2304a6ce3008Seric separator != NULL) 230503c02fdeSeric { 230603c02fdeSeric /* possible separator */ 230703c02fdeSeric int sl = strlen(separator); 230803c02fdeSeric 230903c02fdeSeric if (strncmp(&buf[2], separator, sl) == 0) 23108d0f8cdfSeric padc = ' '; 231103c02fdeSeric } 23128d0f8cdfSeric if (buf[0] == '.' && 23138d0f8cdfSeric bitnset(M_XDOT, mci->mci_mailer->m_flags)) 23148d0f8cdfSeric { 23158d0f8cdfSeric padc = '.'; 23168d0f8cdfSeric } 23178d0f8cdfSeric 23188d0f8cdfSeric /* now copy out saved line */ 23198d0f8cdfSeric if (TrafficLogFile != NULL) 23208d0f8cdfSeric { 23218d0f8cdfSeric fprintf(TrafficLogFile, "%05d >>> ", getpid()); 23228d0f8cdfSeric if (padc != EOF) 23238d0f8cdfSeric fputc(padc, TrafficLogFile); 23248d0f8cdfSeric for (xp = buf; xp < bp; xp++) 23258d0f8cdfSeric fputc(*xp, TrafficLogFile); 23268d0f8cdfSeric if (c == '\n') 23278d0f8cdfSeric fputs(mci->mci_mailer->m_eol, 23288d0f8cdfSeric TrafficLogFile); 23298d0f8cdfSeric } 23308d0f8cdfSeric if (padc != EOF) 23318d0f8cdfSeric { 23328d0f8cdfSeric fputc(padc, mci->mci_out); 23338d0f8cdfSeric pos++; 23348d0f8cdfSeric } 23358d0f8cdfSeric for (xp = buf; xp < bp; xp++) 23368d0f8cdfSeric fputc(*xp, mci->mci_out); 23378d0f8cdfSeric if (c == '\n') 23388d0f8cdfSeric { 23398d0f8cdfSeric fputs(mci->mci_mailer->m_eol, 23408d0f8cdfSeric mci->mci_out); 23418d0f8cdfSeric pos = 0; 23428d0f8cdfSeric } 23438d0f8cdfSeric else 23448d0f8cdfSeric { 23458d0f8cdfSeric pos += bp - buf; 23464565addbSeric if (c != '\r') 23478d0f8cdfSeric *pbp++ = c; 23488d0f8cdfSeric } 23498d0f8cdfSeric bp = buf; 23508d0f8cdfSeric 23518d0f8cdfSeric /* determine next state */ 23528d0f8cdfSeric if (c == '\n') 23538d0f8cdfSeric ostate = OS_HEAD; 23548d0f8cdfSeric else if (c == '\r') 23558d0f8cdfSeric ostate = OS_CR; 23568d0f8cdfSeric else 23578d0f8cdfSeric ostate = OS_INLINE; 23588d0f8cdfSeric continue; 23598d0f8cdfSeric 23608d0f8cdfSeric case OS_CR: 23618d0f8cdfSeric if (c == '\n') 23628d0f8cdfSeric { 23638d0f8cdfSeric /* got CRLF */ 23648d0f8cdfSeric fputs(mci->mci_mailer->m_eol, mci->mci_out); 23658d0f8cdfSeric if (TrafficLogFile != NULL) 23668d0f8cdfSeric { 23678d0f8cdfSeric fputs(mci->mci_mailer->m_eol, 23688d0f8cdfSeric TrafficLogFile); 23698d0f8cdfSeric } 23708d0f8cdfSeric ostate = OS_HEAD; 23718d0f8cdfSeric continue; 23728d0f8cdfSeric } 23738d0f8cdfSeric 23748d0f8cdfSeric /* had a naked carriage return */ 23758d0f8cdfSeric *pbp++ = c; 23768d0f8cdfSeric c = '\r'; 23778270283dSeric goto putch; 23788d0f8cdfSeric 23798d0f8cdfSeric case OS_INLINE: 23808d0f8cdfSeric if (c == '\r') 23818d0f8cdfSeric { 23828d0f8cdfSeric ostate = OS_CR; 23838d0f8cdfSeric continue; 23848d0f8cdfSeric } 23858270283dSeric putch: 2386a1112e6cSeric if (mci->mci_mailer->m_linelimit > 0 && 2387a1112e6cSeric pos > mci->mci_mailer->m_linelimit && 23888d0f8cdfSeric c != '\n') 23898d0f8cdfSeric { 23908d0f8cdfSeric putc('!', mci->mci_out); 23918d0f8cdfSeric fputs(mci->mci_mailer->m_eol, mci->mci_out); 23928d0f8cdfSeric if (TrafficLogFile != NULL) 23938d0f8cdfSeric { 23948d0f8cdfSeric fprintf(TrafficLogFile, "!%s", 23958d0f8cdfSeric mci->mci_mailer->m_eol); 23968d0f8cdfSeric } 23978d0f8cdfSeric ostate = OS_HEAD; 23988d0f8cdfSeric *pbp++ = c; 23998d0f8cdfSeric continue; 24008d0f8cdfSeric } 24018d0f8cdfSeric if (TrafficLogFile != NULL) 24028d0f8cdfSeric fputc(c, TrafficLogFile); 24038d0f8cdfSeric putc(c, mci->mci_out); 24048d0f8cdfSeric pos++; 24054565addbSeric ostate = c == '\n' ? OS_HEAD : OS_INLINE; 24068d0f8cdfSeric break; 24078d0f8cdfSeric } 240824fc8aeeSeric } 2409a6ce3008Seric } 241051552439Seric 24119a6a5f55Seric if (ferror(e->e_dfp)) 241251552439Seric { 2413df106f0bSeric syserr("putbody: %s: read error", e->e_df); 241451552439Seric ExitStat = EX_IOERR; 241551552439Seric } 241651552439Seric 24178d0f8cdfSeric endofmessage: 24180890ba1fSeric /* some mailers want extra blank line at end of message */ 24195aa0f353Seric if (bitnset(M_BLANKEND, mci->mci_mailer->m_flags) && 24205aa0f353Seric buf[0] != '\0' && buf[0] != '\n') 24215aa0f353Seric putline("", mci); 24220890ba1fSeric 24235aa0f353Seric (void) fflush(mci->mci_out); 24245aa0f353Seric if (ferror(mci->mci_out) && errno != EPIPE) 242551552439Seric { 242651552439Seric syserr("putbody: write error"); 242751552439Seric ExitStat = EX_IOERR; 242851552439Seric } 242951552439Seric errno = 0; 243025a99e2eSeric } 243125a99e2eSeric /* 243225a99e2eSeric ** MAILFILE -- Send a message to a file. 243325a99e2eSeric ** 2434f129ec7dSeric ** If the file has the setuid/setgid bits set, but NO execute 2435f129ec7dSeric ** bits, sendmail will try to become the owner of that file 2436f129ec7dSeric ** rather than the real user. Obviously, this only works if 2437f129ec7dSeric ** sendmail runs as root. 2438f129ec7dSeric ** 2439588cad61Seric ** This could be done as a subordinate mailer, except that it 2440588cad61Seric ** is used implicitly to save messages in ~/dead.letter. We 2441588cad61Seric ** view this as being sufficiently important as to include it 2442588cad61Seric ** here. For example, if the system is dying, we shouldn't have 2443588cad61Seric ** to create another process plus some pipes to save the message. 2444588cad61Seric ** 244525a99e2eSeric ** Parameters: 244625a99e2eSeric ** filename -- the name of the file to send to. 24476259796dSeric ** ctladdr -- the controlling address header -- includes 24486259796dSeric ** the userid/groupid to be when sending. 244925a99e2eSeric ** 245025a99e2eSeric ** Returns: 245125a99e2eSeric ** The exit code associated with the operation. 245225a99e2eSeric ** 245325a99e2eSeric ** Side Effects: 245425a99e2eSeric ** none. 245525a99e2eSeric */ 245625a99e2eSeric 2457b31e7f2bSeric mailfile(filename, ctladdr, e) 245825a99e2eSeric char *filename; 24596259796dSeric ADDRESS *ctladdr; 2460b31e7f2bSeric register ENVELOPE *e; 246125a99e2eSeric { 246225a99e2eSeric register FILE *f; 246332d19d43Seric register int pid; 246415d084d5Seric int mode; 246525a99e2eSeric 2466671745f3Seric if (tTd(11, 1)) 2467671745f3Seric { 2468671745f3Seric printf("mailfile %s\n ctladdr=", filename); 2469671745f3Seric printaddr(ctladdr, FALSE); 2470671745f3Seric } 2471671745f3Seric 2472f170942cSeric if (e->e_xfp != NULL) 2473f170942cSeric fflush(e->e_xfp); 2474f170942cSeric 247532d19d43Seric /* 247632d19d43Seric ** Fork so we can change permissions here. 247732d19d43Seric ** Note that we MUST use fork, not vfork, because of 247832d19d43Seric ** the complications of calling subroutines, etc. 247932d19d43Seric */ 248032d19d43Seric 248132d19d43Seric DOFORK(fork); 248232d19d43Seric 248332d19d43Seric if (pid < 0) 248432d19d43Seric return (EX_OSERR); 248532d19d43Seric else if (pid == 0) 248632d19d43Seric { 248732d19d43Seric /* child -- actually write to file */ 2488f129ec7dSeric struct stat stb; 24895aa0f353Seric MCI mcibuf; 2490f129ec7dSeric 24912b9178d3Seric (void) setsignal(SIGINT, SIG_DFL); 24922b9178d3Seric (void) setsignal(SIGHUP, SIG_DFL); 24932b9178d3Seric (void) setsignal(SIGTERM, SIG_DFL); 24943462ad9eSeric (void) umask(OldUmask); 249595f16dc0Seric 2496f129ec7dSeric if (stat(filename, &stb) < 0) 24973a98e7eaSeric stb.st_mode = FileMode; 249815d084d5Seric mode = stb.st_mode; 249995f16dc0Seric 250095f16dc0Seric /* limit the errors to those actually caused in the child */ 250195f16dc0Seric errno = 0; 250295f16dc0Seric ExitStat = EX_OK; 250395f16dc0Seric 2504f129ec7dSeric if (bitset(0111, stb.st_mode)) 2505f129ec7dSeric exit(EX_CANTCREAT); 250619428781Seric if (ctladdr != NULL) 250715d084d5Seric { 250815d084d5Seric /* ignore setuid and setgid bits */ 250915d084d5Seric mode &= ~(S_ISGID|S_ISUID); 251015d084d5Seric } 251115d084d5Seric 25128f9146b0Srick /* we have to open the dfile BEFORE setuid */ 25138f9146b0Srick if (e->e_dfp == NULL && e->e_df != NULL) 25148f9146b0Srick { 25158f9146b0Srick e->e_dfp = fopen(e->e_df, "r"); 251695f16dc0Seric if (e->e_dfp == NULL) 251795f16dc0Seric { 25188f9146b0Srick syserr("mailfile: Cannot open %s for %s from %s", 2519e76a6a8fSeric e->e_df, e->e_to, e->e_from.q_paddr); 25208f9146b0Srick } 25218f9146b0Srick } 25228f9146b0Srick 252315d084d5Seric if (!bitset(S_ISGID, mode) || setgid(stb.st_gid) < 0) 2524e36b99e2Seric { 2525e3c3bea9Seric if (ctladdr != NULL && ctladdr->q_uid != 0) 2526898a126bSbostic (void) initgroups(ctladdr->q_ruser ? 2527898a126bSbostic ctladdr->q_ruser : ctladdr->q_user, 2528898a126bSbostic ctladdr->q_gid); 2529e3c3bea9Seric else if (FileMailer != NULL && FileMailer->m_gid != 0) 2530e3c3bea9Seric (void) initgroups(DefUser, FileMailer->m_gid); 2531e3c3bea9Seric else 2532e3c3bea9Seric (void) initgroups(DefUser, DefGid); 2533e36b99e2Seric } 253415d084d5Seric if (!bitset(S_ISUID, mode) || setuid(stb.st_uid) < 0) 2535e36b99e2Seric { 2536e3c3bea9Seric if (ctladdr != NULL && ctladdr->q_uid != 0) 25376259796dSeric (void) setuid(ctladdr->q_uid); 2538e3c3bea9Seric else if (FileMailer != NULL && FileMailer->m_uid != 0) 2539e3c3bea9Seric (void) setuid(FileMailer->m_uid); 2540e3c3bea9Seric else 2541e3c3bea9Seric (void) setuid(DefUid); 2542e36b99e2Seric } 254395f16dc0Seric FileName = filename; 254495f16dc0Seric LineNumber = 0; 25453a98e7eaSeric f = dfopen(filename, O_WRONLY|O_CREAT|O_APPEND, FileMode); 254625a99e2eSeric if (f == NULL) 254795f16dc0Seric { 2548b6a0de9dSeric message("554 cannot open: %s", errstring(errno)); 254932d19d43Seric exit(EX_CANTCREAT); 255095f16dc0Seric } 255125a99e2eSeric 25525aa0f353Seric bzero(&mcibuf, sizeof mcibuf); 25535aa0f353Seric mcibuf.mci_mailer = FileMailer; 25545aa0f353Seric mcibuf.mci_out = f; 25555aa0f353Seric if (bitnset(M_7BITS, FileMailer->m_flags)) 25565aa0f353Seric mcibuf.mci_flags |= MCIF_7BIT; 25575aa0f353Seric 25585aa0f353Seric putfromline(&mcibuf, e); 2559*6ffc2dd1Seric (*e->e_puthdr)(&mcibuf, e->e_header, e); 2560*6ffc2dd1Seric (*e->e_putbody)(&mcibuf, e, NULL); 25615aa0f353Seric putline("\n", &mcibuf); 256295f16dc0Seric if (ferror(f)) 256395f16dc0Seric { 2564b6a0de9dSeric message("451 I/O error: %s", errstring(errno)); 256595f16dc0Seric setstat(EX_IOERR); 256695f16dc0Seric } 2567ee4b0922Seric (void) xfclose(f, "mailfile", filename); 256832d19d43Seric (void) fflush(stdout); 2569e36b99e2Seric 257027628d59Seric /* reset ISUID & ISGID bits for paranoid systems */ 2571c77d1c25Seric (void) chmod(filename, (int) stb.st_mode); 257295f16dc0Seric exit(ExitStat); 257313bbc08cSeric /*NOTREACHED*/ 257432d19d43Seric } 257532d19d43Seric else 257632d19d43Seric { 257732d19d43Seric /* parent -- wait for exit status */ 2578588cad61Seric int st; 257932d19d43Seric 2580588cad61Seric st = waitfor(pid); 2581bf9bc890Seric if (WIFEXITED(st)) 2582bf9bc890Seric return (WEXITSTATUS(st)); 2583588cad61Seric else 2584b6a0de9dSeric { 2585b6a0de9dSeric syserr("child died on signal %d", st); 2586bf9bc890Seric return (EX_UNAVAILABLE); 2587b6a0de9dSeric } 25888f9146b0Srick /*NOTREACHED*/ 258932d19d43Seric } 259025a99e2eSeric } 2591ea4dc939Seric /* 2592e103b48fSeric ** HOSTSIGNATURE -- return the "signature" for a host. 2593e103b48fSeric ** 2594e103b48fSeric ** The signature describes how we are going to send this -- it 2595e103b48fSeric ** can be just the hostname (for non-Internet hosts) or can be 2596e103b48fSeric ** an ordered list of MX hosts. 2597e103b48fSeric ** 2598e103b48fSeric ** Parameters: 2599e103b48fSeric ** m -- the mailer describing this host. 2600e103b48fSeric ** host -- the host name. 2601e103b48fSeric ** e -- the current envelope. 2602e103b48fSeric ** 2603e103b48fSeric ** Returns: 2604e103b48fSeric ** The signature for this host. 2605e103b48fSeric ** 2606e103b48fSeric ** Side Effects: 2607e103b48fSeric ** Can tweak the symbol table. 2608e103b48fSeric */ 2609e103b48fSeric 2610e103b48fSeric char * 2611e103b48fSeric hostsignature(m, host, e) 2612e103b48fSeric register MAILER *m; 2613e103b48fSeric char *host; 2614e103b48fSeric ENVELOPE *e; 2615e103b48fSeric { 2616e103b48fSeric register char *p; 2617e103b48fSeric register STAB *s; 2618e103b48fSeric int i; 2619e103b48fSeric int len; 26209d4a8008Seric #if NAMED_BIND 2621e103b48fSeric int nmx; 2622e103b48fSeric auto int rcode; 2623bafdc4e5Seric char *hp; 2624bafdc4e5Seric char *endp; 2625516782b4Seric int oldoptions; 2626e103b48fSeric char *mxhosts[MAXMXHOSTS + 1]; 2627e103b48fSeric #endif 2628e103b48fSeric 2629e103b48fSeric /* 2630e103b48fSeric ** Check to see if this uses IPC -- if not, it can't have MX records. 2631e103b48fSeric */ 2632e103b48fSeric 2633e103b48fSeric p = m->m_mailer; 2634e103b48fSeric if (strcmp(p, "[IPC]") != 0 && strcmp(p, "[TCP]") != 0) 2635e103b48fSeric { 2636e103b48fSeric /* just an ordinary mailer */ 2637e103b48fSeric return host; 2638e103b48fSeric } 2639e103b48fSeric 2640e103b48fSeric /* 2641e103b48fSeric ** Look it up in the symbol table. 2642e103b48fSeric */ 2643e103b48fSeric 2644e103b48fSeric s = stab(host, ST_HOSTSIG, ST_ENTER); 2645e103b48fSeric if (s->s_hostsig != NULL) 2646e103b48fSeric return s->s_hostsig; 2647e103b48fSeric 2648e103b48fSeric /* 2649e103b48fSeric ** Not already there -- create a signature. 2650e103b48fSeric */ 2651e103b48fSeric 26529d4a8008Seric #if NAMED_BIND 2653516782b4Seric if (ConfigLevel < 2) 2654516782b4Seric { 2655516782b4Seric oldoptions = _res.options; 2656516782b4Seric _res.options &= ~(RES_DEFNAMES | RES_DNSRCH); /* XXX */ 2657516782b4Seric } 2658516782b4Seric 2659bafdc4e5Seric for (hp = host; hp != NULL; hp = endp) 2660bafdc4e5Seric { 2661bafdc4e5Seric endp = strchr(hp, ':'); 2662bafdc4e5Seric if (endp != NULL) 2663bafdc4e5Seric *endp = '\0'; 2664bafdc4e5Seric 26657bf809e6Seric nmx = getmxrr(hp, mxhosts, TRUE, &rcode); 26667d55540cSeric 2667e103b48fSeric if (nmx <= 0) 2668e103b48fSeric { 2669e103b48fSeric register MCI *mci; 2670e103b48fSeric 2671e103b48fSeric /* update the connection info for this host */ 2672bafdc4e5Seric mci = mci_get(hp, m); 2673e103b48fSeric mci->mci_exitstat = rcode; 2674e103b48fSeric mci->mci_errno = errno; 26759d4a8008Seric #if NAMED_BIND 2676f170942cSeric mci->mci_herrno = h_errno; 2677f170942cSeric #endif 2678e103b48fSeric 2679e103b48fSeric /* and return the original host name as the signature */ 2680bafdc4e5Seric nmx = 1; 2681bafdc4e5Seric mxhosts[0] = hp; 2682e103b48fSeric } 2683e103b48fSeric 2684e103b48fSeric len = 0; 2685e103b48fSeric for (i = 0; i < nmx; i++) 2686e103b48fSeric { 2687e103b48fSeric len += strlen(mxhosts[i]) + 1; 2688e103b48fSeric } 2689bafdc4e5Seric if (s->s_hostsig != NULL) 2690bafdc4e5Seric len += strlen(s->s_hostsig) + 1; 2691bafdc4e5Seric p = xalloc(len); 2692bafdc4e5Seric if (s->s_hostsig != NULL) 2693bafdc4e5Seric { 2694bafdc4e5Seric (void) strcpy(p, s->s_hostsig); 2695bafdc4e5Seric free(s->s_hostsig); 2696bafdc4e5Seric s->s_hostsig = p; 2697bafdc4e5Seric p += strlen(p); 2698bafdc4e5Seric *p++ = ':'; 2699bafdc4e5Seric } 2700bafdc4e5Seric else 2701bafdc4e5Seric s->s_hostsig = p; 2702e103b48fSeric for (i = 0; i < nmx; i++) 2703e103b48fSeric { 2704e103b48fSeric if (i != 0) 2705e103b48fSeric *p++ = ':'; 2706e103b48fSeric strcpy(p, mxhosts[i]); 2707e103b48fSeric p += strlen(p); 2708e103b48fSeric } 2709bafdc4e5Seric if (endp != NULL) 2710bafdc4e5Seric *endp++ = ':'; 2711bafdc4e5Seric } 2712e103b48fSeric makelower(s->s_hostsig); 2713516782b4Seric if (ConfigLevel < 2) 2714516782b4Seric _res.options = oldoptions; 2715e103b48fSeric #else 2716e103b48fSeric /* not using BIND -- the signature is just the host name */ 2717e103b48fSeric s->s_hostsig = host; 2718e103b48fSeric #endif 2719e103b48fSeric if (tTd(17, 1)) 2720e103b48fSeric printf("hostsignature(%s) = %s\n", host, s->s_hostsig); 2721e103b48fSeric return s->s_hostsig; 2722e103b48fSeric } 27239447f5ceSeric /* 27249447f5ceSeric ** SETSTATUS -- set the address status for return messages 27259447f5ceSeric ** 27269447f5ceSeric ** Parameters: 27279447f5ceSeric ** a -- the address to set. 27289447f5ceSeric ** msg -- the text of the message, which must be in standard 27299447f5ceSeric ** SMTP form (3 digits, a space, and a message). 27309447f5ceSeric ** 27319447f5ceSeric ** Returns: 27329447f5ceSeric ** none. 27339447f5ceSeric */ 27349447f5ceSeric 27359447f5ceSeric setstatus(a, msg) 27369447f5ceSeric register ADDRESS *a; 27379447f5ceSeric char *msg; 27389447f5ceSeric { 27399447f5ceSeric char buf[MAXLINE]; 27409447f5ceSeric 2741c3e281c6Seric if (a->q_rstatus != NULL) 2742c3e281c6Seric free(a->q_rstatus); 27439447f5ceSeric if (strlen(msg) > 4) 27449447f5ceSeric { 27459447f5ceSeric register char *p, *q; 27469447f5ceSeric int parenlev = 0; 27479447f5ceSeric 27489447f5ceSeric strncpy(buf, msg, 4); 27499447f5ceSeric p = &buf[4]; 27509447f5ceSeric *p++ = '('; 2751dd8d19eeSeric for (q = &msg[4]; *q != '\0'; q++) 27529447f5ceSeric { 27539447f5ceSeric switch (*q) 27549447f5ceSeric { 27559447f5ceSeric case '(': 27569447f5ceSeric parenlev++; 27579447f5ceSeric break; 27589447f5ceSeric 27599447f5ceSeric case ')': 27609447f5ceSeric if (parenlev > 0) 27619447f5ceSeric parenlev--; 27629447f5ceSeric else 27639447f5ceSeric *p++ = '\\'; 27649447f5ceSeric break; 27659447f5ceSeric } 27669447f5ceSeric *p++ = *q; 27679447f5ceSeric } 27689447f5ceSeric while (parenlev-- >= 0) 27699447f5ceSeric *p++ = ')'; 27709447f5ceSeric *p++ = '\0'; 27719447f5ceSeric msg = buf; 27729447f5ceSeric } 2773c3e281c6Seric a->q_rstatus = newstr(msg); 27749447f5ceSeric } 2775