Annotation of 43BSD/usr.lib/sendmail/src/usersmtp.c, revision 1.1.1.1

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

unix.superglobalmegacorp.com

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