Annotation of researchv10no/cmd/nupas/send/main.c, revision 1.1.1.1

1.1       root        1: #include <stdio.h>
                      2: #include <regexp.h>
                      3: #include <signal.h>
                      4: #include "mail.h"
                      5: #include "string.h"
                      6: #include "message.h"
                      7: #include "dest.h"
                      8: #include "aux.h"
                      9: #include "process.h"
                     10: 
                     11: /* globals to all files */
                     12: int rmail = 0;
                     13: int onatty = 0;
                     14: char *thissys;
                     15: int nflg = 0;
                     16: int debug = 0;
                     17: 
                     18: /* global to this file */
                     19: static string *errstr;
                     20: static message *mp;
                     21: static int interrupt;
                     22: static char stderrbuf[BUFSIZ];
                     23: static int savemail;
                     24: 
                     25: /* imports (other than in .h's) */
                     26: extern int nsysfile;
                     27: extern void exit();
                     28: extern FILE* lockopen();
                     29: 
                     30: /* interrupt handling */
                     31: SIGRETURN
                     32: catch_int(s)
                     33:        int s;
                     34: {
                     35:        signal(SIGINT, catch_int);
                     36:        interrupt = 1;
                     37: }
                     38: 
                     39: /* save the mail and go away */
                     40: SIGRETURN
                     41: save_on_int(s)
                     42:        int s;
                     43: {
                     44:        cleanlocks();
                     45:        save_mail(mp);
                     46:        exit(1);
                     47: }
                     48: 
                     49: /* save the mail and go away */
                     50: SIGRETURN
                     51: die_on_quit(s)
                     52:        int s;
                     53: {
                     54:        cleanlocks();
                     55:        exit(1);
                     56: }
                     57: 
                     58: main(ac, av)
                     59:        int ac;
                     60:        char *av[];
                     61: {
                     62:        int i,j;
                     63:        dest *dp=NULL;
                     64:        int checkforward;
                     65:        SIG_TYP fint, fquit, fhup;
                     66:        char *base;
                     67:        int rv;
                     68: 
                     69:        /* process args */
                     70:        setbuf(stderr, stderrbuf);
                     71:        for (i = 1; i < ac; i++) {
                     72:                if (av[i][0] == '-') {
                     73:                        for(j=1; av[i][j]; j++)
                     74:                                /* option */
                     75:                                switch (av[i][1]) {
                     76:                                case '#':
                     77:                                        nflg = 1;
                     78:                                        break;
                     79:                                case 'd':
                     80:                                        debug = 1;
                     81:                                        break;
                     82:                                default:
                     83:                                        fprintf(stderr, "usage: mail [-#] list-of-addresses\n");
                     84:                                        exit(1);
                     85:                                }
                     86:                } else
                     87:                        /* destination */
                     88:                        d_insert(&dp, d_new(s_copy(av[i])));
                     89:        }
                     90:        if (dp == NULL) {
                     91:                fprintf(stderr, "usage: mail [-#] address-list\n");
                     92:                exit(1);
                     93:        }
                     94: 
                     95:        /*
                     96:         * get context:
                     97:         *      - whether we're rmail or mail
                     98:         *      - whether on a tty
                     99:         */
                    100:        base = basename(av[0]);
                    101:        checkforward = rmail = strcmp(base, "rmail")==0;
                    102:        onatty = (!rmail) && isatty(0);
                    103:        thissys = sysname_read();
                    104:        if (!nflg) {
                    105:                if ((fint=signal(SIGINT, SIG_IGN))!=SIG_DFL)
                    106:                        signal(SIGINT, fint);
                    107:                else
                    108:                        signal(SIGINT, fint = (SIG_TYP)catch_int);
                    109:                if ((fquit=signal(SIGQUIT, SIG_IGN))!=SIG_DFL)
                    110:                        signal(SIGQUIT, fquit);
                    111:                else
                    112:                        signal(SIGQUIT, die_on_quit);
                    113:                if ((fhup=signal(SIGHUP, SIG_IGN))!=SIG_DFL)
                    114:                        signal(SIGHUP, fhup);
                    115:                else
                    116:                        signal(SIGHUP, fhup = (SIG_TYP)catch_int);
                    117: 
                    118:                mp = m_read(stdin, rmail, onatty);
                    119:                if (mp == NULL)
                    120:                        exit(0);
                    121:                if (interrupt != 0) {
                    122:                        save_mail(mp);
                    123:                        exit(1);
                    124:                }
                    125: 
                    126:                if (fint==(SIG_TYP)catch_int)
                    127:                        signal(SIGINT, save_on_int);
                    128:                if (fhup==(SIG_TYP)catch_int)
                    129:                        signal(SIGHUP, save_on_int);
                    130:        } else {
                    131:                mp = m_new();
                    132:                default_from(mp);
                    133:        }
                    134:        errstr = s_new();
                    135:        (void)getrules();
                    136: 
                    137:        /*
                    138:         *  If this is a gateway, translate the sender address into a local
                    139:         *  address.  This only happens if mail to the local address is 
                    140:         *  forwarded to the sender.
                    141:         */
                    142:        gateway(mp);
                    143: 
                    144:        /*
                    145:         *  Protect against shell characters in the sender name for
                    146:         *  security reasons.
                    147:         */
                    148:        s_restart(mp->sender);
                    149:        if (shellchars(s_to_c(mp->sender)))
                    150:                mp->replyaddr = s_copy("postmaster");
                    151:        else
                    152:                mp->replyaddr = s_clone(mp->sender);
                    153:        s_restart(mp->replyaddr);
                    154: 
                    155:        /*
                    156:         *  reject messages that are too long.  We don't do it earlier
                    157:         *  in m_read since we haven't set up enough things yet.
                    158:         */
                    159:        if(mp->size < 0)
                    160:                return refuse(dp, mp, "message too long", 0);
                    161: 
                    162:        rv = send(dp, mp, checkforward);
                    163:        if(savemail)
                    164:                save_mail(mp);
                    165:        return rv;
                    166: }
                    167: 
                    168: 
                    169: /* send a message to a list of sites */
                    170: send(destp, mp, checkforward)
                    171:        dest *destp;
                    172:        message *mp;
                    173: {
                    174:        dest *dp;               /* destination being acted upon */
                    175:        dest *bound;            /* bound destinations */
                    176:        int errors=0;
                    177:        static int forked;
                    178:        extern dest *up_bind();
                    179: 
                    180:        /* bind the destinations to actions */
                    181:        bound = up_bind(destp, mp, checkforward);
                    182: 
                    183:        /* loop through and execute commands */
                    184:        for (dp = d_rm(&bound); dp != NULL; dp = d_rm(&bound)) {
                    185:                switch (dp->status) {
                    186:                case d_cat:
                    187:                        errors += cat_mail(dp, mp);
                    188:                        break;
                    189:                case d_pipeto:
                    190:                case d_pipe:
                    191:                        if (!rmail && !nflg && !forked) {
                    192:                                forked = 1;
                    193:                                lesstedious();
                    194:                        }
                    195:                        errors += pipe_mail(dp, mp, dp->status==d_pipeto);
                    196:                        break;
                    197:                default:
                    198:                        errors += complain_mail(dp, mp);
                    199:                        break;
                    200:                }
                    201:        }
                    202: 
                    203:        return errors;
                    204: }
                    205: 
                    206: /* avoid user tedium (as Mike Lesk said in a previous version) */
                    207: lesstedious()
                    208: {
                    209:        int i;
                    210: 
                    211:        switch(fork()){
                    212:        case -1:
                    213:                onatty = 0;
                    214:                break;
                    215:        case 0:
                    216:                signal(SIGHUP, SIG_IGN);
                    217:                signal(SIGINT, SIG_IGN);
                    218:                signal(SIGQUIT, SIG_IGN);
                    219:                signal(SIGTERM, SIG_IGN);
                    220:                setpgrp(getpid());
                    221:                for(i=0; i<nsysfile; i++)
                    222:                        close(i);
                    223:                onatty = 0;
                    224:                savemail=0;
                    225:                break;
                    226:        default:
                    227:                exit(0);
                    228:        }
                    229: }
                    230: 
                    231: 
                    232: /* save the mail */
                    233: save_mail(mp)
                    234:        message *mp;
                    235: {
                    236:        FILE *fp;
                    237:        string *file=s_new();
                    238:        char *home;
                    239:        static saved = 0;
                    240:        int uid, gid;
                    241:        extern char *getenv();
                    242: 
                    243:        setuid(uid=getuid());
                    244:        setgid(gid=getgid());
                    245:        if ((home = getenv("HOME")) == NULL)
                    246:                return;
                    247:        s_append(file, home);
                    248:        s_append(file, "/dead.letter");
                    249:        if ((fp = lockopen(s_to_c(file), "w", MBOXMODE, uid, gid)) == NULL)
                    250:                return;
                    251:        m_bprint(mp, fp);
                    252:        lockclose(fp);
                    253:        fprintf(stderr, "saved in %s\n", s_to_c(file));
                    254: }
                    255: 
                    256: /* remember the interrupt happened */
                    257: /* dispose of incorrect addresses */
                    258: complain_mail(dp, mp)
                    259:        dest *dp;
                    260:        message *mp;
                    261: {
                    262:        char *msg;
                    263: 
                    264:        switch (dp->status) {
                    265:        case d_undefined:
                    266:                msg = "Invalid address"; /* a little different, for debugging */
                    267:                break;
                    268:        case d_syntax:
                    269:                msg = "invalid address";
                    270:                break;
                    271:        case d_unknown:
                    272:                msg = "unknown user";
                    273:                break;
                    274:        case d_eloop:
                    275:        case d_loop:
                    276:                msg = "forwarding loop";
                    277:                break;
                    278:        case d_noforward:
                    279:                if(dp->pstat && *s_to_c(dp->repl2))
                    280:                        return refuse(dp, mp, s_to_c(dp->repl2), dp->pstat);
                    281:                else
                    282:                        msg = "destination unknown or forwarding disallowed";
                    283:                break;
                    284:        case d_pipe:
                    285:                msg = "broken pipe";
                    286:                break;
                    287:        case d_cat:
                    288:                msg = "broken cat";
                    289:                break;
                    290:        case d_translate:
                    291:                if(dp->pstat && *s_to_c(dp->repl2))
                    292:                        return refuse(dp, mp, s_to_c(dp->repl2), dp->pstat);
                    293:                else
                    294:                        msg = "name translation failed";
                    295:                break;
                    296:        case d_alias:
                    297:                msg = "broken alias";
                    298:                break;
                    299:        case d_badmbox:
                    300:                msg = "corrupted mailbox";
                    301:                break;
                    302:        case d_resource:
                    303:                msg = "out of some resource.  Try again later.";
                    304:                break;
                    305:        }
                    306:        if (nflg) {
                    307:                printf("%s: %s\n", msg, s_to_c(dp->addr));
                    308:                return 0;
                    309:        }
                    310:        return refuse(dp, mp, msg, 0);
                    311: }
                    312: 
                    313: /* dispose of remote addresses */
                    314: pipe_mail(dp, mp, dolock)
                    315:        dest *dp;
                    316:        message *mp;
                    317:        int dolock;
                    318: {
                    319:        string *file;
                    320:        FILE *fp;
                    321:        dest *next, *list=NULL;
                    322:        string *cmd;
                    323:        process *pp;
                    324:        int status;
                    325:        string *errstr=s_new();
                    326: 
                    327:        /*
                    328:         *  collect the arguments
                    329:         */
                    330:        file = s_new();
                    331:        abspath(s_to_c(dp->addr), MAILROOT, file);
                    332:        next = d_rm_same(&dp);
                    333:        cmd = s_clone(s_restart(next->repl1));
                    334:        for(; next != NULL; next = d_rm_same(&dp)) {
                    335:                if ((next->uid!=-1 || next->gid !=-1)
                    336:                && shellchars(s_to_c(next->addr))){
                    337:                        /* this could be a serious security violation */
                    338:                        next->status=d_syntax;
                    339:                        complain_mail(next, mp);
                    340:                        continue;
                    341:                }
                    342:                if (next->repl2 != NULL) {
                    343:                        s_append(cmd, " ");
                    344:                        s_append(cmd, s_to_c(next->repl2));
                    345:                }
                    346:                d_insert(&list, next);
                    347:        }
                    348: 
                    349:        if (nflg) {
                    350:                puts(s_to_c(cmd));
                    351:                s_free(cmd);
                    352:                s_free(file);
                    353:                return 0;
                    354:        }
                    355: 
                    356:        /*
                    357:         *  lock the mailbox (so that `Pipe to's run sequentially)
                    358:         */
                    359:        if(dolock)
                    360:                fp = lockopen(s_to_c(file), "r", 0, 0, 0);
                    361:        else
                    362:                fp = NULL;
                    363:        s_free(file);
                    364: 
                    365:        /*
                    366:         *  run the process
                    367:         */
                    368:        pp = proc_start(s_to_c(cmd), instream(), (stream *)NULL,
                    369:                        outstream(), list->uid);
                    370:        if(pp==NULL || pp->std[0]==NULL || pp->std[2]==NULL)
                    371:                return refuse(list, mp, "out of processes, pipes, or memory", 0);
                    372:        m_print(mp, pp->std[0]->fp, thissys, 0);
                    373:        stream_free(pp->std[0]); pp->std[0] = NULL;
                    374:        while(s_read_line(pp->std[2]->fp, errstr) != NULL)
                    375:                ;
                    376:        status = proc_wait(pp);
                    377:        proc_free(pp);
                    378:        s_free(cmd);
                    379: 
                    380:        /*
                    381:         *  unlock the mailbox (if it was locked)
                    382:         */
                    383:        if(fp!=NULL)
                    384:                lockclose(fp);
                    385: 
                    386:        /*
                    387:         *  return status
                    388:         */
                    389:        if (status != 0)
                    390:                return refuse(list, mp, s_to_c(errstr), status);
                    391:        loglist(list, mp, "remote");
                    392:        return 0;
                    393: }
                    394: 
                    395: /* dispose of local addresses */
                    396: cat_mail(dp, mp)
                    397:        dest *dp;
                    398:        message *mp;
                    399: {
                    400:        FILE *fp;
                    401:        char *rcvr;
                    402: 
                    403:        if (nflg) {
                    404:                printf("cat >> %s\n", s_to_c(dp->repl1));
                    405:                return 0;
                    406:        }
                    407:        fp=lockopen(s_to_c(dp->repl1), "a", MBOXMODE, dp->uid, dp->gid);
                    408:        if (fp == NULL)
                    409:                return refuse(dp, mp, "mail file cannot be opened", 0);
                    410:        m_print(mp, fp, (char *)NULL, 1);
                    411:        fputs("\n", fp);
                    412:        fflush(fp);
                    413:        if (ferror(fp)) {
                    414:                lockclose(fp);
                    415:                return refuse(dp, mp, "error writing mail file", 0);
                    416:        }
                    417:        lockclose(fp);
                    418:        rcvr = basename(s_to_c(dp->repl1));
                    419:        logdelivery(dp, rcvr, mp);
                    420:        notify(rcvr, mp);
                    421:        return 0;
                    422: }
                    423: 
                    424: static void
                    425: appaddr(sp, dp)
                    426:        string *sp;
                    427:        dest *dp;
                    428: {
                    429:        dest *parent;
                    430: 
                    431:        if (dp->parent != NULL) {
                    432:                for(parent=dp->parent; parent->parent!=NULL; parent=parent->parent)
                    433:                        ;
                    434:                s_append(sp, s_to_c(parent->addr));
                    435:                s_append(sp, "' alias `");
                    436:        }
                    437:        s_append(sp, s_to_c(dp->addr));
                    438: }
                    439: 
                    440: /* reject delivery */
                    441: refuse(list, mp, cp, status)
                    442:        dest *list;
                    443:        message *mp;
                    444:        char *cp;
                    445:        int status;
                    446: {
                    447:        string *errstr=s_new();
                    448:        dest *dp;
                    449:        int rv=0;
                    450: 
                    451:        dp = d_rm(&list);
                    452:        mkerrstr(errstr, mp, dp, list, cp, status);
                    453:        /*
                    454:         * if on a tty just report the error.  Otherwise send mail
                    455:         * reporting the error.  N.B. To avoid mail loops, don't
                    456:         * send mail reporting a failure of mail to reach the postmaster.
                    457:         */
                    458:        if (onatty) {
                    459:                fputs(s_to_c(errstr), stderr);
                    460:                savemail = 1;
                    461:                rv = 1;
                    462:        } else {
                    463:                if (strcmp(s_to_c(mp->replyaddr), "postmaster")!=0)
                    464:                        rv = replymsg(errstr, mp, dp);
                    465:                else
                    466:                        rv = 1;
                    467:        }
                    468:        logrefusal(dp, mp, s_to_c(errstr));
                    469:        s_free(errstr);
                    470:        return rv;
                    471: }
                    472: 
                    473: /* make the error message */
                    474: mkerrstr(errstr, mp, dp, list, cp, status)
                    475:        string *errstr;
                    476:        message *mp;
                    477:        dest *dp;
                    478:        dest *list;
                    479:        char *cp;
                    480: {
                    481:        dest *next;
                    482:        char smsg[64];
                    483: 
                    484:        /* list all aliases */
                    485:        s_append(errstr, "Mail to `");
                    486:        appaddr(errstr, dp);
                    487:        for(next = d_rm(&list); next != NULL; next = d_rm(&list)) {
                    488:                s_append(errstr, "', '");
                    489:                appaddr(errstr, next);
                    490:                d_insert(&dp, next);
                    491:        }
                    492:        s_append(errstr, "' from '");
                    493:        s_append(errstr, s_to_c(mp->sender));
                    494:        s_append(errstr, "' failed.\n");
                    495: 
                    496:        /* >> and | deserve different flavored messages */
                    497:        switch(dp->status) {
                    498:        case d_pipe:
                    499:                s_append(errstr, "The mailer `");
                    500:                s_append(errstr, s_to_c(dp->repl1));
                    501:                sprintf(smsg, "' returned error status %x.\n", status);
                    502:                s_append(errstr, smsg);
                    503:                s_append(errstr, "The error message was:\n");
                    504:                s_append(errstr, cp);
                    505:                break;
                    506:        default:
                    507:                s_append(errstr, "The error message was:\n");
                    508:                s_append(errstr, cp);
                    509:                break;
                    510:        }
                    511: }
                    512: 
                    513: /*
                    514:  *  reply with up to 1024 characters of the
                    515:  *  original message
                    516:  */
                    517: replymsg(errstr, mp, dp)
                    518:        string *errstr;
                    519:        message *mp;
                    520:        dest *dp;
                    521: {
                    522:        message *refp = m_new();
                    523:        dest *ndp;
                    524:        char *rcvr;
                    525:        int rv;
                    526: 
                    527:        rcvr = dp->status==d_eloop ? "postmaster" : s_to_c(mp->replyaddr);
                    528:        ndp = d_new(s_copy(rcvr));
                    529:        s_append(refp->sender, "postmaster");
                    530:        s_append(refp->replyaddr, "postmaster");
                    531:        s_append(refp->date, thedate());
                    532:        s_append(refp->body, s_to_c(errstr));
                    533:        s_append(refp->body, "\nThe message began:\n");
                    534:        s_nappend(refp->body, s_to_c(mp->body), 8*1024);
                    535:        refp->size = strlen(s_to_c(refp->body));
                    536:        rv = send(ndp, refp, 0);
                    537:        m_free(refp);
                    538:        d_free(ndp);
                    539:        return rv;
                    540: }
                    541: 

unix.superglobalmegacorp.com

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