Annotation of 43BSDTahoe/new/news/src/inews.c, revision 1.1.1.1

1.1       root        1: /*
                      2:  * This software is Copyright (c) 1986 by Rick Adams.
                      3:  *
                      4:  * Permission is hereby granted to copy, reproduce, redistribute or
                      5:  * otherwise use this software as long as: there is no monetary
                      6:  * profit gained specifically from the use or reproduction or this
                      7:  * software, it is not sold, rented, traded or otherwise marketed, and
                      8:  * this copyright notice is included prominently in any copy
                      9:  * made.
                     10:  *
                     11:  * The author make no claims as to the fitness or correctness of
                     12:  * this software for any use whatsoever, and it is provided as is. 
                     13:  * Any use of this software is at the user's own risk.
                     14:  *
                     15:  * inews - insert, receive, and transmit news articles.
                     16:  *
                     17:  */
                     18: 
                     19: #ifdef SCCSID
                     20: static char    *SccsId = "@(#)inews.c  2.82    10/15/87";
                     21: #endif /* SCCSID */
                     22: 
                     23: #include "iparams.h"
                     24: 
                     25: # ifdef LOCKF
                     26: # include <unistd.h>
                     27: # include <fcntl.h>
                     28: 
                     29: # if defined(F_RDLCK) && defined(F_SETLK)
                     30: struct flock news_lock;
                     31: #  endif /* F_RDLCK  && F_SETLK */
                     32: # endif /* LOCKF */
                     33: 
                     34: #ifdef BSD4_2
                     35: # include <sys/file.h>
                     36: #else  /* !BSD4_2 */
                     37: # if defined(USG) && !defined(LOCKF)
                     38: # include <fcntl.h>
                     39: # endif /* USG */
                     40: #endif /* !BSD4_2 */
                     41: /* local defines for inews */
                     42: 
                     43: #define OPTION 0       /* pick up an option string */
                     44: #define STRING 1       /* pick up a string of arguments */
                     45: 
                     46: #define UNKNOWN 0001   /* possible modes for news program */
                     47: #define UNPROC 0002    /* Unprocessed input */
                     48: #define PROC   0004    /* Processed input */
                     49: #define        CONTROL 0010    /* Control Message */
                     50: #define        CREATENG 0020   /* Create a new newsgroup */
                     51: 
                     52: #define DONT_SPOOL     0
                     53: #define        DO_SPOOL        1
                     54: #define        EXPIRE_RUNNING  2
                     55: int spool_news = DONT_SPOOL;
                     56: 
                     57: extern char histline[];
                     58: char   forgedname[NAMELEN];    /* A user specified -f option. */
                     59: /* Fake sys line in case they forget their own system */
                     60: struct srec dummy_srec = { "MEMEME", "", "all", "", "" };
                     61: 
                     62: char *Progname = "inews";      /* used by xerror to identify failing program */
                     63: 
                     64: struct {                       /* options table. */
                     65:        char    optlet;         /* option character. */
                     66:        char    filchar;        /* if to pickup string, fill character. */
                     67:        int     flag;           /* TRUE if have seen this opt. */
                     68:        int     oldmode;        /* OR of legal input modes. */
                     69:        int     newmode;        /* output mode. */
                     70:        char    *buf;           /* string buffer */
                     71: } *optpt, options[] = { /*
                     72: optlet filchar         flag    oldmode newmode         buf     */
                     73: 't',   ' ',            FALSE,  UNPROC, UNKNOWN,        header.title,
                     74: 'n',   NGDELIM,        FALSE,  UNPROC, UNKNOWN,        header.nbuf,
                     75: 'd',   '\0',           FALSE,  UNPROC, UNKNOWN,        header.distribution,
                     76: 'e',   ' ',            FALSE,  UNPROC, UNKNOWN,        header.expdate,
                     77: 'p',   '\0',           FALSE,  UNKNOWN|PROC,   PROC,   filename,
                     78: 'f',   '\0',           FALSE,  UNPROC, UNKNOWN,        forgedname,
                     79: 'F',   ' ',            FALSE,  UNPROC, UNKNOWN,        header.followid,
                     80: 'c',   ' ',            FALSE,  UNKNOWN,UNKNOWN,        header.ctlmsg,
                     81: 'C',   ' ',            FALSE,  UNKNOWN,CREATENG,       header.ctlmsg,
                     82: #define hflag  options[9].flag
                     83: 'h',   '\0',           FALSE,  UNPROC, UNKNOWN,        filename,
                     84: #define oflag  options[10].flag
                     85: 'o',   '\0',           FALSE,  UNPROC, UNKNOWN,        header.organization,
                     86: #define Mflag  options[11].flag
                     87: 'M',   '\0',           FALSE,  UNPROC, UNKNOWN,        filename,
                     88: 'a',   '\0',           FALSE,  UNPROC, UNKNOWN,        header.approved,
                     89: 'U',   '\0',           FALSE,  PROC, PROC,             filename,
                     90: #define Sflag  options[14].flag
                     91: 'S',   '\0',           FALSE,  UNKNOWN|PROC,   UNPROC, filename,
                     92: 'x',   '\0',           FALSE,  UNPROC, UNKNOWN,        not_here,
                     93: 'r',   '\0',           FALSE,  UNPROC, UNKNOWN,        header.replyto,
                     94: '\0',  '\0',           0,      0,      0,              (char *)NULL
                     95: };
                     96: 
                     97: FILE *mailhdr();
                     98: extern int errno;
                     99: 
                    100: struct timeb Now;
                    101: 
                    102: /*
                    103:  *     Authors:
                    104:  *             Matt Glickman   [email protected]
                    105:  *             Mark Horton     [email protected]
                    106:  *             Stephen Daniels [email protected]
                    107:  *             Tom Truscott    [email protected]
                    108:  *             Rick Adams      [email protected]
                    109:  *     IHCC version adapted by:
                    110:  *             Larry Marek     [email protected]
                    111:  */
                    112: main(argc, argv)
                    113: int    argc;
                    114: register char **argv;
                    115: {
                    116:        int     state;          /* which type of argument to pick up    */
                    117:        int     tlen, len;      /* temps for string processing routine  */
                    118:        register char *ptr;     /* pointer to rest of buffer            */
                    119:        int     filchar;        /* fill character (state = STRING)      */
                    120:        char    *user = NULL, *home = NULL;     /* environment temps    */
                    121:        struct passwd   *pw;    /* struct for pw lookup                 */
                    122:        struct group    *gp;    /* struct for group lookup              */
                    123:        register int    i;
                    124:        FILE    *mfd;           /* mail file file-descriptor            */
                    125: 
                    126:        /* uuxqt doesn't close all its files */
                    127:        for (i = 3; !close(i); i++)
                    128:                ;
                    129:        /* set up defaults and initialize. */
                    130:        mode = UNKNOWN;
                    131:        infp = stdin;
                    132:        pathinit();
                    133:        savmask = umask(N_UMASK);       /* set up mask */
                    134:        ptr = rindex(*argv, '/');
                    135:        if (!ptr)
                    136:                ptr = *argv - 1;
                    137:        actfp = xfopen(ACTIVE, "r+");
                    138: #ifdef LOCKF
                    139: # if   defined(F_RDLCK) && defined(F_SETLK)
                    140:        news_lock.l_type = F_RDLCK;
                    141:        if (fcntl(fileno(actfp), F_SETLK, &news_lock) < 0) {
                    142: # else /* !F_RDLCK */
                    143:        if (lockf(fileno(actfp), F_TLOCK, 0L) < 0) {
                    144: # endif /* !F_RDLCK */
                    145:                if (errno != EAGAIN && errno != EACCES)
                    146: #else  /* !LOCKF */
                    147: #ifdef BSD4_2
                    148:        if (flock(fileno(actfp), LOCK_SH|LOCK_NB) < 0) {
                    149:                if (errno != EWOULDBLOCK)
                    150: #else  /* !BSD4_2 */
                    151:        sprintf(bfr, "%s.lock", ACTIVE);
                    152:        if (LINK(ACTIVE, bfr) < 0) {
                    153:                if (errno != EEXIST)
                    154: #endif /* V7 */
                    155: #endif /* !BSD4_2 */
                    156:                        xerror("Can't lock %s: %s", ACTIVE, errmsg(errno));
                    157:                spool_news = EXPIRE_RUNNING;
                    158:        } else {
                    159: #ifdef SPOOLNEWS
                    160:                if (argc > 1 && !strcmp(*(argv+1), "-S")) {
                    161:                        argc--;
                    162:                        argv++;
                    163:                        Sflag = 1;
                    164:                } else
                    165:                        spool_news = DO_SPOOL;
                    166: 
                    167: #endif /* SPOOLNEWS */
                    168:        }
                    169:        if (spool_news != EXPIRE_RUNNING) {
                    170:                /* only unlock if we locked */
                    171: #ifdef LOCKF
                    172:                (void) lockf(fileno(actfp), F_ULOCK, 0L);
                    173: #else  /* !LOCKF */
                    174: #ifdef         BSD4_2
                    175:                (void) flock(fileno(actfp), LOCK_UN);
                    176: #else  /* !BSD4_2 */
                    177:                (void) UNLINK(bfr);
                    178: #endif         /* V7 */
                    179: #endif /* !BSD4_2 */
                    180:        } else {        /* expire is running */
                    181:                if (argc > 1 && !strcmp(*(argv+1), "-S"))
                    182:                        exit(42);       /* inform rnews -U by exit status */
                    183:        }
                    184:        if (argc > 1 && !strcmp(*(argv+1), "-U")) {
                    185:                /* can't unspool while things are locked */
                    186:                if (spool_news == EXPIRE_RUNNING)
                    187:                        xxit(0);
                    188:                dounspool();
                    189:                /* NOT REACHED */
                    190:        }
                    191: 
                    192:        if (!STRNCMP(ptr+1, "rnews", 5)) {
                    193:                mode = PROC;
                    194:                if (spool_news != DONT_SPOOL) {
                    195:                        dospool((char *)NULL, FALSE);
                    196:                        /* NOT REACHED */
                    197:                }
                    198: #ifdef NICENESS
                    199:                if (nice(0) < NICENESS)
                    200:                        (void) nice(NICENESS);
                    201: #endif /* NICENESS */
                    202:        } else {
                    203:        /* it's not rnews, so it must be inews */
                    204:                if (argc < 2)
                    205:                        goto usage;
                    206: #ifndef SPOOLINEWS
                    207:                if (spool_news == DO_SPOOL)
                    208:                        spool_news = DONT_SPOOL;
                    209: #endif /* SPOOLINEWS */
                    210:        }
                    211: 
                    212:        state = OPTION;
                    213:        header.title[0] = header.nbuf[0] = filename[0] = '\0';
                    214: 
                    215:        /* check for existence of special files */
                    216: #ifdef DBM
                    217:        chkfile(ARTFILE);
                    218: #else
                    219:        chkdir(ARTFILE);
                    220: #endif /* DBM */
                    221:        chkfile(ACTIVE);
                    222:        SigTrap = FALSE;        /* true if a signal has been caught */
                    223:        if (mode != PROC) {
                    224:                (void) signal(SIGHUP, onsig);
                    225:                (void) signal(SIGINT, onsig);
                    226:        }
                    227:        /*
                    228:         * Catch "filesize exceeded" signals on 4.2BSD systems
                    229:         * - the history files may exceed this limit.
                    230:         */
                    231: #ifdef  SIGXFSZ
                    232:        (void) signal(SIGXFSZ, SIG_IGN);
                    233: #endif /* SIGXFSZ */
                    234:        uid = getuid();
                    235:        gid = getgid();
                    236:        duid = geteuid();
                    237:        dgid = getegid();
                    238:        (void) ftime(&Now);
                    239:        if (uid == 0 && duid == 0) {
                    240:                /*
                    241:                 * Must go through with this kludge since
                    242:                 * some systems do not honor the setuid bit
                    243:                 * when root invokes a setuid program.
                    244:                 */
                    245:                if ((pw = getpwnam(NEWSUSR)) == NULL)
                    246:                        xerror("Cannot get NEWSU pw entry");
                    247: 
                    248:                duid = pw->pw_uid;
                    249:                if ((gp = getgrnam(NEWSGRP)) == NULL)
                    250:                        xerror("Cannot get NEWSG gr entry");
                    251:                dgid = gp->gr_gid;
                    252:                (void) setgid(dgid);
                    253:                (void) setuid(duid);
                    254:        }
                    255: 
                    256: #ifndef DOGETUSER
                    257:        /*
                    258:         * Force the use of 'getuser()' to prevent forgery of articles
                    259:         * by just changing $LOGNAME
                    260:         */
                    261:        if (isatty(fileno(stderr))) {
                    262:                if ((user = getenv("USER")) == NULL)
                    263:                        user = getenv("LOGNAME");
                    264:                if ((home = getenv("HOME")) == NULL)
                    265:                        home = getenv("LOGDIR");
                    266:        }
                    267: #endif /* !DOGETUSER */
                    268:        if (user == NULL || home == NULL)
                    269:                getuser();
                    270:        else {
                    271:                if (STRCMP(username, "Unknown") == 0 || username[0] == 0) {
                    272:                        username = AllocCpy(user);
                    273:                }
                    274:                userhome = AllocCpy(home);
                    275:        }
                    276:        getuser();
                    277: 
                    278:        /* loop once per arg. */
                    279: 
                    280:        ++argv;         /* skip first arg, which is prog name. */
                    281: 
                    282:        while (--argc) {
                    283:            if (state == OPTION) {
                    284:                if (**argv != '-') {
                    285:                        xerror("Bad option string \"%s\"", *argv);
                    286:                }
                    287:                while (*++*argv != '\0') {
                    288:                        for (optpt = options; optpt->optlet != '\0'; ++optpt) {
                    289:                                if (optpt->optlet == **argv)
                    290:                                        goto found;
                    291:                        }
                    292:                        /* unknown option letter */
                    293: usage:
                    294:                        fprintf(stderr, "usage: inews -t title");
                    295:                        fprintf(stderr, " [ -n newsgroups ]");
                    296:                        fprintf(stderr, " [ -e expiration date ]\n");
                    297:                        fprintf(stderr, "\t[ -f sender]\n\n");
                    298:                        xxit(1);
                    299: 
                    300:                    found:;
                    301:                        if (optpt->flag == TRUE || (mode != UNKNOWN &&
                    302:                            (mode&optpt->oldmode) == 0)) {
                    303:                                xerror("Bad %c option", **argv);
                    304:                        }
                    305:                        if (mode == UNKNOWN)
                    306:                                mode = optpt->newmode;
                    307:                        filchar = optpt->filchar;
                    308:                        optpt->flag = TRUE;
                    309:                        state = STRING;
                    310:                        ptr = optpt->buf;
                    311:                        len = BUFLEN;
                    312:                }
                    313: 
                    314:                argv++;         /* done with this option arg. */
                    315: 
                    316:            } else {
                    317: 
                    318:                /*
                    319:                 * Pick up a piece of a string and put it into
                    320:                 * the appropriate buffer.
                    321:                 */
                    322:                if (**argv == '-') {
                    323:                        state = OPTION;
                    324:                        argc++; /* uncount this arg. */
                    325:                        continue;
                    326:                }
                    327: 
                    328:                if ((tlen = strlen(*argv)) >= len)
                    329:                        xerror("Argument string too long");
                    330:                (void) strcpy(ptr, *argv++);
                    331:                ptr += tlen;
                    332:                if (*(ptr-1) != filchar)
                    333:                        *ptr++ = filchar;
                    334:                len -= tlen + 1;
                    335:                *ptr = '\0';
                    336:            }
                    337:        }
                    338: 
                    339:        /*
                    340:         * ALL of the command line has now been processed. (!)
                    341:         */
                    342: 
                    343:        if (*filename) {
                    344:                infp = freopen(filename, "r", stdin);
                    345:                if (infp == NULL)
                    346:                        xerror("freopen(%s): %s", filename, errmsg(errno));
                    347:        } else
                    348:                infp = stdin;
                    349: 
                    350:        tty = isatty(fileno(infp));
                    351: 
                    352:        if (mode == CREATENG)
                    353:                createng();
                    354: 
                    355:        if (header.ctlmsg[0] != '\0' && header.title[0] == '\0')
                    356:                (void) strcpy(header.title, header.ctlmsg);
                    357: 
                    358:        if (*header.nbuf) {
                    359:                lcase(header.nbuf);
                    360:                ptr = index(header.nbuf, '\0');
                    361:                if (ptr[-1] == NGDELIM)
                    362:                        *--ptr = '\0';
                    363:        }
                    364:        (void) nstrip(header.title);
                    365:        (void) nstrip(header.expdate);
                    366:        (void) nstrip(header.followid);
                    367:        if (mode != PROC) {
                    368:                if (hflag) {
                    369:                        header.path[0] = '\0';
                    370:                        (void) hread(&header, infp, FALSE);
                    371:                        /* there are certain fields we won't let him specify. */
                    372:                        if (header.from[0]) {
                    373:                                (void) fixfrom(&header);
                    374:                                if (Sflag && !Mflag && !header.approved[0] &
                    375:                                        !header.sender[0]) {
                    376:                                        register char *p;
                    377:                                        strcpy(bfr, header.from);
                    378:                                        p  = strpbrk(bfr, "@ !");
                    379:                                        if (p)
                    380:                                                *p = '\0';
                    381:                                        if ((pw = getpwnam(bfr)) != NULL) {
                    382:                                                uid = pw->pw_uid;
                    383:                                                gid = pw->pw_gid;
                    384:                                                username = AllocCpy(bfr);
                    385:                                        }
                    386:                                } else {
                    387:                                        (void) strcpy(forgedname, header.from);
                    388:                                        header.from[0] = '\0';
                    389:                                }
                    390:                        }
                    391:                        if (!header.approved[0])
                    392:                                Mflag = FALSE;
                    393:                        header.sender[0] = '\0';
                    394:                        if (header.subdate[0] && cgtdate(header.subdate) < 0)
                    395:                                header.subdate[0] = '\0';
                    396:                }
                    397: 
                    398:                if (header.ident[0] == '\0')
                    399:                        getident(&header);
                    400: 
                    401:                if (forgedname[0]) {
                    402:                        register char *p1;
                    403:                        if (Mflag)
                    404:                                sprintf(header.path, "%s!%s",
                    405:                                        PATHSYSNAME, username);
                    406:                        else if (!header.path[0]) {
                    407:                                (void) strcpy(header.path, forgedname);
                    408: 
                    409:                                if ((p1 = strpbrk(header.path, " (<")) != NULL)
                    410:                                        *p1 = '\0';
                    411:                        }
                    412:                        if (!Mflag && !strpbrk(forgedname, "@ (<"))
                    413:                                (void) sprintf(header.from,"%s@%s",
                    414:                                        forgedname, FROMSYSNAME);
                    415:                        else
                    416:                                (void) strncpy(header.from, forgedname, BUFLEN);
                    417: 
                    418:                        (void) sprintf(header.sender, "%s@%s",
                    419:                                username, FROMSYSNAME);
                    420:                } else {
                    421:                        gensender(&header, username);
                    422:                }
                    423: #ifdef MYORG
                    424:                if (header.organization[0] == '\0' && !Mflag &&
                    425:                        header.sender[0] == '\0') {
                    426:                        strncpy(header.organization, MYORG, BUFLEN);
                    427:                        if (STRNCMP(header.organization, "Frobozz", 7) == 0)
                    428:                                header.organization[0] = '\0';
                    429:                        if (ptr = getenv("ORGANIZATION"))
                    430:                                strncpy(header.organization, ptr, BUFLEN);
                    431:                        /*
                    432:                         * Note that the organization can also be turned off by
                    433:                         * setting it to the null string, either in MYORG or
                    434:                         * $ORGANIZATION in the environment.
                    435:                         */
                    436:                        if (header.organization[0] == '/') {
                    437:                                mfd = fopen(header.organization, "r");
                    438:                                if (mfd) {
                    439:                                        (void) fgets(header.organization, sizeof header.organization, mfd);
                    440:                                        (void) fclose(mfd);
                    441:                                } else {
                    442:                                        logerr("Couldn't open %s",
                    443:                                                header.organization);
                    444:                                        header.organization[0] = '\0';
                    445:                                }
                    446:                                ptr = index(header.organization, '\n');
                    447:                                if (ptr)
                    448:                                        *ptr = '\0';
                    449:                        }
                    450:                }
                    451: #endif /* MYORG */
                    452:        }
                    453: 
                    454:        /* Authorize newsgroups. */
                    455:        if (mode == PROC) {
                    456:                checkbatch();
                    457:                (void) signal(SIGHUP, SIG_IGN);
                    458:                (void) signal(SIGINT, SIG_IGN);
                    459:                (void) signal(SIGQUIT, SIG_IGN);
                    460:                header.ident[0] = '\0';
                    461:                if (hread(&header, infp, TRUE) == NULL)
                    462:                        xerror("%s: Inbound news is garbled", filename);
                    463:                input(bfr[0] != '\n');
                    464:        }
                    465:        /* always check history */
                    466: 
                    467:        if (history(&header)) {
                    468:                log("Duplicate article %s rejected. Path: %s",
                    469:                        header.ident, header.path);
                    470:                xxit(0);
                    471:        }
                    472: 
                    473:        /* Easy way to make control messages, since all.all.ctl is unblessed */
                    474:        if (mode != PROC && PREFIX(header.title, "cmsg ") && header.ctlmsg[0] == 0)
                    475:                (void) strcpy(header.ctlmsg, &header.title[5]);
                    476:        is_ctl = mode != CREATENG &&
                    477:                (ngmatch(header.nbuf, "all.all.ctl,") || header.ctlmsg[0]);
                    478: #ifdef DEBUG
                    479:        fprintf(stderr,"is_ctl set to %d\n", is_ctl);
                    480: #endif
                    481: 
                    482:        if (mode != CREATENG) {
                    483:                if (!*header.title)
                    484:                        error("No title, ng %s from %s", header.nbuf,
                    485:                                header.from);
                    486:                if (!*header.nbuf)
                    487:                        (void) strcpy(header.nbuf, DFLTNG);
                    488:        }
                    489: 
                    490:        if (mode <= UNPROC) {
                    491: #ifdef FASCIST
                    492:                if (uid && uid != ROOTID && fascist(username, header.nbuf))
                    493:                        xerror("User %s is not authorized to post to newsgroup %s",
                    494:                                username, header.nbuf);
                    495: #endif /* FASCIST */
                    496:                ctlcheck();
                    497:        }
                    498: 
                    499:        if (mode == CREATENG)
                    500:                createng();
                    501: 
                    502:        /* Determine input. */
                    503:        if (mode != PROC)
                    504:                input(FALSE);
                    505:        if (header.intnumlines == 0 && !is_ctl)
                    506:                error("%s rejected: no text lines", header.ident);
                    507: 
                    508:        dates(&header);
                    509: 
                    510:        /* Do the actual insertion. */
                    511:        insert();
                    512:        /* NOTREACHED */
                    513: }
                    514: 
                    515: /* check for existence of file */
                    516: static chkfile(f)
                    517: char *f;
                    518: {
                    519:        FILE    *mfd;           /* mail file file-descriptor            */
                    520:        char    cbuf[BUFLEN];   /* command buffer                       */
                    521: 
                    522:        if (rwaccess(f))
                    523:                return; /* everything is ok */
                    524:        mfd = mailhdr((struct hbuf *)NULL,
                    525:                exists(f) ? "Unwritable files!" : "Missing files!");
                    526:        if (mfd == NULL)
                    527:                return;
                    528:        putc('\n', mfd);
                    529:        fprintf(mfd, "System: %s\n\nThere was a problem with %s!!\n",
                    530:                LOCALSYSNAME, f);
                    531:        (void) sprintf(cbuf, "touch %s;chmod 666 %s", f, f);
                    532:        (void) system(cbuf);
                    533:        if (rwaccess(f))
                    534:                fprintf(mfd, "The problem has been taken care of.\n");
                    535:        else
                    536:                fprintf(mfd, "Corrective action failed - check suid bits.\n");
                    537:        (void) mclose(mfd);
                    538: }
                    539: 
                    540: #ifndef DBM
                    541: /* check for existence of directory */
                    542: static chkdir(d)
                    543: char *d;
                    544: {
                    545:        FILE    *mfd;           /* mail file file-descriptor            */
                    546:        char    dir[BUFLEN];    /* holds directory name                 */
                    547: 
                    548:        sprintf(dir, "%s.d", d);
                    549:        if (eaccess(dir, 07) == 0)
                    550:                return; /* everything is ok */
                    551:        mfd = mailhdr((struct hbuf *)NULL,
                    552:                exists(dir) ? "Unwritable directories" : "Missing directories");
                    553:        if (mfd == NULL)
                    554:                return;
                    555:        putc('\n', mfd);
                    556:        fprintf(mfd, "System: %s\n\nThere was a problem with %s!\n",
                    557:                LOCALSYSNAME, dir);
                    558:        (void) mkdir(dir, 0775);
                    559:        if (eaccess(dir, 07) == 0)
                    560:                fprintf(mfd, "The problem has been taken care of.\n");
                    561:        else
                    562:                fprintf(mfd, "Corrective action failed - check suid bits.\n");
                    563:        (void) mclose(mfd);
                    564: }
                    565: 
                    566: /*
                    567:  * This version of access checks against effective uid and effective gid
                    568:  */
                    569: eaccess(name, mode)
                    570: register char *name;
                    571: register int mode;
                    572: {      
                    573:        struct stat statb;
                    574:        int euserid = geteuid();
                    575:        int egroupid = getegid();
                    576: 
                    577:        if (stat(name, &statb) == 0) {
                    578:                if (euserid == 0) {
                    579:                        if ((statb.st_mode&S_IFMT) != S_IFREG || mode != 1)
                    580:                                return 0;
                    581:                        /* root needs execute permission for someone */
                    582:                        mode = (S_IEXEC|(S_IEXEC>>3)|(S_IEXEC>>6));
                    583:                }
                    584:                else if (euserid == statb.st_uid)
                    585:                        mode <<= 6;
                    586:                else if (egroupid == statb.st_gid)
                    587:                        mode <<= 3;
                    588: #ifdef BSD4_2
                    589:                /* in BSD4_2 you can be in several groups */
                    590:                else {
                    591:                        int groups[NGROUPS];
                    592:                        register int n;
                    593:                        n = getgroups(NGROUPS,groups);
                    594:                        while(--n >= 0) {
                    595:                                if(groups[n] == statb.st_gid) {
                    596:                                        mode <<= 3;
                    597:                                        break;
                    598:                                }
                    599:                        }
                    600:                }
                    601: #endif /* BSD4_2 */
                    602: 
                    603:                if (statb.st_mode & mode)
                    604:                        return 0;
                    605:        }
                    606:        return -1;
                    607: }
                    608: #endif /* DBM */
                    609: 
                    610: dospool(batchcmd, dolhwrite)
                    611: char *batchcmd;
                    612: int dolhwrite;
                    613: {
                    614:        register int c;
                    615:        register FILE *sp;
                    616:        register struct tm *tp;
                    617:        time_t t;
                    618:        char buf[BUFLEN], sfile[BUFLEN];
                    619:        extern struct tm *gmtime();
                    620: 
                    621:        (void) sprintf(sfile, "%s/.spXXXXXX", SPOOL);
                    622:        sp = xfopen(mktemp(sfile), "w");
                    623:        if (batchcmd != NULL) {
                    624:                if (not_here[0] != '\0')
                    625:                        fprintf(sp, "%s -x %s\n", batchcmd, not_here);
                    626:                else
                    627:                        fprintf(sp, "%s\n", batchcmd);
                    628:        } else
                    629:                if (not_here[0] != '\0')
                    630:                        fprintf(sp, "#! inews -x %s -p\n", not_here);
                    631:        if (dolhwrite)
                    632:                lhwrite(&header, sp);
                    633:        while ((c = getc(infp)) != EOF)
                    634:                putc(c, sp);
                    635:        fclose(sp);
                    636: 
                    637:        (void) time(&t);
                    638:        tp = gmtime(&t);
                    639:        /* This file name "has to" be unique  (right?) */
                    640: #ifdef USG
                    641:        (void) sprintf(buf, "%s/.rnews/%2.2d%2.2d%2.2d%2.2d%2.2d%x",
                    642: #else
                    643: #ifdef VMS
                    644:        /* Eunice doesn't like dots in directory names */
                    645:        (void) sprintf(buf, "%s/+rnews/%02d%02d%02d%02d%02d%x",
                    646: #else /* V7 */
                    647:        (void) sprintf(buf, "%s/.rnews/%02d%02d%02d%02d%02d%x",
                    648: #endif /* V7 */
                    649: #endif /* VMS */
                    650:                SPOOL,
                    651:                tp->tm_year, tp->tm_mon+1, tp->tm_mday,
                    652:                tp->tm_hour, tp->tm_min, getpid());
                    653: 
                    654: #ifdef IHCC
                    655:        log("Spooling %s into %s", header.ident, (rindex(buf,'/') + 1));
                    656: #endif /* IHCC */
                    657: 
                    658:        if (LINK(sfile, buf) < 0) {
                    659:                char dbuf[BUFLEN];
                    660: #ifdef VMS
                    661:                sprintf(dbuf, "%s/+rnews", SPOOL);
                    662: #else /* !VMS */
                    663:                sprintf(dbuf, "%s/.rnews", SPOOL);
                    664: #endif /* !VMS */
                    665:                if (mkdir(dbuf, 0777&~N_UMASK) < 0)
                    666:                        xerror("Cannot mkdir %s: %s", dbuf, errmsg(errno));
                    667:                if (LINK(sfile, buf) < 0) 
                    668:                        xerror("Cannot link(%s,%s): %s", sfile, buf,
                    669:                                errmsg(errno));
                    670:        }
                    671:        (void) UNLINK(sfile);
                    672:        xxit(0);
                    673:        /* NOTREACHED */
                    674: }
                    675: 
                    676: /*
                    677:  *     Create a newsgroup
                    678:  */
                    679: createng()
                    680: {
                    681:        register char *cp;
                    682: 
                    683:        /*
                    684:         * Only certain users are allowed to create newsgroups
                    685:         */
                    686:        if (uid != ROOTID && uid != duid && uid) {
                    687:                logerr("Please contact one of the local netnews people");
                    688:                xerror("to create group \"%s\" for you", header.ctlmsg);
                    689:        }
                    690:        if (header.distribution[0] == '\0')
                    691: #ifdef ORGDISTRIB
                    692:                strcpy(header.distribution, ORGDISTRIB);
                    693: #else /* !ORGDISTRIB */
                    694:                strcpy(header.distribution, "local");
                    695: #endif /* !ORGDISTRIB */
                    696: 
                    697:        (void) strcpy(header.nbuf, header.ctlmsg);
                    698:        if ((cp=index(header.nbuf, ' ')) != NULL)
                    699:                *cp = '\0';
                    700: 
                    701:        if (header.approved[0] == '\0')
                    702:                (void) sprintf(header.approved, "%s@%s",
                    703:                                username, FROMSYSNAME);
                    704:        (void) sprintf(bfr, "%s/inews -n %s.ctl -c newgroup %s -d %s -a \"%s\"",
                    705:                LIB, header.nbuf, header.ctlmsg, header.distribution,
                    706:                header.approved);
                    707:        if (tty) {
                    708:                printf("Please type in a paragraph describing the new newsgroup.\n");
                    709:                printf("End with control D as usual.\n");
                    710:        }
                    711:        printf("%s\n", bfr);
                    712:        (void) fflush(stdout);
                    713:        (void) system(bfr);
                    714:        exit(0);
                    715:        /*NOTREACHED*/
                    716: }
                    717: 
                    718: char firstbufname[BUFLEN];
                    719: /*
                    720:  *     Link ARTICLE into dir for ngname and update active file.
                    721:  */
                    722: long
                    723: localize(ngname)
                    724: char   *ngname;
                    725: {
                    726:        char afline[BUFLEN];
                    727:        long ngsize;
                    728:        long fpos;
                    729:        int e;
                    730:        char *cp;
                    731: 
                    732:        lock();
                    733:        (void) rewind(actfp); clearerr(actfp);
                    734: 
                    735:        for(;;) {
                    736:                fpos = ftell(actfp);
                    737:                if (fgets(afline, sizeof afline, actfp) == NULL) {
                    738:                        unlock();
                    739:                        logerr("Can't find \"%s\" in active file", ngname);
                    740:                        return FALSE;           /* No such newsgroup locally */
                    741:                }
                    742:                if (PREFIX(afline, ngname)) {
                    743:                        (void) sscanf(afline, "%s %ld", bfr, &ngsize);
                    744:                        if (STRCMP(bfr, ngname) == 0) {
                    745:                                if (ngsize < 0 || ngsize > 99998) {
                    746:                                        logerr("found bad ngsize %ld ng %s, setting to 1", ngsize, bfr);
                    747:                                        ngsize = 1;
                    748:                                }
                    749:                                break;
                    750:                        }
                    751:                }
                    752:        }
                    753:        for (;;) {
                    754:                cp = dirname(ngname);
                    755: 
                    756:                (void) sprintf(bfr, "%s/%ld", cp, ngsize+1);
                    757: #ifdef VMS
                    758:                /*
                    759:                 * The effect of this code is to store the article in the first
                    760:                 * newsgroup's directory and to put symbolic links elsewhere.
                    761:                 * If this is the first group, firstbufname is not yet filled
                    762:                 * in. It should be portable to other link-less systems.
                    763:                 * epimass!jbuck
                    764:                 */
                    765:                if (firstbufname[0]) {
                    766:                        if (vmslink(firstbufname, bfr) == 0)
                    767:                                break;
                    768:                } else if (rename(ARTICLE, bfr) == 0)
                    769:                        break;
                    770: #else /* !VMS */
                    771:                if (link(ARTICLE, bfr) == 0)
                    772:                        break;
                    773: #endif /* !VMS */
                    774:                if (!exists(cp))
                    775:                        mknewsg(cp, ngname);
                    776: #ifdef VMS
                    777:                if (firstbufname[0]) {
                    778:                        if (vmslink(firstbufname, bfr) == 0)
                    779:                                break;
                    780:                } else if (rename(ARTICLE, bfr) == 0) 
                    781:                        break;
                    782: #else /* !VMS */
                    783:                if (link(ARTICLE, bfr) == 0)
                    784:                        break;
                    785: #endif /* !VMS */
                    786:                e = errno;      /* keep log from clobbering it */
                    787:                log("Cannot install article as %s: %s", bfr, errmsg(errno));
                    788:                if (e != EEXIST) {
                    789:                        logerr("Link into %s failed (%s); check dir permissions.",
                    790:                            bfr, errmsg(e));
                    791:                        unlock();
                    792:                        return FALSE;
                    793:                }
                    794:                ngsize++;
                    795:        }
                    796: 
                    797:        /*
                    798:         * This works around a bug in the 4.1bsd stdio
                    799:         * on fseeks to non even offsets in r+w files
                    800:         */
                    801:        if (fpos&1)
                    802:                (void) rewind(actfp);
                    803: 
                    804:        (void) fseek(actfp, fpos, 0);
                    805:        /*
                    806:         * Has to be same size as old because of %05d.
                    807:         * This will overflow with 99999 articles.
                    808:         */
                    809:        fprintf(actfp, "%s %05ld", ngname, ngsize+1);
                    810: #if defined(USG) || defined(MG1)
                    811:        /*
                    812:         * U G L Y   K L U D G E
                    813:         * This utter piece of tripe is the only way I know of to get
                    814:         * around the fact that ATT BROKE standard IO in System 5.2.
                    815:         * Basically, you can't open a file for "r+" and then try and
                    816:         * write to it. This works on all "real" USGUnix systems, It will
                    817:         * probably break on some obscure look alike that doesnt use the
                    818:         * real ATT stdio.h
                    819:         * Don't blame me, blame ATT. stdio should have already done the
                    820:         * following line for us, but it doesn't
                    821:         * also broken in WCW MG-1 42nix 2.0
                    822:         */
                    823:         actfp->_flag |= _IOWRT;
                    824: #endif /* USG */
                    825:        (void) fflush(actfp);
                    826:        if (ferror(actfp))
                    827:                xerror("Active file write failed");
                    828:        unlock();
                    829:        if (firstbufname[0] == '\0')
                    830:                (void) strcpy(firstbufname, bfr);
                    831:        (void) sprintf(bfr, "%s/%ld ", ngname, ngsize+1);
                    832:        addhist(bfr);
                    833:        return ngsize+1;
                    834: }
                    835: 
                    836: /*
                    837:  *     Localize for each newsgroup and broadcast.
                    838:  */
                    839: insert()
                    840: {
                    841:        register char *ptr;
                    842:        register FILE *tfp;
                    843:        register int c;
                    844:        struct srec srec;       /* struct for sys file lookup   */
                    845:        struct tm *tm, *gmtime();
                    846:        int is_invalid = FALSE;
                    847:        int exitcode = 0;
                    848:        long now;
                    849: #ifdef DOXREFS
                    850:        register char *nextref = header.xref;
                    851: #endif /* DOXREFS */
                    852: 
                    853:        /* Clean up Newsgroups: line */
                    854:        if (!is_ctl && mode != CREATENG)
                    855:                is_invalid = ngfcheck(mode == PROC);
                    856: 
                    857:        (void) time(&now);
                    858:        tm = gmtime(&now);
                    859:        if (header.expdate[0])
                    860:                addhist(" ");
                    861: #ifdef USG
                    862:        sprintf(bfr,"%2.2d/%2.2d/%d %2.2d:%2.2d\t",
                    863: #else /* !USG */
                    864:        sprintf(bfr,"%02d/%02d/%d %02d:%02d\t",
                    865: #endif /* !USG */
                    866:                tm->tm_mon+1, tm->tm_mday, tm->tm_year,tm->tm_hour, tm->tm_min);
                    867:        addhist(bfr);
                    868:        log("%s %s ng %s subj '%s' from %s", spool_news != DONT_SPOOL
                    869:                ? "queued" : (mode==PROC ? "received" : "posted"),
                    870:                header.ident, header.nbuf, header.title, header.from);
                    871: 
                    872:        /* Write article to temp file. */
                    873:        tfp = xfopen(mktemp(ARTICLE), "w");
                    874: 
                    875:        if (is_invalid) {
                    876:                logerr("No valid newsgroups found, moved to junk");
                    877:                if (localize("junk"))
                    878:                        savehist(histline);
                    879:                exitcode = 1;
                    880:                goto writeout;
                    881:        }
                    882: 
                    883: #ifdef ZAPNOTES
                    884:        if (STRNCMP(header.title, "Re: Orphaned Response", 21) == 0) {
                    885:                logerr("Orphaned Response, moved to junk");
                    886:                if (localize("junk"))
                    887:                        savehist(histline);
                    888:                exitcode = 1;
                    889:                goto writeout;
                    890:        }
                    891: #endif /* ZAPNOTES */
                    892: 
                    893:        if (time((time_t *)0) > (cgtdate(header.subdate) + HISTEXP) ){
                    894:                logerr("Article too old, moved to junk");
                    895:                if (localize("junk"))
                    896:                        savehist(histline);
                    897:                exitcode = 1;
                    898:                goto writeout;
                    899:        }
                    900: 
                    901:        if (is_mod[0] != '\0'   /* one of the groups is moderated */
                    902:                && header.approved[0] == '\0') { /* and unapproved */
                    903:                struct hbuf mhdr;
                    904:                FILE *mfd, *mhopen();
                    905:                register char *p;
                    906:                char modadd[BUFLEN], *replyname();
                    907: #ifdef DONTFOWARD
                    908:                if(mode == PROC) {
                    909:                        logerr("Unapproved article in moderated group %s",
                    910:                                is_mod);
                    911:                        if (localize("junk"))
                    912:                                savehist(histline);
                    913:                        goto writeout;
                    914:                }
                    915: #endif /* DONTFORWARD */
                    916:                fprintf(stderr,"%s is moderated and may not be posted to",
                    917:                        is_mod);
                    918:                fprintf(stderr," directly.\nYour article is being mailed to");
                    919:                fprintf(stderr," the moderator who will post it for you.\n");
                    920:                /* Let's find a path to the backbone */
                    921:                sprintf(bfr, "%s/mailpaths", LIB);
                    922:                mfd = xfopen(bfr, "r");
                    923:                do {
                    924:                        if (fscanf(mfd, "%s %s", bfr, modadd) != 2)
                    925:                                xerror("Can't find backbone in %s/mailpaths",
                    926:                                        LIB);
                    927:                } while (STRCMP(bfr, "backbone") != 0 && !ngmatch(is_mod, bfr));
                    928:                (void) fclose(mfd);
                    929:                /* fake a header for mailhdr */
                    930:                mhdr.from[0] = '\0';
                    931:                mhdr.replyto[0] = '\0';
                    932:                p = is_mod;
                    933:                while (*++p)
                    934:                        if (*p == '.')
                    935:                                *p = '-';
                    936:                sprintf(mhdr.path, modadd, is_mod);
                    937:                mfd = mhopen(&mhdr);
                    938:                if (mfd == NULL)
                    939:                        xerror("Can't send mail to %s", mhdr.path);
                    940:                fprintf(mfd, "To: %s\n", replyname(&mhdr));
                    941:                lhwrite(&header, mfd);
                    942:                putc('\n', mfd);
                    943:                while ((c = getc(infp)) != EOF)
                    944:                        putc(c, mfd);
                    945:                mclose(mfd);
                    946:                log("Article mailed to %s", mhdr.path);
                    947:                xxit(0);
                    948:        }
                    949: 
                    950:        if (mode != PROC && spool_news != DONT_SPOOL)  {
                    951:                if (spool_news != EXPIRE_RUNNING
                    952:                        && ngmatch(header.nbuf,"to.all.ctl"))
                    953:                                spool_news = DONT_SPOOL;
                    954:                if (spool_news != DONT_SPOOL) {
                    955:                        fprintf(stderr,
                    956:                        "Your article has been spooled for later processing.\n");
                    957:                        dospool("#! inews -S -h", TRUE);
                    958:                        /* NOT REACHED */
                    959:                }
                    960:        }
                    961: 
                    962:        if (is_ctl) {
                    963:                exitcode = control(&header);
                    964:                if (localize("control") && exitcode != 0)
                    965:                        savehist(histline);
                    966:        } else {
                    967:                if (s_find(&srec, LOCALPATHSYSNAME) == FALSE) {
                    968:                        logerr("Cannot find my name '%s' in %s",
                    969:                                LOCALPATHSYSNAME, SUBFILE);
                    970:                        srec = dummy_srec;
                    971:                }
                    972: #ifdef DOXREFS
                    973:                (void) strncpy(nextref, PATHSYSNAME, BUFLEN);
                    974: #endif /* DOXREFS */
                    975:                for (ptr = nbuf; *ptr;) {
                    976:                        if (ngmatch(ptr,srec.s_nbuf) || index(ptr,'.') == NULL){
                    977: #ifdef DOXREFS
                    978:                                while (*nextref++)
                    979:                                        ;
                    980:                                (void) sprintf(--nextref, " %s:%ld", ptr, localize(ptr));
                    981: #else /* !DOXREFS */
                    982:                                (void) localize(ptr);
                    983: #endif /* !DOXREFS */
                    984:                        }
                    985:                        while (*ptr++)
                    986:                                ;
                    987:                }
                    988:                if (firstbufname[0] == '\0') {
                    989:                        logerr("Newsgroups in active, but not sys");
                    990:                        (void) localize("junk");
                    991:                }
                    992:        }
                    993: #ifdef DOXREFS
                    994:        if (index(header.nbuf, NGDELIM) == NULL)
                    995:                header.xref[0] = '\0';
                    996: #endif /* DOXREFS */
                    997: 
                    998: writeout:
                    999:        /* Part 1 of kludge to get around article truncation problem */
                   1000:        if ( (c=getc(infp)) != EOF) {
                   1001:                ungetc(c, infp);
                   1002:                if (c == ' ' || c == '\t') {
                   1003:                        header.intnumlines++;
                   1004:                        (void) sprintf(header.numlines, "%d",
                   1005:                                header.intnumlines);
                   1006:                }
                   1007:        }
                   1008:        /* End of part 1 */
                   1009:        if (header.expdate[0] != '\0' && mode != PROC) {
                   1010:                /* Make sure it's fully qualified */
                   1011:                long t = cgtdate(header.expdate);
                   1012:                strcpy(header.expdate, arpadate(&t));
                   1013:        }
                   1014: 
                   1015:        lhwrite(&header, tfp);
                   1016:        if ((c = getc(infp)) != EOF) {
                   1017:                /* Part 2 of kludge to get around article truncation problem */
                   1018:                if (c == ' ' || c == '\t' )
                   1019:                        putc('\n', tfp);
                   1020:                /* End of part 2 */
                   1021:                ungetc(c, infp);
                   1022:                while (fgets(bfr, BUFLEN, infp) != NULL)
                   1023:                        fputs(bfr, tfp);
                   1024:                if (bfr[strlen(bfr)-1] != '\n')
                   1025:                        putc('\n',tfp);
                   1026:        }
                   1027:        if (ferror(tfp))
                   1028:                xerror("Write failed for temp file");
                   1029:        (void) fclose(tfp);
                   1030:        (void) fclose(infp);
                   1031:        if(exitcode == 0) {
                   1032:                /* article has passed all the checks, so work in background */
                   1033:                if (mode != PROC) {
                   1034:                        int pid;
                   1035:                        if ((pid=fork()) < 0)
                   1036:                                xerror("Can't fork");
                   1037:                        else if (pid > 0)
                   1038:                                _exit(0);
                   1039:                }
                   1040: #ifdef SIGTTOU
                   1041:                (void) signal(SIGTTOU, SIG_IGN);
                   1042: #endif /* SIGTTOU */
                   1043:                savehist(histline);
                   1044:                if (header.supersedes[0] != '\0') {
                   1045:                        char *av[2];
                   1046: 
                   1047:                        av[0] = "cancel";
                   1048:                        av[1] = header.supersedes;
                   1049:                        c_cancel(2, av);
                   1050:                }
                   1051:                broadcast(mode==PROC);
                   1052:        }
                   1053:        xxit((mode == PROC && filename[0] == '\0') ? 0 :
                   1054:                (exitcode < 0 ? 0 : exitcode));
                   1055: }
                   1056: 
                   1057: input(usegunk)
                   1058: {
                   1059:        register char *cp;
                   1060:        register int c;
                   1061:        register int empty = TRUE;
                   1062:        FILE *tmpfp;
                   1063:        int consec_newlines = 0;
                   1064:        int linecount = 0;
                   1065:        int linserted = 0;
                   1066: 
                   1067:        tmpfp = xfopen(mktemp(INFILE), "w");
                   1068:        for ( ; ; ) {
                   1069:                if (SigTrap)
                   1070:                        break;
                   1071:                if (usegunk)
                   1072:                        usegunk = FALSE;
                   1073:                else if (fgets(bfr, BUFLEN, infp) != bfr)
                   1074:                        break;
                   1075:                if (mode == PROC) {     /* zap trailing empty lines */
                   1076: #ifdef ZAPNOTES
                   1077:                        if (empty && bfr[0] == '#' && bfr[2] == ':'
                   1078:                                && header.nf_id[0] == '\0'
                   1079:                                && header.nf_from[0] == '\0' ) {
                   1080:                                (void) strcpy(header.nf_id, bfr);
                   1081:                                (void) nstrip(header.nf_id);
                   1082:                                (void) fgets(bfr, BUFLEN, infp);
                   1083:                                (void) strcpy(header.nf_from, bfr);
                   1084:                                (void) nstrip(header.nf_from);
                   1085:                                (void) fgets(bfr, BUFLEN, infp);
                   1086: 
                   1087:                                if (header.numlines[0]) {
                   1088:                                        header.intnumlines -= 2;
                   1089:                                        (void) sprintf(header.numlines, "%d", header.intnumlines);
                   1090:                                }
                   1091: 
                   1092:                                /* Strip trailing " - (nf)" */
                   1093:                                if ((cp = rindex(header.title, '-')) != NULL
                   1094:                                    && !strcmp(--cp, " - (nf)"))
                   1095:                                        *cp = '\0';
                   1096:                                log("Stripped notes header on %s", header.ident);
                   1097:                                continue;
                   1098:                        }
                   1099: #endif /* ZAPNOTES */
                   1100:                        if (bfr[0] == '\n' ||
                   1101:                                /* Bandage for older versions of inews */
                   1102:                                bfr[1] == '\n' && !isascii(bfr[0])) {
                   1103:                                consec_newlines++;      /* count it, in case */
                   1104:                                continue;               /* but don't write it*/
                   1105:                        }
                   1106:                        /* foo! a non-empty line. write out all saved lines. */
                   1107:                        while (consec_newlines > 0) {
                   1108:                                putc('\n', tmpfp);
                   1109:                                consec_newlines--;
                   1110:                                linecount++;
                   1111:                        }
                   1112:                }
                   1113:                if (mode != PROC && tty && STRCMP(bfr, ".\n") == 0)
                   1114:                        break;
                   1115:                for (cp = bfr; c = toascii(*cp); cp++) {
                   1116:                        if (isprint(c) || isspace(c) || c == '\b')
                   1117:                                putc(c, tmpfp);
                   1118:                        if (c == '\n')
                   1119:                                linecount++;
                   1120:                }
                   1121:                if (bfr[0] == '>')
                   1122:                        linserted++;
                   1123:                if (bfr[0] == '<') /* kludge to allow diff's to be posted */
                   1124:                        linserted--;
                   1125:                empty = FALSE;
                   1126:        }
                   1127:        if (*filename)
                   1128:                (void) fclose(infp);
                   1129:        if (mode != PROC &&
                   1130:                linecount > LNCNT && linserted > (linecount-linserted))
                   1131:                error("Article rejected: %s included more text than new text",
                   1132:                        username);
                   1133: 
                   1134:        if (mode != PROC && !is_ctl && header.sender[0] == '\0' && !Sflag) {
                   1135:                int siglines = 0;
                   1136:                char sbuf[BUFLEN];
                   1137:                (void) sprintf(bfr, "%s/%s", userhome, ".signature");
                   1138:                if (access(bfr, 4) == 0) {
                   1139:                        if ((infp = fopen(bfr, "r")) == NULL) {
                   1140:                                (void) fprintf(stderr,
                   1141:     "inews: \"%s\" left off (must be readable by \"inews\" owner)\n", bfr);
                   1142:                                goto finish;
                   1143:                        }
                   1144: 
                   1145:                        while (fgets(sbuf, sizeof sbuf, infp) != NULL)
                   1146:                                if (++siglines > 4)
                   1147:                                        break;
                   1148:                        if (siglines > 4)
                   1149:                                fprintf(stderr,".signature not included (> 4 lines)\n");
                   1150:                        else {
                   1151:                                rewind(infp);
                   1152:                                fprintf(tmpfp, "-- \n");        /* To separate */
                   1153:                                linecount++;
                   1154:                                while ((c = getc(infp)) != EOF) {
                   1155:                                        putc(c, tmpfp);
                   1156:                                        if (c == '\n')
                   1157:                                                linecount++;
                   1158:                                }
                   1159:                        }
                   1160:                        (void) fclose(infp);
                   1161:                }
                   1162:        }
                   1163: 
                   1164: finish:
                   1165:        if (ferror(tmpfp))
                   1166:                xerror("write failed to temp file");
                   1167:        (void) fclose(tmpfp);
                   1168:        if (SigTrap) {
                   1169:                if (tty)
                   1170:                        fprintf(stderr, "Interrupt\n");
                   1171:                if (tty && !empty)
                   1172:                        fwait(fsubr(newssave, (char *) NULL, (char *) NULL));
                   1173:                if (!tty)
                   1174:                        log("Blown away by an interrupt %d", SigTrap);
                   1175:                xxit(1);
                   1176:        }
                   1177:        if (tty)
                   1178:                fprintf(stderr, "EOT\n");
                   1179:        fflush(stdout);
                   1180:        infp = fopen(INFILE, "r");
                   1181:        if (header.numlines[0]) {
                   1182:                /*
                   1183:                 * Check line count if there's already one attached to
                   1184:                 * the article.  Could make this a fatal error -
                   1185:                 * throwing it away if it got chopped, in hopes that
                   1186:                 * another copy will come in later with a correct
                   1187:                 * line count.  But that seems a bit much for now.
                   1188:                 */
                   1189:                if (linecount != header.intnumlines) {
                   1190:                        if (linecount == 0)
                   1191:                                error("%s rejected. linecount expected %d, got 0", header.ident, header.intnumlines);
                   1192:                        if (linecount > header.intnumlines ||
                   1193:                            linecount+consec_newlines < header.intnumlines)
                   1194:                                log("linecount expected %d, got %d", header.intnumlines, linecount+consec_newlines);
                   1195:                }
                   1196:                /* adjust count for blank lines we stripped off */
                   1197:                if (consec_newlines) {
                   1198:                        header.intnumlines -= consec_newlines;
                   1199:                        if (header.intnumlines < 0 )
                   1200:                                header.intnumlines = 0; /* paranoia */
                   1201:                        (void) sprintf(header.numlines, "%d", header.intnumlines);
                   1202:                }
                   1203: 
                   1204:        } else {
                   1205:                /* Attach a line count to the article. */
                   1206:                header.intnumlines = linecount;
                   1207:                (void) sprintf(header.numlines, "%d", linecount);
                   1208:        }
                   1209: }
                   1210: 
                   1211: /*
                   1212:  * Make the directory for a new newsgroup.  ngname should be the
                   1213:  * full pathname of the directory.  Do the other stuff too.
                   1214:  * The various games with setuid and chown are to try to make sure
                   1215:  * the directory is owned by NEWSUSR and NEWSGRP, which is tough to
                   1216:  * do if you aren't root.  This will work on a UCB system (which allows
                   1217:  * setuid(geteuid()) or a USG system (which allows you to give away files
                   1218:  * you own with chown), otherwise you have to change your kernel to allow
                   1219:  * one of these things or run with your dirs 777 so that it doesn't matter
                   1220:  * who owns them.
                   1221:  */
                   1222: mknewsg(fulldir, ngname)
                   1223: char   *fulldir;
                   1224: char   *ngname;
                   1225: {
                   1226: #ifdef USG
                   1227:        register char *p;
                   1228:        char parent[200];
                   1229:        char sysbuf[200];
                   1230:        struct stat sbuf;
                   1231: #endif /* USG */
                   1232: 
                   1233:        if (ngname == NULL || !isalpha(ngname[0]))
                   1234:                xerror("Tried to make illegal newsgroup %s", ngname);
                   1235: 
                   1236: #ifdef USG
                   1237:        /*
                   1238:         * If the parent is 755 the setuid(getuid)
                   1239:         * will fail, and since mkdir is suid, and our real uid is random,
                   1240:         * the mkdir will fail.  So we have to temporarily chmod it to 777.
                   1241:         */
                   1242:        (void) strcpy(parent, fulldir);
                   1243:        while (p = rindex(parent, '/')) {
                   1244:                *p = '\0';
                   1245:                if (stat(parent, &sbuf) == 0) {
                   1246:                        (void) chmod(parent, 0777);
                   1247:                        break;
                   1248:                }
                   1249:        }
                   1250: #endif /* USG */
                   1251: 
                   1252:        /* Create the directory */
                   1253:        mkparents(fulldir);
                   1254:        if (mkdir(fulldir, 0777) < 0)
                   1255:                xerror("Cannot mkdir %s: %s", fulldir, errmsg(errno));
                   1256: 
                   1257: #ifdef USG
                   1258:        /*
                   1259:         * Give away the directories we just created which were assigned
                   1260:         * our real uid.
                   1261:         */
                   1262:        (void) setuid(uid);
                   1263:        (void) chown(fulldir, duid, dgid);
                   1264: 
                   1265:        (void) strcpy(sysbuf, fulldir);
                   1266:        while (p = rindex(sysbuf, '/')) {
                   1267:                *p = '\0';
                   1268:                /* stop when get to last known good parent */
                   1269:                if (strcmp(sysbuf, parent) == 0)
                   1270:                        break;
                   1271:                (void) chown(sysbuf, duid, dgid);
                   1272:        }
                   1273:        (void) setuid(duid);
                   1274:        (void) chmod(parent, (int)sbuf.st_mode);        /* put it back */
                   1275: #endif /* USG */
                   1276: 
                   1277:        log("make newsgroup %s in dir %s", ngname, fulldir);
                   1278: }
                   1279: 
                   1280: /*
                   1281:  * If any parent directories of this dir don't exist, create them.
                   1282:  */
                   1283: mkparents(dname)
                   1284: char *dname;
                   1285: {
                   1286:        char buf[200];
                   1287:        register char *p;
                   1288: 
                   1289:        (void) strcpy(buf, dname);
                   1290:        p = rindex(buf, '/');
                   1291:        if (p)
                   1292:                *p = '\0';
                   1293:        if (exists(buf))
                   1294:                return;
                   1295:        mkparents(buf);
                   1296:        if (mkdir(buf, 0777) < 0)
                   1297:                xerror("Can not mkdir %s: %s", buf, errmsg(errno));
                   1298: }
                   1299: 
                   1300: dounspool()
                   1301: {
                   1302:        register DIR    *dirp;
                   1303:        register struct direct *dir;
                   1304:        register int foundsome;
                   1305:        int pid, status, ret;
                   1306:        char spbuf[BUFLEN];
                   1307: #ifdef LOCKF
                   1308:        FILE* LockFd;
                   1309: #endif /* LOCKF */
                   1310: #ifdef VMS
                   1311:        sprintf(spbuf, "%s/+rnews", SPOOL);
                   1312: #else /* !VMS */
                   1313:        sprintf(spbuf, "%s/.rnews", SPOOL);
                   1314: #endif /* !VMS */
                   1315: 
                   1316:        if (chdir(spbuf) < 0)
                   1317:                xerror("chdir(%s):%s", spbuf, errmsg(errno));
                   1318: 
                   1319:        dirp = opendir(".");
                   1320:        if (dirp == NULL)       /* Boy are things screwed up */
                   1321:                xerror("opendir can't open .:%s", errmsg(errno));
                   1322: #ifdef LOCKF
                   1323:        LockFd = xfopen(SEQFILE, "r+w");
                   1324:        if (lockf(fileno(LockFd), F_TLOCK, 0L) < 0) {
                   1325:                if (errno != EAGAIN && errno != EACCES)
                   1326: #else  /* !LOCKF */
                   1327: #ifdef BSD4_2
                   1328:        if (flock(dirp->dd_fd, LOCK_EX|LOCK_NB) < 0) {
                   1329:                if (errno != EWOULDBLOCK)
                   1330: #else  /* V7 */
                   1331:        strcat(spbuf, ".lock");
                   1332:        sprintf(bfr, "%s.tmp", spbuf);
                   1333:        (void) close(creat(bfr, 0666));
                   1334:        ret = LINK(bfr, spbuf);
                   1335:        status = errno;
                   1336:        (void) UNLINK(bfr);
                   1337:        errno = status;
                   1338:        if (ret < 0) {
                   1339:                if (errno != EEXIST)
                   1340: #endif /* V7 */
                   1341: #endif /* !LOCKF */
                   1342:                        xerror("Can't lock %s: %s", spbuf, errmsg(errno));
                   1343:                xxit(3); /* another rnews -U is running */
                   1344:        }
                   1345: 
                   1346:        do {
                   1347:                foundsome = 0;
                   1348: 
                   1349:                while ((dir=readdir(dirp)) != NULL) {
                   1350:                        if (dir->d_name[0] == '.')
                   1351:                                continue;
                   1352: 
                   1353: #ifdef IHCC
                   1354:                        log("Unspooling from %s", dir->d_name);
                   1355: #endif /* IHCC */
                   1356: 
                   1357:                        if ((pid=vfork()) == -1)
                   1358:                                xerror("Can't fork: %s", errmsg(errno));
                   1359:                        if (pid == 0) {
                   1360: #ifdef LOGDIR
                   1361:                                char bufr[BUFSIZ];
                   1362:                                sprintf(bufr, "%s/%s", logdir(HOME), RNEWS);
                   1363:                                execl(bufr, "rnews", "-S", "-p", dir->d_name,
                   1364:                                        (char *) NULL);
                   1365: #else /* !LOGDIR */
                   1366:                                execl(RNEWS, "rnews", "-S", "-p", dir->d_name,
                   1367:                                        (char *) NULL);
                   1368: #endif /* !LOGDIR */
                   1369:                                _exit(1);
                   1370:                        }
                   1371:                        
                   1372:                        while ((ret=wait(&status)) != pid && ret != -1)
                   1373:                                /* continue */;
                   1374: 
                   1375:                        if (((status>>8)&0177) == 42) {
                   1376:                                /* expire has started up, shutdown rnews -U */
                   1377:                                break;
                   1378:                        }
                   1379: 
                   1380:                        if (status != 0) {
                   1381:                                sprintf(bfr, "../%s", dir->d_name);
                   1382:                                (void) LINK(dir->d_name, bfr);
                   1383:                                logerr("rnews failed, status %ld. Batch saved in %s/%s",
                   1384:                                        (long)status, SPOOL, dir->d_name);
                   1385:                        }
                   1386:                        (void) unlink(dir->d_name);
                   1387:                        foundsome++;
                   1388:                }
                   1389:                rewinddir(dirp);
                   1390:        } while (foundsome); /* keep rereading the directory until it's empty */
                   1391: #ifndef LOCKF
                   1392: #ifndef BSD4_2
                   1393:        (void) UNLINK(spbuf);
                   1394: #endif
                   1395: #endif
                   1396: 
                   1397:        xxit(0);
                   1398: }

unix.superglobalmegacorp.com

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