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.4 (Berkeley) 09/17/85 (no SMTP)"; 20 # endif not lint 21 # else SMTP 22 23 # ifndef lint 24 static char SccsId[] = "@(#)usersmtp.c 5.4 (Berkeley) 09/17/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 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 r = reply(m); 135 clrevent(gte); 136 if (r < 0 || REPLYTYPE(r) != 2) 137 goto tempfail; 138 139 /* 140 ** Send the HELO command. 141 ** My mother taught me to always introduce myself. 142 */ 143 144 smtpmessage("HELO %s", m, HostName); 145 r = reply(m); 146 if (r < 0) 147 goto tempfail; 148 else if (REPLYTYPE(r) == 5) 149 goto unavailable; 150 else if (REPLYTYPE(r) != 2) 151 goto tempfail; 152 153 /* 154 ** If this is expected to be another sendmail, send some internal 155 ** commands. 156 */ 157 158 if (bitnset(M_INTERNAL, m->m_flags)) 159 { 160 /* tell it to be verbose */ 161 smtpmessage("VERB", m); 162 r = reply(m); 163 if (r < 0) 164 goto tempfail; 165 166 /* tell it we will be sending one transaction only */ 167 smtpmessage("ONEX", m); 168 r = reply(m); 169 if (r < 0) 170 goto tempfail; 171 } 172 173 /* 174 ** Send the MAIL command. 175 ** Designates the sender. 176 */ 177 178 expand("\001g", buf, &buf[sizeof buf - 1], CurEnv); 179 if (CurEnv->e_from.q_mailer == LocalMailer || 180 !bitnset(M_FROMPATH, m->m_flags)) 181 { 182 smtpmessage("MAIL From:<%s>", m, buf); 183 } 184 else 185 { 186 smtpmessage("MAIL From:<@%s%c%s>", m, HostName, 187 buf[0] == '@' ? ',' : ':', buf); 188 } 189 r = reply(m); 190 if (r < 0 || REPLYTYPE(r) == 4) 191 goto tempfail; 192 else if (r == 250) 193 return (EX_OK); 194 else if (r == 552) 195 goto unavailable; 196 197 /* protocol error -- close up */ 198 smtpquit(m); 199 return (EX_PROTOCOL); 200 201 /* signal a temporary failure */ 202 tempfail: 203 smtpquit(m); 204 CurEnv->e_flags &= ~EF_FATALERRS; 205 return (EX_TEMPFAIL); 206 207 /* signal service unavailable */ 208 unavailable: 209 smtpquit(m); 210 return (EX_UNAVAILABLE); 211 } 212 213 214 static 215 greettimeout() 216 { 217 /* timeout reading the greeting message */ 218 longjmp(CtxGreeting, 1); 219 } 220 /* 221 ** SMTPRCPT -- designate recipient. 222 ** 223 ** Parameters: 224 ** to -- address of recipient. 225 ** m -- the mailer we are sending to. 226 ** 227 ** Returns: 228 ** exit status corresponding to recipient status. 229 ** 230 ** Side Effects: 231 ** Sends the mail via SMTP. 232 */ 233 234 smtprcpt(to, m) 235 ADDRESS *to; 236 register MAILER *m; 237 { 238 register int r; 239 extern char *remotename(); 240 241 smtpmessage("RCPT To:<%s>", m, remotename(to->q_user, m, FALSE, TRUE)); 242 243 r = reply(m); 244 if (r < 0 || REPLYTYPE(r) == 4) 245 return (EX_TEMPFAIL); 246 else if (REPLYTYPE(r) == 2) 247 return (EX_OK); 248 else if (r == 550 || r == 551 || r == 553) 249 return (EX_NOUSER); 250 else if (r == 552 || r == 554) 251 return (EX_UNAVAILABLE); 252 return (EX_PROTOCOL); 253 } 254 /* 255 ** SMTPDATA -- send the data and clean up the transaction. 256 ** 257 ** Parameters: 258 ** m -- mailer being sent to. 259 ** e -- the envelope for this message. 260 ** 261 ** Returns: 262 ** exit status corresponding to DATA command. 263 ** 264 ** Side Effects: 265 ** none. 266 */ 267 268 smtpdata(m, e) 269 struct mailer *m; 270 register ENVELOPE *e; 271 { 272 register int r; 273 274 /* 275 ** Send the data. 276 ** First send the command and check that it is ok. 277 ** Then send the data. 278 ** Follow it up with a dot to terminate. 279 ** Finally get the results of the transaction. 280 */ 281 282 /* send the command and check ok to proceed */ 283 smtpmessage("DATA", m); 284 r = reply(m); 285 if (r < 0 || REPLYTYPE(r) == 4) 286 return (EX_TEMPFAIL); 287 else if (r == 554) 288 return (EX_UNAVAILABLE); 289 else if (r != 354) 290 return (EX_PROTOCOL); 291 292 /* now output the actual message */ 293 (*e->e_puthdr)(SmtpOut, m, CurEnv); 294 putline("\n", SmtpOut, m); 295 (*e->e_putbody)(SmtpOut, m, CurEnv); 296 297 /* terminate the message */ 298 fprintf(SmtpOut, ".%s", m->m_eol); 299 if (Verbose && !HoldErrs) 300 nmessage(Arpa_Info, ">>> ."); 301 302 /* check for the results of the transaction */ 303 r = reply(m); 304 if (r < 0 || REPLYTYPE(r) == 4) 305 return (EX_TEMPFAIL); 306 else if (r == 250) 307 return (EX_OK); 308 else if (r == 552 || r == 554) 309 return (EX_UNAVAILABLE); 310 return (EX_PROTOCOL); 311 } 312 /* 313 ** SMTPQUIT -- close the SMTP connection. 314 ** 315 ** Parameters: 316 ** m -- a pointer to the mailer. 317 ** 318 ** Returns: 319 ** none. 320 ** 321 ** Side Effects: 322 ** sends the final protocol and closes the connection. 323 */ 324 325 smtpquit(m) 326 register MAILER *m; 327 { 328 int i; 329 330 /* if the connection is already closed, don't bother */ 331 if (SmtpIn == NULL) 332 return; 333 334 /* send the quit message if not a forced quit */ 335 if (SmtpState == SMTP_OPEN || SmtpState == SMTP_SSD) 336 { 337 smtpmessage("QUIT", m); 338 (void) reply(m); 339 if (SmtpState == SMTP_CLOSED) 340 return; 341 } 342 343 /* now actually close the connection */ 344 (void) fclose(SmtpIn); 345 (void) fclose(SmtpOut); 346 SmtpIn = SmtpOut = NULL; 347 SmtpState = SMTP_CLOSED; 348 349 /* and pick up the zombie */ 350 i = endmailer(SmtpPid, m->m_argv[0]); 351 if (i != EX_OK) 352 syserr("smtpquit %s: stat %d", m->m_argv[0], i); 353 } 354 /* 355 ** REPLY -- read arpanet reply 356 ** 357 ** Parameters: 358 ** m -- the mailer we are reading the reply from. 359 ** 360 ** Returns: 361 ** reply code it reads. 362 ** 363 ** Side Effects: 364 ** flushes the mail file. 365 */ 366 367 reply(m) 368 MAILER *m; 369 { 370 (void) fflush(SmtpOut); 371 372 if (tTd(18, 1)) 373 printf("reply\n"); 374 375 /* 376 ** Read the input line, being careful not to hang. 377 */ 378 379 for (;;) 380 { 381 register int r; 382 register char *p; 383 384 /* actually do the read */ 385 if (CurEnv->e_xfp != NULL) 386 (void) fflush(CurEnv->e_xfp); /* for debugging */ 387 388 /* if we are in the process of closing just give the code */ 389 if (SmtpState == SMTP_CLOSED) 390 return (SMTPCLOSING); 391 392 /* get the line from the other side */ 393 p = sfgets(SmtpReplyBuffer, sizeof SmtpReplyBuffer, SmtpIn); 394 if (p == NULL) 395 { 396 extern char MsgBuf[]; /* err.c */ 397 extern char Arpa_TSyserr[]; /* conf.c */ 398 399 /* if the remote end closed early, fake an error */ 400 if (errno == 0) 401 # ifdef ECONNRESET 402 errno = ECONNRESET; 403 # else ECONNRESET 404 errno = EPIPE; 405 # endif ECONNRESET 406 407 message(Arpa_TSyserr, "reply: read error"); 408 # ifdef DEBUG 409 /* if debugging, pause so we can see state */ 410 if (tTd(18, 100)) 411 pause(); 412 # endif DEBUG 413 # ifdef LOG 414 syslog(LOG_ERR, "%s", &MsgBuf[4]); 415 # endif LOG 416 SmtpState = SMTP_CLOSED; 417 smtpquit(m); 418 return (-1); 419 } 420 fixcrlf(SmtpReplyBuffer, TRUE); 421 422 if (CurEnv->e_xfp != NULL && index("45", SmtpReplyBuffer[0]) != NULL) 423 { 424 /* serious error -- log the previous command */ 425 if (SmtpMsgBuffer[0] != '\0') 426 fprintf(CurEnv->e_xfp, ">>> %s\n", SmtpMsgBuffer); 427 SmtpMsgBuffer[0] = '\0'; 428 429 /* now log the message as from the other side */ 430 fprintf(CurEnv->e_xfp, "<<< %s\n", SmtpReplyBuffer); 431 } 432 433 /* display the input for verbose mode */ 434 if (Verbose && !HoldErrs) 435 nmessage(Arpa_Info, "%s", SmtpReplyBuffer); 436 437 /* if continuation is required, we can go on */ 438 if (SmtpReplyBuffer[3] == '-' || !isdigit(SmtpReplyBuffer[0])) 439 continue; 440 441 /* decode the reply code */ 442 r = atoi(SmtpReplyBuffer); 443 444 /* extra semantics: 0xx codes are "informational" */ 445 if (r < 100) 446 continue; 447 448 /* reply code 421 is "Service Shutting Down" */ 449 if (r == SMTPCLOSING && SmtpState != SMTP_SSD) 450 { 451 /* send the quit protocol */ 452 SmtpState = SMTP_SSD; 453 smtpquit(m); 454 } 455 456 /* save temporary failure messages for posterity */ 457 if (SmtpReplyBuffer[0] == '4' && SmtpError[0] == '\0') 458 (void) strcpy(SmtpError, &SmtpReplyBuffer[4]); 459 460 return (r); 461 } 462 } 463 /* 464 ** SMTPMESSAGE -- send message to server 465 ** 466 ** Parameters: 467 ** f -- format 468 ** m -- the mailer to control formatting. 469 ** a, b, c -- parameters 470 ** 471 ** Returns: 472 ** none. 473 ** 474 ** Side Effects: 475 ** writes message to SmtpOut. 476 */ 477 478 /*VARARGS1*/ 479 smtpmessage(f, m, a, b, c) 480 char *f; 481 MAILER *m; 482 { 483 (void) sprintf(SmtpMsgBuffer, f, a, b, c); 484 if (tTd(18, 1) || (Verbose && !HoldErrs)) 485 nmessage(Arpa_Info, ">>> %s", SmtpMsgBuffer); 486 if (SmtpOut != NULL) 487 fprintf(SmtpOut, "%s%s", SmtpMsgBuffer, m->m_eol); 488 } 489 490 # endif SMTP 491