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