1 /* 2 * Copyright (c) 1983 Eric P. Allman 3 * Copyright (c) 1988 Regents of the University of California. 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms are permitted 7 * provided that the above copyright notice and this paragraph are 8 * duplicated in all such forms and that any documentation, 9 * advertising materials, and other materials related to such 10 * distribution and use acknowledge that the software was developed 11 * by the University of California, Berkeley. The name of the 12 * University may not be used to endorse or promote products derived 13 * from this software without specific prior written permission. 14 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 15 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 16 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 17 */ 18 19 # include "sendmail.h" 20 21 #ifndef lint 22 #ifdef SMTP 23 static char sccsid[] = "@(#)usersmtp.c 5.12 (Berkeley) 01/01/89 (with SMTP)"; 24 #else 25 static char sccsid[] = "@(#)usersmtp.c 5.12 (Berkeley) 01/01/89 (without SMTP)"; 26 #endif 27 #endif /* not lint */ 28 29 # include <sysexits.h> 30 # include <errno.h> 31 32 # ifdef SMTP 33 34 /* 35 ** USERSMTP -- run SMTP protocol from the user end. 36 ** 37 ** This protocol is described in RFC821. 38 */ 39 40 #define REPLYTYPE(r) ((r) / 100) /* first digit of reply code */ 41 #define REPLYCLASS(r) (((r) / 10) % 10) /* second digit of reply code */ 42 #define SMTPCLOSING 421 /* "Service Shutting Down" */ 43 44 char SmtpMsgBuffer[MAXLINE]; /* buffer for commands */ 45 char SmtpReplyBuffer[MAXLINE]; /* buffer for replies */ 46 char SmtpError[MAXLINE] = ""; /* save failure error messages */ 47 FILE *SmtpOut; /* output file */ 48 FILE *SmtpIn; /* input file */ 49 int SmtpPid; /* pid of mailer */ 50 51 /* following represents the state of the SMTP connection */ 52 int SmtpState; /* connection state, see below */ 53 54 #define SMTP_CLOSED 0 /* connection is closed */ 55 #define SMTP_OPEN 1 /* connection is open for business */ 56 #define SMTP_SSD 2 /* service shutting down */ 57 /* 58 ** SMTPINIT -- initialize SMTP. 59 ** 60 ** Opens the connection and sends the initial protocol. 61 ** 62 ** Parameters: 63 ** m -- mailer to create connection to. 64 ** pvp -- pointer to parameter vector to pass to 65 ** the mailer. 66 ** 67 ** Returns: 68 ** appropriate exit status -- EX_OK on success. 69 ** If not EX_OK, it should close the connection. 70 ** 71 ** Side Effects: 72 ** creates connection and sends initial protocol. 73 */ 74 75 jmp_buf CtxGreeting; 76 77 smtpinit(m, pvp) 78 struct mailer *m; 79 char **pvp; 80 { 81 register int r; 82 EVENT *gte; 83 char buf[MAXNAME]; 84 extern greettimeout(); 85 86 /* 87 ** Open the connection to the mailer. 88 */ 89 90 if (SmtpState == SMTP_OPEN) 91 syserr("smtpinit: already open"); 92 93 SmtpIn = SmtpOut = NULL; 94 SmtpState = SMTP_CLOSED; 95 SmtpError[0] = '\0'; 96 SmtpPhase = "user open"; 97 SmtpPid = openmailer(m, pvp, (ADDRESS *) NULL, TRUE, &SmtpOut, &SmtpIn); 98 if (SmtpPid < 0) 99 { 100 if (tTd(18, 1)) 101 printf("smtpinit: cannot open %s: stat %d errno %d\n", 102 pvp[0], ExitStat, errno); 103 if (CurEnv->e_xfp != NULL) 104 { 105 register char *p; 106 extern char *errstring(); 107 extern char *statstring(); 108 109 if (errno == 0) 110 { 111 p = statstring(ExitStat); 112 fprintf(CurEnv->e_xfp, 113 "%.3s %s.%s... %s\n", 114 p, pvp[1], m->m_name, p); 115 } 116 else 117 { 118 fprintf(CurEnv->e_xfp, 119 "421 %s.%s... Deferred: %s\n", 120 pvp[1], m->m_name, errstring(errno)); 121 } 122 } 123 return (ExitStat); 124 } 125 SmtpState = SMTP_OPEN; 126 127 /* 128 ** Get the greeting message. 129 ** This should appear spontaneously. Give it five minutes to 130 ** happen. 131 */ 132 133 if (setjmp(CtxGreeting) != 0) 134 goto tempfail; 135 gte = setevent((time_t) 300, greettimeout, 0); 136 SmtpPhase = "greeting wait"; 137 r = reply(m); 138 clrevent(gte); 139 if (r < 0 || REPLYTYPE(r) != 2) 140 goto tempfail; 141 142 /* 143 ** Send the HELO command. 144 ** My mother taught me to always introduce myself. 145 */ 146 147 smtpmessage("HELO %s", m, MyHostName); 148 SmtpPhase = "HELO wait"; 149 r = reply(m); 150 if (r < 0) 151 goto tempfail; 152 else if (REPLYTYPE(r) == 5) 153 goto unavailable; 154 else if (REPLYTYPE(r) != 2) 155 goto tempfail; 156 157 /* 158 ** If this is expected to be another sendmail, send some internal 159 ** commands. 160 */ 161 162 if (bitnset(M_INTERNAL, m->m_flags)) 163 { 164 /* tell it to be verbose */ 165 smtpmessage("VERB", m); 166 r = reply(m); 167 if (r < 0) 168 goto tempfail; 169 170 /* tell it we will be sending one transaction only */ 171 smtpmessage("ONEX", m); 172 r = reply(m); 173 if (r < 0) 174 goto tempfail; 175 } 176 177 /* 178 ** Send the MAIL command. 179 ** Designates the sender. 180 */ 181 182 expand("\001g", buf, &buf[sizeof buf - 1], CurEnv); 183 if (CurEnv->e_from.q_mailer == LocalMailer || 184 !bitnset(M_FROMPATH, m->m_flags)) 185 { 186 smtpmessage("MAIL From:<%s>", m, buf); 187 } 188 else 189 { 190 smtpmessage("MAIL From:<@%s%c%s>", m, MyHostName, 191 buf[0] == '@' ? ',' : ':', buf); 192 } 193 SmtpPhase = "MAIL wait"; 194 r = reply(m); 195 if (r < 0 || REPLYTYPE(r) == 4) 196 goto tempfail; 197 else if (r == 250) 198 return (EX_OK); 199 else if (r == 552) 200 goto unavailable; 201 202 /* protocol error -- close up */ 203 smtpquit(m); 204 return (EX_PROTOCOL); 205 206 /* signal a temporary failure */ 207 tempfail: 208 smtpquit(m); 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 /* if debugging, pause so we can see state */ 416 if (tTd(18, 100)) 417 pause(); 418 # ifdef LOG 419 syslog(LOG_INFO, "%s", &MsgBuf[4]); 420 # endif LOG 421 SmtpState = SMTP_CLOSED; 422 smtpquit(m); 423 return (-1); 424 } 425 fixcrlf(SmtpReplyBuffer, TRUE); 426 427 if (CurEnv->e_xfp != NULL && index("45", SmtpReplyBuffer[0]) != NULL) 428 { 429 /* serious error -- log the previous command */ 430 if (SmtpMsgBuffer[0] != '\0') 431 fprintf(CurEnv->e_xfp, ">>> %s\n", SmtpMsgBuffer); 432 SmtpMsgBuffer[0] = '\0'; 433 434 /* now log the message as from the other side */ 435 fprintf(CurEnv->e_xfp, "<<< %s\n", SmtpReplyBuffer); 436 } 437 438 /* display the input for verbose mode */ 439 if (Verbose && !HoldErrs) 440 nmessage(Arpa_Info, "%s", SmtpReplyBuffer); 441 442 /* if continuation is required, we can go on */ 443 if (SmtpReplyBuffer[3] == '-' || !isdigit(SmtpReplyBuffer[0])) 444 continue; 445 446 /* decode the reply code */ 447 r = atoi(SmtpReplyBuffer); 448 449 /* extra semantics: 0xx codes are "informational" */ 450 if (r < 100) 451 continue; 452 453 /* reply code 421 is "Service Shutting Down" */ 454 if (r == SMTPCLOSING && SmtpState != SMTP_SSD) 455 { 456 /* send the quit protocol */ 457 SmtpState = SMTP_SSD; 458 smtpquit(m); 459 } 460 461 /* save temporary failure messages for posterity */ 462 if (SmtpReplyBuffer[0] == '4' && SmtpError[0] == '\0') 463 (void) strcpy(SmtpError, &SmtpReplyBuffer[4]); 464 465 return (r); 466 } 467 } 468 /* 469 ** SMTPMESSAGE -- send message to server 470 ** 471 ** Parameters: 472 ** f -- format 473 ** m -- the mailer to control formatting. 474 ** a, b, c -- parameters 475 ** 476 ** Returns: 477 ** none. 478 ** 479 ** Side Effects: 480 ** writes message to SmtpOut. 481 */ 482 483 /*VARARGS1*/ 484 smtpmessage(f, m, a, b, c) 485 char *f; 486 MAILER *m; 487 { 488 (void) sprintf(SmtpMsgBuffer, f, a, b, c); 489 if (tTd(18, 1) || (Verbose && !HoldErrs)) 490 nmessage(Arpa_Info, ">>> %s", SmtpMsgBuffer); 491 if (SmtpOut != NULL) 492 fprintf(SmtpOut, "%s%s", SmtpMsgBuffer, m->m_eol); 493 } 494 495 # endif SMTP 496