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.5 (Berkeley) 09/19/85 (no SMTP)"; 20 # endif not lint 21 # else SMTP 22 23 # ifndef lint 24 static char SccsId[] = "@(#)usersmtp.c 5.5 (Berkeley) 09/19/85"; 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, HostName); 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, HostName, 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 CurEnv->e_flags &= ~EF_FATALERRS; 209 return (EX_TEMPFAIL); 210 211 /* signal service unavailable */ 212 unavailable: 213 smtpquit(m); 214 return (EX_UNAVAILABLE); 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) 239 ADDRESS *to; 240 register MAILER *m; 241 { 242 register int r; 243 extern char *remotename(); 244 245 smtpmessage("RCPT To:<%s>", m, remotename(to->q_user, m, FALSE, TRUE)); 246 247 SmtpPhase = "RCPT wait"; 248 r = reply(m); 249 if (r < 0 || REPLYTYPE(r) == 4) 250 return (EX_TEMPFAIL); 251 else if (REPLYTYPE(r) == 2) 252 return (EX_OK); 253 else if (r == 550 || r == 551 || r == 553) 254 return (EX_NOUSER); 255 else if (r == 552 || r == 554) 256 return (EX_UNAVAILABLE); 257 return (EX_PROTOCOL); 258 } 259 /* 260 ** SMTPDATA -- send the data and clean up the transaction. 261 ** 262 ** Parameters: 263 ** m -- mailer being sent to. 264 ** e -- the envelope for this message. 265 ** 266 ** Returns: 267 ** exit status corresponding to DATA command. 268 ** 269 ** Side Effects: 270 ** none. 271 */ 272 273 smtpdata(m, e) 274 struct mailer *m; 275 register ENVELOPE *e; 276 { 277 register int r; 278 279 /* 280 ** Send the data. 281 ** First send the command and check that it is ok. 282 ** Then send the data. 283 ** Follow it up with a dot to terminate. 284 ** Finally get the results of the transaction. 285 */ 286 287 /* send the command and check ok to proceed */ 288 smtpmessage("DATA", m); 289 SmtpPhase = "DATA wait"; 290 r = reply(m); 291 if (r < 0 || REPLYTYPE(r) == 4) 292 return (EX_TEMPFAIL); 293 else if (r == 554) 294 return (EX_UNAVAILABLE); 295 else if (r != 354) 296 return (EX_PROTOCOL); 297 298 /* now output the actual message */ 299 (*e->e_puthdr)(SmtpOut, m, CurEnv); 300 putline("\n", SmtpOut, m); 301 (*e->e_putbody)(SmtpOut, m, CurEnv); 302 303 /* terminate the message */ 304 fprintf(SmtpOut, ".%s", m->m_eol); 305 if (Verbose && !HoldErrs) 306 nmessage(Arpa_Info, ">>> ."); 307 308 /* check for the results of the transaction */ 309 SmtpPhase = "result wait"; 310 r = reply(m); 311 if (r < 0 || REPLYTYPE(r) == 4) 312 return (EX_TEMPFAIL); 313 else if (r == 250) 314 return (EX_OK); 315 else if (r == 552 || r == 554) 316 return (EX_UNAVAILABLE); 317 return (EX_PROTOCOL); 318 } 319 /* 320 ** SMTPQUIT -- close the SMTP connection. 321 ** 322 ** Parameters: 323 ** m -- a pointer to the mailer. 324 ** 325 ** Returns: 326 ** none. 327 ** 328 ** Side Effects: 329 ** sends the final protocol and closes the connection. 330 */ 331 332 smtpquit(m) 333 register MAILER *m; 334 { 335 int i; 336 337 /* if the connection is already closed, don't bother */ 338 if (SmtpIn == NULL) 339 return; 340 341 /* send the quit message if not a forced quit */ 342 if (SmtpState == SMTP_OPEN || SmtpState == SMTP_SSD) 343 { 344 smtpmessage("QUIT", m); 345 (void) reply(m); 346 if (SmtpState == SMTP_CLOSED) 347 return; 348 } 349 350 /* now actually close the connection */ 351 (void) fclose(SmtpIn); 352 (void) fclose(SmtpOut); 353 SmtpIn = SmtpOut = NULL; 354 SmtpState = SMTP_CLOSED; 355 356 /* and pick up the zombie */ 357 i = endmailer(SmtpPid, m->m_argv[0]); 358 if (i != EX_OK) 359 syserr("smtpquit %s: stat %d", m->m_argv[0], i); 360 } 361 /* 362 ** REPLY -- read arpanet reply 363 ** 364 ** Parameters: 365 ** m -- the mailer we are reading the reply from. 366 ** 367 ** Returns: 368 ** reply code it reads. 369 ** 370 ** Side Effects: 371 ** flushes the mail file. 372 */ 373 374 reply(m) 375 MAILER *m; 376 { 377 (void) fflush(SmtpOut); 378 379 if (tTd(18, 1)) 380 printf("reply\n"); 381 382 /* 383 ** Read the input line, being careful not to hang. 384 */ 385 386 for (;;) 387 { 388 register int r; 389 register char *p; 390 391 /* actually do the read */ 392 if (CurEnv->e_xfp != NULL) 393 (void) fflush(CurEnv->e_xfp); /* for debugging */ 394 395 /* if we are in the process of closing just give the code */ 396 if (SmtpState == SMTP_CLOSED) 397 return (SMTPCLOSING); 398 399 /* get the line from the other side */ 400 p = sfgets(SmtpReplyBuffer, sizeof SmtpReplyBuffer, SmtpIn); 401 if (p == NULL) 402 { 403 extern char MsgBuf[]; /* err.c */ 404 extern char Arpa_TSyserr[]; /* conf.c */ 405 406 /* if the remote end closed early, fake an error */ 407 if (errno == 0) 408 # ifdef ECONNRESET 409 errno = ECONNRESET; 410 # else ECONNRESET 411 errno = EPIPE; 412 # endif ECONNRESET 413 414 message(Arpa_TSyserr, "reply: read error"); 415 # ifdef DEBUG 416 /* if debugging, pause so we can see state */ 417 if (tTd(18, 100)) 418 pause(); 419 # endif DEBUG 420 # ifdef LOG 421 syslog(LOG_ERR, "%s", &MsgBuf[4]); 422 # endif LOG 423 SmtpState = SMTP_CLOSED; 424 smtpquit(m); 425 return (-1); 426 } 427 fixcrlf(SmtpReplyBuffer, TRUE); 428 429 if (CurEnv->e_xfp != NULL && index("45", SmtpReplyBuffer[0]) != NULL) 430 { 431 /* serious error -- log the previous command */ 432 if (SmtpMsgBuffer[0] != '\0') 433 fprintf(CurEnv->e_xfp, ">>> %s\n", SmtpMsgBuffer); 434 SmtpMsgBuffer[0] = '\0'; 435 436 /* now log the message as from the other side */ 437 fprintf(CurEnv->e_xfp, "<<< %s\n", SmtpReplyBuffer); 438 } 439 440 /* display the input for verbose mode */ 441 if (Verbose && !HoldErrs) 442 nmessage(Arpa_Info, "%s", SmtpReplyBuffer); 443 444 /* if continuation is required, we can go on */ 445 if (SmtpReplyBuffer[3] == '-' || !isdigit(SmtpReplyBuffer[0])) 446 continue; 447 448 /* decode the reply code */ 449 r = atoi(SmtpReplyBuffer); 450 451 /* extra semantics: 0xx codes are "informational" */ 452 if (r < 100) 453 continue; 454 455 /* reply code 421 is "Service Shutting Down" */ 456 if (r == SMTPCLOSING && SmtpState != SMTP_SSD) 457 { 458 /* send the quit protocol */ 459 SmtpState = SMTP_SSD; 460 smtpquit(m); 461 } 462 463 /* save temporary failure messages for posterity */ 464 if (SmtpReplyBuffer[0] == '4' && SmtpError[0] == '\0') 465 (void) strcpy(SmtpError, &SmtpReplyBuffer[4]); 466 467 return (r); 468 } 469 } 470 /* 471 ** SMTPMESSAGE -- send message to server 472 ** 473 ** Parameters: 474 ** f -- format 475 ** m -- the mailer to control formatting. 476 ** a, b, c -- parameters 477 ** 478 ** Returns: 479 ** none. 480 ** 481 ** Side Effects: 482 ** writes message to SmtpOut. 483 */ 484 485 /*VARARGS1*/ 486 smtpmessage(f, m, a, b, c) 487 char *f; 488 MAILER *m; 489 { 490 (void) sprintf(SmtpMsgBuffer, f, a, b, c); 491 if (tTd(18, 1) || (Verbose && !HoldErrs)) 492 nmessage(Arpa_Info, ">>> %s", SmtpMsgBuffer); 493 if (SmtpOut != NULL) 494 fprintf(SmtpOut, "%s%s", SmtpMsgBuffer, m->m_eol); 495 } 496 497 # endif SMTP 498