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

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

unix.superglobalmegacorp.com

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