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