1 # include <stdio.h> 2 # include <pwd.h> 3 # include <signal.h> 4 # include <ctype.h> 5 # include <errno.h> 6 # include "sendmail.h" 7 # ifdef LOG 8 # include <syslog.h> 9 # endif LOG 10 11 static char SccsId[] = "@(#)deliver.c 3.24 08/20/81"; 12 13 /* 14 ** DELIVER -- Deliver a message to a particular address. 15 ** 16 ** Parameters: 17 ** to -- the address to deliver the message to. 18 ** editfcn -- if non-NULL, we want to call this function 19 ** to output the letter (instead of just out- 20 ** putting it raw). 21 ** 22 ** Returns: 23 ** zero -- successfully delivered. 24 ** else -- some failure, see ExitStat for more info. 25 ** 26 ** Side Effects: 27 ** The standard input is passed off to someone. 28 */ 29 30 deliver(to, editfcn) 31 ADDRESS *to; 32 int (*editfcn)(); 33 { 34 char *host; 35 char *user; 36 char **pvp; 37 register char **mvp; 38 register char *p; 39 register struct mailer *m; 40 register int i; 41 extern putmessage(); 42 extern bool checkcompat(); 43 char *pv[MAXPV+1]; 44 char tobuf[MAXLINE]; 45 char buf[MAXNAME]; 46 bool firstone; 47 48 if (bitset(QDONTSEND, to->q_flags)) 49 return (0); 50 51 # ifdef DEBUG 52 if (Debug) 53 printf("\n--deliver, mailer=%d, host=`%s', first user=`%s'\n", 54 to->q_mailer, to->q_host, to->q_user); 55 # endif DEBUG 56 57 /* 58 ** Do initial argv setup. 59 ** Insert the mailer name. Notice that $x expansion is 60 ** NOT done on the mailer name. Then, if the mailer has 61 ** a picky -f flag, we insert it as appropriate. This 62 ** code does not check for 'pv' overflow; this places a 63 ** manifest lower limit of 4 for MAXPV. 64 */ 65 66 m = Mailer[to->q_mailer]; 67 host = to->q_host; 68 define('g', m->m_from); /* translated from address */ 69 define('h', host); /* to host */ 70 Errors = 0; 71 errno = 0; 72 pvp = pv; 73 *pvp++ = m->m_argv[0]; 74 75 /* insert -f or -r flag as appropriate */ 76 if (bitset(M_FOPT|M_ROPT, m->m_flags) && FromFlag) 77 { 78 if (bitset(M_FOPT, m->m_flags)) 79 *pvp++ = "-f"; 80 else 81 *pvp++ = "-r"; 82 (void) expand("$g", buf, &buf[sizeof buf - 1]); 83 *pvp++ = newstr(buf); 84 } 85 86 /* 87 ** Append the other fixed parts of the argv. These run 88 ** up to the first entry containing "$u". There can only 89 ** be one of these, and there are only a few more slots 90 ** in the pv after it. 91 */ 92 93 for (mvp = m->m_argv; (p = *++mvp) != NULL; ) 94 { 95 while ((p = index(p, '$')) != NULL) 96 if (*++p == 'u') 97 break; 98 if (p != NULL) 99 break; 100 101 /* this entry is safe -- go ahead and process it */ 102 (void) expand(*mvp, buf, &buf[sizeof buf - 1]); 103 *pvp++ = newstr(buf); 104 if (pvp >= &pv[MAXPV - 3]) 105 { 106 syserr("Too many parameters to %s before $u", pv[0]); 107 return (-1); 108 } 109 } 110 if (*mvp == NULL) 111 syserr("No $u in mailer argv for %s", pv[0]); 112 113 /* 114 ** At this point *mvp points to the argument with $u. We 115 ** run through our address list and append all the addresses 116 ** we can. If we run out of space, do not fret! We can 117 ** always send another copy later. 118 */ 119 120 tobuf[0] = '\0'; 121 firstone = TRUE; 122 To = tobuf; 123 for (; to != NULL; to = to->q_next) 124 { 125 /* avoid sending multiple recipients to dumb mailers */ 126 if (!firstone && !bitset(M_MUSER, m->m_flags)) 127 break; 128 129 /* if already sent or not for this host, don't send */ 130 if (bitset(QDONTSEND, to->q_flags) || strcmp(to->q_host, host) != 0) 131 continue; 132 user = to->q_user; 133 To = to->q_paddr; 134 to->q_flags |= QDONTSEND; 135 firstone = FALSE; 136 137 # ifdef DEBUG 138 if (Debug) 139 printf(" send to `%s'\n", user); 140 # endif DEBUG 141 142 /* 143 ** Check to see that these people are allowed to 144 ** talk to each other. 145 */ 146 147 if (!checkcompat(to)) 148 { 149 giveresponse(EX_UNAVAILABLE, TRUE, m); 150 continue; 151 } 152 153 /* 154 ** Strip quote bits from names if the mailer is dumb 155 ** about them. 156 */ 157 158 if (bitset(M_STRIPQ, m->m_flags)) 159 { 160 stripquotes(user, TRUE); 161 stripquotes(host, TRUE); 162 } 163 else 164 { 165 stripquotes(user, FALSE); 166 stripquotes(host, FALSE); 167 } 168 169 /* 170 ** If an error message has already been given, don't 171 ** bother to send to this address. 172 ** 173 ** >>>>>>>>>> This clause assumes that the local mailer 174 ** >> NOTE >> cannot do any further aliasing; that 175 ** >>>>>>>>>> function is subsumed by sendmail. 176 */ 177 178 if (bitset(QBADADDR, to->q_flags)) 179 continue; 180 181 /* 182 ** See if this user name is "special". 183 ** If the user name has a slash in it, assume that this 184 ** is a file -- send it off without further ado. 185 ** Note that this means that editfcn's will not 186 ** be applied to the message. Also note that 187 ** this type of addresses is not processed along 188 ** with the others, so we fudge on the To person. 189 */ 190 191 if (m == Mailer[M_LOCAL]) 192 { 193 if (index(user, '/') != NULL) 194 { 195 i = mailfile(user); 196 giveresponse(i, TRUE, m); 197 continue; 198 } 199 } 200 201 /* create list of users for error messages */ 202 if (tobuf[0] != '\0') 203 (void) strcat(tobuf, ","); 204 (void) strcat(tobuf, to->q_paddr); 205 define('u', user); /* to user */ 206 define('z', to->q_home); /* user's home */ 207 208 /* expand out this user */ 209 (void) expand(user, buf, &buf[sizeof buf - 1]); 210 *pvp++ = newstr(buf); 211 if (pvp >= &pv[MAXPV - 2]) 212 { 213 /* allow some space for trailing parms */ 214 break; 215 } 216 } 217 218 /* see if any addresses still exist */ 219 if (tobuf[0] == '\0') 220 return (0); 221 222 /* print out messages as full list */ 223 To = tobuf; 224 225 /* 226 ** Fill out any parameters after the $u parameter. 227 */ 228 229 while (*++mvp != NULL) 230 { 231 (void) expand(*mvp, buf, &buf[sizeof buf - 1]); 232 *pvp++ = newstr(buf); 233 if (pvp >= &pv[MAXPV]) 234 syserr("deliver: pv overflow after $u for %s", pv[0]); 235 } 236 *pvp++ = NULL; 237 238 /* 239 ** Call the mailer. 240 ** The argument vector gets built, pipes 241 ** are created as necessary, and we fork & exec as 242 ** appropriate. 243 ** 244 ** Notice the tacky hack to handle private mailers. 245 */ 246 247 if (editfcn == NULL) 248 editfcn = putmessage; 249 i = sendoff(m, pv, editfcn); 250 251 return (i); 252 } 253 /* 254 ** SENDOFF -- send off call to mailer & collect response. 255 ** 256 ** Parameters: 257 ** m -- mailer descriptor. 258 ** pvp -- parameter vector to send to it. 259 ** editfcn -- function to pipe it through. 260 ** 261 ** Returns: 262 ** exit status of mailer. 263 ** 264 ** Side Effects: 265 ** none. 266 */ 267 268 #define NFORKTRIES 5 269 270 sendoff(m, pvp, editfcn) 271 struct mailer *m; 272 char **pvp; 273 int (*editfcn)(); 274 { 275 auto int st; 276 register int i; 277 int pid; 278 int pvect[2]; 279 FILE *mfile; 280 extern putmessage(); 281 extern FILE *fdopen(); 282 283 # ifdef DEBUG 284 if (Debug) 285 { 286 printf("Sendoff:\n"); 287 printav(pvp); 288 } 289 # endif DEBUG 290 291 /* create a pipe to shove the mail through */ 292 if (pipe(pvect) < 0) 293 { 294 syserr("pipe"); 295 return (-1); 296 } 297 for (i = NFORKTRIES; i-- > 0; ) 298 { 299 # ifdef VFORK 300 pid = vfork(); 301 # else 302 pid = fork(); 303 # endif 304 if (pid >= 0) 305 break; 306 sleep((unsigned) NFORKTRIES - i); 307 } 308 if (pid < 0) 309 { 310 syserr("Cannot fork"); 311 (void) close(pvect[0]); 312 (void) close(pvect[1]); 313 return (-1); 314 } 315 else if (pid == 0) 316 { 317 /* child -- set up input & exec mailer */ 318 /* make diagnostic output be standard output */ 319 (void) close(2); 320 (void) dup(1); 321 (void) signal(SIGINT, SIG_IGN); 322 (void) close(0); 323 if (dup(pvect[0]) < 0) 324 { 325 syserr("Cannot dup to zero!"); 326 _exit(EX_OSERR); 327 } 328 (void) close(pvect[0]); 329 (void) close(pvect[1]); 330 if (!bitset(M_RESTR, m->m_flags)) 331 (void) setuid(getuid()); 332 # ifndef VFORK 333 /* 334 ** We have to be careful with vfork - we can't mung up the 335 ** memory but we don't want the mailer to inherit any extra 336 ** open files. Chances are the mailer won't 337 ** care about an extra file, but then again you never know. 338 ** Actually, we would like to close(fileno(pwf)), but it's 339 ** declared static so we can't. But if we fclose(pwf), which 340 ** is what endpwent does, it closes it in the parent too and 341 ** the next getpwnam will be slower. If you have a weird 342 ** mailer that chokes on the extra file you should do the 343 ** endpwent(). 344 ** 345 ** Similar comments apply to log. However, openlog is 346 ** clever enough to set the FIOCLEX mode on the file, 347 ** so it will be closed automatically on the exec. 348 */ 349 350 endpwent(); 351 # ifdef LOG 352 closelog(); 353 # endif LOG 354 # endif VFORK 355 execv(m->m_mailer, pvp); 356 /* syserr fails because log is closed */ 357 /* syserr("Cannot exec %s", m->m_mailer); */ 358 printf("Cannot exec %s\n", m->m_mailer); 359 (void) fflush(stdout); 360 _exit(EX_UNAVAILABLE); 361 } 362 363 /* write out message to mailer */ 364 (void) close(pvect[0]); 365 (void) signal(SIGPIPE, SIG_IGN); 366 mfile = fdopen(pvect[1], "w"); 367 if (editfcn == NULL) 368 editfcn = putmessage; 369 (*editfcn)(mfile, m); 370 (void) fclose(mfile); 371 372 /* 373 ** Wait for child to die and report status. 374 ** We should never get fatal errors (e.g., segmentation 375 ** violation), so we report those specially. For other 376 ** errors, we choose a status message (into statmsg), 377 ** and if it represents an error, we print it. 378 */ 379 380 while ((i = wait(&st)) > 0 && i != pid) 381 continue; 382 if (i < 0) 383 { 384 syserr("wait"); 385 return (-1); 386 } 387 if ((st & 0377) != 0) 388 { 389 syserr("%s: stat %o", pvp[0], st); 390 ExitStat = EX_UNAVAILABLE; 391 return (-1); 392 } 393 i = (st >> 8) & 0377; 394 giveresponse(i, TRUE, m); 395 return (i); 396 } 397 /* 398 ** GIVERESPONSE -- Interpret an error response from a mailer 399 ** 400 ** Parameters: 401 ** stat -- the status code from the mailer (high byte 402 ** only; core dumps must have been taken care of 403 ** already). 404 ** force -- if set, force an error message output, even 405 ** if the mailer seems to like to print its own 406 ** messages. 407 ** m -- the mailer descriptor for this mailer. 408 ** 409 ** Returns: 410 ** none. 411 ** 412 ** Side Effects: 413 ** Errors may be incremented. 414 ** ExitStat may be set. 415 ** 416 ** Called By: 417 ** deliver 418 */ 419 420 giveresponse(stat, force, m) 421 int stat; 422 int force; 423 register struct mailer *m; 424 { 425 register char *statmsg; 426 extern char *SysExMsg[]; 427 register int i; 428 extern int N_SysEx; 429 extern long MsgSize; 430 char buf[30]; 431 432 i = stat - EX__BASE; 433 if (i < 0 || i > N_SysEx) 434 statmsg = NULL; 435 else 436 statmsg = SysExMsg[i]; 437 if (stat == 0) 438 { 439 if (bitset(M_FINAL, m->m_flags)) 440 statmsg = "delivered"; 441 else 442 statmsg = "queued"; 443 if (Verbose) 444 message(Arpa_Info, statmsg); 445 } 446 else 447 { 448 Errors++; 449 if (statmsg == NULL && m->m_badstat != 0) 450 { 451 stat = m->m_badstat; 452 i = stat - EX__BASE; 453 # ifdef DEBUG 454 if (i < 0 || i >= N_SysEx) 455 syserr("Bad m_badstat %d", stat); 456 else 457 # endif DEBUG 458 statmsg = SysExMsg[i]; 459 } 460 if (statmsg == NULL) 461 usrerr("unknown mailer response %d", stat); 462 else if (force || !bitset(M_QUIET, m->m_flags) || Verbose) 463 usrerr("%s", statmsg); 464 } 465 466 /* 467 ** Final cleanup. 468 ** Log a record of the transaction. Compute the new 469 ** ExitStat -- if we already had an error, stick with 470 ** that. 471 */ 472 473 if (statmsg == NULL) 474 { 475 (void) sprintf(buf, "error %d", stat); 476 statmsg = buf; 477 } 478 479 # ifdef LOG 480 syslog(LOG_INFO, "%s->%s: %ld: %s", From.q_paddr, To, MsgSize, statmsg); 481 # endif LOG 482 setstat(stat); 483 } 484 /* 485 ** PUTMESSAGE -- output a message to the final mailer. 486 ** 487 ** This routine takes care of recreating the header from the 488 ** in-core copy, etc. 489 ** 490 ** Parameters: 491 ** fp -- file to output onto. 492 ** m -- a mailer descriptor. 493 ** 494 ** Returns: 495 ** none. 496 ** 497 ** Side Effects: 498 ** The message is written onto fp. 499 */ 500 501 putmessage(fp, m) 502 FILE *fp; 503 struct mailer *m; 504 { 505 char buf[BUFSIZ]; 506 register int i; 507 HDR *h; 508 register char *p; 509 extern char *arpadate(); 510 bool anyheader = FALSE; 511 extern char *capitalize(); 512 513 /* output "From" line unless supressed */ 514 if (!bitset(M_NHDR, m->m_flags)) 515 fprintf(fp, "%s\n", FromLine); 516 517 /* output all header lines */ 518 for (h = Header; h != NULL; h = h->h_link) 519 { 520 if (bitset(H_DELETE, h->h_flags)) 521 continue; 522 if (bitset(H_CHECK|H_ACHECK, h->h_flags) && !bitset(h->h_mflags, m->m_flags)) 523 continue; 524 if (bitset(H_DEFAULT, h->h_flags)) 525 { 526 (void) expand(h->h_value, buf, &buf[sizeof buf]); 527 p = buf; 528 } 529 else 530 p = h->h_value; 531 if (*p == '\0') 532 continue; 533 fprintf(fp, "%s: %s\n", capitalize(h->h_field), p); 534 h->h_flags |= H_USED; 535 anyheader = TRUE; 536 } 537 538 if (anyheader) 539 fprintf(fp, "\n"); 540 541 /* output the body of the message */ 542 rewind(stdin); 543 while (!ferror(fp) && (i = fread(buf, 1, BUFSIZ, stdin)) > 0) 544 (void) fwrite(buf, 1, i, fp); 545 546 if (ferror(fp) && errno != EPIPE) 547 { 548 syserr("putmessage: write error"); 549 setstat(EX_IOERR); 550 } 551 errno = 0; 552 } 553 /* 554 ** MAILFILE -- Send a message to a file. 555 ** 556 ** Parameters: 557 ** filename -- the name of the file to send to. 558 ** 559 ** Returns: 560 ** The exit code associated with the operation. 561 ** 562 ** Side Effects: 563 ** none. 564 ** 565 ** Called By: 566 ** deliver 567 */ 568 569 mailfile(filename) 570 char *filename; 571 { 572 register FILE *f; 573 574 f = fopen(filename, "a"); 575 if (f == NULL) 576 return (EX_CANTCREAT); 577 578 putmessage(f, Mailer[1]); 579 fputs("\n", f); 580 (void) fclose(f); 581 return (EX_OK); 582 } 583