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