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