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