|
|
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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.