Annotation of 43BSDReno/usr.sbin/sendmail/src/usersmtp.c, revision 1.1.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.