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