Annotation of 42BSD/usr.lib/sendmail/src/srvrsmtp.c, revision 1.1

1.1     ! root        1: # include <errno.h>
        !             2: # include "sendmail.h"
        !             3: # include <signal.h>
        !             4: 
        !             5: # ifndef SMTP
        !             6: SCCSID(@(#)srvrsmtp.c  4.3             8/28/83 (no SMTP));
        !             7: # else SMTP
        !             8: 
        !             9: SCCSID(@(#)srvrsmtp.c  4.3             8/28/83);
        !            10: 
        !            11: /*
        !            12: **  SMTP -- run the SMTP protocol.
        !            13: **
        !            14: **     Parameters:
        !            15: **             none.
        !            16: **
        !            17: **     Returns:
        !            18: **             never.
        !            19: **
        !            20: **     Side Effects:
        !            21: **             Reads commands from the input channel and processes
        !            22: **                     them.
        !            23: */
        !            24: 
        !            25: struct cmd
        !            26: {
        !            27:        char    *cmdname;       /* command name */
        !            28:        int     cmdcode;        /* internal code, see below */
        !            29: };
        !            30: 
        !            31: /* values for cmdcode */
        !            32: # define CMDERROR      0       /* bad command */
        !            33: # define CMDMAIL       1       /* mail -- designate sender */
        !            34: # define CMDRCPT       2       /* rcpt -- designate recipient */
        !            35: # define CMDDATA       3       /* data -- send message text */
        !            36: # define CMDRSET       4       /* rset -- reset state */
        !            37: # define CMDVRFY       5       /* vrfy -- verify address */
        !            38: # define CMDHELP       6       /* help -- give usage info */
        !            39: # define CMDNOOP       7       /* noop -- do nothing */
        !            40: # define CMDQUIT       8       /* quit -- close connection and die */
        !            41: # define CMDHELO       9       /* helo -- be polite */
        !            42: # define CMDDBGQSHOW   10      /* showq -- show send queue (DEBUG) */
        !            43: # define CMDDBGDEBUG   11      /* debug -- set debug mode */
        !            44: # define CMDVERB       12      /* verb -- go into verbose mode */
        !            45: # define CMDDBGKILL    13      /* kill -- kill sendmail */
        !            46: # define CMDDBGWIZ     14      /* wiz -- become a wizard */
        !            47: # define CMDONEX       15      /* onex -- sending one transaction only */
        !            48: # define CMDDBGSHELL   16      /* shell -- give us a shell */
        !            49: 
        !            50: static struct cmd      CmdTab[] =
        !            51: {
        !            52:        "mail",         CMDMAIL,
        !            53:        "rcpt",         CMDRCPT,
        !            54:        "data",         CMDDATA,
        !            55:        "rset",         CMDRSET,
        !            56:        "vrfy",         CMDVRFY,
        !            57:        "expn",         CMDVRFY,
        !            58:        "help",         CMDHELP,
        !            59:        "noop",         CMDNOOP,
        !            60:        "quit",         CMDQUIT,
        !            61:        "helo",         CMDHELO,
        !            62:        "verb",         CMDVERB,
        !            63:        "onex",         CMDONEX,
        !            64: # ifdef DEBUG
        !            65:        "showq",        CMDDBGQSHOW,
        !            66:        "debug",        CMDDBGDEBUG,
        !            67:        "kill",         CMDDBGKILL,
        !            68:        "wiz",          CMDDBGWIZ,
        !            69:        "shell",        CMDDBGSHELL,
        !            70: # endif DEBUG
        !            71:        NULL,           CMDERROR,
        !            72: };
        !            73: 
        !            74: # ifdef DEBUG
        !            75: bool   IsWiz = FALSE;                  /* set if we are a wizard */
        !            76: char   *WizWord = NULL;                /* the wizard word to compare against */
        !            77: # endif DEBUG
        !            78: bool   InChild = FALSE;                /* true if running in a subprocess */
        !            79: bool   OneXact = FALSE;                /* one xaction only this run */
        !            80: char   *RealHostName = NULL;           /* verified hostname, set in daemon.c */
        !            81: 
        !            82: #define EX_QUIT                22              /* special code for QUIT command */
        !            83: 
        !            84: smtp()
        !            85: {
        !            86:        register char *p;
        !            87:        register struct cmd *c;
        !            88:        char *cmd;
        !            89:        extern char *skipword();
        !            90:        extern bool sameword();
        !            91:        bool hasmail;                   /* mail command received */
        !            92:        int rcps;                       /* number of recipients */
        !            93:        auto ADDRESS *vrfyqueue;
        !            94:        ADDRESS *a;
        !            95:        char inp[MAXLINE];
        !            96:        extern char Version[];
        !            97:        extern tick();
        !            98:        extern bool iswiz();
        !            99:        extern char *arpadate();
        !           100:        extern char *macvalue();
        !           101:        extern ADDRESS *recipient();
        !           102: 
        !           103:        hasmail = FALSE;
        !           104:        rcps = 0;
        !           105:        if (OutChannel != stdout)
        !           106:        {
        !           107:                /* arrange for debugging output to go to remote host */
        !           108:                (void) close(1);
        !           109:                (void) dup(fileno(OutChannel));
        !           110:        }
        !           111:        settime();
        !           112:        expand("$e", inp, &inp[sizeof inp], CurEnv);
        !           113:        message("220", inp);
        !           114:        for (;;)
        !           115:        {
        !           116:                /* arrange for backout */
        !           117:                if (setjmp(TopFrame) > 0 && InChild)
        !           118:                        finis();
        !           119:                QuickAbort = FALSE;
        !           120:                HoldErrs = FALSE;
        !           121: 
        !           122:                /* setup for the read */
        !           123:                CurEnv->e_to = NULL;
        !           124:                Errors = 0;
        !           125:                (void) fflush(stdout);
        !           126: 
        !           127:                /* read the input line */
        !           128:                p = sfgets(inp, sizeof inp, InChannel);
        !           129: 
        !           130:                /* handle errors */
        !           131:                if (p == NULL)
        !           132:                {
        !           133:                        /* end of file, just die */
        !           134:                        message("421", "%s Lost input channel", HostName);
        !           135:                        finis();
        !           136:                }
        !           137: 
        !           138:                /* clean up end of line */
        !           139:                fixcrlf(inp, TRUE);
        !           140: 
        !           141:                /* echo command to transcript */
        !           142:                if (CurEnv->e_xfp != NULL)
        !           143:                        fprintf(CurEnv->e_xfp, "<<< %s\n", inp);
        !           144: 
        !           145:                /* break off command */
        !           146:                for (p = inp; isspace(*p); p++)
        !           147:                        continue;
        !           148:                cmd = p;
        !           149:                while (*++p != '\0' && !isspace(*p))
        !           150:                        continue;
        !           151:                if (*p != '\0')
        !           152:                        *p++ = '\0';
        !           153: 
        !           154:                /* decode command */
        !           155:                for (c = CmdTab; c->cmdname != NULL; c++)
        !           156:                {
        !           157:                        if (sameword(c->cmdname, cmd))
        !           158:                                break;
        !           159:                }
        !           160: 
        !           161:                /* process command */
        !           162:                switch (c->cmdcode)
        !           163:                {
        !           164:                  case CMDHELO:         /* hello -- introduce yourself */
        !           165:                        if (sameword(p, HostName))
        !           166:                        {
        !           167:                                /* connected to an echo server */
        !           168:                                message("553", "%s I refuse to talk to myself",
        !           169:                                        HostName);
        !           170:                                break;
        !           171:                        }
        !           172:                        if (RealHostName != NULL && !sameword(p, RealHostName))
        !           173:                        {
        !           174:                                char buf[MAXNAME];
        !           175: 
        !           176:                                (void) sprintf(buf, "%s (%s)", p, RealHostName);
        !           177:                                define('s', newstr(buf), CurEnv);
        !           178:                        }
        !           179:                        else
        !           180:                                define('s', newstr(p), CurEnv);
        !           181:                        message("250", "%s Hello %s, pleased to meet you",
        !           182:                                HostName, p);
        !           183:                        break;
        !           184: 
        !           185:                  case CMDMAIL:         /* mail -- designate sender */
        !           186:                        /* force a sending host even if no HELO given */
        !           187:                        if (RealHostName != NULL && macvalue('s', CurEnv) == NULL)
        !           188:                                define('s', RealHostName, CurEnv);
        !           189: 
        !           190:                        /* check for validity of this command */
        !           191:                        if (hasmail)
        !           192:                        {
        !           193:                                message("503", "Sender already specified");
        !           194:                                break;
        !           195:                        }
        !           196:                        if (InChild)
        !           197:                        {
        !           198:                                syserr("Nested MAIL command");
        !           199:                                exit(0);
        !           200:                        }
        !           201: 
        !           202:                        /* fork a subprocess to process this command */
        !           203:                        if (runinchild("SMTP-MAIL") > 0)
        !           204:                                break;
        !           205:                        initsys();
        !           206: 
        !           207:                        /* child -- go do the processing */
        !           208:                        p = skipword(p, "from");
        !           209:                        if (p == NULL)
        !           210:                                break;
        !           211:                        setsender(p);
        !           212:                        if (Errors == 0)
        !           213:                        {
        !           214:                                message("250", "Sender ok");
        !           215:                                hasmail = TRUE;
        !           216:                        }
        !           217:                        else if (InChild)
        !           218:                                finis();
        !           219:                        break;
        !           220: 
        !           221:                  case CMDRCPT:         /* rcpt -- designate recipient */
        !           222:                        if (setjmp(TopFrame) > 0)
        !           223:                        {
        !           224:                                CurEnv->e_flags &= ~EF_FATALERRS;
        !           225:                                break;
        !           226:                        }
        !           227:                        QuickAbort = TRUE;
        !           228:                        p = skipword(p, "to");
        !           229:                        if (p == NULL)
        !           230:                                break;
        !           231:                        a = parseaddr(p, (ADDRESS *) NULL, 1);
        !           232:                        if (a == NULL)
        !           233:                                break;
        !           234:                        a = recipient(a, &CurEnv->e_sendqueue);
        !           235:                        if (Errors != 0)
        !           236:                                break;
        !           237: 
        !           238:                        /* no errors during parsing, but might be a duplicate */
        !           239:                        CurEnv->e_to = p;
        !           240:                        if (!bitset(QBADADDR, a->q_flags))
        !           241:                                message("250", "Recipient ok");
        !           242:                        else
        !           243:                        {
        !           244:                                /* punt -- should keep message in ADDRESS.... */
        !           245:                                message("550", "Addressee unknown");
        !           246:                        }
        !           247:                        CurEnv->e_to = NULL;
        !           248:                        rcps++;
        !           249:                        break;
        !           250: 
        !           251:                  case CMDDATA:         /* data -- text of mail */
        !           252:                        if (!hasmail)
        !           253:                        {
        !           254:                                message("503", "Need MAIL command");
        !           255:                                break;
        !           256:                        }
        !           257:                        else if (rcps <= 0)
        !           258:                        {
        !           259:                                message("503", "Need RCPT (recipient)");
        !           260:                                break;
        !           261:                        }
        !           262: 
        !           263:                        /* collect the text of the message */
        !           264:                        collect(TRUE);
        !           265:                        if (Errors != 0)
        !           266:                                break;
        !           267: 
        !           268:                        /*
        !           269:                        **  Arrange to send to everyone.
        !           270:                        **      If sending to multiple people, mail back
        !           271:                        **              errors rather than reporting directly.
        !           272:                        **      In any case, don't mail back errors for
        !           273:                        **              anything that has happened up to
        !           274:                        **              now (the other end will do this).
        !           275:                        **      Truncate our transcript -- the mail has gotten
        !           276:                        **              to us successfully, and if we have
        !           277:                        **              to mail this back, it will be easier
        !           278:                        **              on the reader.
        !           279:                        **      Then send to everyone.
        !           280:                        **      Finally give a reply code.  If an error has
        !           281:                        **              already been given, don't mail a
        !           282:                        **              message back.
        !           283:                        **      We goose error returns by clearing error bit.
        !           284:                        */
        !           285: 
        !           286:                        if (rcps != 1)
        !           287:                        {
        !           288:                                HoldErrs = TRUE;
        !           289:                                ErrorMode == EM_MAIL;
        !           290:                        }
        !           291:                        CurEnv->e_flags &= ~EF_FATALERRS;
        !           292:                        CurEnv->e_xfp = freopen(queuename(CurEnv, 'x'), "w", CurEnv->e_xfp);
        !           293: 
        !           294:                        /* send to all recipients */
        !           295:                        sendall(CurEnv, SM_DEFAULT);
        !           296:                        CurEnv->e_to = NULL;
        !           297: 
        !           298:                        /* issue success if appropriate and reset */
        !           299:                        if (Errors == 0 || HoldErrs)
        !           300:                                message("250", "Ok");
        !           301:                        else
        !           302:                                CurEnv->e_flags &= ~EF_FATALERRS;
        !           303: 
        !           304:                        /* if in a child, pop back to our parent */
        !           305:                        if (InChild)
        !           306:                                finis();
        !           307:                        break;
        !           308: 
        !           309:                  case CMDRSET:         /* rset -- reset state */
        !           310:                        message("250", "Reset state");
        !           311:                        if (InChild)
        !           312:                                finis();
        !           313:                        break;
        !           314: 
        !           315:                  case CMDVRFY:         /* vrfy -- verify address */
        !           316:                        if (runinchild("SMTP-VRFY") > 0)
        !           317:                                break;
        !           318:                        vrfyqueue = NULL;
        !           319:                        QuickAbort = TRUE;
        !           320:                        sendtolist(p, (ADDRESS *) NULL, &vrfyqueue);
        !           321:                        if (Errors != 0)
        !           322:                        {
        !           323:                                if (InChild)
        !           324:                                        finis();
        !           325:                                break;
        !           326:                        }
        !           327:                        while (vrfyqueue != NULL)
        !           328:                        {
        !           329:                                register ADDRESS *a = vrfyqueue->q_next;
        !           330:                                char *code;
        !           331: 
        !           332:                                while (a != NULL && bitset(QDONTSEND|QBADADDR, a->q_flags))
        !           333:                                        a = a->q_next;
        !           334: 
        !           335:                                if (!bitset(QDONTSEND|QBADADDR, vrfyqueue->q_flags))
        !           336:                                {
        !           337:                                        if (a != NULL)
        !           338:                                                code = "250-";
        !           339:                                        else
        !           340:                                                code = "250";
        !           341:                                        if (vrfyqueue->q_fullname == NULL)
        !           342:                                                message(code, "<%s>", vrfyqueue->q_paddr);
        !           343:                                        else
        !           344:                                                message(code, "%s <%s>",
        !           345:                                                    vrfyqueue->q_fullname, vrfyqueue->q_paddr);
        !           346:                                }
        !           347:                                else if (a == NULL)
        !           348:                                        message("554", "Self destructive alias loop");
        !           349:                                vrfyqueue = a;
        !           350:                        }
        !           351:                        if (InChild)
        !           352:                                finis();
        !           353:                        break;
        !           354: 
        !           355:                  case CMDHELP:         /* help -- give user info */
        !           356:                        if (*p == '\0')
        !           357:                                p = "SMTP";
        !           358:                        help(p);
        !           359:                        break;
        !           360: 
        !           361:                  case CMDNOOP:         /* noop -- do nothing */
        !           362:                        message("200", "OK");
        !           363:                        break;
        !           364: 
        !           365:                  case CMDQUIT:         /* quit -- leave mail */
        !           366:                        message("221", "%s closing connection", HostName);
        !           367:                        if (InChild)
        !           368:                                ExitStat = EX_QUIT;
        !           369:                        finis();
        !           370: 
        !           371:                  case CMDVERB:         /* set verbose mode */
        !           372:                        Verbose = TRUE;
        !           373:                        message("200", "Verbose mode");
        !           374:                        break;
        !           375: 
        !           376:                  case CMDONEX:         /* doing one transaction only */
        !           377:                        OneXact = TRUE;
        !           378:                        message("200", "Only one transaction");
        !           379:                        break;
        !           380: 
        !           381: # ifdef DEBUG
        !           382:                  case CMDDBGQSHOW:     /* show queues */
        !           383:                        printf("Send Queue=");
        !           384:                        printaddr(CurEnv->e_sendqueue, TRUE);
        !           385:                        break;
        !           386: 
        !           387:                  case CMDDBGDEBUG:     /* set debug mode */
        !           388:                        tTsetup(tTdvect, sizeof tTdvect, "0-99.1");
        !           389:                        tTflag(p);
        !           390:                        message("200", "Debug set");
        !           391:                        break;
        !           392: 
        !           393:                  case CMDDBGKILL:      /* kill the parent */
        !           394:                        if (!iswiz())
        !           395:                                break;
        !           396:                        if (kill(MotherPid, SIGTERM) >= 0)
        !           397:                                message("200", "Mother is dead");
        !           398:                        else
        !           399:                                message("500", "Can't kill Mom");
        !           400:                        break;
        !           401: 
        !           402:                  case CMDDBGSHELL:     /* give us an interactive shell */
        !           403:                        if (!iswiz())
        !           404:                                break;
        !           405:                        if (fileno(InChannel) != 0)
        !           406:                        {
        !           407:                                (void) close(0);
        !           408:                                (void) dup(fileno(InChannel));
        !           409:                                if (fileno(InChannel) != fileno(OutChannel))
        !           410:                                        (void) fclose(InChannel);
        !           411:                                InChannel = stdin;
        !           412:                        }
        !           413:                        if (fileno(OutChannel) != 1)
        !           414:                        {
        !           415:                                (void) close(1);
        !           416:                                (void) dup(fileno(OutChannel));
        !           417:                                (void) fclose(OutChannel);
        !           418:                                OutChannel = stdout;
        !           419:                        }
        !           420:                        (void) close(2);
        !           421:                        (void) dup(1);
        !           422:                        execl("/bin/csh", "sendmail", 0);
        !           423:                        execl("/bin/sh", "sendmail", 0);
        !           424:                        message("500", "Can't");
        !           425:                        exit(EX_UNAVAILABLE);
        !           426: 
        !           427:                  case CMDDBGWIZ:       /* become a wizard */
        !           428:                        if (WizWord != NULL)
        !           429:                        {
        !           430:                                char seed[3];
        !           431:                                extern char *crypt();
        !           432: 
        !           433:                                strncpy(seed, WizWord, 2);
        !           434:                                if (strcmp(WizWord, crypt(p, seed)) != 0)
        !           435:                                {
        !           436:                                        message("500", "You are no wizard!");
        !           437:                                        break;
        !           438:                                }
        !           439:                        }
        !           440:                        IsWiz = TRUE;
        !           441:                        message("200", "Please pass, oh mighty wizard");
        !           442:                        break;
        !           443: # endif DEBUG
        !           444: 
        !           445:                  case CMDERROR:        /* unknown command */
        !           446:                        message("500", "Command unrecognized");
        !           447:                        break;
        !           448: 
        !           449:                  default:
        !           450:                        syserr("smtp: unknown code %d", c->cmdcode);
        !           451:                        break;
        !           452:                }
        !           453:        }
        !           454: }
        !           455: /*
        !           456: **  SKIPWORD -- skip a fixed word.
        !           457: **
        !           458: **     Parameters:
        !           459: **             p -- place to start looking.
        !           460: **             w -- word to skip.
        !           461: **
        !           462: **     Returns:
        !           463: **             p following w.
        !           464: **             NULL on error.
        !           465: **
        !           466: **     Side Effects:
        !           467: **             clobbers the p data area.
        !           468: */
        !           469: 
        !           470: static char *
        !           471: skipword(p, w)
        !           472:        register char *p;
        !           473:        char *w;
        !           474: {
        !           475:        register char *q;
        !           476:        extern bool sameword();
        !           477: 
        !           478:        /* find beginning of word */
        !           479:        while (isspace(*p))
        !           480:                p++;
        !           481:        q = p;
        !           482: 
        !           483:        /* find end of word */
        !           484:        while (*p != '\0' && *p != ':' && !isspace(*p))
        !           485:                p++;
        !           486:        while (isspace(*p))
        !           487:                *p++ = '\0';
        !           488:        if (*p != ':')
        !           489:        {
        !           490:          syntax:
        !           491:                message("501", "Syntax error");
        !           492:                Errors++;
        !           493:                return (NULL);
        !           494:        }
        !           495:        *p++ = '\0';
        !           496:        while (isspace(*p))
        !           497:                p++;
        !           498: 
        !           499:        /* see if the input word matches desired word */
        !           500:        if (!sameword(q, w))
        !           501:                goto syntax;
        !           502: 
        !           503:        return (p);
        !           504: }
        !           505: /*
        !           506: **  HELP -- implement the HELP command.
        !           507: **
        !           508: **     Parameters:
        !           509: **             topic -- the topic we want help for.
        !           510: **
        !           511: **     Returns:
        !           512: **             none.
        !           513: **
        !           514: **     Side Effects:
        !           515: **             outputs the help file to message output.
        !           516: */
        !           517: 
        !           518: help(topic)
        !           519:        char *topic;
        !           520: {
        !           521:        register FILE *hf;
        !           522:        int len;
        !           523:        char buf[MAXLINE];
        !           524:        bool noinfo;
        !           525: 
        !           526:        if (HelpFile == NULL || (hf = fopen(HelpFile, "r")) == NULL)
        !           527:        {
        !           528:                /* no help */
        !           529:                errno = 0;
        !           530:                message("502", "HELP not implemented");
        !           531:                return;
        !           532:        }
        !           533: 
        !           534:        len = strlen(topic);
        !           535:        makelower(topic);
        !           536:        noinfo = TRUE;
        !           537: 
        !           538:        while (fgets(buf, sizeof buf, hf) != NULL)
        !           539:        {
        !           540:                if (strncmp(buf, topic, len) == 0)
        !           541:                {
        !           542:                        register char *p;
        !           543: 
        !           544:                        p = index(buf, '\t');
        !           545:                        if (p == NULL)
        !           546:                                p = buf;
        !           547:                        else
        !           548:                                p++;
        !           549:                        fixcrlf(p, TRUE);
        !           550:                        message("214-", p);
        !           551:                        noinfo = FALSE;
        !           552:                }
        !           553:        }
        !           554: 
        !           555:        if (noinfo)
        !           556:                message("504", "HELP topic unknown");
        !           557:        else
        !           558:                message("214", "End of HELP info");
        !           559:        (void) fclose(hf);
        !           560: }
        !           561: /*
        !           562: **  ISWIZ -- tell us if we are a wizard
        !           563: **
        !           564: **     If not, print a nasty message.
        !           565: **
        !           566: **     Parameters:
        !           567: **             none.
        !           568: **
        !           569: **     Returns:
        !           570: **             TRUE if we are a wizard.
        !           571: **             FALSE if we are not a wizard.
        !           572: **
        !           573: **     Side Effects:
        !           574: **             Prints a 500 exit stat if we are not a wizard.
        !           575: */
        !           576: 
        !           577: bool
        !           578: iswiz()
        !           579: {
        !           580:        if (!IsWiz)
        !           581:                message("500", "Mere mortals musn't mutter that mantra");
        !           582:        return (IsWiz);
        !           583: }
        !           584: /*
        !           585: **  RUNINCHILD -- return twice -- once in the child, then in the parent again
        !           586: **
        !           587: **     Parameters:
        !           588: **             label -- a string used in error messages
        !           589: **
        !           590: **     Returns:
        !           591: **             zero in the child
        !           592: **             one in the parent
        !           593: **
        !           594: **     Side Effects:
        !           595: **             none.
        !           596: */
        !           597: 
        !           598: runinchild(label)
        !           599:        char *label;
        !           600: {
        !           601:        int childpid;
        !           602: 
        !           603:        if (OneXact)
        !           604:                return (0);
        !           605: 
        !           606:        childpid = dofork();
        !           607:        if (childpid < 0)
        !           608:        {
        !           609:                syserr("%s: cannot fork", label);
        !           610:                return (1);
        !           611:        }
        !           612:        if (childpid > 0)
        !           613:        {
        !           614:                auto int st;
        !           615: 
        !           616:                /* parent -- wait for child to complete */
        !           617:                st = waitfor(childpid);
        !           618:                if (st == -1)
        !           619:                        syserr("%s: lost child", label);
        !           620: 
        !           621:                /* if we exited on a QUIT command, complete the process */
        !           622:                if (st == (EX_QUIT << 8))
        !           623:                        finis();
        !           624: 
        !           625:                return (1);
        !           626:        }
        !           627:        else
        !           628:        {
        !           629:                /* child */
        !           630:                InChild = TRUE;
        !           631:                clearenvelope(CurEnv);
        !           632:                return (0);
        !           633:        }
        !           634: }
        !           635: 
        !           636: # endif SMTP

unix.superglobalmegacorp.com

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