1 /* 2 * Copyright (c) 1983 Eric P. Allman 3 * Copyright (c) 1988 Regents of the University of California. 4 * All rights reserved. 5 * 6 * %sccs.include.redist.c% 7 */ 8 9 # include "sendmail.h" 10 11 #ifndef lint 12 #ifdef SMTP 13 static char sccsid[] = "@(#)usersmtp.c 6.17 (Berkeley) 03/18/93 (with SMTP)"; 14 #else 15 static char sccsid[] = "@(#)usersmtp.c 6.17 (Berkeley) 03/18/93 (without SMTP)"; 16 #endif 17 #endif /* not lint */ 18 19 # include <sysexits.h> 20 # include <errno.h> 21 22 # ifdef SMTP 23 24 /* 25 ** USERSMTP -- run SMTP protocol from the user end. 26 ** 27 ** This protocol is described in RFC821. 28 */ 29 30 #define REPLYTYPE(r) ((r) / 100) /* first digit of reply code */ 31 #define REPLYCLASS(r) (((r) / 10) % 10) /* second digit of reply code */ 32 #define SMTPCLOSING 421 /* "Service Shutting Down" */ 33 34 char SmtpMsgBuffer[MAXLINE]; /* buffer for commands */ 35 char SmtpReplyBuffer[MAXLINE]; /* buffer for replies */ 36 char SmtpError[MAXLINE] = ""; /* save failure error messages */ 37 int SmtpPid; /* pid of mailer */ 38 39 #ifdef __STDC__ 40 extern smtpmessage(char *f, MAILER *m, MCI *mci, ...); 41 #endif 42 /* 43 ** SMTPINIT -- initialize SMTP. 44 ** 45 ** Opens the connection and sends the initial protocol. 46 ** 47 ** Parameters: 48 ** m -- mailer to create connection to. 49 ** pvp -- pointer to parameter vector to pass to 50 ** the mailer. 51 ** 52 ** Returns: 53 ** none. 54 ** 55 ** Side Effects: 56 ** creates connection and sends initial protocol. 57 */ 58 59 smtpinit(m, mci, e) 60 struct mailer *m; 61 register MCI *mci; 62 ENVELOPE *e; 63 { 64 register int r; 65 EVENT *gte; 66 extern STAB *stab(); 67 68 if (tTd(17, 1)) 69 { 70 printf("smtpinit "); 71 mci_dump(mci); 72 } 73 74 /* 75 ** Open the connection to the mailer. 76 */ 77 78 SmtpError[0] = '\0'; 79 CurHostName = mci->mci_host; /* XXX UGLY XXX */ 80 switch (mci->mci_state) 81 { 82 case MCIS_ACTIVE: 83 /* need to clear old information */ 84 smtprset(m, mci, e); 85 /* fall through */ 86 87 case MCIS_OPEN: 88 return; 89 90 case MCIS_ERROR: 91 case MCIS_SSD: 92 /* shouldn't happen */ 93 smtpquit(m, mci, e); 94 /* fall through */ 95 96 case MCIS_CLOSED: 97 syserr("451 smtpinit: state CLOSED"); 98 return; 99 100 case MCIS_OPENING: 101 break; 102 } 103 104 SmtpPhase = mci->mci_phase = "user open"; 105 mci->mci_state = MCIS_OPENING; 106 107 /* 108 ** Get the greeting message. 109 ** This should appear spontaneously. Give it five minutes to 110 ** happen. 111 */ 112 113 SmtpPhase = mci->mci_phase = "greeting wait"; 114 setproctitle("%s %s: %s", e->e_id, CurHostName, mci->mci_phase); 115 r = reply(m, mci, e, TimeOuts.to_initial); 116 if (r < 0 || REPLYTYPE(r) != 2) 117 goto tempfail1; 118 119 /* 120 ** Send the HELO command. 121 ** My mother taught me to always introduce myself. 122 */ 123 124 smtpmessage("HELO %s", m, mci, MyHostName); 125 SmtpPhase = mci->mci_phase = "HELO wait"; 126 setproctitle("%s %s: %s", e->e_id, CurHostName, mci->mci_phase); 127 r = reply(m, mci, e, TimeOuts.to_helo); 128 if (r < 0) 129 goto tempfail1; 130 else if (REPLYTYPE(r) == 5) 131 goto unavailable; 132 else if (REPLYTYPE(r) != 2) 133 goto tempfail1; 134 135 /* 136 ** If this is expected to be another sendmail, send some internal 137 ** commands. 138 */ 139 140 if (bitnset(M_INTERNAL, m->m_flags)) 141 { 142 /* tell it to be verbose */ 143 smtpmessage("VERB", m, mci); 144 r = reply(m, mci, e, TimeOuts.to_miscshort); 145 if (r < 0) 146 goto tempfail2; 147 } 148 149 mci->mci_state = MCIS_OPEN; 150 return; 151 152 tempfail1: 153 tempfail2: 154 mci->mci_exitstat = EX_TEMPFAIL; 155 if (mci->mci_errno == 0) 156 mci->mci_errno = errno; 157 if (mci->mci_state != MCIS_CLOSED) 158 smtpquit(m, mci, e); 159 return; 160 161 unavailable: 162 mci->mci_exitstat = EX_UNAVAILABLE; 163 mci->mci_errno = errno; 164 smtpquit(m, mci, e); 165 return; 166 } 167 168 smtpmailfrom(m, mci, e) 169 struct mailer *m; 170 MCI *mci; 171 ENVELOPE *e; 172 { 173 int r; 174 char buf[MAXNAME]; 175 176 if (tTd(17, 2)) 177 printf("smtpmailfrom: CurHost=%s\n", CurHostName); 178 179 /* 180 ** Send the MAIL command. 181 ** Designates the sender. 182 */ 183 184 mci->mci_state = MCIS_ACTIVE; 185 186 if (bitset(EF_RESPONSE, e->e_flags)) 187 (void) strcpy(buf, ""); 188 else 189 expand("\201g", buf, &buf[sizeof buf - 1], e); 190 if (e->e_from.q_mailer == LocalMailer || 191 !bitnset(M_FROMPATH, m->m_flags)) 192 { 193 smtpmessage("MAIL From:<%s>", m, mci, buf); 194 } 195 else 196 { 197 smtpmessage("MAIL From:<@%s%c%s>", m, mci, MyHostName, 198 buf[0] == '@' ? ',' : ':', buf); 199 } 200 SmtpPhase = mci->mci_phase = "MAIL wait"; 201 setproctitle("%s %s: %s", e->e_id, CurHostName, mci->mci_phase); 202 r = reply(m, mci, e, TimeOuts.to_mail); 203 if (r < 0 || REPLYTYPE(r) == 4) 204 { 205 mci->mci_exitstat = EX_TEMPFAIL; 206 mci->mci_errno = errno; 207 smtpquit(m, mci, e); 208 return EX_TEMPFAIL; 209 } 210 else if (r == 250) 211 { 212 mci->mci_exitstat = EX_OK; 213 return EX_OK; 214 } 215 else if (r == 552) 216 { 217 /* signal service unavailable */ 218 mci->mci_exitstat = EX_UNAVAILABLE; 219 smtpquit(m, mci, e); 220 return EX_UNAVAILABLE; 221 } 222 223 #ifdef LOG 224 if (LogLevel > 1) 225 { 226 syslog(LOG_CRIT, "%s: SMTP MAIL protocol error: %s", 227 e->e_id, SmtpReplyBuffer); 228 } 229 #endif 230 231 /* protocol error -- close up */ 232 smtpquit(m, mci, e); 233 mci->mci_exitstat = EX_PROTOCOL; 234 return EX_PROTOCOL; 235 } 236 /* 237 ** SMTPRCPT -- designate recipient. 238 ** 239 ** Parameters: 240 ** to -- address of recipient. 241 ** m -- the mailer we are sending to. 242 ** mci -- the connection info for this transaction. 243 ** e -- the envelope for this transaction. 244 ** 245 ** Returns: 246 ** exit status corresponding to recipient status. 247 ** 248 ** Side Effects: 249 ** Sends the mail via SMTP. 250 */ 251 252 smtprcpt(to, m, mci, e) 253 ADDRESS *to; 254 register MAILER *m; 255 MCI *mci; 256 ENVELOPE *e; 257 { 258 register int r; 259 260 smtpmessage("RCPT To:<%s>", m, mci, to->q_user); 261 262 SmtpPhase = mci->mci_phase = "RCPT wait"; 263 setproctitle("%s %s: %s", e->e_id, CurHostName, mci->mci_phase); 264 r = reply(m, mci, e, TimeOuts.to_rcpt); 265 if (r < 0 || REPLYTYPE(r) == 4) 266 return (EX_TEMPFAIL); 267 else if (REPLYTYPE(r) == 2) 268 return (EX_OK); 269 else if (r == 550 || r == 551 || r == 553) 270 return (EX_NOUSER); 271 else if (r == 552 || r == 554) 272 return (EX_UNAVAILABLE); 273 274 #ifdef LOG 275 if (LogLevel > 1) 276 { 277 syslog(LOG_CRIT, "%s: SMTP RCPT protocol error: %s", 278 e->e_id, SmtpReplyBuffer); 279 } 280 #endif 281 282 return (EX_PROTOCOL); 283 } 284 /* 285 ** SMTPDATA -- send the data and clean up the transaction. 286 ** 287 ** Parameters: 288 ** m -- mailer being sent to. 289 ** e -- the envelope for this message. 290 ** 291 ** Returns: 292 ** exit status corresponding to DATA command. 293 ** 294 ** Side Effects: 295 ** none. 296 */ 297 298 smtpdata(m, mci, e) 299 struct mailer *m; 300 register MCI *mci; 301 register ENVELOPE *e; 302 { 303 register int r; 304 305 /* 306 ** Send the data. 307 ** First send the command and check that it is ok. 308 ** Then send the data. 309 ** Follow it up with a dot to terminate. 310 ** Finally get the results of the transaction. 311 */ 312 313 /* send the command and check ok to proceed */ 314 smtpmessage("DATA", m, mci); 315 SmtpPhase = mci->mci_phase = "DATA wait"; 316 setproctitle("%s %s: %s", e->e_id, CurHostName, mci->mci_phase); 317 r = reply(m, mci, e, TimeOuts.to_datainit); 318 if (r < 0 || REPLYTYPE(r) == 4) 319 { 320 smtpquit(m, mci, e); 321 return (EX_TEMPFAIL); 322 } 323 else if (r == 554) 324 { 325 smtprset(m, mci, e); 326 return (EX_UNAVAILABLE); 327 } 328 else if (r != 354) 329 { 330 #ifdef LOG 331 if (LogLevel > 1) 332 { 333 syslog(LOG_CRIT, "%s: SMTP DATA-1 protocol error: %s", 334 e->e_id, SmtpReplyBuffer); 335 } 336 #endif 337 smtprset(m, mci, e); 338 return (EX_PROTOCOL); 339 } 340 341 /* now output the actual message */ 342 (*e->e_puthdr)(mci->mci_out, m, e); 343 putline("\n", mci->mci_out, m); 344 (*e->e_putbody)(mci->mci_out, m, e); 345 346 /* terminate the message */ 347 fprintf(mci->mci_out, ".%s", m->m_eol); 348 if (Verbose) 349 nmessage(">>> ."); 350 351 /* check for the results of the transaction */ 352 SmtpPhase = mci->mci_phase = "result wait"; 353 setproctitle("%s %s: %s", e->e_id, CurHostName, mci->mci_phase); 354 r = reply(m, mci, e, TimeOuts.to_datafinal); 355 if (r < 0) 356 { 357 smtpquit(m, mci, e); 358 return (EX_TEMPFAIL); 359 } 360 mci->mci_state = MCIS_OPEN; 361 if (REPLYTYPE(r) == 4) 362 return (EX_TEMPFAIL); 363 else if (r == 250) 364 return (EX_OK); 365 else if (r == 552 || r == 554) 366 return (EX_UNAVAILABLE); 367 #ifdef LOG 368 if (LogLevel > 1) 369 { 370 syslog(LOG_CRIT, "%s: SMTP DATA-2 protocol error: %s", 371 e->e_id, SmtpReplyBuffer); 372 } 373 #endif 374 return (EX_PROTOCOL); 375 } 376 /* 377 ** SMTPQUIT -- close the SMTP connection. 378 ** 379 ** Parameters: 380 ** m -- a pointer to the mailer. 381 ** 382 ** Returns: 383 ** none. 384 ** 385 ** Side Effects: 386 ** sends the final protocol and closes the connection. 387 */ 388 389 smtpquit(m, mci, e) 390 register MAILER *m; 391 register MCI *mci; 392 ENVELOPE *e; 393 { 394 int i; 395 396 /* send the quit message if we haven't gotten I/O error */ 397 if (mci->mci_state != MCIS_ERROR) 398 { 399 smtpmessage("QUIT", m, mci); 400 (void) reply(m, mci, e, TimeOuts.to_quit); 401 if (mci->mci_state == MCIS_CLOSED) 402 return; 403 } 404 405 /* now actually close the connection and pick up the zombie */ 406 i = endmailer(mci, m->m_argv[0]); 407 if (i != EX_OK) 408 syserr("451 smtpquit %s: stat %d", m->m_argv[0], i); 409 } 410 /* 411 ** SMTPRSET -- send a RSET (reset) command 412 */ 413 414 smtprset(m, mci, e) 415 register MAILER *m; 416 register MCI *mci; 417 ENVELOPE *e; 418 { 419 int r; 420 421 smtpmessage("RSET", m, mci); 422 r = reply(m, mci, e, TimeOuts.to_rset); 423 if (r < 0) 424 mci->mci_state = MCIS_ERROR; 425 else if (REPLYTYPE(r) == 2) 426 { 427 mci->mci_state = MCIS_OPEN; 428 return; 429 } 430 smtpquit(m, mci, e); 431 } 432 /* 433 ** SMTPNOOP -- send a NOOP (no operation) command to check the connection state 434 */ 435 436 smtpnoop(mci) 437 register MCI *mci; 438 { 439 int r; 440 MAILER *m = mci->mci_mailer; 441 extern ENVELOPE BlankEnvelope; 442 ENVELOPE *e = &BlankEnvelope; 443 444 smtpmessage("NOOP", m, mci); 445 r = reply(m, mci, e, TimeOuts.to_miscshort); 446 if (r < 0 || REPLYTYPE(r) != 2) 447 smtpquit(m, mci, e); 448 return r; 449 } 450 /* 451 ** REPLY -- read arpanet reply 452 ** 453 ** Parameters: 454 ** m -- the mailer we are reading the reply from. 455 ** mci -- the mailer connection info structure. 456 ** e -- the current envelope. 457 ** timeout -- the timeout for reads. 458 ** 459 ** Returns: 460 ** reply code it reads. 461 ** 462 ** Side Effects: 463 ** flushes the mail file. 464 */ 465 466 reply(m, mci, e, timeout) 467 MAILER *m; 468 MCI *mci; 469 ENVELOPE *e; 470 { 471 if (mci->mci_out != NULL) 472 (void) fflush(mci->mci_out); 473 474 if (tTd(18, 1)) 475 printf("reply\n"); 476 477 /* 478 ** Read the input line, being careful not to hang. 479 */ 480 481 for (;;) 482 { 483 register int r; 484 register char *p; 485 extern time_t curtime(); 486 487 /* actually do the read */ 488 if (e->e_xfp != NULL) 489 (void) fflush(e->e_xfp); /* for debugging */ 490 491 /* if we are in the process of closing just give the code */ 492 if (mci->mci_state == MCIS_CLOSED) 493 return (SMTPCLOSING); 494 495 if (mci->mci_out != NULL) 496 fflush(mci->mci_out); 497 498 /* get the line from the other side */ 499 p = sfgets(SmtpReplyBuffer, sizeof SmtpReplyBuffer, mci->mci_in, 500 timeout); 501 mci->mci_lastuse = curtime(); 502 503 if (p == NULL) 504 { 505 extern char MsgBuf[]; /* err.c */ 506 507 /* if the remote end closed early, fake an error */ 508 if (errno == 0) 509 # ifdef ECONNRESET 510 errno = ECONNRESET; 511 # else /* ECONNRESET */ 512 errno = EPIPE; 513 # endif /* ECONNRESET */ 514 515 mci->mci_errno = errno; 516 mci->mci_exitstat = EX_TEMPFAIL; 517 message("451 %s: reply: read error from %s", 518 e->e_id == NULL ? "NOQUEUE" : e->e_id, 519 mci->mci_host); 520 /* if debugging, pause so we can see state */ 521 if (tTd(18, 100)) 522 pause(); 523 # ifdef LOG 524 if (LogLevel > 1) 525 syslog(LOG_INFO, "%s", &MsgBuf[4]); 526 # endif /* LOG */ 527 mci->mci_state = MCIS_ERROR; 528 smtpquit(m, mci, e); 529 return (-1); 530 } 531 fixcrlf(SmtpReplyBuffer, TRUE); 532 533 if (e->e_xfp != NULL && strchr("45", SmtpReplyBuffer[0]) != NULL) 534 { 535 /* serious error -- log the previous command */ 536 if (SmtpMsgBuffer[0] != '\0') 537 fprintf(e->e_xfp, ">>> %s\n", SmtpMsgBuffer); 538 SmtpMsgBuffer[0] = '\0'; 539 540 /* now log the message as from the other side */ 541 fprintf(e->e_xfp, "<<< %s\n", SmtpReplyBuffer); 542 } 543 544 /* display the input for verbose mode */ 545 if (Verbose) 546 nmessage("%s", SmtpReplyBuffer); 547 548 /* if continuation is required, we can go on */ 549 if (SmtpReplyBuffer[3] == '-' || 550 !(isascii(SmtpReplyBuffer[0]) && isdigit(SmtpReplyBuffer[0]))) 551 continue; 552 553 /* decode the reply code */ 554 r = atoi(SmtpReplyBuffer); 555 556 /* extra semantics: 0xx codes are "informational" */ 557 if (r < 100) 558 continue; 559 560 /* save temporary failure messages for posterity */ 561 if (SmtpReplyBuffer[0] == '4' && SmtpError[0] == '\0') 562 (void) strcpy(SmtpError, SmtpReplyBuffer); 563 564 /* reply code 421 is "Service Shutting Down" */ 565 if (r == SMTPCLOSING && mci->mci_state != MCIS_SSD) 566 { 567 /* send the quit protocol */ 568 mci->mci_state = MCIS_SSD; 569 smtpquit(m, mci, e); 570 } 571 572 return (r); 573 } 574 } 575 /* 576 ** SMTPMESSAGE -- send message to server 577 ** 578 ** Parameters: 579 ** f -- format 580 ** m -- the mailer to control formatting. 581 ** a, b, c -- parameters 582 ** 583 ** Returns: 584 ** none. 585 ** 586 ** Side Effects: 587 ** writes message to mci->mci_out. 588 */ 589 590 /*VARARGS1*/ 591 #ifdef __STDC__ 592 smtpmessage(char *f, MAILER *m, MCI *mci, ...) 593 #else 594 smtpmessage(f, m, mci, va_alist) 595 char *f; 596 MAILER *m; 597 MCI *mci; 598 va_dcl 599 #endif 600 { 601 VA_LOCAL_DECL 602 603 VA_START(mci); 604 (void) vsprintf(SmtpMsgBuffer, f, ap); 605 VA_END; 606 607 if (tTd(18, 1) || Verbose) 608 nmessage(">>> %s", SmtpMsgBuffer); 609 if (mci->mci_out != NULL) 610 { 611 fprintf(mci->mci_out, "%s%s", SmtpMsgBuffer, 612 m == NULL ? "\r\n" : m->m_eol); 613 } 614 else 615 { 616 syserr("smtpmessage: NULL mci_out"); 617 } 618 } 619 620 # endif /* SMTP */ 621