Annotation of 43BSDReno/usr.sbin/sendmail/src/usersmtp.c, revision 1.1

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

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.