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