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