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