122716Sdist /* 234921Sbostic * Copyright (c) 1983 Eric P. Allman 333731Sbostic * Copyright (c) 1988 Regents of the University of California. 433731Sbostic * All rights reserved. 533731Sbostic * 642831Sbostic * %sccs.include.redist.c% 733731Sbostic */ 822716Sdist 933731Sbostic # include "sendmail.h" 1022716Sdist 1133731Sbostic #ifndef lint 1233731Sbostic #ifdef SMTP 13*54967Seric static char sccsid[] = "@(#)usersmtp.c 5.22 (Berkeley) 07/11/92 (with SMTP)"; 1433731Sbostic #else 15*54967Seric static char sccsid[] = "@(#)usersmtp.c 5.22 (Berkeley) 07/11/92 (without SMTP)"; 1633731Sbostic #endif 1733731Sbostic #endif /* not lint */ 1833731Sbostic 194684Seric # include <sysexits.h> 2021065Seric # include <errno.h> 214684Seric 2233731Sbostic # ifdef SMTP 234684Seric 244684Seric /* 259391Seric ** USERSMTP -- run SMTP protocol from the user end. 269391Seric ** 279391Seric ** This protocol is described in RFC821. 289391Seric */ 299391Seric 309391Seric #define REPLYTYPE(r) ((r) / 100) /* first digit of reply code */ 319391Seric #define REPLYCLASS(r) (((r) / 10) % 10) /* second digit of reply code */ 329391Seric #define SMTPCLOSING 421 /* "Service Shutting Down" */ 339391Seric 3414900Seric char SmtpMsgBuffer[MAXLINE]; /* buffer for commands */ 3510054Seric char SmtpReplyBuffer[MAXLINE]; /* buffer for replies */ 3621065Seric char SmtpError[MAXLINE] = ""; /* save failure error messages */ 3710054Seric int SmtpPid; /* pid of mailer */ 389391Seric /* 394865Seric ** SMTPINIT -- initialize SMTP. 404684Seric ** 414865Seric ** Opens the connection and sends the initial protocol. 424684Seric ** 434684Seric ** Parameters: 444865Seric ** m -- mailer to create connection to. 454865Seric ** pvp -- pointer to parameter vector to pass to 464865Seric ** the mailer. 474684Seric ** 484684Seric ** Returns: 49*54967Seric ** none. 504684Seric ** 514684Seric ** Side Effects: 524865Seric ** creates connection and sends initial protocol. 534684Seric */ 544684Seric 5514886Seric jmp_buf CtxGreeting; 5614886Seric 57*54967Seric smtpinit(m, mci, e) 584865Seric struct mailer *m; 59*54967Seric register MCI *mci; 6053751Seric ENVELOPE *e; 614684Seric { 624865Seric register int r; 6314886Seric EVENT *gte; 6446928Sbostic static int greettimeout(); 6552107Seric extern STAB *stab(); 66*54967Seric extern MCI *openmailer(); 674684Seric 684865Seric /* 694865Seric ** Open the connection to the mailer. 704865Seric */ 714684Seric 7221065Seric SmtpError[0] = '\0'; 73*54967Seric switch (mci->mci_state) 746051Seric { 75*54967Seric case MCIS_ACTIVE: 76*54967Seric /* need to clear old information */ 77*54967Seric smtprset(m, mci, e); 78*54967Seric mci->mci_state = MCIS_OPEN; 7915139Seric 80*54967Seric case MCIS_OPEN: 81*54967Seric return; 82*54967Seric 83*54967Seric case MCIS_ERROR: 84*54967Seric case MCIS_SSD: 85*54967Seric /* shouldn't happen */ 86*54967Seric smtpquit(m, mci, e); 87*54967Seric 88*54967Seric case MCIS_CLOSED: 89*54967Seric syserr("smtpinit: state CLOSED"); 90*54967Seric return; 91*54967Seric 92*54967Seric case MCIS_OPENING: 93*54967Seric break; 946051Seric } 954796Seric 96*54967Seric mci->mci_phase = "user open"; 97*54967Seric mci->mci_state = MCIS_OPENING; 98*54967Seric 994865Seric /* 1004865Seric ** Get the greeting message. 10114913Seric ** This should appear spontaneously. Give it five minutes to 10214886Seric ** happen. 1034865Seric */ 1044797Seric 10514886Seric if (setjmp(CtxGreeting) != 0) 10652104Seric goto tempfail1; 10716141Seric gte = setevent((time_t) 300, greettimeout, 0); 10853751Seric mci->mci_phase = "greeting wait"; 10953751Seric setproctitle("%s %s: %s", e->e_id, CurHostName, mci->mci_phase); 11053751Seric r = reply(m, mci, e); 11114886Seric clrevent(gte); 1128005Seric if (r < 0 || REPLYTYPE(r) != 2) 11352104Seric goto tempfail1; 1144684Seric 1154865Seric /* 1164976Seric ** Send the HELO command. 1177963Seric ** My mother taught me to always introduce myself. 1184976Seric */ 1194976Seric 12053751Seric smtpmessage("HELO %s", m, mci, MyHostName); 12153751Seric mci->mci_phase = "HELO wait"; 12253751Seric setproctitle("%s %s: %s", e->e_id, CurHostName, mci->mci_phase); 12353751Seric r = reply(m, mci, e); 1248005Seric if (r < 0) 12552104Seric goto tempfail1; 1268005Seric else if (REPLYTYPE(r) == 5) 12714913Seric goto unavailable; 1287963Seric else if (REPLYTYPE(r) != 2) 12952104Seric goto tempfail1; 1304976Seric 1314976Seric /* 1329315Seric ** If this is expected to be another sendmail, send some internal 1339315Seric ** commands. 1349315Seric */ 1359315Seric 13610688Seric if (bitnset(M_INTERNAL, m->m_flags)) 1379315Seric { 1389315Seric /* tell it to be verbose */ 13953751Seric smtpmessage("VERB", m, mci); 14053751Seric r = reply(m, mci, e); 1419315Seric if (r < 0) 14252104Seric goto tempfail2; 1439315Seric } 1449315Seric 14553751Seric mci->mci_state = MCIS_OPEN; 146*54967Seric return; 14753751Seric 14853751Seric tempfail1: 14953751Seric tempfail2: 15053751Seric mci->mci_exitstat = EX_TEMPFAIL; 15153751Seric mci->mci_errno = errno; 15253751Seric smtpquit(m, mci, e); 153*54967Seric return; 15453751Seric 15553751Seric unavailable: 15653751Seric mci->mci_exitstat = EX_UNAVAILABLE; 15753751Seric mci->mci_errno = errno; 15853751Seric smtpquit(m, mci, e); 159*54967Seric return; 16053751Seric } 16153751Seric 16253751Seric smtpmailfrom(m, mci, e) 16353751Seric struct mailer *m; 164*54967Seric MCI *mci; 16553751Seric ENVELOPE *e; 16653751Seric { 16753751Seric int r; 16853751Seric char buf[MAXNAME]; 16953751Seric 1709315Seric /* 1714865Seric ** Send the MAIL command. 1724865Seric ** Designates the sender. 1734865Seric */ 1744796Seric 17553751Seric mci->mci_state = MCIS_ACTIVE; 17653751Seric 17753751Seric expand("\001<", buf, &buf[sizeof buf - 1], e); 17853751Seric if (e->e_from.q_mailer == LocalMailer || 17910688Seric !bitnset(M_FROMPATH, m->m_flags)) 1808436Seric { 18153751Seric smtpmessage("MAIL From:<%s>", m, mci, buf); 1828436Seric } 1838436Seric else 1848436Seric { 18553751Seric smtpmessage("MAIL From:<@%s%c%s>", m, mci, MyHostName, 18610308Seric buf[0] == '@' ? ',' : ':', buf); 1878436Seric } 18853751Seric mci->mci_phase = "MAIL wait"; 18953751Seric setproctitle("%s %s: %s", e->e_id, CurHostName, mci->mci_phase); 19053751Seric r = reply(m, mci, e); 1918005Seric if (r < 0 || REPLYTYPE(r) == 4) 19253751Seric { 19353751Seric mci->mci_exitstat = EX_TEMPFAIL; 19453751Seric mci->mci_errno = errno; 19553751Seric smtpquit(m, mci, e); 19653751Seric return EX_TEMPFAIL; 19753751Seric } 1987963Seric else if (r == 250) 19953751Seric { 20053751Seric mci->mci_exitstat = EX_OK; 20153751Seric return EX_OK; 20253751Seric } 2037963Seric else if (r == 552) 20453751Seric { 20553751Seric /* signal service unavailable */ 20653751Seric mci->mci_exitstat = EX_UNAVAILABLE; 20753751Seric smtpquit(m, mci, e); 20853751Seric return EX_UNAVAILABLE; 20953751Seric } 21014913Seric 21114913Seric /* protocol error -- close up */ 21253751Seric smtpquit(m, mci, e); 21353751Seric mci->mci_exitstat = EX_PROTOCOL; 21453751Seric return EX_PROTOCOL; 2154684Seric } 21614886Seric 21714886Seric 21814886Seric static 21914886Seric greettimeout() 22014886Seric { 22114886Seric /* timeout reading the greeting message */ 22214886Seric longjmp(CtxGreeting, 1); 22314886Seric } 2244684Seric /* 2254976Seric ** SMTPRCPT -- designate recipient. 2264797Seric ** 2274797Seric ** Parameters: 2284865Seric ** to -- address of recipient. 22910175Seric ** m -- the mailer we are sending to. 2304797Seric ** 2314797Seric ** Returns: 2324865Seric ** exit status corresponding to recipient status. 2334797Seric ** 2344797Seric ** Side Effects: 2354865Seric ** Sends the mail via SMTP. 2364797Seric */ 2374797Seric 23853751Seric smtprcpt(to, m, mci, e) 2394865Seric ADDRESS *to; 24010175Seric register MAILER *m; 241*54967Seric MCI *mci; 24253751Seric ENVELOPE *e; 2434797Seric { 2444797Seric register int r; 24510308Seric extern char *remotename(); 2464797Seric 24753751Seric smtpmessage("RCPT To:<%s>", m, mci, to->q_user); 2484865Seric 24953751Seric mci->mci_phase = "RCPT wait"; 25053751Seric setproctitle("%s %s: %s", e->e_id, CurHostName, mci->mci_phase); 25153751Seric r = reply(m, mci, e); 2528005Seric if (r < 0 || REPLYTYPE(r) == 4) 2534865Seric return (EX_TEMPFAIL); 2547963Seric else if (REPLYTYPE(r) == 2) 2557963Seric return (EX_OK); 2567964Seric else if (r == 550 || r == 551 || r == 553) 2577964Seric return (EX_NOUSER); 2587964Seric else if (r == 552 || r == 554) 2597964Seric return (EX_UNAVAILABLE); 2607964Seric return (EX_PROTOCOL); 2614797Seric } 2624797Seric /* 26310175Seric ** SMTPDATA -- send the data and clean up the transaction. 2644684Seric ** 2654684Seric ** Parameters: 2664865Seric ** m -- mailer being sent to. 2676980Seric ** e -- the envelope for this message. 2684684Seric ** 2694684Seric ** Returns: 2704976Seric ** exit status corresponding to DATA command. 2714684Seric ** 2724684Seric ** Side Effects: 2734865Seric ** none. 2744684Seric */ 2754684Seric 27653740Seric smtpdata(m, mci, e) 2774865Seric struct mailer *m; 278*54967Seric register MCI *mci; 2796980Seric register ENVELOPE *e; 2804684Seric { 2814684Seric register int r; 2824684Seric 2834797Seric /* 2844797Seric ** Send the data. 28510175Seric ** First send the command and check that it is ok. 28610175Seric ** Then send the data. 28710175Seric ** Follow it up with a dot to terminate. 28810175Seric ** Finally get the results of the transaction. 2894797Seric */ 2904797Seric 29110175Seric /* send the command and check ok to proceed */ 29253751Seric smtpmessage("DATA", m, mci); 29353751Seric mci->mci_phase = "DATA wait"; 29453751Seric setproctitle("%s %s: %s", e->e_id, CurHostName, mci->mci_phase); 29553751Seric r = reply(m, mci, e); 2968005Seric if (r < 0 || REPLYTYPE(r) == 4) 2974797Seric return (EX_TEMPFAIL); 2987963Seric else if (r == 554) 2997963Seric return (EX_UNAVAILABLE); 3007963Seric else if (r != 354) 3017964Seric return (EX_PROTOCOL); 30210175Seric 30310175Seric /* now output the actual message */ 30453751Seric (*e->e_puthdr)(mci->mci_out, m, e); 30553740Seric putline("\n", mci->mci_out, m); 30653751Seric (*e->e_putbody)(mci->mci_out, m, e); 30710175Seric 30810175Seric /* terminate the message */ 30953740Seric fprintf(mci->mci_out, ".%s", m->m_eol); 31010215Seric if (Verbose && !HoldErrs) 31110215Seric nmessage(Arpa_Info, ">>> ."); 31210175Seric 31310175Seric /* check for the results of the transaction */ 31453751Seric mci->mci_phase = "result wait"; 31553751Seric setproctitle("%s %s: %s", e->e_id, CurHostName, mci->mci_phase); 31653751Seric r = reply(m, mci, e); 31753751Seric if (r < 0) 3184797Seric return (EX_TEMPFAIL); 31953751Seric mci->mci_state = MCIS_OPEN; 32053751Seric if (REPLYTYPE(r) == 4) 32153751Seric return (EX_TEMPFAIL); 3227963Seric else if (r == 250) 3237963Seric return (EX_OK); 3247963Seric else if (r == 552 || r == 554) 3257963Seric return (EX_UNAVAILABLE); 3267964Seric return (EX_PROTOCOL); 3274684Seric } 3284684Seric /* 3294865Seric ** SMTPQUIT -- close the SMTP connection. 3304865Seric ** 3314865Seric ** Parameters: 33215535Seric ** m -- a pointer to the mailer. 3334865Seric ** 3344865Seric ** Returns: 3354865Seric ** none. 3364865Seric ** 3374865Seric ** Side Effects: 3384865Seric ** sends the final protocol and closes the connection. 3394865Seric */ 3404865Seric 34153751Seric smtpquit(m, mci, e) 34253751Seric register MAILER *m; 343*54967Seric register MCI *mci; 34453751Seric ENVELOPE *e; 3454865Seric { 3469391Seric int i; 3474865Seric 348*54967Seric /* send the quit message if we haven't gotten I/O error */ 34953751Seric if (mci->mci_state != MCIS_ERROR) 3509391Seric { 35153751Seric smtpmessage("QUIT", m, mci); 35253751Seric (void) reply(m, mci, e); 35353740Seric if (mci->mci_state == MCIS_CLOSED) 35410159Seric return; 3559391Seric } 3569391Seric 35752676Seric /* now actually close the connection and pick up the zombie */ 35852676Seric i = endmailer(mci, m->m_argv[0]); 3599391Seric if (i != EX_OK) 36015535Seric syserr("smtpquit %s: stat %d", m->m_argv[0], i); 3614865Seric } 3624865Seric /* 363*54967Seric ** SMTPRSET -- send a RSET (reset) command 364*54967Seric */ 365*54967Seric 366*54967Seric smtprset(m, mci, e) 367*54967Seric register MAILER *m; 368*54967Seric register MCI *mci; 369*54967Seric ENVELOPE *e; 370*54967Seric { 371*54967Seric int r; 372*54967Seric 373*54967Seric smtpmessage("RSET", m, mci); 374*54967Seric r = reply(m, mci, e); 375*54967Seric if (r < 0 || REPLYTYPE(r) == 4) 376*54967Seric return EX_TEMPFAIL; 377*54967Seric else if (REPLYTYPE(r) == 2) 378*54967Seric return EX_OK; 379*54967Seric else 380*54967Seric return EX_PROTOCOL; 381*54967Seric } 382*54967Seric /* 383*54967Seric ** SMTPNOOP -- send a NOOP (no operation) command to check the connection state 384*54967Seric */ 385*54967Seric 386*54967Seric smtpnoop(mci) 387*54967Seric register MCI *mci; 388*54967Seric { 389*54967Seric int r; 390*54967Seric MAILER *m = mci->mci_mailer; 391*54967Seric extern ENVELOPE BlankEnvelope; 392*54967Seric ENVELOPE *e = &BlankEnvelope; 393*54967Seric 394*54967Seric smtpmessage("NOOP", m, mci); 395*54967Seric r = reply(m, mci, e); 396*54967Seric if (REPLYTYPE(r) != 2) 397*54967Seric smtpquit(m, mci, e); 398*54967Seric return r; 399*54967Seric } 400*54967Seric /* 4014684Seric ** REPLY -- read arpanet reply 4024684Seric ** 4034684Seric ** Parameters: 40410175Seric ** m -- the mailer we are reading the reply from. 4054684Seric ** 4064684Seric ** Returns: 4074684Seric ** reply code it reads. 4084684Seric ** 4094684Seric ** Side Effects: 4104684Seric ** flushes the mail file. 4114684Seric */ 4124684Seric 41353751Seric reply(m, mci, e) 41453751Seric MAILER *m; 415*54967Seric MCI *mci; 41653751Seric ENVELOPE *e; 4174684Seric { 41853740Seric (void) fflush(mci->mci_out); 4194684Seric 4207677Seric if (tTd(18, 1)) 4214796Seric printf("reply\n"); 4224796Seric 4237356Seric /* 4247356Seric ** Read the input line, being careful not to hang. 4257356Seric */ 4267356Seric 4274684Seric for (;;) 4284684Seric { 4294684Seric register int r; 4307356Seric register char *p; 43153751Seric extern time_t curtime(); 4324684Seric 4337685Seric /* actually do the read */ 43453751Seric if (e->e_xfp != NULL) 43553751Seric (void) fflush(e->e_xfp); /* for debugging */ 4367356Seric 43710054Seric /* if we are in the process of closing just give the code */ 43853740Seric if (mci->mci_state == MCIS_CLOSED) 43910054Seric return (SMTPCLOSING); 44010054Seric 44110054Seric /* get the line from the other side */ 44253740Seric p = sfgets(SmtpReplyBuffer, sizeof SmtpReplyBuffer, mci->mci_in); 44353751Seric mci->mci_lastuse = curtime(); 44453751Seric 44510054Seric if (p == NULL) 44610131Seric { 44710148Seric extern char MsgBuf[]; /* err.c */ 44810148Seric extern char Arpa_TSyserr[]; /* conf.c */ 44910148Seric 45021065Seric /* if the remote end closed early, fake an error */ 45121065Seric if (errno == 0) 45221065Seric # ifdef ECONNRESET 45321065Seric errno = ECONNRESET; 45421065Seric # else ECONNRESET 45521065Seric errno = EPIPE; 45621065Seric # endif ECONNRESET 45721065Seric 45810148Seric message(Arpa_TSyserr, "reply: read error"); 45910420Seric /* if debugging, pause so we can see state */ 46010420Seric if (tTd(18, 100)) 46110420Seric pause(); 46210148Seric # ifdef LOG 46336234Skarels syslog(LOG_INFO, "%s", &MsgBuf[4]); 46410148Seric # endif LOG 465*54967Seric mci->mci_state = MCIS_ERROR; 46653751Seric smtpquit(m, mci, e); 46710054Seric return (-1); 46810131Seric } 46910054Seric fixcrlf(SmtpReplyBuffer, TRUE); 47010054Seric 47153751Seric if (e->e_xfp != NULL && index("45", SmtpReplyBuffer[0]) != NULL) 47214900Seric { 47314900Seric /* serious error -- log the previous command */ 47414900Seric if (SmtpMsgBuffer[0] != '\0') 47553751Seric fprintf(e->e_xfp, ">>> %s\n", SmtpMsgBuffer); 47614900Seric SmtpMsgBuffer[0] = '\0'; 47714900Seric 47814900Seric /* now log the message as from the other side */ 47953751Seric fprintf(e->e_xfp, "<<< %s\n", SmtpReplyBuffer); 48014900Seric } 48114900Seric 48214900Seric /* display the input for verbose mode */ 4837229Seric if (Verbose && !HoldErrs) 4849391Seric nmessage(Arpa_Info, "%s", SmtpReplyBuffer); 4857356Seric 4867356Seric /* if continuation is required, we can go on */ 4879391Seric if (SmtpReplyBuffer[3] == '-' || !isdigit(SmtpReplyBuffer[0])) 4884684Seric continue; 4897356Seric 4907356Seric /* decode the reply code */ 4919391Seric r = atoi(SmtpReplyBuffer); 4927356Seric 4937356Seric /* extra semantics: 0xx codes are "informational" */ 4944684Seric if (r < 100) 4954684Seric continue; 4967356Seric 4979391Seric /* reply code 421 is "Service Shutting Down" */ 49853740Seric if (r == SMTPCLOSING && mci->mci_state != MCIS_SSD) 4999391Seric { 50010054Seric /* send the quit protocol */ 50153740Seric mci->mci_state = MCIS_SSD; 50253751Seric smtpquit(m, mci, e); 5039391Seric } 5049391Seric 50521065Seric /* save temporary failure messages for posterity */ 50621065Seric if (SmtpReplyBuffer[0] == '4' && SmtpError[0] == '\0') 50721065Seric (void) strcpy(SmtpError, &SmtpReplyBuffer[4]); 50821065Seric 5094684Seric return (r); 5104684Seric } 5114684Seric } 5124796Seric /* 5134865Seric ** SMTPMESSAGE -- send message to server 5144796Seric ** 5154796Seric ** Parameters: 5164796Seric ** f -- format 51710175Seric ** m -- the mailer to control formatting. 5184796Seric ** a, b, c -- parameters 5194796Seric ** 5204796Seric ** Returns: 5214796Seric ** none. 5224796Seric ** 5234796Seric ** Side Effects: 52453740Seric ** writes message to mci->mci_out. 5254796Seric */ 5264796Seric 5274865Seric /*VARARGS1*/ 52853740Seric smtpmessage(f, m, mci, a, b, c) 5294796Seric char *f; 53010175Seric MAILER *m; 531*54967Seric MCI *mci; 5324796Seric { 53314900Seric (void) sprintf(SmtpMsgBuffer, f, a, b, c); 5347677Seric if (tTd(18, 1) || (Verbose && !HoldErrs)) 53514900Seric nmessage(Arpa_Info, ">>> %s", SmtpMsgBuffer); 53653740Seric if (mci->mci_out != NULL) 53753740Seric fprintf(mci->mci_out, "%s%s", SmtpMsgBuffer, 538*54967Seric m == NULL ? "\r\n" : m->m_eol); 5394796Seric } 5405182Seric 5415182Seric # endif SMTP 542