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