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

unix.superglobalmegacorp.com

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