14227346bSdist /* 20942ea6aSbostic * Copyright (c) 1983 Eric P. Allman 3e70a7521Sbostic * Copyright (c) 1988 Regents of the University of California. 4e70a7521Sbostic * All rights reserved. 5e70a7521Sbostic * 63bc94712Sbostic * %sccs.include.redist.c% 74227346bSdist */ 84227346bSdist 94227346bSdist #ifndef lint 10*0890ba1fSeric static char sccsid[] = "@(#)deliver.c 6.70 (Berkeley) 04/29/93"; 11e70a7521Sbostic #endif /* not lint */ 124227346bSdist 13fcde9cc8Sbostic #include "sendmail.h" 14a8c080f0Seric #include <signal.h> 15f28da541Smiriam #include <netdb.h> 16911693bfSbostic #include <errno.h> 17134746fbSeric #ifdef NAMED_BIND 18912a731aSbostic #include <arpa/nameser.h> 19912a731aSbostic #include <resolv.h> 20134746fbSeric #endif 2125a99e2eSeric 2225a99e2eSeric /* 239c9e68d9Seric ** SENDALL -- actually send all the messages. 249c9e68d9Seric ** 259c9e68d9Seric ** Parameters: 269c9e68d9Seric ** e -- the envelope to send. 279c9e68d9Seric ** mode -- the delivery mode to use. If SM_DEFAULT, use 289c9e68d9Seric ** the current e->e_sendmode. 299c9e68d9Seric ** 309c9e68d9Seric ** Returns: 319c9e68d9Seric ** none. 329c9e68d9Seric ** 339c9e68d9Seric ** Side Effects: 349c9e68d9Seric ** Scans the send lists and sends everything it finds. 359c9e68d9Seric ** Delivers any appropriate error messages. 369c9e68d9Seric ** If we are running in a non-interactive mode, takes the 379c9e68d9Seric ** appropriate action. 389c9e68d9Seric */ 399c9e68d9Seric 409c9e68d9Seric sendall(e, mode) 419c9e68d9Seric ENVELOPE *e; 429c9e68d9Seric char mode; 439c9e68d9Seric { 449c9e68d9Seric register ADDRESS *q; 459c9e68d9Seric char *owner; 469c9e68d9Seric int otherowners; 479c9e68d9Seric register ENVELOPE *ee; 489c9e68d9Seric ENVELOPE *splitenv = NULL; 496103d9b4Seric bool announcequeueup; 509c9e68d9Seric 519c9e68d9Seric /* determine actual delivery mode */ 529c9e68d9Seric if (mode == SM_DEFAULT) 539c9e68d9Seric { 549c9e68d9Seric extern bool shouldqueue(); 559c9e68d9Seric 569c9e68d9Seric mode = e->e_sendmode; 579c9e68d9Seric if (mode != SM_VERIFY && 589c9e68d9Seric shouldqueue(e->e_msgpriority, e->e_ctime)) 599c9e68d9Seric mode = SM_QUEUE; 606103d9b4Seric announcequeueup = mode == SM_QUEUE; 619c9e68d9Seric } 626103d9b4Seric else 636103d9b4Seric announcequeueup = FALSE; 649c9e68d9Seric 659c9e68d9Seric if (tTd(13, 1)) 669c9e68d9Seric { 679c9e68d9Seric printf("\nSENDALL: mode %c, e_from ", mode); 689c9e68d9Seric printaddr(&e->e_from, FALSE); 699c9e68d9Seric printf("sendqueue:\n"); 709c9e68d9Seric printaddr(e->e_sendqueue, TRUE); 719c9e68d9Seric } 729c9e68d9Seric 739c9e68d9Seric /* 749c9e68d9Seric ** Do any preprocessing necessary for the mode we are running. 759c9e68d9Seric ** Check to make sure the hop count is reasonable. 769c9e68d9Seric ** Delete sends to the sender in mailing lists. 779c9e68d9Seric */ 789c9e68d9Seric 799c9e68d9Seric CurEnv = e; 809c9e68d9Seric 819c9e68d9Seric if (e->e_hopcount > MaxHopCount) 829c9e68d9Seric { 839c9e68d9Seric errno = 0; 849c9e68d9Seric syserr("554 too many hops %d (%d max): from %s, to %s", 859c9e68d9Seric e->e_hopcount, MaxHopCount, e->e_from.q_paddr, 869c9e68d9Seric e->e_sendqueue->q_paddr); 879c9e68d9Seric return; 889c9e68d9Seric } 899c9e68d9Seric 90b8004690Seric /* 91b8004690Seric ** Do sender deletion. 92b8004690Seric ** 93b8004690Seric ** If the sender has the QQUEUEUP flag set, skip this. 94b8004690Seric ** This can happen if the name server is hosed when you 95b8004690Seric ** are trying to send mail. The result is that the sender 96b8004690Seric ** is instantiated in the queue as a recipient. 97b8004690Seric */ 98b8004690Seric 99b8004690Seric if (!MeToo && !bitset(QQUEUEUP, e->e_from.q_flags)) 1009c9e68d9Seric { 1019c9e68d9Seric extern ADDRESS *recipient(); 1029c9e68d9Seric 1039c9e68d9Seric if (tTd(13, 5)) 1049c9e68d9Seric { 1059c9e68d9Seric printf("sendall: QDONTSEND "); 1069c9e68d9Seric printaddr(&e->e_from, FALSE); 1079c9e68d9Seric } 1089c9e68d9Seric e->e_from.q_flags |= QDONTSEND; 1099c9e68d9Seric (void) recipient(&e->e_from, &e->e_sendqueue, e); 1109c9e68d9Seric } 1119c9e68d9Seric 112ce5531bdSeric /* 113ce5531bdSeric ** Handle alias owners. 114ce5531bdSeric ** 115ce5531bdSeric ** We scan up the q_alias chain looking for owners. 116ce5531bdSeric ** We discard owners that are the same as the return path. 117ce5531bdSeric */ 118ce5531bdSeric 119ce5531bdSeric for (q = e->e_sendqueue; q != NULL; q = q->q_next) 120ce5531bdSeric { 121ce5531bdSeric register struct address *a; 122ce5531bdSeric 123ce5531bdSeric for (a = q; a != NULL && a->q_owner == NULL; a = a->q_alias) 124ce5531bdSeric continue; 125ce5531bdSeric if (a != NULL) 126ce5531bdSeric q->q_owner = a->q_owner; 127ce5531bdSeric 128ce5531bdSeric if (q->q_owner != NULL && 129ce5531bdSeric !bitset(QDONTSEND, q->q_flags) && 130ce5531bdSeric strcmp(q->q_owner, e->e_from.q_paddr) == 0) 131ce5531bdSeric q->q_owner = NULL; 132ce5531bdSeric } 133ce5531bdSeric 134ce5531bdSeric owner = ""; 135ce5531bdSeric otherowners = 1; 136ce5531bdSeric while (owner != NULL && otherowners > 0) 137ce5531bdSeric { 138ce5531bdSeric owner = NULL; 139ce5531bdSeric otherowners = 0; 140ce5531bdSeric 141ce5531bdSeric for (q = e->e_sendqueue; q != NULL; q = q->q_next) 142ce5531bdSeric { 143ce5531bdSeric if (bitset(QDONTSEND, q->q_flags)) 144ce5531bdSeric continue; 145ce5531bdSeric 146ce5531bdSeric if (q->q_owner != NULL) 147ce5531bdSeric { 148ce5531bdSeric if (owner == NULL) 149ce5531bdSeric owner = q->q_owner; 150ce5531bdSeric else if (owner != q->q_owner) 151ce5531bdSeric { 152ce5531bdSeric if (strcmp(owner, q->q_owner) == 0) 153ce5531bdSeric { 154ce5531bdSeric /* make future comparisons cheap */ 155ce5531bdSeric q->q_owner = owner; 156ce5531bdSeric } 157ce5531bdSeric else 158ce5531bdSeric { 159ce5531bdSeric otherowners++; 160ce5531bdSeric } 161ce5531bdSeric owner = q->q_owner; 162ce5531bdSeric } 163ce5531bdSeric } 164ce5531bdSeric else 165ce5531bdSeric { 166ce5531bdSeric otherowners++; 167ce5531bdSeric } 168ce5531bdSeric } 169ce5531bdSeric 170ce5531bdSeric if (owner != NULL && otherowners > 0) 171ce5531bdSeric { 172ce5531bdSeric extern HDR *copyheader(); 173ce5531bdSeric extern ADDRESS *copyqueue(); 174ce5531bdSeric 175ce5531bdSeric /* 176ce5531bdSeric ** Split this envelope into two. 177ce5531bdSeric */ 178ce5531bdSeric 179ce5531bdSeric ee = (ENVELOPE *) xalloc(sizeof(ENVELOPE)); 180ce5531bdSeric *ee = *e; 181ce5531bdSeric ee->e_id = NULL; 182ce5531bdSeric (void) queuename(ee, '\0'); 183ce5531bdSeric 184ce5531bdSeric if (tTd(13, 1)) 185ce5531bdSeric printf("sendall: split %s into %s\n", 186ce5531bdSeric e->e_id, ee->e_id); 187ce5531bdSeric 188ce5531bdSeric ee->e_header = copyheader(e->e_header); 189ce5531bdSeric ee->e_sendqueue = copyqueue(e->e_sendqueue); 190ce5531bdSeric ee->e_errorqueue = copyqueue(e->e_errorqueue); 191ce5531bdSeric ee->e_flags = e->e_flags & ~(EF_INQUEUE|EF_CLRQUEUE|EF_FATALERRS); 192ce5531bdSeric setsender(owner, ee, NULL, TRUE); 193ce5531bdSeric if (tTd(13, 5)) 194ce5531bdSeric { 195ce5531bdSeric printf("sendall(split): QDONTSEND "); 196ce5531bdSeric printaddr(&ee->e_from, FALSE); 197ce5531bdSeric } 198ce5531bdSeric ee->e_from.q_flags |= QDONTSEND; 199ce5531bdSeric ee->e_dfp = NULL; 200ce5531bdSeric ee->e_xfp = NULL; 201ce5531bdSeric ee->e_lockfp = NULL; 202ce5531bdSeric ee->e_df = NULL; 203ce5531bdSeric ee->e_errormode = EM_MAIL; 204ce5531bdSeric ee->e_sibling = splitenv; 205ce5531bdSeric splitenv = ee; 206ce5531bdSeric 207ce5531bdSeric for (q = e->e_sendqueue; q != NULL; q = q->q_next) 208ce5531bdSeric if (q->q_owner == owner) 209ce5531bdSeric q->q_flags |= QDONTSEND; 210ce5531bdSeric for (q = ee->e_sendqueue; q != NULL; q = q->q_next) 211ce5531bdSeric if (q->q_owner != owner) 212ce5531bdSeric q->q_flags |= QDONTSEND; 213ce5531bdSeric 214ce5531bdSeric if (e->e_df != NULL && mode != SM_VERIFY) 215ce5531bdSeric { 216ce5531bdSeric ee->e_dfp = NULL; 217ce5531bdSeric ee->e_df = newstr(queuename(ee, 'd')); 218ce5531bdSeric if (link(e->e_df, ee->e_df) < 0) 219ce5531bdSeric { 220ce5531bdSeric syserr("sendall: link(%s, %s)", 221ce5531bdSeric e->e_df, ee->e_df); 222ce5531bdSeric } 223ce5531bdSeric } 224ce5531bdSeric 225ce5531bdSeric if (mode != SM_VERIFY) 226ce5531bdSeric openxscript(ee); 227ce5531bdSeric #ifdef LOG 228ce5531bdSeric if (LogLevel > 4) 229ce5531bdSeric syslog(LOG_INFO, "%s: clone %s", 230ce5531bdSeric ee->e_id, e->e_id); 231ce5531bdSeric #endif 232ce5531bdSeric } 233ce5531bdSeric } 234ce5531bdSeric 235ce5531bdSeric if (owner != NULL) 236ce5531bdSeric { 237ce5531bdSeric setsender(owner, e, NULL, TRUE); 238ce5531bdSeric if (tTd(13, 5)) 239ce5531bdSeric { 240ce5531bdSeric printf("sendall(owner): QDONTSEND "); 241ce5531bdSeric printaddr(&e->e_from, FALSE); 242ce5531bdSeric } 243ce5531bdSeric e->e_from.q_flags |= QDONTSEND; 244ce5531bdSeric e->e_errormode = EM_MAIL; 245ce5531bdSeric } 246ce5531bdSeric 247c1ac89b1Seric # ifdef QUEUE 248c1ac89b1Seric if ((mode == SM_QUEUE || mode == SM_FORK || 249c1ac89b1Seric (mode != SM_VERIFY && SuperSafe)) && 250c1ac89b1Seric !bitset(EF_INQUEUE, e->e_flags)) 251c1ac89b1Seric { 252c1ac89b1Seric /* be sure everything is instantiated in the queue */ 2536103d9b4Seric queueup(e, TRUE, announcequeueup); 254ce5531bdSeric for (ee = splitenv; ee != NULL; ee = ee->e_sibling) 2556103d9b4Seric queueup(ee, TRUE, announcequeueup); 256c1ac89b1Seric } 257c1ac89b1Seric #endif /* QUEUE */ 258c1ac89b1Seric 259ce5531bdSeric if (splitenv != NULL) 260ce5531bdSeric { 261ce5531bdSeric if (tTd(13, 1)) 262ce5531bdSeric { 263ce5531bdSeric printf("\nsendall: Split queue; remaining queue:\n"); 264ce5531bdSeric printaddr(e->e_sendqueue, TRUE); 265ce5531bdSeric } 266ce5531bdSeric 267ce5531bdSeric for (ee = splitenv; ee != NULL; ee = ee->e_sibling) 268ce5531bdSeric { 269ce5531bdSeric CurEnv = ee; 270ce5531bdSeric sendenvelope(ee, mode); 271ce5531bdSeric } 272ce5531bdSeric 273ce5531bdSeric CurEnv = e; 274ce5531bdSeric } 275ce5531bdSeric sendenvelope(e, mode); 276ce5531bdSeric 277ce5531bdSeric for (; splitenv != NULL; splitenv = splitenv->e_sibling) 278ce5531bdSeric dropenvelope(splitenv); 279ce5531bdSeric } 280ce5531bdSeric 281ce5531bdSeric sendenvelope(e, mode) 282ce5531bdSeric register ENVELOPE *e; 283ce5531bdSeric char mode; 284ce5531bdSeric { 285ce5531bdSeric bool oldverbose; 286ce5531bdSeric int pid; 287ce5531bdSeric register ADDRESS *q; 288ce5531bdSeric #ifdef LOCKF 289ce5531bdSeric struct flock lfd; 290ce5531bdSeric #endif 291ce5531bdSeric 292ce5531bdSeric oldverbose = Verbose; 293c1ac89b1Seric switch (mode) 294c1ac89b1Seric { 295c1ac89b1Seric case SM_VERIFY: 296c1ac89b1Seric Verbose = TRUE; 297c1ac89b1Seric break; 298c1ac89b1Seric 299c1ac89b1Seric case SM_QUEUE: 300c1ac89b1Seric queueonly: 301c1ac89b1Seric e->e_flags |= EF_INQUEUE|EF_KEEPQUEUE; 302c1ac89b1Seric return; 303c1ac89b1Seric 304c1ac89b1Seric case SM_FORK: 305c1ac89b1Seric if (e->e_xfp != NULL) 306c1ac89b1Seric (void) fflush(e->e_xfp); 307c1ac89b1Seric 308c1ac89b1Seric # ifdef LOCKF 309c1ac89b1Seric /* 310c1ac89b1Seric ** Since lockf has the interesting semantic that the 311c1ac89b1Seric ** lock is lost when we fork, we have to risk losing 312c1ac89b1Seric ** the lock here by closing before the fork, and then 313c1ac89b1Seric ** trying to get it back in the child. 314c1ac89b1Seric */ 315c1ac89b1Seric 316c1ac89b1Seric if (e->e_lockfp != NULL) 317c1ac89b1Seric { 318c1ac89b1Seric (void) xfclose(e->e_lockfp, "sendenvelope", "lockfp"); 319c1ac89b1Seric e->e_lockfp = NULL; 320c1ac89b1Seric } 321c1ac89b1Seric # endif /* LOCKF */ 322c1ac89b1Seric 323c1ac89b1Seric pid = fork(); 324c1ac89b1Seric if (pid < 0) 325c1ac89b1Seric { 326c1ac89b1Seric goto queueonly; 327c1ac89b1Seric } 328c1ac89b1Seric else if (pid > 0) 329c1ac89b1Seric { 330c1ac89b1Seric /* be sure we leave the temp files to our child */ 331c1ac89b1Seric e->e_id = e->e_df = NULL; 332c1ac89b1Seric # ifndef LOCKF 333c1ac89b1Seric if (e->e_lockfp != NULL) 334c1ac89b1Seric { 335c1ac89b1Seric (void) xfclose(e->e_lockfp, "sendenvelope", "lockfp"); 336c1ac89b1Seric e->e_lockfp = NULL; 337c1ac89b1Seric } 338c1ac89b1Seric # endif 339c1ac89b1Seric 340c1ac89b1Seric /* close any random open files in the envelope */ 341c1ac89b1Seric if (e->e_dfp != NULL) 342c1ac89b1Seric { 343c1ac89b1Seric (void) xfclose(e->e_dfp, "sendenvelope", "dfp"); 344c1ac89b1Seric e->e_dfp = NULL; 345c1ac89b1Seric } 346c1ac89b1Seric if (e->e_xfp != NULL) 347c1ac89b1Seric { 348c1ac89b1Seric (void) xfclose(e->e_xfp, "sendenvelope", "xfp"); 349c1ac89b1Seric e->e_xfp = NULL; 350c1ac89b1Seric } 351c1ac89b1Seric return; 352c1ac89b1Seric } 353c1ac89b1Seric 354c1ac89b1Seric /* double fork to avoid zombies */ 355c1ac89b1Seric if (fork() > 0) 356c1ac89b1Seric exit(EX_OK); 357c1ac89b1Seric 358c1ac89b1Seric /* be sure we are immune from the terminal */ 359c1ac89b1Seric disconnect(FALSE, e); 360c1ac89b1Seric 361c1ac89b1Seric # ifdef LOCKF 362c1ac89b1Seric /* 363c1ac89b1Seric ** Now try to get our lock back. 364c1ac89b1Seric */ 365c1ac89b1Seric 366c1ac89b1Seric lfd.l_type = F_WRLCK; 367c1ac89b1Seric lfd.l_whence = lfd.l_start = lfd.l_len = 0; 368c1ac89b1Seric e->e_lockfp = fopen(queuename(e, 'q'), "r+"); 369c1ac89b1Seric if (e->e_lockfp == NULL || 370c1ac89b1Seric fcntl(fileno(e->e_lockfp), F_SETLK, &lfd) < 0) 371c1ac89b1Seric { 372c1ac89b1Seric /* oops.... lost it */ 373c1ac89b1Seric if (tTd(13, 1)) 374c1ac89b1Seric printf("sendenvelope: %s lost lock: lockfp=%x, %s\n", 375c1ac89b1Seric e->e_id, e->e_lockfp, errstring(errno)); 376c1ac89b1Seric 377c1ac89b1Seric # ifdef LOG 378c1ac89b1Seric if (LogLevel > 29) 379c1ac89b1Seric syslog(LOG_NOTICE, "%s: lost lock: %m", 380c1ac89b1Seric e->e_id); 381c1ac89b1Seric # endif /* LOG */ 382c1ac89b1Seric exit(EX_OK); 383c1ac89b1Seric } 384c1ac89b1Seric # endif /* LOCKF */ 385c1ac89b1Seric 386c1ac89b1Seric /* 387c1ac89b1Seric ** Close any cached connections. 388c1ac89b1Seric ** 389c1ac89b1Seric ** We don't send the QUIT protocol because the parent 390c1ac89b1Seric ** still knows about the connection. 391c1ac89b1Seric ** 392c1ac89b1Seric ** This should only happen when delivering an error 393c1ac89b1Seric ** message. 394c1ac89b1Seric */ 395c1ac89b1Seric 396c1ac89b1Seric mci_flush(FALSE, NULL); 397c1ac89b1Seric 398c1ac89b1Seric break; 399c1ac89b1Seric } 400c1ac89b1Seric 401c1ac89b1Seric /* 4029c9e68d9Seric ** Run through the list and send everything. 4039c9e68d9Seric */ 4049c9e68d9Seric 4059c9e68d9Seric e->e_nsent = 0; 4069c9e68d9Seric for (q = e->e_sendqueue; q != NULL; q = q->q_next) 4079c9e68d9Seric { 4089c9e68d9Seric if (mode == SM_VERIFY) 4099c9e68d9Seric { 4109c9e68d9Seric e->e_to = q->q_paddr; 4119c9e68d9Seric if (!bitset(QDONTSEND|QBADADDR, q->q_flags)) 4129c9e68d9Seric message("deliverable"); 4139c9e68d9Seric } 4149c9e68d9Seric else if (!bitset(QDONTSEND|QBADADDR, q->q_flags)) 4159c9e68d9Seric { 4169c9e68d9Seric # ifdef QUEUE 4179c9e68d9Seric /* 4189c9e68d9Seric ** Checkpoint the send list every few addresses 4199c9e68d9Seric */ 4209c9e68d9Seric 4219c9e68d9Seric if (e->e_nsent >= CheckpointInterval) 4229c9e68d9Seric { 4239c9e68d9Seric queueup(e, TRUE, FALSE); 4249c9e68d9Seric e->e_nsent = 0; 4259c9e68d9Seric } 4269c9e68d9Seric # endif /* QUEUE */ 4279c9e68d9Seric (void) deliver(e, q); 4289c9e68d9Seric } 4299c9e68d9Seric } 4309c9e68d9Seric Verbose = oldverbose; 4319c9e68d9Seric 4329c9e68d9Seric /* 4339c9e68d9Seric ** Now run through and check for errors. 4349c9e68d9Seric */ 4359c9e68d9Seric 4369c9e68d9Seric if (mode == SM_VERIFY) 4379c9e68d9Seric { 4389c9e68d9Seric return; 4399c9e68d9Seric } 4409c9e68d9Seric 4419c9e68d9Seric for (q = e->e_sendqueue; q != NULL; q = q->q_next) 4429c9e68d9Seric { 4439c9e68d9Seric if (tTd(13, 3)) 4449c9e68d9Seric { 4459c9e68d9Seric printf("Checking "); 4469c9e68d9Seric printaddr(q, FALSE); 4479c9e68d9Seric } 4489c9e68d9Seric 4499c9e68d9Seric /* only send errors if the message failed */ 450ce5531bdSeric if (!bitset(QBADADDR, q->q_flags) || 451ce5531bdSeric bitset(QDONTSEND, q->q_flags)) 4529c9e68d9Seric continue; 4539c9e68d9Seric 4549c9e68d9Seric e->e_flags |= EF_FATALERRS; 4559c9e68d9Seric 4569c9e68d9Seric if (q->q_owner == NULL && strcmp(e->e_from.q_paddr, "<>") != 0) 4579c9e68d9Seric (void) sendtolist(e->e_from.q_paddr, NULL, 4589c9e68d9Seric &e->e_errorqueue, e); 4599c9e68d9Seric } 4609c9e68d9Seric 4619c9e68d9Seric if (mode == SM_FORK) 4629c9e68d9Seric finis(); 4639c9e68d9Seric } 4649c9e68d9Seric /* 4659c9e68d9Seric ** DOFORK -- do a fork, retrying a couple of times on failure. 4669c9e68d9Seric ** 4679c9e68d9Seric ** This MUST be a macro, since after a vfork we are running 4689c9e68d9Seric ** two processes on the same stack!!! 4699c9e68d9Seric ** 4709c9e68d9Seric ** Parameters: 4719c9e68d9Seric ** none. 4729c9e68d9Seric ** 4739c9e68d9Seric ** Returns: 4749c9e68d9Seric ** From a macro??? You've got to be kidding! 4759c9e68d9Seric ** 4769c9e68d9Seric ** Side Effects: 4779c9e68d9Seric ** Modifies the ==> LOCAL <== variable 'pid', leaving: 4789c9e68d9Seric ** pid of child in parent, zero in child. 4799c9e68d9Seric ** -1 on unrecoverable error. 4809c9e68d9Seric ** 4819c9e68d9Seric ** Notes: 4829c9e68d9Seric ** I'm awfully sorry this looks so awful. That's 4839c9e68d9Seric ** vfork for you..... 4849c9e68d9Seric */ 4859c9e68d9Seric 4869c9e68d9Seric # define NFORKTRIES 5 4879c9e68d9Seric 4889c9e68d9Seric # ifndef FORK 4899c9e68d9Seric # define FORK fork 4909c9e68d9Seric # endif 4919c9e68d9Seric 4929c9e68d9Seric # define DOFORK(fORKfN) \ 4939c9e68d9Seric {\ 4949c9e68d9Seric register int i;\ 4959c9e68d9Seric \ 4969c9e68d9Seric for (i = NFORKTRIES; --i >= 0; )\ 4979c9e68d9Seric {\ 4989c9e68d9Seric pid = fORKfN();\ 4999c9e68d9Seric if (pid >= 0)\ 5009c9e68d9Seric break;\ 5019c9e68d9Seric if (i > 0)\ 5029c9e68d9Seric sleep((unsigned) NFORKTRIES - i);\ 5039c9e68d9Seric }\ 5049c9e68d9Seric } 5059c9e68d9Seric /* 5069c9e68d9Seric ** DOFORK -- simple fork interface to DOFORK. 5079c9e68d9Seric ** 5089c9e68d9Seric ** Parameters: 5099c9e68d9Seric ** none. 5109c9e68d9Seric ** 5119c9e68d9Seric ** Returns: 5129c9e68d9Seric ** pid of child in parent. 5139c9e68d9Seric ** zero in child. 5149c9e68d9Seric ** -1 on error. 5159c9e68d9Seric ** 5169c9e68d9Seric ** Side Effects: 5179c9e68d9Seric ** returns twice, once in parent and once in child. 5189c9e68d9Seric */ 5199c9e68d9Seric 5209c9e68d9Seric dofork() 5219c9e68d9Seric { 5229c9e68d9Seric register int pid; 5239c9e68d9Seric 5249c9e68d9Seric DOFORK(fork); 5259c9e68d9Seric return (pid); 5269c9e68d9Seric } 5279c9e68d9Seric /* 52813bbc08cSeric ** DELIVER -- Deliver a message to a list of addresses. 52913bbc08cSeric ** 53013bbc08cSeric ** This routine delivers to everyone on the same host as the 53113bbc08cSeric ** user on the head of the list. It is clever about mailers 53213bbc08cSeric ** that don't handle multiple users. It is NOT guaranteed 53313bbc08cSeric ** that it will deliver to all these addresses however -- so 53413bbc08cSeric ** deliver should be called once for each address on the 53513bbc08cSeric ** list. 53625a99e2eSeric ** 53725a99e2eSeric ** Parameters: 538588cad61Seric ** e -- the envelope to deliver. 539c77d1c25Seric ** firstto -- head of the address list to deliver to. 54025a99e2eSeric ** 54125a99e2eSeric ** Returns: 54225a99e2eSeric ** zero -- successfully delivered. 54325a99e2eSeric ** else -- some failure, see ExitStat for more info. 54425a99e2eSeric ** 54525a99e2eSeric ** Side Effects: 54625a99e2eSeric ** The standard input is passed off to someone. 54725a99e2eSeric */ 54825a99e2eSeric 549588cad61Seric deliver(e, firstto) 550588cad61Seric register ENVELOPE *e; 551c77d1c25Seric ADDRESS *firstto; 55225a99e2eSeric { 55378442df3Seric char *host; /* host being sent to */ 55478442df3Seric char *user; /* user being sent to */ 55525a99e2eSeric char **pvp; 5565dfc646bSeric register char **mvp; 55725a99e2eSeric register char *p; 558588cad61Seric register MAILER *m; /* mailer for this recipient */ 5596259796dSeric ADDRESS *ctladdr; 560b31e7f2bSeric register MCI *mci; 561c77d1c25Seric register ADDRESS *to = firstto; 562c579ef51Seric bool clever = FALSE; /* running user smtp to this mailer */ 563772e6e50Seric ADDRESS *tochain = NULL; /* chain of users in this mailer call */ 564911693bfSbostic int rcode; /* response code */ 565e103b48fSeric char *firstsig; /* signature of firstto */ 5669c9e68d9Seric int pid; 5679c9e68d9Seric char *curhost; 5689c9e68d9Seric int mpvect[2]; 5699c9e68d9Seric int rpvect[2]; 570ee6bf8dfSeric char *pv[MAXPV+1]; 571579ef0ddSeric char tobuf[TOBUFSIZE]; /* text line of to people */ 572ee6bf8dfSeric char buf[MAXNAME]; 573c23ed322Seric char rpathbuf[MAXNAME]; /* translated return path */ 574fabb3bd4Seric extern int checkcompat(); 575ee6bf8dfSeric extern ADDRESS *getctladdr(); 576ee6bf8dfSeric extern char *remotename(); 577e103b48fSeric extern char *hostsignature(); 5789c9e68d9Seric extern FILE *fdopen(); 57925a99e2eSeric 58035490626Seric errno = 0; 581ee4b0922Seric if (bitset(QDONTSEND|QBADADDR|QQUEUEUP, to->q_flags)) 5825dfc646bSeric return (0); 58325a99e2eSeric 584134746fbSeric #ifdef NAMED_BIND 585912a731aSbostic /* unless interactive, try twice, over a minute */ 586912a731aSbostic if (OpMode == MD_DAEMON || OpMode == MD_SMTP) { 587912a731aSbostic _res.retrans = 30; 588912a731aSbostic _res.retry = 2; 589912a731aSbostic } 590d4bd8f0eSbostic #endif 591912a731aSbostic 59251552439Seric m = to->q_mailer; 59351552439Seric host = to->q_host; 594c9be6216Seric CurEnv = e; /* just in case */ 5954384d521Seric e->e_statmsg = NULL; 59651552439Seric 5976ef48975Seric if (tTd(10, 1)) 5985dfc646bSeric printf("\n--deliver, mailer=%d, host=`%s', first user=`%s'\n", 59951552439Seric m->m_mno, host, to->q_user); 600f3dbc832Seric 601f3dbc832Seric /* 602f3dbc832Seric ** If this mailer is expensive, and if we don't want to make 603f3dbc832Seric ** connections now, just mark these addresses and return. 604f3dbc832Seric ** This is useful if we want to batch connections to 605f3dbc832Seric ** reduce load. This will cause the messages to be 606f3dbc832Seric ** queued up, and a daemon will come along to send the 607f3dbc832Seric ** messages later. 608f3dbc832Seric ** This should be on a per-mailer basis. 609f3dbc832Seric */ 610f3dbc832Seric 61119c47125Seric if (NoConnect && !bitset(EF_QUEUERUN, e->e_flags) && 61219c47125Seric bitnset(M_EXPENSIVE, m->m_flags) && !Verbose) 613f3dbc832Seric { 614f3dbc832Seric for (; to != NULL; to = to->q_next) 615f4560e80Seric { 616ee4b0922Seric if (bitset(QDONTSEND|QBADADDR|QQUEUEUP, to->q_flags) || 617c6e18ac5Seric to->q_mailer != m) 618f4560e80Seric continue; 619f3dbc832Seric to->q_flags |= QQUEUEUP|QDONTSEND; 620588cad61Seric e->e_to = to->q_paddr; 62108b25121Seric message("queued"); 6222f624c86Seric if (LogLevel > 8) 62381161401Seric logdelivery(m, NULL, "queued", e); 624f4560e80Seric } 625588cad61Seric e->e_to = NULL; 626f3dbc832Seric return (0); 627f3dbc832Seric } 628f3dbc832Seric 62925a99e2eSeric /* 6305dfc646bSeric ** Do initial argv setup. 6315dfc646bSeric ** Insert the mailer name. Notice that $x expansion is 6325dfc646bSeric ** NOT done on the mailer name. Then, if the mailer has 6335dfc646bSeric ** a picky -f flag, we insert it as appropriate. This 6345dfc646bSeric ** code does not check for 'pv' overflow; this places a 6355dfc646bSeric ** manifest lower limit of 4 for MAXPV. 6363bea8136Seric ** The from address rewrite is expected to make 6373bea8136Seric ** the address relative to the other end. 6385dfc646bSeric */ 6395dfc646bSeric 64078442df3Seric /* rewrite from address, using rewriting rules */ 641efe54562Seric rcode = EX_OK; 642efe54562Seric (void) strcpy(rpathbuf, remotename(e->e_from.q_paddr, m, 643efe54562Seric RF_SENDERADDR|RF_CANONICAL, 644efe54562Seric &rcode, e)); 645ee4b0922Seric define('g', rpathbuf, e); /* translated return path */ 646588cad61Seric define('h', host, e); /* to host */ 6475dfc646bSeric Errors = 0; 6485dfc646bSeric pvp = pv; 6495dfc646bSeric *pvp++ = m->m_argv[0]; 6505dfc646bSeric 6515dfc646bSeric /* insert -f or -r flag as appropriate */ 65257fc6f17Seric if (FromFlag && (bitnset(M_FOPT, m->m_flags) || bitnset(M_ROPT, m->m_flags))) 6535dfc646bSeric { 65457fc6f17Seric if (bitnset(M_FOPT, m->m_flags)) 6555dfc646bSeric *pvp++ = "-f"; 6565dfc646bSeric else 6575dfc646bSeric *pvp++ = "-r"; 658c23ed322Seric *pvp++ = newstr(rpathbuf); 6595dfc646bSeric } 6605dfc646bSeric 6615dfc646bSeric /* 6625dfc646bSeric ** Append the other fixed parts of the argv. These run 6635dfc646bSeric ** up to the first entry containing "$u". There can only 6645dfc646bSeric ** be one of these, and there are only a few more slots 6655dfc646bSeric ** in the pv after it. 6665dfc646bSeric */ 6675dfc646bSeric 6685dfc646bSeric for (mvp = m->m_argv; (p = *++mvp) != NULL; ) 6695dfc646bSeric { 6702bc47524Seric /* can't use strchr here because of sign extension problems */ 6712bc47524Seric while (*p != '\0') 6722bc47524Seric { 6732bc47524Seric if ((*p++ & 0377) == MACROEXPAND) 6742bc47524Seric { 6752bc47524Seric if (*p == 'u') 6765dfc646bSeric break; 6772bc47524Seric } 6782bc47524Seric } 6792bc47524Seric 6802bc47524Seric if (*p != '\0') 6815dfc646bSeric break; 6825dfc646bSeric 6835dfc646bSeric /* this entry is safe -- go ahead and process it */ 684588cad61Seric expand(*mvp, buf, &buf[sizeof buf - 1], e); 6855dfc646bSeric *pvp++ = newstr(buf); 6865dfc646bSeric if (pvp >= &pv[MAXPV - 3]) 6875dfc646bSeric { 68808b25121Seric syserr("554 Too many parameters to %s before $u", pv[0]); 6895dfc646bSeric return (-1); 6905dfc646bSeric } 6915dfc646bSeric } 692c579ef51Seric 69333db8731Seric /* 69433db8731Seric ** If we have no substitution for the user name in the argument 69533db8731Seric ** list, we know that we must supply the names otherwise -- and 69633db8731Seric ** SMTP is the answer!! 69733db8731Seric */ 69833db8731Seric 6995dfc646bSeric if (*mvp == NULL) 700c579ef51Seric { 701c579ef51Seric /* running SMTP */ 7022c7e1b8dSeric # ifdef SMTP 703c579ef51Seric clever = TRUE; 704c579ef51Seric *pvp = NULL; 7056c2c3107Seric # else /* SMTP */ 70633db8731Seric /* oops! we don't implement SMTP */ 70708b25121Seric syserr("554 SMTP style mailer"); 7082c7e1b8dSeric return (EX_SOFTWARE); 7096c2c3107Seric # endif /* SMTP */ 710c579ef51Seric } 7115dfc646bSeric 7125dfc646bSeric /* 7135dfc646bSeric ** At this point *mvp points to the argument with $u. We 7145dfc646bSeric ** run through our address list and append all the addresses 7155dfc646bSeric ** we can. If we run out of space, do not fret! We can 7165dfc646bSeric ** always send another copy later. 7175dfc646bSeric */ 7185dfc646bSeric 7195dfc646bSeric tobuf[0] = '\0'; 720588cad61Seric e->e_to = tobuf; 7216259796dSeric ctladdr = NULL; 722e103b48fSeric firstsig = hostsignature(firstto->q_mailer, firstto->q_host, e); 7235dfc646bSeric for (; to != NULL; to = to->q_next) 7245dfc646bSeric { 7255dfc646bSeric /* avoid sending multiple recipients to dumb mailers */ 72657fc6f17Seric if (tobuf[0] != '\0' && !bitnset(M_MUSER, m->m_flags)) 7275dfc646bSeric break; 7285dfc646bSeric 7295dfc646bSeric /* if already sent or not for this host, don't send */ 730ee4b0922Seric if (bitset(QDONTSEND|QBADADDR|QQUEUEUP, to->q_flags) || 731e103b48fSeric to->q_mailer != firstto->q_mailer || 732e103b48fSeric strcmp(hostsignature(to->q_mailer, to->q_host, e), firstsig) != 0) 7335dfc646bSeric continue; 7346259796dSeric 7354b22ea87Seric /* avoid overflowing tobuf */ 736aa50a568Sbostic if (sizeof tobuf < (strlen(to->q_paddr) + strlen(tobuf) + 2)) 7374b22ea87Seric break; 7384b22ea87Seric 7396ef48975Seric if (tTd(10, 1)) 740772e6e50Seric { 741772e6e50Seric printf("\nsend to "); 742772e6e50Seric printaddr(to, FALSE); 743772e6e50Seric } 744772e6e50Seric 7456259796dSeric /* compute effective uid/gid when sending */ 7467da1035fSeric if (to->q_mailer == ProgMailer) 7476259796dSeric ctladdr = getctladdr(to); 7486259796dSeric 7495dfc646bSeric user = to->q_user; 750588cad61Seric e->e_to = to->q_paddr; 75175f1ade9Seric if (tTd(10, 5)) 75275f1ade9Seric { 75375f1ade9Seric printf("deliver: QDONTSEND "); 75475f1ade9Seric printaddr(to, FALSE); 75575f1ade9Seric } 756ee4b0922Seric to->q_flags |= QDONTSEND; 7575dfc646bSeric 7585dfc646bSeric /* 7595dfc646bSeric ** Check to see that these people are allowed to 7605dfc646bSeric ** talk to each other. 7612a6e0786Seric */ 7622a6e0786Seric 76369582d2fSeric if (m->m_maxsize != 0 && e->e_msgsize > m->m_maxsize) 76469582d2fSeric { 76569582d2fSeric NoReturn = TRUE; 76608b25121Seric usrerr("552 Message is too large; %ld bytes max", m->m_maxsize); 76781161401Seric giveresponse(EX_UNAVAILABLE, m, NULL, e); 76869582d2fSeric continue; 76969582d2fSeric } 770fabb3bd4Seric rcode = checkcompat(to, e); 7711793c9c5Seric if (rcode != EX_OK) 7725dfc646bSeric { 77381161401Seric giveresponse(rcode, m, NULL, e); 7745dfc646bSeric continue; 7755dfc646bSeric } 7762a6e0786Seric 7772a6e0786Seric /* 7789ec9501bSeric ** Strip quote bits from names if the mailer is dumb 7799ec9501bSeric ** about them. 78025a99e2eSeric */ 78125a99e2eSeric 78257fc6f17Seric if (bitnset(M_STRIPQ, m->m_flags)) 78325a99e2eSeric { 7841d8f1806Seric stripquotes(user); 7851d8f1806Seric stripquotes(host); 78625a99e2eSeric } 78725a99e2eSeric 788cdb828c5Seric /* hack attack -- delivermail compatibility */ 789cdb828c5Seric if (m == ProgMailer && *user == '|') 790cdb828c5Seric user++; 791cdb828c5Seric 79225a99e2eSeric /* 7933efaed6eSeric ** If an error message has already been given, don't 7943efaed6eSeric ** bother to send to this address. 7953efaed6eSeric ** 7963efaed6eSeric ** >>>>>>>>>> This clause assumes that the local mailer 7973efaed6eSeric ** >> NOTE >> cannot do any further aliasing; that 7983efaed6eSeric ** >>>>>>>>>> function is subsumed by sendmail. 7993efaed6eSeric */ 8003efaed6eSeric 8016cae517dSeric if (bitset(QBADADDR|QQUEUEUP, to->q_flags)) 8023efaed6eSeric continue; 8033efaed6eSeric 804f2fec898Seric /* save statistics.... */ 805588cad61Seric markstats(e, to); 806f2fec898Seric 8073efaed6eSeric /* 80825a99e2eSeric ** See if this user name is "special". 80925a99e2eSeric ** If the user name has a slash in it, assume that this 81051552439Seric ** is a file -- send it off without further ado. Note 81151552439Seric ** that this type of addresses is not processed along 81251552439Seric ** with the others, so we fudge on the To person. 81325a99e2eSeric */ 81425a99e2eSeric 8152c017f8dSeric if (m == FileMailer) 81625a99e2eSeric { 817b31e7f2bSeric rcode = mailfile(user, getctladdr(to), e); 81881161401Seric giveresponse(rcode, m, NULL, e); 819dde5acadSeric if (rcode == EX_OK) 820dde5acadSeric to->q_flags |= QSENT; 8215dfc646bSeric continue; 82225a99e2eSeric } 82325a99e2eSeric 82413bbc08cSeric /* 82513bbc08cSeric ** Address is verified -- add this user to mailer 82613bbc08cSeric ** argv, and add it to the print list of recipients. 82713bbc08cSeric */ 82813bbc08cSeric 829508daeccSeric /* link together the chain of recipients */ 830508daeccSeric to->q_tchain = tochain; 831508daeccSeric tochain = to; 832508daeccSeric 8335dfc646bSeric /* create list of users for error messages */ 834db8841e9Seric (void) strcat(tobuf, ","); 835db8841e9Seric (void) strcat(tobuf, to->q_paddr); 836588cad61Seric define('u', user, e); /* to user */ 837588cad61Seric define('z', to->q_home, e); /* user's home */ 8385dfc646bSeric 839c579ef51Seric /* 840508daeccSeric ** Expand out this user into argument list. 841c579ef51Seric */ 842c579ef51Seric 843508daeccSeric if (!clever) 844c579ef51Seric { 845588cad61Seric expand(*mvp, buf, &buf[sizeof buf - 1], e); 8465dfc646bSeric *pvp++ = newstr(buf); 8475dfc646bSeric if (pvp >= &pv[MAXPV - 2]) 8485dfc646bSeric { 8495dfc646bSeric /* allow some space for trailing parms */ 8505dfc646bSeric break; 8515dfc646bSeric } 8525dfc646bSeric } 853c579ef51Seric } 8545dfc646bSeric 855145b49b1Seric /* see if any addresses still exist */ 856145b49b1Seric if (tobuf[0] == '\0') 857c579ef51Seric { 858588cad61Seric define('g', (char *) NULL, e); 859145b49b1Seric return (0); 860c579ef51Seric } 861145b49b1Seric 8625dfc646bSeric /* print out messages as full list */ 86363780dbdSeric e->e_to = tobuf + 1; 8645dfc646bSeric 8655dfc646bSeric /* 8665dfc646bSeric ** Fill out any parameters after the $u parameter. 8675dfc646bSeric */ 8685dfc646bSeric 869c579ef51Seric while (!clever && *++mvp != NULL) 8705dfc646bSeric { 871588cad61Seric expand(*mvp, buf, &buf[sizeof buf - 1], e); 8725dfc646bSeric *pvp++ = newstr(buf); 8735dfc646bSeric if (pvp >= &pv[MAXPV]) 87408b25121Seric syserr("554 deliver: pv overflow after $u for %s", pv[0]); 8755dfc646bSeric } 8765dfc646bSeric *pvp++ = NULL; 8775dfc646bSeric 87825a99e2eSeric /* 87925a99e2eSeric ** Call the mailer. 8806328bdf7Seric ** The argument vector gets built, pipes 88125a99e2eSeric ** are created as necessary, and we fork & exec as 8826328bdf7Seric ** appropriate. 883c579ef51Seric ** If we are running SMTP, we just need to clean up. 88425a99e2eSeric */ 88525a99e2eSeric 8867ee87e5fSeric if (ctladdr == NULL && m != ProgMailer) 88786b26461Seric ctladdr = &e->e_from; 888134746fbSeric #ifdef NAMED_BIND 8892bcc6d2dSeric if (ConfigLevel < 2) 890912a731aSbostic _res.options &= ~(RES_DEFNAMES | RES_DNSRCH); /* XXX */ 891134746fbSeric #endif 8929c9e68d9Seric 8939c9e68d9Seric if (tTd(11, 1)) 894134746fbSeric { 8959c9e68d9Seric printf("openmailer:"); 8969c9e68d9Seric printav(pv); 8979c9e68d9Seric } 8989c9e68d9Seric errno = 0; 8999c9e68d9Seric 9009c9e68d9Seric CurHostName = m->m_mailer; 9019c9e68d9Seric 9029c9e68d9Seric /* 9039c9e68d9Seric ** Deal with the special case of mail handled through an IPC 9049c9e68d9Seric ** connection. 9059c9e68d9Seric ** In this case we don't actually fork. We must be 9069c9e68d9Seric ** running SMTP for this to work. We will return a 9079c9e68d9Seric ** zero pid to indicate that we are running IPC. 9089c9e68d9Seric ** We also handle a debug version that just talks to stdin/out. 9099c9e68d9Seric */ 9109c9e68d9Seric 9119c9e68d9Seric curhost = NULL; 9129c9e68d9Seric 9139c9e68d9Seric /* check for Local Person Communication -- not for mortals!!! */ 9149c9e68d9Seric if (strcmp(m->m_mailer, "[LPC]") == 0) 9159c9e68d9Seric { 9169c9e68d9Seric mci = (MCI *) xalloc(sizeof *mci); 9179c9e68d9Seric bzero((char *) mci, sizeof *mci); 9189c9e68d9Seric mci->mci_in = stdin; 9199c9e68d9Seric mci->mci_out = stdout; 9209c9e68d9Seric mci->mci_state = clever ? MCIS_OPENING : MCIS_OPEN; 9219c9e68d9Seric mci->mci_mailer = m; 9229c9e68d9Seric } 9239c9e68d9Seric else if (strcmp(m->m_mailer, "[IPC]") == 0 || 9249c9e68d9Seric strcmp(m->m_mailer, "[TCP]") == 0) 9259c9e68d9Seric { 9269c9e68d9Seric #ifdef DAEMON 9279c9e68d9Seric register int i; 9289c9e68d9Seric register u_short port; 9299c9e68d9Seric extern MCI *mci_get(); 9309c9e68d9Seric extern char *hostsignature(); 9319c9e68d9Seric 9329c9e68d9Seric CurHostName = pv[1]; 9339c9e68d9Seric curhost = hostsignature(m, pv[1], e); 9349c9e68d9Seric 9359c9e68d9Seric if (curhost == NULL || curhost[0] == '\0') 9369c9e68d9Seric { 9379c9e68d9Seric syserr("null signature"); 938845e533cSeric rcode = EX_OSERR; 939b31e7f2bSeric goto give_up; 940b31e7f2bSeric } 9419c9e68d9Seric 9429c9e68d9Seric if (!clever) 9439c9e68d9Seric { 9449c9e68d9Seric syserr("554 non-clever IPC"); 9459c9e68d9Seric rcode = EX_OSERR; 9469c9e68d9Seric goto give_up; 9479c9e68d9Seric } 9489c9e68d9Seric if (pv[2] != NULL) 9499c9e68d9Seric port = atoi(pv[2]); 9509c9e68d9Seric else 9519c9e68d9Seric port = 0; 9529c9e68d9Seric tryhost: 9539c9e68d9Seric mci = NULL; 9549c9e68d9Seric while (*curhost != '\0') 9559c9e68d9Seric { 9569c9e68d9Seric register char *p; 9579c9e68d9Seric static char hostbuf[MAXNAME]; 9589c9e68d9Seric 9599c9e68d9Seric mci = NULL; 9609c9e68d9Seric 9619c9e68d9Seric /* pull the next host from the signature */ 9629c9e68d9Seric p = strchr(curhost, ':'); 9639c9e68d9Seric if (p == NULL) 9649c9e68d9Seric p = &curhost[strlen(curhost)]; 9659c9e68d9Seric strncpy(hostbuf, curhost, p - curhost); 9669c9e68d9Seric hostbuf[p - curhost] = '\0'; 9679c9e68d9Seric if (*p != '\0') 9689c9e68d9Seric p++; 9699c9e68d9Seric curhost = p; 9709c9e68d9Seric 9719c9e68d9Seric /* see if we already know that this host is fried */ 9729c9e68d9Seric CurHostName = hostbuf; 9739c9e68d9Seric mci = mci_get(hostbuf, m); 9749c9e68d9Seric if (mci->mci_state != MCIS_CLOSED) 9759c9e68d9Seric { 9769c9e68d9Seric if (tTd(11, 1)) 9779c9e68d9Seric { 9789c9e68d9Seric printf("openmailer: "); 9799c9e68d9Seric mci_dump(mci); 9809c9e68d9Seric } 9819c9e68d9Seric CurHostName = mci->mci_host; 9829c9e68d9Seric break; 9839c9e68d9Seric } 9849c9e68d9Seric mci->mci_mailer = m; 9859c9e68d9Seric if (mci->mci_exitstat != EX_OK) 9869c9e68d9Seric continue; 9879c9e68d9Seric 9889c9e68d9Seric /* try the connection */ 9899c9e68d9Seric setproctitle("%s %s: %s", e->e_id, hostbuf, "user open"); 9909c9e68d9Seric message("Connecting to %s (%s)...", 9919c9e68d9Seric hostbuf, m->m_name); 9929c9e68d9Seric i = makeconnection(hostbuf, port, mci, 9939c9e68d9Seric bitnset(M_SECURE_PORT, m->m_flags)); 9949c9e68d9Seric mci->mci_exitstat = i; 9959c9e68d9Seric mci->mci_errno = errno; 9969c9e68d9Seric if (i == EX_OK) 9979c9e68d9Seric { 9989c9e68d9Seric mci->mci_state = MCIS_OPENING; 9999c9e68d9Seric mci_cache(mci); 10009c9e68d9Seric break; 10019c9e68d9Seric } 10029c9e68d9Seric else if (tTd(11, 1)) 10039c9e68d9Seric printf("openmailer: makeconnection => stat=%d, errno=%d\n", 10049c9e68d9Seric i, errno); 10059c9e68d9Seric 10069c9e68d9Seric 10079c9e68d9Seric /* enter status of this host */ 10089c9e68d9Seric setstat(i); 10099c9e68d9Seric } 10109c9e68d9Seric mci->mci_pid = 0; 10119c9e68d9Seric #else /* no DAEMON */ 10129c9e68d9Seric syserr("554 openmailer: no IPC"); 10139c9e68d9Seric if (tTd(11, 1)) 10149c9e68d9Seric printf("openmailer: NULL\n"); 10159c9e68d9Seric return NULL; 10169c9e68d9Seric #endif /* DAEMON */ 10179c9e68d9Seric } 10189c9e68d9Seric else 10199c9e68d9Seric { 10206fe8c3bcSeric int i; 10216fe8c3bcSeric struct stat stbuf; 10226fe8c3bcSeric 10236fe8c3bcSeric /* make absolutely certain 0, 1, and 2 are in use */ 10246fe8c3bcSeric for (i = 0; i < 3; i++) 10256fe8c3bcSeric { 10266fe8c3bcSeric if (fstat(i, &stbuf) < 0) 10276fe8c3bcSeric { 10286fe8c3bcSeric /* oops.... */ 10290e3bfef5Seric int fd; 10300e3bfef5Seric 10310e3bfef5Seric syserr("%s... openmailer(%s): fd %d not open", 10320e3bfef5Seric e->e_to, m->m_name, i); 10330e3bfef5Seric fd = open("/dev/null", O_RDONLY, 0666); 10340e3bfef5Seric if (fd != i) 10350e3bfef5Seric { 10360e3bfef5Seric (void) dup2(fd, i); 10370e3bfef5Seric (void) close(fd); 10380e3bfef5Seric } 10396fe8c3bcSeric } 10406fe8c3bcSeric } 10416fe8c3bcSeric 10429c9e68d9Seric /* create a pipe to shove the mail through */ 10439c9e68d9Seric if (pipe(mpvect) < 0) 10449c9e68d9Seric { 10450e3bfef5Seric syserr("%s... openmailer(%s): pipe (to mailer)", 10460e3bfef5Seric e->e_to, m->m_name); 10479c9e68d9Seric if (tTd(11, 1)) 10489c9e68d9Seric printf("openmailer: NULL\n"); 10499c9e68d9Seric rcode = EX_OSERR; 10509c9e68d9Seric goto give_up; 10519c9e68d9Seric } 10529c9e68d9Seric 10539c9e68d9Seric /* if this mailer speaks smtp, create a return pipe */ 10549c9e68d9Seric if (clever && pipe(rpvect) < 0) 10559c9e68d9Seric { 10560e3bfef5Seric syserr("%s... openmailer(%s): pipe (from mailer)", 10570e3bfef5Seric e->e_to, m->m_name); 10589c9e68d9Seric (void) close(mpvect[0]); 10599c9e68d9Seric (void) close(mpvect[1]); 10609c9e68d9Seric if (tTd(11, 1)) 10619c9e68d9Seric printf("openmailer: NULL\n"); 10629c9e68d9Seric rcode = EX_OSERR; 10639c9e68d9Seric goto give_up; 10649c9e68d9Seric } 10659c9e68d9Seric 10669c9e68d9Seric /* 10679c9e68d9Seric ** Actually fork the mailer process. 10689c9e68d9Seric ** DOFORK is clever about retrying. 10699c9e68d9Seric ** 10709c9e68d9Seric ** Dispose of SIGCHLD signal catchers that may be laying 10719c9e68d9Seric ** around so that endmail will get it. 10729c9e68d9Seric */ 10739c9e68d9Seric 10749c9e68d9Seric if (e->e_xfp != NULL) 10759c9e68d9Seric (void) fflush(e->e_xfp); /* for debugging */ 10769c9e68d9Seric (void) fflush(stdout); 10779c9e68d9Seric # ifdef SIGCHLD 10789c9e68d9Seric (void) signal(SIGCHLD, SIG_DFL); 10799c9e68d9Seric # endif /* SIGCHLD */ 10809c9e68d9Seric DOFORK(FORK); 10819c9e68d9Seric /* pid is set by DOFORK */ 10829c9e68d9Seric if (pid < 0) 10839c9e68d9Seric { 10849c9e68d9Seric /* failure */ 10850e3bfef5Seric syserr("%s... openmailer(%s): cannot fork", 10860e3bfef5Seric e->e_to, m->m_name); 10879c9e68d9Seric (void) close(mpvect[0]); 10889c9e68d9Seric (void) close(mpvect[1]); 10899c9e68d9Seric if (clever) 10909c9e68d9Seric { 10919c9e68d9Seric (void) close(rpvect[0]); 10929c9e68d9Seric (void) close(rpvect[1]); 10939c9e68d9Seric } 10949c9e68d9Seric if (tTd(11, 1)) 10959c9e68d9Seric printf("openmailer: NULL\n"); 10969c9e68d9Seric rcode = EX_OSERR; 10979c9e68d9Seric goto give_up; 10989c9e68d9Seric } 10999c9e68d9Seric else if (pid == 0) 11009c9e68d9Seric { 11019c9e68d9Seric int i; 11029c9e68d9Seric int saveerrno; 11039c9e68d9Seric char **ep; 11049c9e68d9Seric char *env[MAXUSERENVIRON]; 11059c9e68d9Seric extern char **environ; 11069c9e68d9Seric extern int DtableSize; 11079c9e68d9Seric 11089c9e68d9Seric /* child -- set up input & exec mailer */ 11099c9e68d9Seric /* make diagnostic output be standard output */ 11109c9e68d9Seric (void) signal(SIGINT, SIG_IGN); 11119c9e68d9Seric (void) signal(SIGHUP, SIG_IGN); 11129c9e68d9Seric (void) signal(SIGTERM, SIG_DFL); 11139c9e68d9Seric 11149c9e68d9Seric /* close any other cached connections */ 11159c9e68d9Seric mci_flush(FALSE, mci); 11169c9e68d9Seric 1117b986f6aaSeric /* move into some "safe" directory */ 1118b986f6aaSeric if (m->m_execdir != NULL) 1119b986f6aaSeric { 1120b986f6aaSeric char *p, *q; 1121b986f6aaSeric char buf[MAXLINE]; 1122b986f6aaSeric 1123b986f6aaSeric for (p = m->m_execdir; p != NULL; p = q) 1124b986f6aaSeric { 1125b986f6aaSeric q = strchr(p, ':'); 1126b986f6aaSeric if (q != NULL) 1127b986f6aaSeric *q = '\0'; 1128b986f6aaSeric expand(p, buf, &buf[sizeof buf] - 1, e); 1129b986f6aaSeric if (q != NULL) 1130b986f6aaSeric *q++ = ':'; 1131b986f6aaSeric if (tTd(11, 20)) 1132b986f6aaSeric printf("openmailer: trydir %s\n", 1133b986f6aaSeric buf); 1134b986f6aaSeric if (buf[0] != '\0' && chdir(buf) >= 0) 1135b986f6aaSeric break; 1136b986f6aaSeric } 1137b986f6aaSeric } 1138b986f6aaSeric 11399c9e68d9Seric /* arrange to filter std & diag output of command */ 11409c9e68d9Seric if (clever) 11419c9e68d9Seric { 11429c9e68d9Seric (void) close(rpvect[0]); 11436fe8c3bcSeric if (dup2(rpvect[1], STDOUT_FILENO) < 0) 11446fe8c3bcSeric { 11450e3bfef5Seric syserr("%s... openmailer(%s): cannot dup pipe %d for stdout", 11460e3bfef5Seric e->e_to, m->m_name, rpvect[1]); 11476fe8c3bcSeric _exit(EX_OSERR); 11486fe8c3bcSeric } 11499c9e68d9Seric (void) close(rpvect[1]); 11509c9e68d9Seric } 11519c9e68d9Seric else if (OpMode == MD_SMTP || HoldErrs) 11529c9e68d9Seric { 11539c9e68d9Seric /* put mailer output in transcript */ 11546fe8c3bcSeric if (dup2(fileno(e->e_xfp), STDOUT_FILENO) < 0) 11556fe8c3bcSeric { 11560e3bfef5Seric syserr("%s... openmailer(%s): cannot dup xscript %d for stdout", 11570e3bfef5Seric e->e_to, m->m_name, 11586fe8c3bcSeric fileno(e->e_xfp)); 11596fe8c3bcSeric _exit(EX_OSERR); 11609c9e68d9Seric } 11616fe8c3bcSeric } 11626fe8c3bcSeric if (dup2(STDOUT_FILENO, STDERR_FILENO) < 0) 11636fe8c3bcSeric { 11640e3bfef5Seric syserr("%s... openmailer(%s): cannot dup stdout for stderr", 11650e3bfef5Seric e->e_to, m->m_name); 11666fe8c3bcSeric _exit(EX_OSERR); 11676fe8c3bcSeric } 11689c9e68d9Seric 11699c9e68d9Seric /* arrange to get standard input */ 11709c9e68d9Seric (void) close(mpvect[1]); 11719c9e68d9Seric if (dup2(mpvect[0], STDIN_FILENO) < 0) 11729c9e68d9Seric { 11730e3bfef5Seric syserr("%s... openmailer(%s): cannot dup pipe %d for stdin", 11740e3bfef5Seric e->e_to, m->m_name, mpvect[0]); 11759c9e68d9Seric _exit(EX_OSERR); 11769c9e68d9Seric } 11779c9e68d9Seric (void) close(mpvect[0]); 11789c9e68d9Seric if (!bitnset(M_RESTR, m->m_flags)) 11799c9e68d9Seric { 11809c9e68d9Seric if (ctladdr == NULL || ctladdr->q_uid == 0) 11819c9e68d9Seric { 11829c9e68d9Seric (void) setgid(DefGid); 11839c9e68d9Seric (void) initgroups(DefUser, DefGid); 11849c9e68d9Seric (void) setuid(DefUid); 11859c9e68d9Seric } 11869c9e68d9Seric else 11879c9e68d9Seric { 11889c9e68d9Seric (void) setgid(ctladdr->q_gid); 11899c9e68d9Seric (void) initgroups(ctladdr->q_ruser? 11909c9e68d9Seric ctladdr->q_ruser: ctladdr->q_user, 11919c9e68d9Seric ctladdr->q_gid); 11929c9e68d9Seric (void) setuid(ctladdr->q_uid); 11939c9e68d9Seric } 11949c9e68d9Seric } 11959c9e68d9Seric 11969c9e68d9Seric /* arrange for all the files to be closed */ 11979c9e68d9Seric for (i = 3; i < DtableSize; i++) 11989c9e68d9Seric { 11999c9e68d9Seric register int j; 12009c9e68d9Seric if ((j = fcntl(i, F_GETFD, 0)) != -1) 12019c9e68d9Seric (void)fcntl(i, F_SETFD, j|1); 12029c9e68d9Seric } 12039c9e68d9Seric 12049c9e68d9Seric /* set up the mailer environment */ 12059c9e68d9Seric i = 0; 12069c9e68d9Seric env[i++] = "AGENT=sendmail"; 12079c9e68d9Seric for (ep = environ; *ep != NULL; ep++) 12089c9e68d9Seric { 12099c9e68d9Seric if (strncmp(*ep, "TZ=", 3) == 0) 12109c9e68d9Seric env[i++] = *ep; 12119c9e68d9Seric } 12129c9e68d9Seric env[i++] = NULL; 12139c9e68d9Seric 12149c9e68d9Seric /* try to execute the mailer */ 12159c9e68d9Seric execve(m->m_mailer, pv, env); 12169c9e68d9Seric saveerrno = errno; 12179c9e68d9Seric syserr("Cannot exec %s", m->m_mailer); 12189c9e68d9Seric if (m == LocalMailer) 12199c9e68d9Seric _exit(EX_TEMPFAIL); 12209c9e68d9Seric if (transienterror(saveerrno)) 12219c9e68d9Seric _exit(EX_TEMPFAIL); 12229c9e68d9Seric _exit(EX_UNAVAILABLE); 12239c9e68d9Seric } 12249c9e68d9Seric 12259c9e68d9Seric /* 12269c9e68d9Seric ** Set up return value. 12279c9e68d9Seric */ 12289c9e68d9Seric 12299c9e68d9Seric mci = (MCI *) xalloc(sizeof *mci); 12309c9e68d9Seric bzero((char *) mci, sizeof *mci); 12319c9e68d9Seric mci->mci_mailer = m; 12329c9e68d9Seric mci->mci_state = clever ? MCIS_OPENING : MCIS_OPEN; 12339c9e68d9Seric mci->mci_pid = pid; 12349c9e68d9Seric (void) close(mpvect[0]); 12359c9e68d9Seric mci->mci_out = fdopen(mpvect[1], "w"); 12369c9e68d9Seric if (clever) 12379c9e68d9Seric { 12389c9e68d9Seric (void) close(rpvect[1]); 12399c9e68d9Seric mci->mci_in = fdopen(rpvect[0], "r"); 12409c9e68d9Seric } 12419c9e68d9Seric else 12429c9e68d9Seric { 12439c9e68d9Seric mci->mci_flags |= MCIF_TEMP; 12449c9e68d9Seric mci->mci_in = NULL; 12459c9e68d9Seric } 12469c9e68d9Seric } 12479c9e68d9Seric 12489c9e68d9Seric /* 12499c9e68d9Seric ** If we are in SMTP opening state, send initial protocol. 12509c9e68d9Seric */ 12519c9e68d9Seric 12529c9e68d9Seric if (clever && mci->mci_state != MCIS_CLOSED) 12539c9e68d9Seric { 12549c9e68d9Seric smtpinit(m, mci, e); 12559c9e68d9Seric } 12569c9e68d9Seric if (tTd(11, 1)) 12579c9e68d9Seric { 12589c9e68d9Seric printf("openmailer: "); 12599c9e68d9Seric mci_dump(mci); 12609c9e68d9Seric } 12619c9e68d9Seric 12629c9e68d9Seric if (mci->mci_state != MCIS_OPEN) 1263b31e7f2bSeric { 1264b31e7f2bSeric /* couldn't open the mailer */ 1265b31e7f2bSeric rcode = mci->mci_exitstat; 12662a6bc25bSeric errno = mci->mci_errno; 1267b31e7f2bSeric if (rcode == EX_OK) 1268b31e7f2bSeric { 1269b31e7f2bSeric /* shouldn't happen */ 127008b25121Seric syserr("554 deliver: rcode=%d, mci_state=%d, sig=%s", 12716b0f339dSeric rcode, mci->mci_state, firstsig); 1272b31e7f2bSeric rcode = EX_SOFTWARE; 1273b31e7f2bSeric } 1274b31e7f2bSeric } 1275b31e7f2bSeric else if (!clever) 1276b31e7f2bSeric { 1277b31e7f2bSeric /* 1278b31e7f2bSeric ** Format and send message. 1279b31e7f2bSeric */ 128015d084d5Seric 1281b31e7f2bSeric putfromline(mci->mci_out, m, e); 1282b31e7f2bSeric (*e->e_puthdr)(mci->mci_out, m, e); 1283b31e7f2bSeric putline("\n", mci->mci_out, m); 1284b31e7f2bSeric (*e->e_putbody)(mci->mci_out, m, e); 1285b31e7f2bSeric 1286b31e7f2bSeric /* get the exit status */ 1287c9be6216Seric rcode = endmailer(mci, e, pv); 1288134746fbSeric } 1289134746fbSeric else 1290b31e7f2bSeric #ifdef SMTP 1291134746fbSeric { 1292b31e7f2bSeric /* 1293b31e7f2bSeric ** Send the MAIL FROM: protocol 1294b31e7f2bSeric */ 129515d084d5Seric 1296b31e7f2bSeric rcode = smtpmailfrom(m, mci, e); 1297b31e7f2bSeric if (rcode == EX_OK) 129875889e88Seric { 1299ded0d3daSkarels register char *t = tobuf; 1300ded0d3daSkarels register int i; 1301ded0d3daSkarels 1302588cad61Seric /* send the recipient list */ 130363780dbdSeric tobuf[0] = '\0'; 130475889e88Seric for (to = tochain; to != NULL; to = to->q_tchain) 130575889e88Seric { 130663780dbdSeric e->e_to = to->q_paddr; 130715d084d5Seric if ((i = smtprcpt(to, m, mci, e)) != EX_OK) 130875889e88Seric { 130983b7ddc9Seric markfailure(e, to, i); 131081161401Seric giveresponse(i, m, mci, e); 131163780dbdSeric } 131275889e88Seric else 131375889e88Seric { 1314911693bfSbostic *t++ = ','; 1315b31e7f2bSeric for (p = to->q_paddr; *p; *t++ = *p++) 1316b31e7f2bSeric continue; 1317588cad61Seric } 1318588cad61Seric } 1319588cad61Seric 132063780dbdSeric /* now send the data */ 132163780dbdSeric if (tobuf[0] == '\0') 1322b31e7f2bSeric { 13239c9e68d9Seric rcode = EX_OK; 132463780dbdSeric e->e_to = NULL; 1325b31e7f2bSeric if (bitset(MCIF_CACHED, mci->mci_flags)) 1326b31e7f2bSeric smtprset(m, mci, e); 1327b31e7f2bSeric } 132875889e88Seric else 132975889e88Seric { 133063780dbdSeric e->e_to = tobuf + 1; 133175889e88Seric rcode = smtpdata(m, mci, e); 133263780dbdSeric } 133363780dbdSeric 133463780dbdSeric /* now close the connection */ 1335b31e7f2bSeric if (!bitset(MCIF_CACHED, mci->mci_flags)) 133615d084d5Seric smtpquit(m, mci, e); 133763780dbdSeric } 13389c9e68d9Seric if (rcode != EX_OK && *curhost != '\0') 13399c9e68d9Seric { 13409c9e68d9Seric /* try next MX site */ 13419c9e68d9Seric goto tryhost; 13429c9e68d9Seric } 1343c579ef51Seric } 1344b31e7f2bSeric #else /* not SMTP */ 1345a05b3449Sbostic { 134608b25121Seric syserr("554 deliver: need SMTP compiled to use clever mailer"); 1347845e533cSeric rcode = EX_CONFIG; 1348b31e7f2bSeric goto give_up; 1349a05b3449Sbostic } 1350b31e7f2bSeric #endif /* SMTP */ 1351134746fbSeric #ifdef NAMED_BIND 13522bcc6d2dSeric if (ConfigLevel < 2) 1353912a731aSbostic _res.options |= RES_DEFNAMES | RES_DNSRCH; /* XXX */ 1354134746fbSeric #endif 13555dfc646bSeric 1356b31e7f2bSeric /* arrange a return receipt if requested */ 13578c13bf07Seric if (e->e_receiptto != NULL && bitnset(M_LOCALMAILER, m->m_flags)) 1358b31e7f2bSeric { 1359b31e7f2bSeric e->e_flags |= EF_SENDRECEIPT; 1360b31e7f2bSeric /* do we want to send back more info? */ 1361b31e7f2bSeric } 1362b31e7f2bSeric 1363c77d1c25Seric /* 136463780dbdSeric ** Do final status disposal. 136563780dbdSeric ** We check for something in tobuf for the SMTP case. 1366c77d1c25Seric ** If we got a temporary failure, arrange to queue the 1367c77d1c25Seric ** addressees. 1368c77d1c25Seric */ 1369c77d1c25Seric 1370b31e7f2bSeric give_up: 137163780dbdSeric if (tobuf[0] != '\0') 137281161401Seric giveresponse(rcode, m, mci, e); 1373772e6e50Seric for (to = tochain; to != NULL; to = to->q_tchain) 1374b31e7f2bSeric { 1375dde5acadSeric if (rcode != EX_OK) 137683b7ddc9Seric markfailure(e, to, rcode); 1377dde5acadSeric else 1378655518ecSeric { 1379dde5acadSeric to->q_flags |= QSENT; 1380655518ecSeric e->e_nsent++; 1381655518ecSeric } 1382b31e7f2bSeric } 1383b31e7f2bSeric 1384b31e7f2bSeric /* 1385b31e7f2bSeric ** Restore state and return. 1386b31e7f2bSeric */ 1387c77d1c25Seric 138835490626Seric errno = 0; 1389588cad61Seric define('g', (char *) NULL, e); 13905826d9d3Seric return (rcode); 139125a99e2eSeric } 13925dfc646bSeric /* 139383b7ddc9Seric ** MARKFAILURE -- mark a failure on a specific address. 139483b7ddc9Seric ** 139583b7ddc9Seric ** Parameters: 139683b7ddc9Seric ** e -- the envelope we are sending. 139783b7ddc9Seric ** q -- the address to mark. 139883b7ddc9Seric ** rcode -- the code signifying the particular failure. 139983b7ddc9Seric ** 140083b7ddc9Seric ** Returns: 140183b7ddc9Seric ** none. 140283b7ddc9Seric ** 140383b7ddc9Seric ** Side Effects: 140483b7ddc9Seric ** marks the address (and possibly the envelope) with the 140583b7ddc9Seric ** failure so that an error will be returned or 140683b7ddc9Seric ** the message will be queued, as appropriate. 140783b7ddc9Seric */ 140883b7ddc9Seric 140983b7ddc9Seric markfailure(e, q, rcode) 141083b7ddc9Seric register ENVELOPE *e; 141183b7ddc9Seric register ADDRESS *q; 141283b7ddc9Seric int rcode; 141383b7ddc9Seric { 141419c47125Seric char buf[MAXLINE]; 141519c47125Seric extern char *pintvl(); 141619c47125Seric 141783b7ddc9Seric if (rcode == EX_OK) 141883b7ddc9Seric return; 1419ef137175Sbostic else if (rcode != EX_TEMPFAIL && rcode != EX_IOERR && rcode != EX_OSERR) 142083b7ddc9Seric q->q_flags |= QBADADDR; 142119c47125Seric else if (curtime() > e->e_ctime + TimeOuts.to_q_return) 142283b7ddc9Seric { 142383b7ddc9Seric if (!bitset(EF_TIMEOUT, e->e_flags)) 1424198d9be0Seric { 1425198d9be0Seric (void) sprintf(buf, "Cannot send message for %s", 142619c47125Seric pintvl(TimeOuts.to_q_return, FALSE)); 1427198d9be0Seric if (e->e_message != NULL) 1428198d9be0Seric free(e->e_message); 1429198d9be0Seric e->e_message = newstr(buf); 143008b25121Seric message(buf); 1431198d9be0Seric } 143283b7ddc9Seric q->q_flags |= QBADADDR; 143383b7ddc9Seric e->e_flags |= EF_TIMEOUT; 1434c13b5dfcSeric fprintf(e->e_xfp, "421 %s... Message timed out\n", q->q_paddr); 143583b7ddc9Seric } 143683b7ddc9Seric else 143719c47125Seric { 143883b7ddc9Seric q->q_flags |= QQUEUEUP; 143919c47125Seric if (TimeOuts.to_q_warning > 0 && 144019c47125Seric curtime() > e->e_ctime + TimeOuts.to_q_warning) 144119c47125Seric { 144219c47125Seric if (!bitset(EF_WARNING, e->e_flags) && 144319c47125Seric e->e_class >= 0) 144419c47125Seric { 144519c47125Seric (void) sprintf(buf, 144619c47125Seric "warning: cannot send message for %s", 144719c47125Seric pintvl(TimeOuts.to_q_warning, FALSE)); 144819c47125Seric if (e->e_message != NULL) 144919c47125Seric free(e->e_message); 145019c47125Seric e->e_message = newstr(buf); 145119c47125Seric message(buf); 145219c47125Seric e->e_flags |= EF_WARNING|EF_TIMEOUT; 145319c47125Seric } 145419c47125Seric fprintf(e->e_xfp, 145519c47125Seric "%s... Warning: message still undelivered after %s\n", 145619c47125Seric q->q_paddr, pintvl(TimeOuts.to_q_warning, FALSE)); 145719c47125Seric fprintf(e->e_xfp, "Will keep trying until message is %s old\n", 145819c47125Seric pintvl(TimeOuts.to_q_return, FALSE)); 145919c47125Seric } 146019c47125Seric } 146183b7ddc9Seric } 146283b7ddc9Seric /* 1463c579ef51Seric ** ENDMAILER -- Wait for mailer to terminate. 1464c579ef51Seric ** 1465c579ef51Seric ** We should never get fatal errors (e.g., segmentation 1466c579ef51Seric ** violation), so we report those specially. For other 1467c579ef51Seric ** errors, we choose a status message (into statmsg), 1468c579ef51Seric ** and if it represents an error, we print it. 1469c579ef51Seric ** 1470c579ef51Seric ** Parameters: 1471c579ef51Seric ** pid -- pid of mailer. 1472c9be6216Seric ** e -- the current envelope. 1473c9be6216Seric ** pv -- the parameter vector that invoked the mailer 1474c9be6216Seric ** (for error messages). 1475c579ef51Seric ** 1476c579ef51Seric ** Returns: 1477c579ef51Seric ** exit code of mailer. 1478c579ef51Seric ** 1479c579ef51Seric ** Side Effects: 1480c579ef51Seric ** none. 1481c579ef51Seric */ 1482c579ef51Seric 1483c9be6216Seric endmailer(mci, e, pv) 1484b31e7f2bSeric register MCI *mci; 1485c9be6216Seric register ENVELOPE *e; 1486c9be6216Seric char **pv; 1487c579ef51Seric { 1488588cad61Seric int st; 1489c579ef51Seric 149075889e88Seric /* close any connections */ 149175889e88Seric if (mci->mci_in != NULL) 1492c9be6216Seric (void) xfclose(mci->mci_in, pv[0], "mci_in"); 149375889e88Seric if (mci->mci_out != NULL) 1494c9be6216Seric (void) xfclose(mci->mci_out, pv[0], "mci_out"); 149575889e88Seric mci->mci_in = mci->mci_out = NULL; 149675889e88Seric mci->mci_state = MCIS_CLOSED; 149775889e88Seric 149833db8731Seric /* in the IPC case there is nothing to wait for */ 149975889e88Seric if (mci->mci_pid == 0) 150033db8731Seric return (EX_OK); 150133db8731Seric 150233db8731Seric /* wait for the mailer process to die and collect status */ 150375889e88Seric st = waitfor(mci->mci_pid); 1504588cad61Seric if (st == -1) 150578de67c1Seric { 1506c9be6216Seric syserr("endmailer %s: wait", pv[0]); 1507588cad61Seric return (EX_SOFTWARE); 1508c579ef51Seric } 150933db8731Seric 151033db8731Seric /* see if it died a horrid death */ 1511c579ef51Seric if ((st & 0377) != 0) 1512c579ef51Seric { 1513c9be6216Seric syserr("mailer %s died with signal %o", pv[0], st); 1514c9be6216Seric 1515c9be6216Seric /* log the arguments */ 1516c9be6216Seric if (e->e_xfp != NULL) 1517c9be6216Seric { 1518c9be6216Seric register char **av; 1519c9be6216Seric 1520c9be6216Seric fprintf(e->e_xfp, "Arguments:"); 1521c9be6216Seric for (av = pv; *av != NULL; av++) 1522c9be6216Seric fprintf(e->e_xfp, " %s", *av); 1523c9be6216Seric fprintf(e->e_xfp, "\n"); 1524c9be6216Seric } 1525c9be6216Seric 15265f73204aSeric ExitStat = EX_TEMPFAIL; 15275f73204aSeric return (EX_TEMPFAIL); 1528c579ef51Seric } 152933db8731Seric 153033db8731Seric /* normal death -- return status */ 1531588cad61Seric st = (st >> 8) & 0377; 1532588cad61Seric return (st); 1533c579ef51Seric } 1534c579ef51Seric /* 153525a99e2eSeric ** GIVERESPONSE -- Interpret an error response from a mailer 153625a99e2eSeric ** 153725a99e2eSeric ** Parameters: 153825a99e2eSeric ** stat -- the status code from the mailer (high byte 153925a99e2eSeric ** only; core dumps must have been taken care of 154025a99e2eSeric ** already). 154181161401Seric ** m -- the mailer info for this mailer. 154281161401Seric ** mci -- the mailer connection info -- can be NULL if the 154381161401Seric ** response is given before the connection is made. 154481161401Seric ** e -- the current envelope. 154525a99e2eSeric ** 154625a99e2eSeric ** Returns: 1547db8841e9Seric ** none. 154825a99e2eSeric ** 154925a99e2eSeric ** Side Effects: 1550c1f9df2cSeric ** Errors may be incremented. 155125a99e2eSeric ** ExitStat may be set. 155225a99e2eSeric */ 155325a99e2eSeric 155481161401Seric giveresponse(stat, m, mci, e) 155525a99e2eSeric int stat; 1556588cad61Seric register MAILER *m; 155781161401Seric register MCI *mci; 1558198d9be0Seric ENVELOPE *e; 155925a99e2eSeric { 156025a99e2eSeric register char *statmsg; 156125a99e2eSeric extern char *SysExMsg[]; 156225a99e2eSeric register int i; 1563d4bd8f0eSbostic extern int N_SysEx; 1564d4bd8f0eSbostic #ifdef NAMED_BIND 1565d4bd8f0eSbostic extern int h_errno; 1566d4bd8f0eSbostic #endif 1567198d9be0Seric char buf[MAXLINE]; 15687d55540cSeric extern char *errstring(); 156925a99e2eSeric 157013bbc08cSeric /* 157113bbc08cSeric ** Compute status message from code. 157213bbc08cSeric */ 157313bbc08cSeric 157425a99e2eSeric i = stat - EX__BASE; 1575588cad61Seric if (stat == 0) 15766fe8c3bcSeric { 1577588cad61Seric statmsg = "250 Sent"; 1578ce5531bdSeric if (e->e_statmsg != NULL) 15796fe8c3bcSeric { 1580ce5531bdSeric (void) sprintf(buf, "%s (%s)", statmsg, e->e_statmsg); 15816fe8c3bcSeric statmsg = buf; 15826fe8c3bcSeric } 15836fe8c3bcSeric } 1584588cad61Seric else if (i < 0 || i > N_SysEx) 1585588cad61Seric { 1586588cad61Seric (void) sprintf(buf, "554 unknown mailer error %d", stat); 1587588cad61Seric stat = EX_UNAVAILABLE; 1588588cad61Seric statmsg = buf; 1589588cad61Seric } 1590198d9be0Seric else if (stat == EX_TEMPFAIL) 1591198d9be0Seric { 15927d55540cSeric (void) strcpy(buf, SysExMsg[i] + 1); 1593d4bd8f0eSbostic #ifdef NAMED_BIND 1594f28da541Smiriam if (h_errno == TRY_AGAIN) 1595f28da541Smiriam statmsg = errstring(h_errno+MAX_ERRNO); 1596f28da541Smiriam else 1597d4bd8f0eSbostic #endif 1598f28da541Smiriam { 15998557d168Seric if (errno != 0) 1600d87e85f3Seric statmsg = errstring(errno); 1601d87e85f3Seric else 1602d87e85f3Seric { 1603d87e85f3Seric #ifdef SMTP 1604d87e85f3Seric extern char SmtpError[]; 1605d87e85f3Seric 1606d87e85f3Seric statmsg = SmtpError; 16076c2c3107Seric #else /* SMTP */ 1608d87e85f3Seric statmsg = NULL; 16096c2c3107Seric #endif /* SMTP */ 1610d87e85f3Seric } 1611f28da541Smiriam } 1612d87e85f3Seric if (statmsg != NULL && statmsg[0] != '\0') 1613d87e85f3Seric { 161487c9b3e7Seric (void) strcat(buf, ": "); 1615d87e85f3Seric (void) strcat(buf, statmsg); 16168557d168Seric } 1617198d9be0Seric statmsg = buf; 1618198d9be0Seric } 161925a99e2eSeric else 1620d87e85f3Seric { 162125a99e2eSeric statmsg = SysExMsg[i]; 16227d55540cSeric if (*statmsg++ == ':') 16237d55540cSeric { 16247d55540cSeric (void) sprintf(buf, "%s: %s", statmsg, errstring(errno)); 16257d55540cSeric statmsg = buf; 16267d55540cSeric } 1627d87e85f3Seric } 1628588cad61Seric 1629588cad61Seric /* 1630588cad61Seric ** Print the message as appropriate 1631588cad61Seric */ 1632588cad61Seric 1633198d9be0Seric if (stat == EX_OK || stat == EX_TEMPFAIL) 1634e12d03eeSeric message(&statmsg[4], errstring(errno)); 163525a99e2eSeric else 163625a99e2eSeric { 1637c1f9df2cSeric Errors++; 1638e12d03eeSeric usrerr(statmsg, errstring(errno)); 163925a99e2eSeric } 164025a99e2eSeric 164125a99e2eSeric /* 164225a99e2eSeric ** Final cleanup. 164325a99e2eSeric ** Log a record of the transaction. Compute the new 164425a99e2eSeric ** ExitStat -- if we already had an error, stick with 164525a99e2eSeric ** that. 164625a99e2eSeric */ 164725a99e2eSeric 16482f624c86Seric if (LogLevel > ((stat == EX_TEMPFAIL) ? 8 : (stat == EX_OK) ? 7 : 6)) 164981161401Seric logdelivery(m, mci, &statmsg[4], e); 1650eb238f8cSeric 1651eb238f8cSeric if (stat != EX_TEMPFAIL) 1652eb238f8cSeric setstat(stat); 1653198d9be0Seric if (stat != EX_OK) 1654198d9be0Seric { 1655198d9be0Seric if (e->e_message != NULL) 1656198d9be0Seric free(e->e_message); 1657198d9be0Seric e->e_message = newstr(&statmsg[4]); 1658198d9be0Seric } 16598557d168Seric errno = 0; 1660d4bd8f0eSbostic #ifdef NAMED_BIND 1661f28da541Smiriam h_errno = 0; 1662d4bd8f0eSbostic #endif 1663eb238f8cSeric } 1664eb238f8cSeric /* 1665eb238f8cSeric ** LOGDELIVERY -- log the delivery in the system log 1666eb238f8cSeric ** 1667eb238f8cSeric ** Parameters: 166881161401Seric ** m -- the mailer info. Can be NULL for initial queue. 166981161401Seric ** mci -- the mailer connection info -- can be NULL if the 167081161401Seric ** log is occuring when no connection is active. 167181161401Seric ** stat -- the message to print for the status. 167281161401Seric ** e -- the current envelope. 1673eb238f8cSeric ** 1674eb238f8cSeric ** Returns: 1675eb238f8cSeric ** none 1676eb238f8cSeric ** 1677eb238f8cSeric ** Side Effects: 1678eb238f8cSeric ** none 1679eb238f8cSeric */ 1680eb238f8cSeric 168181161401Seric logdelivery(m, mci, stat, e) 168281161401Seric MAILER *m; 168381161401Seric register MCI *mci; 1684eb238f8cSeric char *stat; 1685b31e7f2bSeric register ENVELOPE *e; 16865cf56be3Seric { 1687eb238f8cSeric # ifdef LOG 16889507d1f9Seric char *curhost; 1689d6acf3eeSeric char buf[512]; 16909507d1f9Seric extern char *pintvl(); 16919507d1f9Seric extern char *macvalue(); 16929507d1f9Seric 169348ed5d33Seric (void) sprintf(buf, "delay=%s", pintvl(curtime() - e->e_ctime, TRUE)); 169481161401Seric 169548ed5d33Seric if (m != NULL) 169671ff6caaSeric { 169748ed5d33Seric (void) strcat(buf, ", mailer="); 169848ed5d33Seric (void) strcat(buf, m->m_name); 169971ff6caaSeric } 170048ed5d33Seric 170148ed5d33Seric if (mci != NULL && mci->mci_host != NULL) 170271ff6caaSeric { 170371ff6caaSeric # ifdef DAEMON 1704e2f2f828Seric extern SOCKADDR CurHostAddr; 1705e2f2f828Seric extern char *anynet_ntoa(); 170648ed5d33Seric # endif 170771ff6caaSeric 170848ed5d33Seric (void) strcat(buf, ", relay="); 170948ed5d33Seric (void) strcat(buf, mci->mci_host); 171048ed5d33Seric 171148ed5d33Seric # ifdef DAEMON 171248ed5d33Seric (void) strcat(buf, " ("); 1713e2f2f828Seric (void) strcat(buf, anynet_ntoa(&CurHostAddr)); 171448ed5d33Seric (void) strcat(buf, ")"); 171571ff6caaSeric # endif 171671ff6caaSeric } 17179507d1f9Seric else 171848ed5d33Seric { 171948ed5d33Seric char *p = macvalue('h', e); 17209507d1f9Seric 172148ed5d33Seric if (p != NULL && p[0] != '\0') 172248ed5d33Seric { 172348ed5d33Seric (void) strcat(buf, ", relay="); 172448ed5d33Seric (void) strcat(buf, p); 172548ed5d33Seric } 172648ed5d33Seric } 1727d6acf3eeSeric 1728d6acf3eeSeric syslog(LOG_INFO, "%s: to=%s, %s, stat=%s", 1729d6acf3eeSeric e->e_id, e->e_to, buf, stat); 17306c2c3107Seric # endif /* LOG */ 173125a99e2eSeric } 173225a99e2eSeric /* 173351552439Seric ** PUTFROMLINE -- output a UNIX-style from line (or whatever) 173425a99e2eSeric ** 173551552439Seric ** This can be made an arbitrary message separator by changing $l 173651552439Seric ** 17379b6c17a6Seric ** One of the ugliest hacks seen by human eyes is contained herein: 17389b6c17a6Seric ** UUCP wants those stupid "remote from <host>" lines. Why oh why 17399b6c17a6Seric ** does a well-meaning programmer such as myself have to deal with 17409b6c17a6Seric ** this kind of antique garbage???? 174125a99e2eSeric ** 174225a99e2eSeric ** Parameters: 174351552439Seric ** fp -- the file to output to. 174451552439Seric ** m -- the mailer describing this entry. 174525a99e2eSeric ** 174625a99e2eSeric ** Returns: 174751552439Seric ** none 174825a99e2eSeric ** 174925a99e2eSeric ** Side Effects: 175051552439Seric ** outputs some text to fp. 175125a99e2eSeric */ 175225a99e2eSeric 1753b31e7f2bSeric putfromline(fp, m, e) 175451552439Seric register FILE *fp; 175551552439Seric register MAILER *m; 1756b31e7f2bSeric ENVELOPE *e; 175725a99e2eSeric { 17582bc47524Seric char *template = "\201l\n"; 175951552439Seric char buf[MAXLINE]; 176025a99e2eSeric 176157fc6f17Seric if (bitnset(M_NHDR, m->m_flags)) 176251552439Seric return; 176313bbc08cSeric 17642c7e1b8dSeric # ifdef UGLYUUCP 176557fc6f17Seric if (bitnset(M_UGLYUUCP, m->m_flags)) 176674b6e67bSeric { 1767ea09d6edSeric char *bang; 1768ea09d6edSeric char xbuf[MAXLINE]; 176974b6e67bSeric 1770ee4b0922Seric expand("\201g", buf, &buf[sizeof buf - 1], e); 17716c2c3107Seric bang = strchr(buf, '!'); 177274b6e67bSeric if (bang == NULL) 177308b25121Seric syserr("554 No ! in UUCP! (%s)", buf); 177474b6e67bSeric else 1775588cad61Seric { 1776ea09d6edSeric *bang++ = '\0'; 17772bc47524Seric (void) sprintf(xbuf, "From %s \201d remote from %s\n", bang, buf); 1778ea09d6edSeric template = xbuf; 177974b6e67bSeric } 1780588cad61Seric } 17816c2c3107Seric # endif /* UGLYUUCP */ 1782b31e7f2bSeric expand(template, buf, &buf[sizeof buf - 1], e); 178377b52738Seric putline(buf, fp, m); 1784bc6e2962Seric } 1785bc6e2962Seric /* 178651552439Seric ** PUTBODY -- put the body of a message. 178751552439Seric ** 178851552439Seric ** Parameters: 178951552439Seric ** fp -- file to output onto. 179077b52738Seric ** m -- a mailer descriptor to control output format. 17919a6a5f55Seric ** e -- the envelope to put out. 179251552439Seric ** 179351552439Seric ** Returns: 179451552439Seric ** none. 179551552439Seric ** 179651552439Seric ** Side Effects: 179751552439Seric ** The message is written onto fp. 179851552439Seric */ 179951552439Seric 180077b52738Seric putbody(fp, m, e) 180151552439Seric FILE *fp; 1802588cad61Seric MAILER *m; 18039a6a5f55Seric register ENVELOPE *e; 180451552439Seric { 180577b52738Seric char buf[MAXLINE]; 180651552439Seric 180751552439Seric /* 180851552439Seric ** Output the body of the message 180951552439Seric */ 181051552439Seric 18119a6a5f55Seric if (e->e_dfp == NULL) 181251552439Seric { 18139a6a5f55Seric if (e->e_df != NULL) 18149a6a5f55Seric { 18159a6a5f55Seric e->e_dfp = fopen(e->e_df, "r"); 18169a6a5f55Seric if (e->e_dfp == NULL) 18178f9146b0Srick syserr("putbody: Cannot open %s for %s from %s", 18188f9146b0Srick e->e_df, e->e_to, e->e_from); 18199a6a5f55Seric } 18209a6a5f55Seric else 182177b52738Seric putline("<<< No Message Collected >>>", fp, m); 18229a6a5f55Seric } 18239a6a5f55Seric if (e->e_dfp != NULL) 18249a6a5f55Seric { 18259a6a5f55Seric rewind(e->e_dfp); 182677b52738Seric while (!ferror(fp) && fgets(buf, sizeof buf, e->e_dfp) != NULL) 182724fc8aeeSeric { 182824fc8aeeSeric if (buf[0] == 'F' && bitnset(M_ESCFROM, m->m_flags) && 1829d6fa2b58Sbostic strncmp(buf, "From ", 5) == 0) 18303462ad9eSeric (void) putc('>', fp); 183177b52738Seric putline(buf, fp, m); 183224fc8aeeSeric } 183351552439Seric 18349a6a5f55Seric if (ferror(e->e_dfp)) 183551552439Seric { 183651552439Seric syserr("putbody: read error"); 183751552439Seric ExitStat = EX_IOERR; 183851552439Seric } 183951552439Seric } 184051552439Seric 1841*0890ba1fSeric /* some mailers want extra blank line at end of message */ 1842*0890ba1fSeric if (bitnset(M_BLANKEND, m->m_flags) && buf[0] != '\0' && buf[0] != '\n') 1843*0890ba1fSeric putline("", fp, m); 1844*0890ba1fSeric 184551552439Seric (void) fflush(fp); 184651552439Seric if (ferror(fp) && errno != EPIPE) 184751552439Seric { 184851552439Seric syserr("putbody: write error"); 184951552439Seric ExitStat = EX_IOERR; 185051552439Seric } 185151552439Seric errno = 0; 185225a99e2eSeric } 185325a99e2eSeric /* 185425a99e2eSeric ** MAILFILE -- Send a message to a file. 185525a99e2eSeric ** 1856f129ec7dSeric ** If the file has the setuid/setgid bits set, but NO execute 1857f129ec7dSeric ** bits, sendmail will try to become the owner of that file 1858f129ec7dSeric ** rather than the real user. Obviously, this only works if 1859f129ec7dSeric ** sendmail runs as root. 1860f129ec7dSeric ** 1861588cad61Seric ** This could be done as a subordinate mailer, except that it 1862588cad61Seric ** is used implicitly to save messages in ~/dead.letter. We 1863588cad61Seric ** view this as being sufficiently important as to include it 1864588cad61Seric ** here. For example, if the system is dying, we shouldn't have 1865588cad61Seric ** to create another process plus some pipes to save the message. 1866588cad61Seric ** 186725a99e2eSeric ** Parameters: 186825a99e2eSeric ** filename -- the name of the file to send to. 18696259796dSeric ** ctladdr -- the controlling address header -- includes 18706259796dSeric ** the userid/groupid to be when sending. 187125a99e2eSeric ** 187225a99e2eSeric ** Returns: 187325a99e2eSeric ** The exit code associated with the operation. 187425a99e2eSeric ** 187525a99e2eSeric ** Side Effects: 187625a99e2eSeric ** none. 187725a99e2eSeric */ 187825a99e2eSeric 1879b31e7f2bSeric mailfile(filename, ctladdr, e) 188025a99e2eSeric char *filename; 18816259796dSeric ADDRESS *ctladdr; 1882b31e7f2bSeric register ENVELOPE *e; 188325a99e2eSeric { 188425a99e2eSeric register FILE *f; 188532d19d43Seric register int pid; 188615d084d5Seric int mode; 188725a99e2eSeric 1888671745f3Seric if (tTd(11, 1)) 1889671745f3Seric { 1890671745f3Seric printf("mailfile %s\n ctladdr=", filename); 1891671745f3Seric printaddr(ctladdr, FALSE); 1892671745f3Seric } 1893671745f3Seric 189432d19d43Seric /* 189532d19d43Seric ** Fork so we can change permissions here. 189632d19d43Seric ** Note that we MUST use fork, not vfork, because of 189732d19d43Seric ** the complications of calling subroutines, etc. 189832d19d43Seric */ 189932d19d43Seric 190032d19d43Seric DOFORK(fork); 190132d19d43Seric 190232d19d43Seric if (pid < 0) 190332d19d43Seric return (EX_OSERR); 190432d19d43Seric else if (pid == 0) 190532d19d43Seric { 190632d19d43Seric /* child -- actually write to file */ 1907f129ec7dSeric struct stat stb; 1908f129ec7dSeric 19090984da9fSeric (void) signal(SIGINT, SIG_DFL); 19100984da9fSeric (void) signal(SIGHUP, SIG_DFL); 19110984da9fSeric (void) signal(SIGTERM, SIG_DFL); 19123462ad9eSeric (void) umask(OldUmask); 191395f16dc0Seric 1914f129ec7dSeric if (stat(filename, &stb) < 0) 1915e6e1265fSeric stb.st_mode = 0666; 191615d084d5Seric mode = stb.st_mode; 191795f16dc0Seric 191895f16dc0Seric /* limit the errors to those actually caused in the child */ 191995f16dc0Seric errno = 0; 192095f16dc0Seric ExitStat = EX_OK; 192195f16dc0Seric 1922f129ec7dSeric if (bitset(0111, stb.st_mode)) 1923f129ec7dSeric exit(EX_CANTCREAT); 192403827b5fSeric if (ctladdr == NULL) 19258f9146b0Srick ctladdr = &e->e_from; 192615d084d5Seric else 192715d084d5Seric { 192815d084d5Seric /* ignore setuid and setgid bits */ 192915d084d5Seric mode &= ~(S_ISGID|S_ISUID); 193015d084d5Seric } 193115d084d5Seric 19328f9146b0Srick /* we have to open the dfile BEFORE setuid */ 19338f9146b0Srick if (e->e_dfp == NULL && e->e_df != NULL) 19348f9146b0Srick { 19358f9146b0Srick e->e_dfp = fopen(e->e_df, "r"); 193695f16dc0Seric if (e->e_dfp == NULL) 193795f16dc0Seric { 19388f9146b0Srick syserr("mailfile: Cannot open %s for %s from %s", 19398f9146b0Srick e->e_df, e->e_to, e->e_from); 19408f9146b0Srick } 19418f9146b0Srick } 19428f9146b0Srick 194315d084d5Seric if (!bitset(S_ISGID, mode) || setgid(stb.st_gid) < 0) 1944e36b99e2Seric { 194595f16dc0Seric if (ctladdr->q_uid == 0) 194695f16dc0Seric { 1947e36b99e2Seric (void) setgid(DefGid); 1948898a126bSbostic (void) initgroups(DefUser, DefGid); 194995f16dc0Seric } 195095f16dc0Seric else 195195f16dc0Seric { 19526259796dSeric (void) setgid(ctladdr->q_gid); 1953898a126bSbostic (void) initgroups(ctladdr->q_ruser ? 1954898a126bSbostic ctladdr->q_ruser : ctladdr->q_user, 1955898a126bSbostic ctladdr->q_gid); 1956898a126bSbostic } 1957e36b99e2Seric } 195815d084d5Seric if (!bitset(S_ISUID, mode) || setuid(stb.st_uid) < 0) 1959e36b99e2Seric { 1960e36b99e2Seric if (ctladdr->q_uid == 0) 1961e36b99e2Seric (void) setuid(DefUid); 1962e36b99e2Seric else 19636259796dSeric (void) setuid(ctladdr->q_uid); 1964e36b99e2Seric } 196595f16dc0Seric FileName = filename; 196695f16dc0Seric LineNumber = 0; 196727628d59Seric f = dfopen(filename, "a"); 196825a99e2eSeric if (f == NULL) 196995f16dc0Seric { 197008b25121Seric message("554 cannot open"); 197132d19d43Seric exit(EX_CANTCREAT); 197295f16dc0Seric } 197325a99e2eSeric 19740331ce05Seric putfromline(f, FileMailer, e); 19750331ce05Seric (*e->e_puthdr)(f, FileMailer, e); 19760331ce05Seric putline("\n", f, FileMailer); 19770331ce05Seric (*e->e_putbody)(f, FileMailer, e); 19780331ce05Seric putline("\n", f, FileMailer); 197995f16dc0Seric if (ferror(f)) 198095f16dc0Seric { 198108b25121Seric message("451 I/O error"); 198295f16dc0Seric setstat(EX_IOERR); 198395f16dc0Seric } 1984ee4b0922Seric (void) xfclose(f, "mailfile", filename); 198532d19d43Seric (void) fflush(stdout); 1986e36b99e2Seric 198727628d59Seric /* reset ISUID & ISGID bits for paranoid systems */ 1988c77d1c25Seric (void) chmod(filename, (int) stb.st_mode); 198995f16dc0Seric exit(ExitStat); 199013bbc08cSeric /*NOTREACHED*/ 199132d19d43Seric } 199232d19d43Seric else 199332d19d43Seric { 199432d19d43Seric /* parent -- wait for exit status */ 1995588cad61Seric int st; 199632d19d43Seric 1997588cad61Seric st = waitfor(pid); 1998588cad61Seric if ((st & 0377) != 0) 1999588cad61Seric return (EX_UNAVAILABLE); 2000588cad61Seric else 2001588cad61Seric return ((st >> 8) & 0377); 20028f9146b0Srick /*NOTREACHED*/ 200332d19d43Seric } 200425a99e2eSeric } 2005ea4dc939Seric /* 2006e103b48fSeric ** HOSTSIGNATURE -- return the "signature" for a host. 2007e103b48fSeric ** 2008e103b48fSeric ** The signature describes how we are going to send this -- it 2009e103b48fSeric ** can be just the hostname (for non-Internet hosts) or can be 2010e103b48fSeric ** an ordered list of MX hosts. 2011e103b48fSeric ** 2012e103b48fSeric ** Parameters: 2013e103b48fSeric ** m -- the mailer describing this host. 2014e103b48fSeric ** host -- the host name. 2015e103b48fSeric ** e -- the current envelope. 2016e103b48fSeric ** 2017e103b48fSeric ** Returns: 2018e103b48fSeric ** The signature for this host. 2019e103b48fSeric ** 2020e103b48fSeric ** Side Effects: 2021e103b48fSeric ** Can tweak the symbol table. 2022e103b48fSeric */ 2023e103b48fSeric 2024e103b48fSeric char * 2025e103b48fSeric hostsignature(m, host, e) 2026e103b48fSeric register MAILER *m; 2027e103b48fSeric char *host; 2028e103b48fSeric ENVELOPE *e; 2029e103b48fSeric { 2030e103b48fSeric register char *p; 2031e103b48fSeric register STAB *s; 2032e103b48fSeric int i; 2033e103b48fSeric int len; 2034e103b48fSeric #ifdef NAMED_BIND 2035e103b48fSeric int nmx; 2036e103b48fSeric auto int rcode; 2037bafdc4e5Seric char *hp; 2038bafdc4e5Seric char *endp; 2039516782b4Seric int oldoptions; 2040e103b48fSeric char *mxhosts[MAXMXHOSTS + 1]; 2041e103b48fSeric #endif 2042e103b48fSeric 2043e103b48fSeric /* 2044e103b48fSeric ** Check to see if this uses IPC -- if not, it can't have MX records. 2045e103b48fSeric */ 2046e103b48fSeric 2047e103b48fSeric p = m->m_mailer; 2048e103b48fSeric if (strcmp(p, "[IPC]") != 0 && strcmp(p, "[TCP]") != 0) 2049e103b48fSeric { 2050e103b48fSeric /* just an ordinary mailer */ 2051e103b48fSeric return host; 2052e103b48fSeric } 2053e103b48fSeric 2054e103b48fSeric /* 2055e103b48fSeric ** If it is a numeric address, just return it. 2056e103b48fSeric */ 2057e103b48fSeric 2058e103b48fSeric if (host[0] == '[') 2059e103b48fSeric return host; 2060e103b48fSeric 2061e103b48fSeric /* 2062e103b48fSeric ** Look it up in the symbol table. 2063e103b48fSeric */ 2064e103b48fSeric 2065e103b48fSeric s = stab(host, ST_HOSTSIG, ST_ENTER); 2066e103b48fSeric if (s->s_hostsig != NULL) 2067e103b48fSeric return s->s_hostsig; 2068e103b48fSeric 2069e103b48fSeric /* 2070e103b48fSeric ** Not already there -- create a signature. 2071e103b48fSeric */ 2072e103b48fSeric 2073e103b48fSeric #ifdef NAMED_BIND 2074516782b4Seric if (ConfigLevel < 2) 2075516782b4Seric { 2076516782b4Seric oldoptions = _res.options; 2077516782b4Seric _res.options &= ~(RES_DEFNAMES | RES_DNSRCH); /* XXX */ 2078516782b4Seric } 2079516782b4Seric 2080bafdc4e5Seric for (hp = host; hp != NULL; hp = endp) 2081bafdc4e5Seric { 2082bafdc4e5Seric endp = strchr(hp, ':'); 2083bafdc4e5Seric if (endp != NULL) 2084bafdc4e5Seric *endp = '\0'; 2085bafdc4e5Seric 20867bf809e6Seric nmx = getmxrr(hp, mxhosts, TRUE, &rcode); 20877d55540cSeric 2088e103b48fSeric if (nmx <= 0) 2089e103b48fSeric { 2090e103b48fSeric register MCI *mci; 2091e103b48fSeric extern int errno; 2092e103b48fSeric extern MCI *mci_get(); 2093e103b48fSeric 2094e103b48fSeric /* update the connection info for this host */ 2095bafdc4e5Seric mci = mci_get(hp, m); 2096e103b48fSeric mci->mci_exitstat = rcode; 2097e103b48fSeric mci->mci_errno = errno; 2098e103b48fSeric 2099e103b48fSeric /* and return the original host name as the signature */ 2100bafdc4e5Seric nmx = 1; 2101bafdc4e5Seric mxhosts[0] = hp; 2102e103b48fSeric } 2103e103b48fSeric 2104e103b48fSeric len = 0; 2105e103b48fSeric for (i = 0; i < nmx; i++) 2106e103b48fSeric { 2107e103b48fSeric len += strlen(mxhosts[i]) + 1; 2108e103b48fSeric } 2109bafdc4e5Seric if (s->s_hostsig != NULL) 2110bafdc4e5Seric len += strlen(s->s_hostsig) + 1; 2111bafdc4e5Seric p = xalloc(len); 2112bafdc4e5Seric if (s->s_hostsig != NULL) 2113bafdc4e5Seric { 2114bafdc4e5Seric (void) strcpy(p, s->s_hostsig); 2115bafdc4e5Seric free(s->s_hostsig); 2116bafdc4e5Seric s->s_hostsig = p; 2117bafdc4e5Seric p += strlen(p); 2118bafdc4e5Seric *p++ = ':'; 2119bafdc4e5Seric } 2120bafdc4e5Seric else 2121bafdc4e5Seric s->s_hostsig = p; 2122e103b48fSeric for (i = 0; i < nmx; i++) 2123e103b48fSeric { 2124e103b48fSeric if (i != 0) 2125e103b48fSeric *p++ = ':'; 2126e103b48fSeric strcpy(p, mxhosts[i]); 2127e103b48fSeric p += strlen(p); 2128e103b48fSeric } 2129bafdc4e5Seric if (endp != NULL) 2130bafdc4e5Seric *endp++ = ':'; 2131bafdc4e5Seric } 2132e103b48fSeric makelower(s->s_hostsig); 2133516782b4Seric if (ConfigLevel < 2) 2134516782b4Seric _res.options = oldoptions; 2135e103b48fSeric #else 2136e103b48fSeric /* not using BIND -- the signature is just the host name */ 2137e103b48fSeric s->s_hostsig = host; 2138e103b48fSeric #endif 2139e103b48fSeric if (tTd(17, 1)) 2140e103b48fSeric printf("hostsignature(%s) = %s\n", host, s->s_hostsig); 2141e103b48fSeric return s->s_hostsig; 2142e103b48fSeric } 2143