|
|
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.61 3/19/86"; ! 21: #endif /* SCCSID */ ! 22: ! 23: #include "iparams.h" ! 24: #include <errno.h> ! 25: ! 26: /* local defines for inews */ ! 27: ! 28: #define OPTION 0 /* pick up an option string */ ! 29: #define STRING 1 /* pick up a string of arguments */ ! 30: ! 31: #define UNKNOWN 0001 /* possible modes for news program */ ! 32: #define UNPROC 0002 /* Unprocessed input */ ! 33: #define PROC 0004 /* Processed input */ ! 34: #define CANCEL 0010 /* Cancel an article */ ! 35: #define CREATENG 0020 /* Create a new newsgroup */ ! 36: ! 37: char forgedname[NAMELEN]; /* A user specified -f option. */ ! 38: extern char histline[]; ! 39: /* Fake sys line in case they forget their own system */ ! 40: struct srec dummy_srec = { "MEMEME", "", "all", "", "" }; ! 41: ! 42: char *Progname = "inews"; /* used by xerror to identify failing program */ ! 43: ! 44: struct { /* options table. */ ! 45: char optlet; /* option character. */ ! 46: char filchar; /* if to pickup string, fill character. */ ! 47: int flag; /* TRUE if have seen this opt. */ ! 48: int oldmode; /* OR of legal input modes. */ ! 49: int newmode; /* output mode. */ ! 50: char *buf; /* string buffer */ ! 51: } *optpt, options[] = { /* ! 52: optlet filchar flag oldmode newmode buf */ ! 53: 't', ' ', FALSE, UNPROC, UNKNOWN, header.title, ! 54: 'n', NGDELIM, FALSE, UNPROC, UNKNOWN, header.nbuf, ! 55: 'd', '\0', FALSE, UNPROC, UNKNOWN, header.distribution, ! 56: 'e', ' ', FALSE, UNPROC, UNKNOWN, header.expdate, ! 57: 'p', '\0', FALSE, UNKNOWN,PROC, filename, ! 58: 'f', '\0', FALSE, UNPROC, UNKNOWN, forgedname, ! 59: 'F', ' ', FALSE, UNPROC, UNKNOWN, header.followid, ! 60: 'c', '\0', FALSE, UNKNOWN,CANCEL, filename, ! 61: 'C', '\0', FALSE, UNKNOWN,CREATENG, header.nbuf, ! 62: #define hflag options[9].flag ! 63: 'h', '\0', FALSE, UNPROC, UNKNOWN, filename, ! 64: #define oflag options[10].flag ! 65: 'o', '\0', FALSE, UNPROC, UNKNOWN, header.organization, ! 66: #define Mflag options[11].flag ! 67: 'M', '\0', FALSE, UNPROC, UNKNOWN, filename, ! 68: 'a', '\0', FALSE, UNPROC, UNKNOWN, header.approved, ! 69: '\0', '\0', 0, 0, 0, (char *)NULL ! 70: }; ! 71: ! 72: FILE *mailhdr(); ! 73: char *genversion(); ! 74: extern int errno; ! 75: ! 76: /* ! 77: * Authors: ! 78: * Matt Glickman [email protected] ! 79: * Mark Horton [email protected] ! 80: * Stephen Daniels [email protected] ! 81: * Tom Truscott [email protected] ! 82: * IHCC version adapted by: ! 83: * Larry Marek [email protected] ! 84: */ ! 85: main(argc, argv) ! 86: int argc; ! 87: register char **argv; ! 88: { ! 89: int state; /* which type of argument to pick up */ ! 90: int tlen, len; /* temps for string processing routine */ ! 91: register char *ptr; /* pointer to rest of buffer */ ! 92: int filchar; /* fill character (state = STRING) */ ! 93: char *user = NULL, *home = NULL; /* environment temps */ ! 94: struct passwd *pw; /* struct for pw lookup */ ! 95: struct group *gp; /* struct for group lookup */ ! 96: register int i; ! 97: FILE *mfd; /* mail file file-descriptor */ ! 98: char cbuf[BUFLEN]; /* command buffer */ ! 99: ! 100: /* uuxqt doesn't close all it's files */ ! 101: for (i = 3; !close(i); i++) ! 102: ; ! 103: /* set up defaults and initialize. */ ! 104: mode = UNKNOWN; ! 105: pathinit(); ! 106: ptr = rindex(*argv, '/'); ! 107: if (!ptr) ! 108: ptr = *argv - 1; ! 109: if (!strncmp(ptr+1, "rnews", 5)) { ! 110: mode = PROC; ! 111: #ifdef NICENESS ! 112: nice(NICENESS); ! 113: #endif /* NICENESS */ ! 114: } else if (argc < 2) ! 115: goto usage; ! 116: ! 117: state = OPTION; ! 118: header.title[0] = header.nbuf[0] = filename[0] = '\0'; ! 119: ! 120: /* check for existence of special files */ ! 121: if (!rwaccess(ARTFILE)) { ! 122: mfd = mailhdr((struct hbuf *)NULL, exists(ARTFILE) ? "Unwritable files!" : "Missing files!"); ! 123: if (mfd != NULL) { ! 124: #ifdef HIDDENNET ! 125: fprintf(mfd,"System: %s.%s\n\nThere was a problem with %s!!\n", LOCALSYSNAME, FULLSYSNAME, ARTFILE); ! 126: #else /* !HIDDENNET */ ! 127: fprintf(mfd,"System: %s\n\nThere was a problem with %s!!\n", FULLSYSNAME, ARTFILE); ! 128: #endif /* !HIDDENNET */ ! 129: (void) sprintf(cbuf, "touch %s;chmod 666 %s", ARTFILE, ARTFILE); ! 130: (void) system(cbuf); ! 131: if (rwaccess(ARTFILE)) ! 132: fprintf(mfd, "The problem has been taken care of.\n"); ! 133: else ! 134: fprintf(mfd, "Corrective action failed - check suid bits.\n"); ! 135: (void) mclose(mfd); ! 136: } ! 137: } ! 138: if (!rwaccess(ACTIVE)) { ! 139: mfd = mailhdr((struct hbuf *)NULL, exists(ACTIVE) ? "Unwritable files!" : "Missing files!"); ! 140: if (mfd != NULL) { ! 141: #ifdef HIDDENNET ! 142: fprintf(mfd,"System: %s.%s\n\nThere was a problem with %s!!\n", LOCALSYSNAME, FULLSYSNAME, ARTFILE); ! 143: #else /* !HIDDENNET */ ! 144: fprintf(mfd, "System: %s\n\nThere was a problem with %s!!\n", FULLSYSNAME, ACTIVE); ! 145: #endif /* !HIDDENNET */ ! 146: (void) sprintf(cbuf, "touch %s;chmod 666 %s", ACTIVE, ACTIVE); ! 147: (void) system(cbuf); ! 148: if (rwaccess(ACTIVE)) ! 149: fprintf(mfd, "The problem has been taken care of.\n"); ! 150: else ! 151: fprintf(mfd, "Corrective action failed - check suid bits.\n"); ! 152: (void) mclose(mfd); ! 153: } ! 154: } ! 155: SigTrap = FALSE; /* true if a signal has been caught */ ! 156: if (mode != PROC) { ! 157: (void) signal(SIGHUP, onsig); ! 158: (void) signal(SIGINT, onsig); ! 159: } ! 160: savmask = umask(N_UMASK); /* set up mask */ ! 161: uid = getuid(); ! 162: gid = getgid(); ! 163: duid = geteuid(); ! 164: dgid = getegid(); ! 165: if (uid == 0 && duid == 0) { ! 166: /* ! 167: * Must go through with this kludge since ! 168: * some systems do not honor the setuid bit ! 169: * when root invokes a setuid program. ! 170: */ ! 171: if ((pw = getpwnam(NEWSUSR)) == NULL) ! 172: xerror("Cannot get NEWSU pw entry"); ! 173: ! 174: duid = pw->pw_uid; ! 175: if ((gp = getgrnam(NEWSGRP)) == NULL) ! 176: xerror("Cannot get NEWSG gr entry"); ! 177: dgid = gp->gr_gid; ! 178: (void) setgid(dgid); ! 179: (void) setuid(duid); ! 180: } ! 181: ! 182: #ifndef IHCC ! 183: /* ! 184: * We force the use of 'getuser()' to prevent forgery of articles ! 185: * by just changing $LOGNAME ! 186: */ ! 187: if (isatty(fileno(stderr))) { ! 188: if ((user = getenv("USER")) == NULL) ! 189: user = getenv("LOGNAME"); ! 190: if ((home = getenv("HOME")) == NULL) ! 191: home = getenv("LOGDIR"); ! 192: } ! 193: #endif ! 194: if (user == NULL || home == NULL) ! 195: getuser(); ! 196: else { ! 197: if (username == NULL || username[0] == 0) { ! 198: username = AllocCpy(user); ! 199: } ! 200: userhome = AllocCpy(home); ! 201: } ! 202: getuser(); ! 203: ! 204: /* loop once per arg. */ ! 205: ! 206: ++argv; /* skip first arg, which is prog name. */ ! 207: ! 208: while (--argc) { ! 209: if (state == OPTION) { ! 210: if (**argv != '-') { ! 211: xerror("Bad option string \"%s\"", *argv); ! 212: } ! 213: while (*++*argv != '\0') { ! 214: for (optpt = options; optpt->optlet != '\0'; ++optpt) { ! 215: if (optpt->optlet == **argv) ! 216: goto found; ! 217: } ! 218: /* unknown option letter */ ! 219: usage: ! 220: fprintf(stderr, "usage: inews -t title"); ! 221: fprintf(stderr, " [ -n newsgroups ]"); ! 222: fprintf(stderr, " [ -e expiration date ]\n"); ! 223: fprintf(stderr, "\t[ -f sender]\n\n"); ! 224: xxit(1); ! 225: ! 226: found:; ! 227: if (optpt->flag == TRUE || (mode != UNKNOWN && ! 228: (mode&optpt->oldmode) == 0)) { ! 229: xerror("Bad %c option", **argv); ! 230: } ! 231: if (mode == UNKNOWN) ! 232: mode = optpt->newmode; ! 233: filchar = optpt->filchar; ! 234: optpt->flag = TRUE; ! 235: state = STRING; ! 236: ptr = optpt->buf; ! 237: len = BUFLEN; ! 238: } ! 239: ! 240: argv++; /* done with this option arg. */ ! 241: ! 242: } else { ! 243: ! 244: /* ! 245: * Pick up a piece of a string and put it into ! 246: * the appropriate buffer. ! 247: */ ! 248: if (**argv == '-') { ! 249: state = OPTION; ! 250: argc++; /* uncount this arg. */ ! 251: continue; ! 252: } ! 253: ! 254: if ((tlen = strlen(*argv)) >= len) ! 255: xerror("Argument string too long"); ! 256: (void) strcpy(ptr, *argv++); ! 257: ptr += tlen; ! 258: if (*(ptr-1) != filchar) ! 259: *ptr++ = filchar; ! 260: len -= tlen + 1; ! 261: *ptr = '\0'; ! 262: } ! 263: } ! 264: ! 265: /* ! 266: * ALL of the command line has now been processed. (!) ! 267: */ ! 268: ! 269: tty = isatty(fileno(stdin)); ! 270: ! 271: /* This code is really intended to be replaced by the control message. */ ! 272: if (mode == CANCEL) { ! 273: char *p; FILE *f; ! 274: f = xfopen(filename, "r"); ! 275: (void) hread(&header, f, TRUE); ! 276: p = index(header.path, ' '); ! 277: if (p != NULL) ! 278: *p = 0; ! 279: p = header.path; ! 280: if (strncmp(username, p, strlen(username)) ! 281: && uid != ROOTID && uid != geteuid() && uid) ! 282: xerror("Not contributor"); ! 283: cancel(); ! 284: xxit(0); ! 285: } ! 286: ! 287: if (*header.nbuf) { ! 288: lcase(header.nbuf); ! 289: ptr = index(header.nbuf, '\0'); ! 290: if (ptr[-1] == NGDELIM) ! 291: *--ptr = '\0'; ! 292: } ! 293: (void) nstrip(header.title); ! 294: (void) nstrip(header.expdate); ! 295: (void) nstrip(header.followid); ! 296: if (mode != PROC) { ! 297: getident(&header); ! 298: if (hflag) { ! 299: header.path[0] = '\0'; ! 300: (void) hread(&header, stdin, FALSE); ! 301: /* there are certain fields we won't let him specify. */ ! 302: if (header.from[0]) ! 303: (void) strcpy(forgedname, header.from); ! 304: if (!header.approved[0]) ! 305: Mflag = FALSE; ! 306: header.from[0] = '\0'; ! 307: header.subdate[0] = '\0'; ! 308: header.sender[0] = '\0'; ! 309: } ! 310: #ifdef MYORG ! 311: if (header.organization[0] == '\0' && !Mflag) { ! 312: strncpy(header.organization, MYORG, BUFLEN); ! 313: if (strncmp(header.organization, "Frobozz", 7) == 0) ! 314: header.organization[0] = '\0'; ! 315: if (ptr = getenv("ORGANIZATION")) ! 316: strncpy(header.organization, ptr, BUFLEN); ! 317: /* ! 318: * Note that the organization can also be turned off by ! 319: * setting it to the null string, either in MYORG or ! 320: * $ORGANIZATION in the environment. ! 321: */ ! 322: if (header.organization[0] == '/') { ! 323: mfd = fopen(header.organization, "r"); ! 324: if (mfd) { ! 325: (void) fgets(header.organization, sizeof header.organization, mfd); ! 326: (void) fclose(mfd); ! 327: } else { ! 328: header.organization[0] = '\0'; ! 329: logerr("Couldn't open %s", ! 330: header.organization); ! 331: } ! 332: ptr = index(header.organization, '\n'); ! 333: if (ptr) ! 334: *ptr = '\0'; ! 335: } ! 336: } ! 337: #endif /* MYORG */ ! 338: if (forgedname[0]) { ! 339: register char *p1; ! 340: if (Mflag) ! 341: sprintf(header.path, "%s!%s", ! 342: FULLSYSNAME, username); ! 343: else if (!header.path[0]) { ! 344: (void) strcpy(header.path, forgedname); ! 345: ! 346: if ((p1 = strpbrk(header.path, "@ (<")) != NULL) ! 347: *p1 = '\0'; ! 348: } ! 349: if (!Mflag && !strpbrk(forgedname, "@ (<")) ! 350: (void) sprintf(header.from,"%s@%s%s", ! 351: forgedname, FULLSYSNAME, MYDOMAIN); ! 352: else ! 353: (void) strncpy(header.from, forgedname, BUFLEN); ! 354: ! 355: (void) sprintf(header.sender, "%s@%s%s", ! 356: username, FULLSYSNAME, MYDOMAIN); ! 357: } else { ! 358: gensender(&header, username); ! 359: } ! 360: } ! 361: ! 362: /* Authorize newsgroups. */ ! 363: if (mode == PROC) { ! 364: #ifdef BATCH ! 365: checkbatch(); ! 366: #endif /* BATCH */ ! 367: (void) signal(SIGHUP, SIG_IGN); ! 368: (void) signal(SIGINT, SIG_IGN); ! 369: (void) signal(SIGQUIT, SIG_IGN); ! 370: header.ident[0] = '\0'; ! 371: if (hread(&header, stdin, TRUE) == NULL) ! 372: xerror("Inbound news is garbled"); ! 373: input(); ! 374: if (history(&header)) { ! 375: log("Duplicate article %s rejected. Path: %s", ! 376: header.ident, header.path); ! 377: xxit(0); ! 378: } ! 379: } ! 380: ! 381: /* Easy way to make control messages, since all.all.ctl is unblessed */ ! 382: if (mode != PROC && prefix(header.title, "cmsg ") && header.ctlmsg[0] == 0) ! 383: (void) strcpy(header.ctlmsg, &header.title[5]); ! 384: is_ctl = mode != CREATENG && ! 385: (ngmatch(header.nbuf, "all.all.ctl,") || header.ctlmsg[0]); ! 386: #ifdef DEBUG ! 387: fprintf(stderr,"is_ctl set to %d\n", is_ctl); ! 388: #endif ! 389: ! 390: /* Must end in comma (NGDELIM) */ ! 391: #define MODGROUPS "mod.all,all.mod,all.announce," ! 392: if (ngmatch(header.nbuf, MODGROUPS) && !header.approved[0]) { ! 393: mfd = mailhdr(&header, "Moderated newsgroup"); ! 394: if (mfd) { ! 395: fprintf(mfd, "This newsgroup is moderated, and cannot be posted to directly.\n"); ! 396: fprintf(mfd, "Please mail your article to the moderator for posting.\n"); ! 397: hwrite(&header, mfd); ! 398: if (infp) ! 399: while ((i = getc(infp)) != EOF) ! 400: putc(i, mfd); ! 401: (void) mclose(mfd); ! 402: } ! 403: xerror("Unapproved moderated newsgroup."); ! 404: } ! 405: ! 406: if (mode != CREATENG) { ! 407: if (!*header.title) ! 408: xerror("No title, ng %s from %s", header.nbuf, ! 409: header.from); ! 410: if (!*header.nbuf) ! 411: (void) strcpy(header.nbuf, DFLTNG); ! 412: } ! 413: ! 414: if (mode <= UNPROC) { ! 415: #ifdef FASCIST ! 416: if (uid && uid != ROOTID && fascist(user, header.nbuf)) ! 417: xerror("User %s is not authorized to post to newsgroup %s", user, header.nbuf); ! 418: #endif /* FASCIST */ ! 419: ctlcheck(); ! 420: } ! 421: ! 422: if (mode == CREATENG) ! 423: createng(); ! 424: /* Determine input. */ ! 425: if (mode != PROC) ! 426: input(); ! 427: ! 428: /* Do the actual insertion. */ ! 429: insert(); ! 430: } ! 431: ! 432: /* ! 433: * Create a newsgroup ! 434: */ ! 435: createng() ! 436: { ! 437: ! 438: /* ! 439: * Only certain users are allowed to create newsgroups ! 440: */ ! 441: if (uid != ROOTID && uid != geteuid() && uid) { ! 442: fprintf(stderr, "Please contact one of the local netnews people\n\tto create this group for you"); ! 443: xxit(1); ! 444: } ! 445: ! 446: (void) sprintf(bfr, "%s/inews -n %s.ctl -t cmsg newgroup %s -d local", ! 447: LIB, header.nbuf, header.nbuf); ! 448: printf("Please type in a paragraph describing the new newsgroup.\n"); ! 449: printf("End with control D as usual.\n"); ! 450: printf("%s\n", bfr); ! 451: (void) fflush(stdout); ! 452: (void) system(bfr); ! 453: exit(0); ! 454: /*NOTREACHED*/ ! 455: } ! 456: ! 457: char firstbufname[BUFLEN]; ! 458: /* ! 459: * Link ARTICLE into dir for ngname and update active file. ! 460: */ ! 461: long ! 462: localize(ngname) ! 463: char *ngname; ! 464: { ! 465: char afline[BUFLEN]; ! 466: long ngsize; ! 467: long fpos; ! 468: int e; ! 469: char *cp; ! 470: ! 471: lock(); ! 472: actfp = xfopen(ACTIVE, "r+"); ! 473: ! 474: for(;;) { ! 475: fpos = ftell(actfp); ! 476: if (fgets(afline, sizeof afline, actfp) == NULL) { ! 477: unlock(); ! 478: (void) fclose(actfp); ! 479: logerr("Can't fine \"%s\" in active file", ngname); ! 480: return FALSE; /* No such newsgroup locally */ ! 481: } ! 482: if (prefix(afline, ngname)) { ! 483: (void) sscanf(afline, "%s %ld", bfr, &ngsize); ! 484: if (strcmp(bfr, ngname) == 0) { ! 485: if (ngsize < 0 || ngsize > 99998) { ! 486: logerr("found bad ngsize %ld ng %s, setting to 1", ngsize, bfr); ! 487: ngsize = 1; ! 488: } ! 489: break; ! 490: } ! 491: } ! 492: } ! 493: for (;;) { ! 494: cp = dirname(ngname); ! 495: if (!exists(cp)) ! 496: mknewsg(cp, ngname); ! 497: ! 498: (void) sprintf(bfr, "%s/%ld", cp, ngsize+1); ! 499: #ifdef VMS ! 500: if (vmslink(ARTICLE, bfr) == 0) ! 501: break; ! 502: #else /* !VMS */ ! 503: if (link(ARTICLE, bfr) == 0) ! 504: break; ! 505: #endif /* !VMS */ ! 506: e = errno; /* keep log from clobbering it */ ! 507: log("Cannot install article as %s: %s", bfr, errmsg(errno)); ! 508: if (e != EEXIST) { ! 509: logerr("Link into %s failed (%s); check dir permissions.", ! 510: bfr, errmsg(e)); ! 511: unlock(); ! 512: (void) fclose(actfp); ! 513: return FALSE; ! 514: } ! 515: ngsize++; ! 516: } ! 517: ! 518: (void) fflush(actfp); ! 519: #ifdef VMS ! 520: (void) fclose(actfp); ! 521: vmstounix(ACTIVE); ! 522: actfp = fopen(ACTIVE, "r+"); ! 523: #endif /* VMS */ ! 524: ! 525: /* ! 526: * This works around a bug in the 4.1bsd stdio ! 527: * on fseeks to non even offsets in r+w files ! 528: */ ! 529: if (fpos&1) ! 530: (void) rewind(actfp); ! 531: ! 532: (void) fseek(actfp, fpos, 0); ! 533: /* Has to be same size as old because of %05d. ! 534: * This will overflow with 99999 articles. ! 535: */ ! 536: fprintf(actfp, "%s %05ld", ngname, ngsize+1); ! 537: if (ferror(actfp)) ! 538: xerror("Active file write failed"); ! 539: (void) fclose(actfp); ! 540: #ifdef VMS ! 541: unixtovms(ACTIVE); ! 542: #endif /* VMS */ ! 543: unlock(); ! 544: if (firstbufname[0] == '\0') ! 545: (void) strcpy(firstbufname, bfr); ! 546: (void) sprintf(bfr, "%s/%ld ", ngname, ngsize+1); ! 547: addhist(bfr); ! 548: return ngsize+1; ! 549: } ! 550: ! 551: /* ! 552: * Localize for each newsgroup and broadcast. ! 553: */ ! 554: insert() ! 555: { ! 556: register char *ptr; ! 557: register FILE *tfp; ! 558: register int c; ! 559: struct srec srec; /* struct for sys file lookup */ ! 560: struct tm *tm; ! 561: int is_invalid = FALSE; ! 562: int exitcode = 0; ! 563: long now; ! 564: #ifdef DOXREFS ! 565: register char *nextref = header.xref; ! 566: #endif /* DOXREFS */ ! 567: ! 568: /* Fill up the rest of header. */ ! 569: if (mode != PROC) { ! 570: history(&header); ! 571: } ! 572: dates(&header); ! 573: (void) time(&now); ! 574: tm = localtime(&now); ! 575: if (header.expdate[0]) ! 576: addhist(" "); ! 577: #ifdef USG ! 578: sprintf(bfr,"%2.2d/%2.2d/%d %2.2d:%2.2d\t", ! 579: #else /* !USG */ ! 580: sprintf(bfr,"%02d/%02d/%d %02d:%02d\t", ! 581: #endif /* !USG */ ! 582: tm->tm_mon+1, tm->tm_mday, tm->tm_year,tm->tm_hour, tm->tm_min); ! 583: addhist(bfr); ! 584: log("%s %s ng %s subj '%s' from %s", ! 585: mode==PROC ? "received" : "posted", ! 586: header.ident, header.nbuf, header.title, header.from); ! 587: ! 588: /* Clean up Newsgroups: line */ ! 589: if (!is_ctl && mode != CREATENG) ! 590: is_invalid = ngfcheck(mode == PROC); ! 591: ! 592: /* Write article to temp file. */ ! 593: tfp = xfopen(mktemp(ARTICLE), "w"); ! 594: ! 595: if (is_invalid) { ! 596: logerr("No valid newsgroups found, moved to junk"); ! 597: if (localize("junk")) ! 598: savehist(histline); ! 599: exitcode = 1; ! 600: goto writeout; ! 601: } ! 602: ! 603: if (time((time_t *)0) > (cgtdate(header.subdate) + HISTEXP) ){ ! 604: logerr("Article too old, moved to junk"); ! 605: if (localize("junk")) ! 606: savehist(histline); ! 607: exitcode = 1; ! 608: goto writeout; ! 609: } ! 610: ! 611: if (is_ctl) { ! 612: exitcode = control(&header); ! 613: if (localize("control") && exitcode != 0) ! 614: savehist(histline); ! 615: } else { ! 616: if (s_find(&srec, FULLSYSNAME) == FALSE) { ! 617: logerr("Cannot find my name '%s' in %s", FULLSYSNAME, SUBFILE); ! 618: srec = dummy_srec; ! 619: } ! 620: #ifdef DOXREFS ! 621: (void) strncpy(nextref, FULLSYSNAME, BUFLEN); ! 622: #endif /* DOXREFS */ ! 623: for (ptr = nbuf; *ptr;) { ! 624: if (ngmatch(ptr,srec.s_nbuf) || index(ptr,'.') == NULL){ ! 625: #ifdef DOXREFS ! 626: while (*nextref++) ! 627: ; ! 628: (void) sprintf(--nextref, " %s:%ld", ptr, localize(ptr)); ! 629: #else /* !DOXREFS */ ! 630: (void) localize(ptr); ! 631: #endif /* !DOXREFS */ ! 632: } ! 633: while (*ptr++) ! 634: ; ! 635: } ! 636: if (firstbufname[0] == '\0') { ! 637: logerr("Newsgroups in active, but not sys"); ! 638: (void) localize("junk"); ! 639: } ! 640: } ! 641: #ifdef DOXREFS ! 642: if (index(header.nbuf, NGDELIM) == NULL) ! 643: header.xref[0] = '\0'; ! 644: #endif /* DOXREFS */ ! 645: ! 646: writeout: ! 647: /* Part 1 of kludge to get around article truncation problem */ ! 648: if ( (c=getc(infp)) != EOF) { ! 649: ungetc(c, infp); ! 650: if (c == ' ' || c == '\t') { ! 651: header.intnumlines++; ! 652: (void) sprintf(header.numlines, "%d", ! 653: header.intnumlines); ! 654: } ! 655: } ! 656: /* End of part 1 */ ! 657: lhwrite(&header, tfp); ! 658: if ((c = getc(infp)) != EOF) { ! 659: /* Part 2 of kludge to get around article truncation problem */ ! 660: if (c == ' ' || c == '\t' ) ! 661: putc('\n', tfp); ! 662: /* End of part 2 */ ! 663: ungetc(c, infp); ! 664: while (fgets(bfr, BUFLEN, infp) != NULL) ! 665: fputs(bfr, tfp); ! 666: if (bfr[strlen(bfr)-1] != '\n') ! 667: putc('\n',tfp); ! 668: } ! 669: if (ferror(tfp)) ! 670: xerror("Write failed for temp file"); ! 671: (void) fclose(tfp); ! 672: (void) fclose(infp); ! 673: ! 674: if(exitcode == 0) { ! 675: int pid; ! 676: /* article has passed all the checks, so work in background */ ! 677: if (mode != PROC) ! 678: if ((pid=fork()) < 0) ! 679: xerror("Can't fork"); ! 680: else if (pid > 0) ! 681: exit(0); ! 682: #ifdef SIGTTOU ! 683: signal(SIGTTOU, SIG_IGN); ! 684: #endif /* SIGTTOU */ ! 685: savehist(histline); ! 686: broadcast(); ! 687: } ! 688: xxit(mode == PROC ? 0 : exitcode); ! 689: } ! 690: ! 691: input() ! 692: { ! 693: register char *cp; ! 694: register int c; ! 695: register int empty = TRUE; ! 696: FILE *tmpfp; ! 697: int consec_newlines = 0; ! 698: int linecount = 0; ! 699: int linserted = 0; ! 700: ! 701: tmpfp = xfopen(mktemp(INFILE), "w"); ! 702: if (*filename) { ! 703: tty = FALSE; ! 704: infp = xfopen(filename, "r"); ! 705: } else { ! 706: infp = stdin; ! 707: } ! 708: while (!SigTrap && fgets(bfr, BUFLEN, stdin) != NULL) { ! 709: if (mode == PROC) { /* zap trailing empty lines */ ! 710: #ifdef ZAPNOTES ! 711: if (empty && bfr[0] == '#' && bfr[2] == ':' ! 712: && header.nf_id[0] == '\0' ! 713: && header.nf_from[0] == '\0' ) { ! 714: (void) strcpy(header.nf_id, bfr); ! 715: (void) nstrip(header.nf_id); ! 716: (void) fgets(bfr, BUFLEN, stdin); ! 717: (void) strcpy(header.nf_from, bfr); ! 718: (void) nstrip(header.nf_from); ! 719: (void) fgets(bfr, BUFLEN, stdin); ! 720: ! 721: if (header.numlines[0]) { ! 722: header.intnumlines -= 2; ! 723: (void) sprintf(header.numlines, "%d", header.intnumlines); ! 724: } ! 725: ! 726: /* Strip trailing " - (nf)" */ ! 727: if ((cp = rindex(header.title, '-')) != NULL ! 728: && !strcmp(--cp, " - (nf)")) ! 729: *cp = '\0'; ! 730: log("Stripped notes header on %s", header.ident); ! 731: continue; ! 732: } ! 733: #endif /* ZAPNOTES */ ! 734: if (bfr[0] == '\n' || ! 735: /* Bandage for older versions of inews */ ! 736: bfr[1] == '\n' && !isascii(bfr[0])) { ! 737: consec_newlines++; /* count it, in case */ ! 738: continue; /* but don't write it*/ ! 739: } ! 740: /* foo! a non-empty line. write out all saved lines. */ ! 741: while (consec_newlines > 0) { ! 742: putc('\n', tmpfp); ! 743: consec_newlines--; ! 744: linecount++; ! 745: } ! 746: } ! 747: if (mode != PROC && tty && strcmp(bfr, ".\n") == 0) ! 748: break; ! 749: for (cp = bfr; c = toascii(*cp); cp++) { ! 750: if (isprint(c) || isspace(c) || c == '\b') ! 751: putc(c, tmpfp); ! 752: if (c == '\n') ! 753: linecount++; ! 754: } ! 755: if (bfr[0] == '>') ! 756: linserted++; ! 757: empty = FALSE; ! 758: } ! 759: if (*filename) ! 760: (void) fclose(infp); ! 761: if (mode != PROC && linserted > (linecount-linserted)) ! 762: xerror("Article rejected: More included text than new text"); ! 763: ! 764: if (mode != PROC && !is_ctl && header.sender[0] == '\0') { ! 765: int siglines = 0; ! 766: char sbuf[BUFLEN]; ! 767: (void) sprintf(bfr, "%s/%s", userhome, ".signature"); ! 768: if (access(bfr, 4) == 0) { ! 769: if ((infp = fopen(bfr, "r")) == NULL) { ! 770: (void) fprintf(stderr, ! 771: "inews: \"%s\" left off (must be readable by \"inews\" owner)\n", bfr); ! 772: goto finish; ! 773: } ! 774: ! 775: while (fgets(sbuf, sizeof sbuf, infp) != NULL) ! 776: if (++siglines > 4) ! 777: break; ! 778: if (siglines > 4) ! 779: fprintf(stderr,".signature not included (> 4 lines)\n"); ! 780: else { ! 781: rewind(infp); ! 782: fprintf(tmpfp, "-- \n"); /* To separate */ ! 783: linecount++; ! 784: while ((c = getc(infp)) != EOF) { ! 785: putc(c, tmpfp); ! 786: if (c == '\n') ! 787: linecount++; ! 788: } ! 789: } ! 790: (void) fclose(infp); ! 791: } ! 792: } ! 793: ! 794: finish: ! 795: if (ferror(tmpfp)) ! 796: xerror("write failed to temp file"); ! 797: (void) fclose(tmpfp); ! 798: if (SigTrap) { ! 799: if (tty) ! 800: fprintf(stderr, "Interrupt\n"); ! 801: if (tty && !empty) ! 802: fwait(fsubr(newssave, (char *) NULL, (char *) NULL)); ! 803: if (!tty) ! 804: log("Blown away by an interrupt %d", SigTrap); ! 805: xxit(1); ! 806: } ! 807: if (tty) ! 808: fprintf(stderr, "EOT\n"); ! 809: fflush(stdout); ! 810: infp = fopen(INFILE, "r"); ! 811: if (header.numlines[0]) { ! 812: /* ! 813: * Check line count if there's already one attached to ! 814: * the article. Could make this a fatal error - ! 815: * throwing it away if it got chopped, in hopes that ! 816: * another copy will come in later with a correct ! 817: * line count. But that seems a bit much for now. ! 818: */ ! 819: if (linecount != header.intnumlines) { ! 820: if (linecount == 0) ! 821: xerror("%s rejected. linecount expected %d, got 0", header.ident, header.intnumlines); ! 822: if (linecount > header.intnumlines || ! 823: linecount+consec_newlines < header.intnumlines) ! 824: log("linecount expected %d, got %d", header.intnumlines, linecount+consec_newlines); ! 825: } ! 826: /* adjust count for blank lines we stripped off */ ! 827: if (consec_newlines) { ! 828: header.intnumlines -= consec_newlines; ! 829: if (header.intnumlines < 0 ) ! 830: header.intnumlines = 0; /* paranoia */ ! 831: (void) sprintf(header.numlines, "%d", header.intnumlines); ! 832: } ! 833: ! 834: } else { ! 835: /* Attach a line count to the article. */ ! 836: header.intnumlines = linecount; ! 837: (void) sprintf(header.numlines, "%d", linecount); ! 838: } ! 839: } ! 840: ! 841: /* ! 842: * Make the directory for a new newsgroup. ngname should be the ! 843: * full pathname of the directory. Do the other stuff too. ! 844: * The various games with setuid and chown are to try to make sure ! 845: * the directory is owned by NEWSUSR and NEWSGRP, which is tough to ! 846: * do if you aren't root. This will work on a UCB system (which allows ! 847: * setuid(geteuid()) or a USG system (which allows you to give away files ! 848: * you own with chown), otherwise you have to change your kernel to allow ! 849: * one of these things or run with your dirs 777 so that it doesn't matter ! 850: * who owns them. ! 851: */ ! 852: mknewsg(fulldir, ngname) ! 853: char *fulldir; ! 854: char *ngname; ! 855: { ! 856: #ifdef USG ! 857: register char *p; ! 858: char parent[200]; ! 859: char sysbuf[200]; ! 860: struct stat sbuf; ! 861: #endif /* USG */ ! 862: ! 863: if (ngname == NULL || !isalpha(ngname[0])) ! 864: xerror("Tried to make illegal newsgroup %s", ngname); ! 865: ! 866: #ifdef USG ! 867: /* ! 868: * If the parent is 755 the setuid(getuid) ! 869: * will fail, and since mkdir is suid, and our real uid is random, ! 870: * the mkdir will fail. So we have to temporarily chmod it to 777. ! 871: */ ! 872: (void) strcpy(parent, fulldir); ! 873: while (p = rindex(parent, '/')) { ! 874: *p = '\0'; ! 875: if (stat(parent, &sbuf) == 0) { ! 876: (void) chmod(parent, 0777); ! 877: break; ! 878: } ! 879: } ! 880: #endif /* USG */ ! 881: ! 882: /* Create the directory */ ! 883: mkparents(fulldir); ! 884: if (mkdir(fulldir, 0777) < 0) ! 885: xerror("Cannot mkdir %s: %s", fulldir, errmsg(errno)); ! 886: ! 887: #ifdef USG ! 888: (void) chmod(parent, (int)sbuf.st_mode); /* put it back */ ! 889: /* ! 890: * Give away the directories we just created which were assigned ! 891: * our real uid. ! 892: */ ! 893: (void) setuid(uid); ! 894: (void) chown(fulldir, duid, dgid); ! 895: (void) strcpy(sysbuf, fulldir); ! 896: while (p = rindex(sysbuf, '/')) { ! 897: *p = '\0'; ! 898: /* stop when get to last known good parent */ ! 899: if (strcmp(sysbuf, parent) == 0) ! 900: break; ! 901: (void) chown(sysbuf, duid, dgid); ! 902: } ! 903: (void) setuid(duid); ! 904: #endif /* USG */ ! 905: ! 906: log("make newsgroup %s in dir %s", ngname, fulldir); ! 907: } ! 908: ! 909: /* ! 910: * If any parent directories of this dir don't exist, create them. ! 911: */ ! 912: mkparents(dname) ! 913: char *dname; ! 914: { ! 915: char buf[200]; ! 916: register char *p; ! 917: ! 918: (void) strcpy(buf, dname); ! 919: p = rindex(buf, '/'); ! 920: if (p) ! 921: *p = '\0'; ! 922: if (exists(buf)) ! 923: return; ! 924: mkparents(buf); ! 925: if (mkdir(buf, 0777) < 0) ! 926: xerror("Can not mkdir %s: %s", buf, errmsg(errno)); ! 927: } ! 928: ! 929: cancel() ! 930: { ! 931: register FILE *fp; ! 932: ! 933: log("cancel article %s", filename); ! 934: fp = fopen(filename, "r"); ! 935: if (fp == NULL) { ! 936: log("article %s not found", filename); ! 937: return; ! 938: } ! 939: if (hread(&header, fp, TRUE) == NULL) ! 940: xerror("Article is garbled."); ! 941: (void) fclose(fp); ! 942: (void) unlink(filename); ! 943: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.