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