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.15 (Berkeley) 03/14/93 (with SMTP)"; 14 #else 15 static char sccsid[] = "@(#)usersmtp.c 6.15 (Berkeley) 03/14/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 expand("\201<", buf, &buf[sizeof buf - 1], e); 187 if (e->e_from.q_mailer == LocalMailer || 188 !bitnset(M_FROMPATH, m->m_flags)) 189 { 190 smtpmessage("MAIL From:<%s>", m, mci, buf); 191 } 192 else 193 { 194 smtpmessage("MAIL From:<@%s%c%s>", m, mci, MyHostName, 195 buf[0] == '@' ? ',' : ':', buf); 196 } 197 SmtpPhase = mci->mci_phase = "MAIL wait"; 198 setproctitle("%s %s: %s", e->e_id, CurHostName, mci->mci_phase); 199 r = reply(m, mci, e, TimeOuts.to_mail); 200 if (r < 0 || REPLYTYPE(r) == 4) 201 { 202 mci->mci_exitstat = EX_TEMPFAIL; 203 mci->mci_errno = errno; 204 smtpquit(m, mci, e); 205 return EX_TEMPFAIL; 206 } 207 else if (r == 250) 208 { 209 mci->mci_exitstat = EX_OK; 210 return EX_OK; 211 } 212 else if (r == 552) 213 { 214 /* signal service unavailable */ 215 mci->mci_exitstat = EX_UNAVAILABLE; 216 smtpquit(m, mci, e); 217 return EX_UNAVAILABLE; 218 } 219 220 #ifdef LOG 221 if (LogLevel > 1) 222 { 223 syslog(LOG_CRIT, "%s: SMTP MAIL protocol error: %s", 224 e->e_id, SmtpReplyBuffer); 225 } 226 #endif 227 228 /* protocol error -- close up */ 229 smtpquit(m, mci, e); 230 mci->mci_exitstat = EX_PROTOCOL; 231 return EX_PROTOCOL; 232 } 233 /* 234 ** SMTPRCPT -- designate recipient. 235 ** 236 ** Parameters: 237 ** to -- address of recipient. 238 ** m -- the mailer we are sending to. 239 ** mci -- the connection info for this transaction. 240 ** e -- the envelope for this transaction. 241 ** 242 ** Returns: 243 ** exit status corresponding to recipient status. 244 ** 245 ** Side Effects: 246 ** Sends the mail via SMTP. 247 */ 248 249 smtprcpt(to, m, mci, e) 250 ADDRESS *to; 251 register MAILER *m; 252 MCI *mci; 253 ENVELOPE *e; 254 { 255 register int r; 256 257 smtpmessage("RCPT To:<%s>", m, mci, to->q_user); 258 259 SmtpPhase = mci->mci_phase = "RCPT wait"; 260 setproctitle("%s %s: %s", e->e_id, CurHostName, mci->mci_phase); 261 r = reply(m, mci, e, TimeOuts.to_rcpt); 262 if (r < 0 || REPLYTYPE(r) == 4) 263 return (EX_TEMPFAIL); 264 else if (REPLYTYPE(r) == 2) 265 return (EX_OK); 266 else if (r == 550 || r == 551 || r == 553) 267 return (EX_NOUSER); 268 else if (r == 552 || r == 554) 269 return (EX_UNAVAILABLE); 270 271 #ifdef LOG 272 if (LogLevel > 1) 273 { 274 syslog(LOG_CRIT, "%s: SMTP RCPT protocol error: %s", 275 e->e_id, SmtpReplyBuffer); 276 } 277 #endif 278 279 return (EX_PROTOCOL); 280 } 281 /* 282 ** SMTPDATA -- send the data and clean up the transaction. 283 ** 284 ** Parameters: 285 ** m -- mailer being sent to. 286 ** e -- the envelope for this message. 287 ** 288 ** Returns: 289 ** exit status corresponding to DATA command. 290 ** 291 ** Side Effects: 292 ** none. 293 */ 294 295 smtpdata(m, mci, e) 296 struct mailer *m; 297 register MCI *mci; 298 register ENVELOPE *e; 299 { 300 register int r; 301 302 /* 303 ** Send the data. 304 ** First send the command and check that it is ok. 305 ** Then send the data. 306 ** Follow it up with a dot to terminate. 307 ** Finally get the results of the transaction. 308 */ 309 310 /* send the command and check ok to proceed */ 311 smtpmessage("DATA", m, mci); 312 SmtpPhase = mci->mci_phase = "DATA wait"; 313 setproctitle("%s %s: %s", e->e_id, CurHostName, mci->mci_phase); 314 r = reply(m, mci, e, TimeOuts.to_datainit); 315 if (r < 0 || REPLYTYPE(r) == 4) 316 { 317 smtpquit(m, mci, e); 318 return (EX_TEMPFAIL); 319 } 320 else if (r == 554) 321 { 322 smtprset(m, mci, e); 323 return (EX_UNAVAILABLE); 324 } 325 else if (r != 354) 326 { 327 #ifdef LOG 328 if (LogLevel > 1) 329 { 330 syslog(LOG_CRIT, "%s: SMTP DATA-1 protocol error: %s", 331 e->e_id, SmtpReplyBuffer); 332 } 333 #endif 334 smtprset(m, mci, e); 335 return (EX_PROTOCOL); 336 } 337 338 /* now output the actual message */ 339 (*e->e_puthdr)(mci->mci_out, m, e); 340 putline("\n", mci->mci_out, m); 341 (*e->e_putbody)(mci->mci_out, m, e); 342 343 /* terminate the message */ 344 fprintf(mci->mci_out, ".%s", m->m_eol); 345 if (Verbose) 346 nmessage(">>> ."); 347 348 /* check for the results of the transaction */ 349 SmtpPhase = mci->mci_phase = "result wait"; 350 setproctitle("%s %s: %s", e->e_id, CurHostName, mci->mci_phase); 351 r = reply(m, mci, e, TimeOuts.to_datafinal); 352 if (r < 0) 353 { 354 smtpquit(m, mci, e); 355 return (EX_TEMPFAIL); 356 } 357 mci->mci_state = MCIS_OPEN; 358 if (REPLYTYPE(r) == 4) 359 return (EX_TEMPFAIL); 360 else if (r == 250) 361 return (EX_OK); 362 else if (r == 552 || r == 554) 363 return (EX_UNAVAILABLE); 364 #ifdef LOG 365 if (LogLevel > 1) 366 { 367 syslog(LOG_CRIT, "%s: SMTP DATA-2 protocol error: %s", 368 e->e_id, SmtpReplyBuffer); 369 } 370 #endif 371 return (EX_PROTOCOL); 372 } 373 /* 374 ** SMTPQUIT -- close the SMTP connection. 375 ** 376 ** Parameters: 377 ** m -- a pointer to the mailer. 378 ** 379 ** Returns: 380 ** none. 381 ** 382 ** Side Effects: 383 ** sends the final protocol and closes the connection. 384 */ 385 386 smtpquit(m, mci, e) 387 register MAILER *m; 388 register MCI *mci; 389 ENVELOPE *e; 390 { 391 int i; 392 393 /* send the quit message if we haven't gotten I/O error */ 394 if (mci->mci_state != MCIS_ERROR) 395 { 396 smtpmessage("QUIT", m, mci); 397 (void) reply(m, mci, e, TimeOuts.to_quit); 398 if (mci->mci_state == MCIS_CLOSED) 399 return; 400 } 401 402 /* now actually close the connection and pick up the zombie */ 403 i = endmailer(mci, m->m_argv[0]); 404 if (i != EX_OK) 405 syserr("451 smtpquit %s: stat %d", m->m_argv[0], i); 406 } 407 /* 408 ** SMTPRSET -- send a RSET (reset) command 409 */ 410 411 smtprset(m, mci, e) 412 register MAILER *m; 413 register MCI *mci; 414 ENVELOPE *e; 415 { 416 int r; 417 418 smtpmessage("RSET", m, mci); 419 r = reply(m, mci, e, TimeOuts.to_rset); 420 if (r < 0) 421 mci->mci_state = MCIS_ERROR; 422 else if (REPLYTYPE(r) == 2) 423 { 424 mci->mci_state = MCIS_OPEN; 425 return; 426 } 427 smtpquit(m, mci, e); 428 } 429 /* 430 ** SMTPNOOP -- send a NOOP (no operation) command to check the connection state 431 */ 432 433 smtpnoop(mci) 434 register MCI *mci; 435 { 436 int r; 437 MAILER *m = mci->mci_mailer; 438 extern ENVELOPE BlankEnvelope; 439 ENVELOPE *e = &BlankEnvelope; 440 441 smtpmessage("NOOP", m, mci); 442 r = reply(m, mci, e, TimeOuts.to_miscshort); 443 if (r < 0 || REPLYTYPE(r) != 2) 444 smtpquit(m, mci, e); 445 return r; 446 } 447 /* 448 ** REPLY -- read arpanet reply 449 ** 450 ** Parameters: 451 ** m -- the mailer we are reading the reply from. 452 ** mci -- the mailer connection info structure. 453 ** e -- the current envelope. 454 ** timeout -- the timeout for reads. 455 ** 456 ** Returns: 457 ** reply code it reads. 458 ** 459 ** Side Effects: 460 ** flushes the mail file. 461 */ 462 463 reply(m, mci, e, timeout) 464 MAILER *m; 465 MCI *mci; 466 ENVELOPE *e; 467 { 468 if (mci->mci_out != NULL) 469 (void) fflush(mci->mci_out); 470 471 if (tTd(18, 1)) 472 printf("reply\n"); 473 474 /* 475 ** Read the input line, being careful not to hang. 476 */ 477 478 for (;;) 479 { 480 register int r; 481 register char *p; 482 extern time_t curtime(); 483 484 /* actually do the read */ 485 if (e->e_xfp != NULL) 486 (void) fflush(e->e_xfp); /* for debugging */ 487 488 /* if we are in the process of closing just give the code */ 489 if (mci->mci_state == MCIS_CLOSED) 490 return (SMTPCLOSING); 491 492 /* get the line from the other side */ 493 p = sfgets(SmtpReplyBuffer, sizeof SmtpReplyBuffer, mci->mci_in, 494 timeout); 495 mci->mci_lastuse = curtime(); 496 497 if (p == NULL) 498 { 499 extern char MsgBuf[]; /* err.c */ 500 501 /* if the remote end closed early, fake an error */ 502 if (errno == 0) 503 # ifdef ECONNRESET 504 errno = ECONNRESET; 505 # else /* ECONNRESET */ 506 errno = EPIPE; 507 # endif /* ECONNRESET */ 508 509 mci->mci_errno = errno; 510 mci->mci_exitstat = EX_TEMPFAIL; 511 message("451 %s: reply: read error from %s", 512 e->e_id == NULL ? "NOQUEUE" : e->e_id, 513 mci->mci_host); 514 /* if debugging, pause so we can see state */ 515 if (tTd(18, 100)) 516 pause(); 517 # ifdef LOG 518 if (LogLevel > 1) 519 syslog(LOG_INFO, "%s", &MsgBuf[4]); 520 # endif /* LOG */ 521 mci->mci_state = MCIS_ERROR; 522 smtpquit(m, mci, e); 523 return (-1); 524 } 525 fixcrlf(SmtpReplyBuffer, TRUE); 526 527 if (e->e_xfp != NULL && strchr("45", SmtpReplyBuffer[0]) != NULL) 528 { 529 /* serious error -- log the previous command */ 530 if (SmtpMsgBuffer[0] != '\0') 531 fprintf(e->e_xfp, ">>> %s\n", SmtpMsgBuffer); 532 SmtpMsgBuffer[0] = '\0'; 533 534 /* now log the message as from the other side */ 535 fprintf(e->e_xfp, "<<< %s\n", SmtpReplyBuffer); 536 } 537 538 /* display the input for verbose mode */ 539 if (Verbose) 540 nmessage("%s", SmtpReplyBuffer); 541 542 /* if continuation is required, we can go on */ 543 if (SmtpReplyBuffer[3] == '-' || 544 !(isascii(SmtpReplyBuffer[0]) && isdigit(SmtpReplyBuffer[0]))) 545 continue; 546 547 /* decode the reply code */ 548 r = atoi(SmtpReplyBuffer); 549 550 /* extra semantics: 0xx codes are "informational" */ 551 if (r < 100) 552 continue; 553 554 /* save temporary failure messages for posterity */ 555 if (SmtpReplyBuffer[0] == '4' && SmtpError[0] == '\0') 556 (void) strcpy(SmtpError, SmtpReplyBuffer); 557 558 /* reply code 421 is "Service Shutting Down" */ 559 if (r == SMTPCLOSING && mci->mci_state != MCIS_SSD) 560 { 561 /* send the quit protocol */ 562 mci->mci_state = MCIS_SSD; 563 smtpquit(m, mci, e); 564 } 565 566 return (r); 567 } 568 } 569 /* 570 ** SMTPMESSAGE -- send message to server 571 ** 572 ** Parameters: 573 ** f -- format 574 ** m -- the mailer to control formatting. 575 ** a, b, c -- parameters 576 ** 577 ** Returns: 578 ** none. 579 ** 580 ** Side Effects: 581 ** writes message to mci->mci_out. 582 */ 583 584 /*VARARGS1*/ 585 #ifdef __STDC__ 586 smtpmessage(char *f, MAILER *m, MCI *mci, ...) 587 #else 588 smtpmessage(f, m, mci, va_alist) 589 char *f; 590 MAILER *m; 591 MCI *mci; 592 va_dcl 593 #endif 594 { 595 VA_LOCAL_DECL 596 597 VA_START(mci); 598 (void) vsprintf(SmtpMsgBuffer, f, ap); 599 VA_END; 600 if (tTd(18, 1) || Verbose) 601 nmessage(">>> %s", SmtpMsgBuffer); 602 if (mci->mci_out != NULL) 603 fprintf(mci->mci_out, "%s%s", SmtpMsgBuffer, 604 m == NULL ? "\r\n" : m->m_eol); 605 } 606 607 # endif /* SMTP */ 608