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: * ifuncs - functions used by inews. 16: */ 17: 18: #ifdef SCCSID 19: static char *SccsId = "@(#)ifuncs.c 2.51 3/19/86"; 20: #endif /* SCCSID */ 21: 22: #include "iparams.h" 23: #include <errno.h> 24: #include <ctype.h> 25: 26: /*LINTLIBRARY*/ 27: 28: #define AFSIZ 4000 /* size of text in the active file for initial malloc */ 29: 30: /* 31: * Transmit this article to all interested systems. 32: */ 33: 34: #ifdef u370 35: static struct srec srec; 36: #endif /* u370 */ 37: 38: static struct hbuf h, hh; 39: 40: #ifdef MULTICAST 41: #define MAXMCAST 20 42: #define MAXMCS 10 43: 44: struct multicast { 45: char mc_name[SBUFLEN]; /* "multi-cast" name */ 46: short mc_syscnt; 47: char mc_tosys[MAXMCAST][SBUFLEN]; 48: } mcast[MAXMCS]; 49: 50: static int mccount; 51: #endif /* MULTICAST */ 52: 53: #ifndef DBM 54: char *histfile(); 55: #endif /* !DBM */ 56: 57: broadcast() 58: { 59: register char *hptr; 60: register char *sptr; 61: register FILE *fp; 62: #ifndef u370 63: struct srec srec; 64: #endif 65: char sentbuf[LBUFLEN]; 66: int nsent = 0; 67: char *sentsys; 68: 69: /* h is a local copy of the header we can scribble on */ 70: fp = xfopen(ARTICLE, "r"); 71: if (hread(&h, fp, TRUE) == NULL) 72: xerror("Cannot reread article"); 73: (void) fclose(fp); 74: 75: (void) strcpy(sentbuf, h.ident); 76: (void) strcat(sentbuf, " sent to "); 77: sentsys = index(sentbuf, 0); 78: nsent = 0; 79: /* break path into list of systems. */ 80: sptr = hptr = h.path; 81: while ((hptr=strpbrk(hptr, NETCHRS)) != NULL) { 82: *hptr++ = '\0'; 83: sptr = hptr; 84: } 85: *sptr = '\0'; 86: 87: #ifdef MULTICAST 88: mccount = 0; 89: #endif /* MULTICAST */ 90: 91: /* loop once per system. */ 92: s_openr(); 93: while (s_read(&srec)) { 94: #ifdef HIDDENNET 95: if (strncmp(srec.s_name, LOCALSYSNAME, SNLN) == 0) 96: continue; 97: #endif /* HIDDENNET */ 98: if (strncmp(srec.s_name, FULLSYSNAME, SNLN) == 0) 99: continue; 100: if (sptr = srec.s_nosend) { 101: while (*sptr) { 102: while (*sptr && *sptr != ',') 103: sptr++; 104: if (*sptr == ',') 105: *sptr++ = '\0'; 106: } 107: *++sptr = '\0'; 108: } 109: hptr = h.path; 110: while (*hptr != '\0') { 111: if (strncmp(srec.s_name, hptr, SNLN) == 0) 112: goto contin; 113: if (sptr = srec.s_nosend) { 114: while (*sptr != '\0') { 115: if (strncmp(sptr, hptr, SNLN) == 0) 116: goto contin; 117: while (*sptr++) 118: ; 119: } 120: } 121: while (*hptr++ != '\0') 122: ; 123: } 124: if (!ngmatch(h.nbuf, srec.s_nbuf)) 125: continue; 126: if (h.distribution[0] != '\0' && 127: !ngmatch(h.distribution, srec.s_nbuf) && 128: !ngmatch(srec.s_nbuf, h.distribution)) 129: continue; 130: if (nsent) { 131: hptr = sentsys; 132: while ((sptr = index(hptr, ',')) != NULL) { 133: *sptr = '\0'; 134: if (strcmp(hptr, srec.s_name) == 0) { 135: *sptr = ','; 136: goto contin; 137: } 138: *sptr++ = ','; 139: for (hptr = sptr; isspace(*hptr); hptr++) 140: ; 141: } 142: if (strcmp(hptr, srec.s_name) == 0) 143: continue; 144: } 145: /* now we've found a system to send this article to */ 146: #ifdef MULTICAST 147: if (index(srec.s_flags, 'M')) { 148: /* do a "multi-cast" transmit */ 149: register struct multicast *m; 150: 151: if (strlen(srec.s_name) >= SBUFLEN || 152: strlen(srec.s_xmit) >= SBUFLEN) 153: xerror("system name too long for multicast"); 154: for (m = mcast; m < &mcast[mccount]; m++) 155: if (strcmp(srec.s_xmit, m->mc_name) == 0) 156: break; 157: if (m >= &mcast[MAXMCS]) 158: xerror("Too many multicasts"); 159: if (m == &mcast[mccount]) { 160: mccount++; 161: m->mc_syscnt = 0; 162: strcpy(m->mc_name, srec.s_xmit); 163: } 164: if (m->mc_syscnt >= MAXMCAST) 165: xerror("Too many systems for multicast"); 166: strcpy(m->mc_tosys[m->mc_syscnt++], srec.s_name); 167: } else { 168: register struct multicast *m; 169: register char **yptr; 170: char *sysptrs[MAXMCAST]; 171: int mc; 172: 173: mc = 0; 174: for (m = mcast; m < &mcast[mccount]; m++) 175: if (strcmp(m->mc_name, srec.s_name) == 0) { 176: yptr = sysptrs; 177: while (mc < m->mc_syscnt) 178: *yptr++ = m->mc_tosys[mc++]; 179: break; 180: } 181: if (!transmit(&srec,xfopen(ARTICLE,"r"),1,sysptrs,mc)) 182: continue; 183: } 184: #else /* !MULTICAST */ 185: if (!transmit(&srec, xfopen(ARTICLE, "r"), 1, (char **)0, 0)) 186: continue; 187: #endif /* !MULTICAST */ 188: if (nsent) 189: (void) strcat(sentbuf, ", "); 190: (void) strcat(sentbuf, srec.s_name); 191: nsent++; 192: contin:; 193: } 194: if (nsent) 195: log(sentbuf); 196: s_close(); 197: } 198: 199: /* 200: * Transmit file to system. 201: */ 202: #define PROC 0004 203: #ifndef MULTICAST 204: /* ARGSUSED */ 205: #endif /* !MULTICAST */ 206: transmit(sp, ifp, maynotify, sysnames, mc) 207: register struct srec *sp; 208: register FILE *ifp; 209: int maynotify; 210: char **sysnames; 211: int mc; 212: { 213: register FILE *ofp; 214: register int c; 215: register char *ptr; 216: char TRANS[BUFLEN]; 217: char *argv[20]; 218: register int pid; 219: extern char firstbufname[]; 220: 221: /* A: afmt: the other machine runs an A news, so we xmit in A format */ 222: int afmt = (index(sp->s_flags, 'A') != NULL); 223: /* B: use B format (this is the default - don't use this letter elsewise). */ 224: /* F: append name to file */ 225: int appfile = (index(sp->s_flags, 'F') != NULL); 226: /* L: local: don't send the article unless it was generated locally */ 227: int local = ((ptr = index(sp->s_flags, 'L')) != NULL); 228: /* H: interpolate history line into command, use existing file */ 229: int history = (index(sp->s_flags, 'H') != NULL); 230: /* M: multi-cast: this is taken care of above, but don't reuse flag */ 231: #ifdef MULTICAST 232: /* O: multi-cast only, don't send article if not multicast hosts */ 233: int multisend = (index(sp->s_flags, 'O') != NULL); 234: #endif /* MULTICAST */ 235: /* N: notify: don't send the article, just tell him we have it */ 236: int notify = maynotify && (index(sp->s_flags, 'N') != NULL); 237: /* S: noshell: don't fork a shell to execute the xmit command */ 238: int noshell = (index(sp->s_flags, 'S') != NULL); 239: /* U: useexist: use the -c option to uux to use the existing copy */ 240: int useexist = (index(sp->s_flags, 'U') != NULL); 241: 242: if (local && mode == PROC) { 243: local = 0; 244: while (isdigit(*++ptr)) 245: local = local * 10 + *ptr - '0'; 246: for (ptr = h.path; *ptr != '\0' && local >= 0; local--) 247: while (*ptr++ != '\0') 248: ; 249: if (local < 0) { 250: (void) fclose(ifp); 251: return FALSE; 252: } 253: } 254: 255: #ifdef DEBUG 256: printf("Transmitting to '%s'\n", sp->s_name); 257: #endif /* DEBUG */ 258: 259: #ifdef MULTICAST 260: if (multisend && mc == 0) { 261: (void) fclose(ifp); 262: return FALSE; 263: } 264: #endif /* MULTICAST */ 265: 266: if (!appfile && !useexist && !history) { 267: if (!hread(&hh, ifp, TRUE)) { 268: logerr("Bad header, not transmitting %s re %s to %s", 269: hh.ident, hh.title, sp->s_name); 270: (void) fclose(ifp); 271: return FALSE; 272: } 273: if (hh.nbuf[0] == '\0') { 274: fprintf(stderr, "Article not subscribed to by %s\n", sp->s_name); 275: (void) fclose(ifp); 276: return FALSE; 277: } 278: (void) sprintf(TRANS, "%s/trXXXXXX", SPOOL); 279: } 280: 281: if (notify) { 282: char oldid[50]; 283: (void) sprintf(hh.title, "ihave %s %s", hh.ident, FULLSYSNAME); 284: (void) sprintf(hh.nbuf, "to.%s.ctl", sp->s_name); 285: (void) strcpy(oldid, hh.ident); 286: getident(&hh); 287: log("tell %s about %s, notif. id %s", 288: sp->s_name, oldid, hh.ident); 289: } 290: 291: if (appfile) { 292: if (firstbufname[0] == '\0') { 293: extern char histline[]; 294: localize("junk"); 295: savehist(histline); 296: xerror("No file name to xmit from"); 297: } 298: if (sp->s_xmit[0] == '\0') 299: sprintf(sp->s_xmit, "%s/%s", BATCHDIR, sp->s_name); 300: #ifdef IHCC 301: (void) sprintf(TRANS, "%s/%s/%s", logdir(HOME), BATCHDIR, sp->s_xmit); 302: ofp = fopen(TRANS, "a"); 303: #else /* !IHCC */ 304: ofp = fopen(sp->s_xmit, "a"); 305: #endif /* !IHCC */ 306: if (ofp == NULL) 307: xerror("Cannot append to %s", sp->s_xmit); 308: #ifdef MULTICAST 309: fprintf(ofp, "%s", firstbufname); 310: while (--mc >= 0) 311: fprintf(ofp, " %s", *sysnames++); 312: fprintf(ofp, "\n"); 313: #else /* !MULTICAST */ 314: fprintf(ofp, "%s\n", firstbufname); 315: #endif /* !MULTICAST */ 316: (void) fclose(ofp); 317: (void) fclose(ifp); 318: return TRUE; 319: } 320: else if (useexist) { 321: if (firstbufname[0] == '\0') 322: xerror("No file name to xmit from"); 323: if (*sp->s_xmit == '\0') 324: #ifdef UXMIT 325: (void) sprintf(bfr, UXMIT, sp->s_name, firstbufname); 326: #else 327: xerror("UXMIT not defined for U flag"); 328: #endif 329: else 330: #ifdef MULTICAST 331: makeargs(bfr, sp->s_xmit, firstbufname, sysnames, mc); 332: #else 333: (void) sprintf(bfr, sp->s_xmit, firstbufname); 334: #endif 335: (void) fclose(ifp); 336: } else if (history) { 337: extern char histline[]; 338: 339: if (*sp->s_xmit == '\0') 340: xerror("no xmit command with H flag"); 341: #ifdef MULTICAST 342: makeargs(bfr, sp->s_xmit, histline, sysnames, mc); 343: #else 344: (void) sprintf(bfr, sp->s_xmit, histline); 345: #endif 346: } else { 347: ofp = xfopen(mktemp(TRANS), "w"); 348: if (afmt) { 349: #ifdef OLD 350: fprintf(ofp, "A%s\n%s\n%s!%s\n%s\n%s\n", oident(hh.ident), hh.nbuf, FULLSYSNAME, 351: hh.path, hh.subdate, hh.title); 352: #else /* !OLD */ 353: logerr("Must have OLD defined to use A flag for xmit"); 354: return FALSE; 355: #endif /* !OLD */ 356: } else 357: hwrite(&hh, ofp); 358: if (!notify) 359: while ((c = getc(ifp)) != EOF) 360: putc(c, ofp); 361: if (ferror(ofp)) 362: xerror("write failed on transmit"); 363: (void) fclose(ifp); 364: (void) fclose(ofp); 365: if (*sp->s_xmit == '\0') 366: (void) sprintf(bfr, DFTXMIT, sp->s_name, TRANS); 367: else 368: #ifdef MULTICAST 369: makeargs(bfr, sp->s_xmit, TRANS, sysnames, mc); 370: #else /* !MULTICAST */ 371: (void) sprintf(bfr, sp->s_xmit, TRANS); 372: #endif /* !MULTICAST */ 373: } 374: 375: /* At this point, the command to be executed is in bfr. */ 376: if (noshell) { 377: if (pid = fork()) 378: fwait(pid); 379: else { 380: (void) close(0); 381: (void) open(TRANS, 0); 382: ptr = bfr; 383: for (pid = 0; pid < 19; pid++) { 384: while (isspace(*ptr)) 385: *ptr++ = 0; 386: argv[pid] = ptr; 387: while (!isspace(*++ptr) && *ptr) 388: ; 389: if (!*ptr) 390: break; 391: } 392: argv[++pid] = 0; 393: (void) setgid(gid); 394: (void) setuid(uid); 395: execv(argv[0], argv); 396: xerror("Can't execv %s", argv[0]); 397: } 398: } else { 399: if (!history && sp->s_xmit[0] && !index(bfr, '<')) { 400: char newcmd[LBUFLEN]; 401: 402: (void) sprintf(newcmd, "(%s) <%s", bfr, 403: useexist ? firstbufname : TRANS); 404: system(newcmd); 405: } else 406: system(bfr); 407: } 408: if (!appfile && !useexist && !history) 409: (void) unlink(TRANS); 410: (void) fclose(ifp); 411: return TRUE; 412: } 413: 414: #ifdef MULTICAST 415: makeargs(buf, cmd, arg2, sysargs, sac) 416: char *buf; 417: char *cmd; 418: char *arg2; 419: register char **sysargs; 420: int sac; 421: { 422: register char *p = cmd; 423: register char *q; 424: register ac = 0; 425: register char *b = buf; 426: 427: q = p; 428: do { 429: if (q = index(q, ' ')) 430: *q = '\0'; 431: if (index(p, '%')) { 432: switch (++ac) { 433: case 1: 434: while (--sac >= 0) { 435: sprintf(b, p, *sysargs++); 436: b = index(b, '\0'); 437: } 438: break; 439: case 2: 440: sprintf(b, p, arg2); 441: b = index(b, '\0'); 442: break; 443: default: 444: if (q) 445: *q = ' '; 446: xerror("badly formed command: %s", cmd); 447: } 448: } else { 449: strcpy(b, p); 450: b = index(b, '\0'); 451: } 452: if (q) { 453: *q = ' '; 454: p = q; 455: while (isspace(*q)) 456: q++; 457: } 458: } while (q != NULL); 459: } 460: #endif /* MULTICAST */ 461: 462: typedef struct { 463: char *dptr; 464: int dsize; 465: } datum; 466: 467: /* 468: * Return TRUE if we have seen this file before, else FALSE. 469: */ 470: history(hp) 471: struct hbuf *hp; 472: { 473: #ifdef DBM 474: datum lhs, rhs; 475: datum fetch(); 476: #else /* !DBM */ 477: register FILE *hfp; 478: register char *p; 479: #endif /* !DBM */ 480: char lcident[BUFLEN]; 481: extern char histline[]; 482: 483: #ifdef DEBUG 484: fprintf(stderr,"history(%s)\n", hp->ident); 485: #endif /* DEBUG */ 486: /* 487: * Make the article ID case insensitive. 488: */ 489: (void) strcpy(lcident, hp->ident); 490: lcase(lcident); 491: 492: idlock(lcident); 493: #ifdef DBM 494: initdbm(ARTFILE); 495: lhs.dptr = lcident; 496: lhs.dsize = strlen(lhs.dptr) + 1; 497: rhs = fetch(lhs); 498: if (rhs.dptr) 499: return(TRUE); 500: #else /* !DBM */ 501: hfp = xfopen(histfile(lcident), "r"); 502: while (fgets(bfr, BUFLEN, hfp) != NULL) { 503: p = index(bfr, '\t'); 504: if (p == NULL) 505: p = index(bfr, '\n'); 506: if (p != NULL) /* can happen if nulls in file */ 507: *p = 0; 508: lcase(bfr); 509: 510: if (strcmp(bfr, lcident) == 0) { 511: (void) fclose(hfp); 512: idunlock(); 513: #ifdef DEBUG 514: fprintf(stderr,"history returns true\n"); 515: #endif /* DEBUG */ 516: return TRUE; 517: } 518: } 519: (void) fclose(hfp); 520: #endif /* !DBM */ 521: histline[0] = '\0'; 522: addhist(hp->ident); 523: addhist("\t"); 524: #ifdef DEBUG 525: fprintf(stderr,"history returns false\n"); 526: #endif 527: return FALSE; 528: } 529: 530: char histline[PATHLEN]; 531: 532: addhist(msg) 533: char *msg; 534: { 535: (void) strcat(histline, msg); 536: } 537: 538: savehist(hline) 539: char *hline; 540: { 541: register FILE *hfp; 542: datum lhs, rhs; 543: long fpos; 544: register char *p; 545: 546: hfp = xfopen(ARTFILE, "a"); 547: fpos = ftell(hfp); 548: fprintf(hfp, "%s\n", hline); 549: (void) fclose(hfp); 550: #ifdef DBM 551: /* We assume that history has already been called, calling dbminit. */ 552: p = index(hline, '\t'); 553: if (p) 554: *p = 0; 555: lcase(hline); 556: lhs.dptr = hline; 557: lhs.dsize = strlen(lhs.dptr) + 1; 558: rhs.dptr = (char *)&fpos; 559: rhs.dsize = sizeof fpos; 560: store(lhs, rhs); 561: #else /* !DBM */ 562: /* also append to proper history subfile */ 563: hfp = xfopen(histfile(hline), "a"); 564: fprintf(hfp, "%s\n", hline); 565: (void) fclose(hfp); 566: #endif /* !DBM */ 567: idunlock(); 568: } 569: 570: /* 571: * Save partial news. 572: */ 573: /* ARGSUSED */ 574: newssave(fd, dummy) 575: FILE *fd; 576: char *dummy; 577: { 578: register FILE *tofd, *fromfd; 579: char sfname[BUFLEN]; 580: register int c; 581: time_t tim; 582: 583: if (fd == NULL) 584: fromfd = xfopen(INFILE, "r"); 585: else 586: fromfd = fd; 587: (void) umask(savmask); 588: (void) setgid(gid); 589: (void) setuid(uid); 590: 591: (void) sprintf(sfname, "%s/%s", userhome, PARTIAL); 592: if ((tofd = fopen(sfname, "a")) == NULL) 593: xerror("Cannot save partial news in %s", sfname); 594: (void) time(&tim); 595: fprintf(tofd, "----- News saved at %s\n", arpadate(&tim)); 596: while ((c = getc(fromfd)) != EOF) 597: putc(c, tofd); 598: (void) fclose(fromfd); 599: (void) fclose(tofd); 600: printf("News saved in %s\n", sfname); 601: xxit(1); 602: } 603: 604: /* 605: * Handle dates in header. 606: */ 607: 608: dates(hp) 609: struct hbuf *hp; 610: { 611: time_t edt; 612: 613: if (*hp->subdate) { 614: if (cgtdate(hp->subdate) < 0) { 615: xerror("Cannot parse submittal date '%s'", hp->subdate); 616: } 617: } else { 618: (void) time(&edt); 619: (void) strcpy(hp->subdate, arpadate(&edt)); 620: } 621: } 622: 623: char lockname[80]; 624: idlock(str) 625: char *str; 626: { 627: register int i; 628: char tempname[80]; 629: time_t now; 630: struct stat sbuf; 631: extern int errno; 632: #ifdef VMS 633: int fd; 634: 635: (void) sprintf(lockname, "/tmp/%s.l.1", str); 636: if ((fd = creat(lockname, 0444)) < 0) { 637: #else /* !VMS */ 638: (void) strcpy(tempname, "/tmp/LTMP.XXXXXX"); 639: (void) mktemp(tempname); 640: (void) sprintf(lockname, "/tmp/L%s", str); 641: #ifdef FOURTEENMAX 642: lockname[5 /* /tmp/ */ + 14] = '\0'; 643: #endif 644: i = creat(tempname, 0666); 645: if (i < 0) 646: xerror("Cannot creat %s: errno %d", tempname, errno); 647: (void) close(i); 648: while (link(tempname, lockname)) { 649: #endif /* !VMS */ 650: (void) time(&now); 651: i = stat(lockname, &sbuf); 652: if (i < 0) { 653: xerror("Directory permission problem in /tmp"); 654: } 655: if (sbuf.st_mtime + 10*60 < now) { 656: (void) unlink(lockname); 657: logerr("Article %s locked up", str); 658: break; 659: } 660: log("waiting on lock for %s", lockname); 661: sleep((unsigned)60); 662: } 663: #ifdef VMS 664: (void) close(fd); 665: #endif 666: (void) unlink(tempname); 667: } 668: 669: idunlock() 670: { 671: (void) unlink(lockname); 672: } 673: 674: /* 675: * Put a unique name into header.ident. 676: */ 677: getident(hp) 678: struct hbuf *hp; 679: { 680: long seqn; 681: register FILE *fp; 682: 683: lock(); 684: fp = xfopen(SEQFILE, "r"); 685: (void) fgets(bfr, BUFLEN, fp); 686: (void) fclose(fp); 687: seqn = atol(bfr) + 1; 688: #ifdef VMS 689: (void) unlink(SEQFILE); 690: #endif /* VMS */ 691: fp = xfopen(SEQFILE, "r+w"); 692: fprintf(fp, "%ld\n", seqn); 693: (void) fclose(fp); 694: unlock(); 695: #ifdef HIDDENNET 696: if (strcmp(LOCALSYSNAME, FULLSYSNAME)) 697: (void) sprintf(hp->ident, "<%ld@%s.%s%s>", seqn, LOCALSYSNAME, FULLSYSNAME, 698: MYDOMAIN); 699: else 700: #endif /* !HIDDENNET */ 701: (void) sprintf(hp->ident, "<%ld@%s%s>", seqn, FULLSYSNAME, MYDOMAIN); 702: } 703: 704: /* 705: * Check that header.nbuf contains only valid newsgroup names; 706: * exit with error if not valid. 707: * 708: */ 709: ngfcheck(isproc) 710: int isproc; 711: { 712: register char *s1, *s2; 713: register FILE *f; 714: register char *os1; 715: int ngroups = 1; 716: unsigned int ngsize = AFSIZ; 717: char tbuf[BUFLEN], *ngcheck; 718: 719: f = xfopen(ACTIVE, "r"); 720: ngcheck = malloc(ngsize); 721: if (ngcheck == NULL) 722: xerror("Can't malloc the active file"); 723: s1 = ngcheck; 724: while (fgets(bfr, BUFLEN, f) != NULL) { 725: os1 = s1; 726: for(s2 = bfr; *s2 != '\0' && *s2 != ' ';) { 727: if (s1 >= &ngcheck[ngsize-2]) { 728: unsigned int offs = s1 - ngcheck; 729: ngsize += LBUFLEN; 730: ngcheck = realloc(ngcheck, ngsize); 731: if (ngcheck == NULL) 732: xerror("Can't realloc active file"); 733: s1 = ngcheck + offs; 734: } 735: *s1++ = *s2++; 736: } 737: *s1++ = '\0'; 738: if (isproc) /* don't check to see if can post to this group */ 739: continue; 740: while (*s2++ != '\0' && *s2 != ' ') 741: ; /* skip max article number */ 742: while (*s2++ != '\0' && *s2 != ' ') 743: ; /* skip min article number */ 744: if (*s2++ != '\0' && *s2 == 'n') 745: s1 = os1; /* can't post to this group */ 746: } 747: *s1++ = '\0'; 748: *s1 = '\0'; 749: (void) fclose(f); 750: 751: s1 = header.nbuf; 752: s2 = nbuf; 753: while (*s1 == NGDELIM || *s1 == ' ') 754: s1++; /* skip leading junk */ 755: do { 756: /* there shouldn't be blanks, but give the jerk a break */ 757: if (*s1 == NGDELIM || *s1 == ' ') { 758: *s2++ = '\0'; 759: while (*++s1 == NGDELIM || *s1 == ' ') 760: ; /* remove extra commas */ 761: if (*s1 != '\0') 762: ngroups++; 763: } else 764: *s2++ = *s1++; 765: } while (*s1 != '\0'); 766: if (s2[-1] == NGDELIM) /* strip trailing commas */ 767: s2--; 768: *s2 = '\0'; 769: 770: s1 = nbuf; 771: while (*s1 != '\0') { /* for each newsgroup in header */ 772: s2 = ngcheck; 773: while (*s2 != '\0') { /* for each newsgroup in active file */ 774: if (strcmp(s1, s2) == 0) 775: break; 776: while (*s2++ != '\0') 777: ; 778: } 779: if (*s2 == '\0') { /* not found. remove it */ 780: if (!isproc) { 781: logerr("Invalid news group '%s'", s1); 782: newssave(stdin, (char *)NULL); 783: } 784: /* See if it's in our alias list */ 785: f = xfopen(ALIASES,"r"); 786: while (fscanf(f,"%s %s", tbuf, bfr) == 2 787: && strcmp(s1, tbuf)) 788: ; 789: (void) fclose(f); 790: if (strcmp(s1, tbuf) == 0) { 791: logerr("Aliased newsgroup '%s' to '%s'", s1, bfr); 792: os1 = s1; 793: s1 = nbuf; 794: s2 = tbuf; 795: while (s1 < os1) /* copy left part */ 796: *s2++ = *s1++; 797: s1 = bfr; 798: while (*s1 != '\0') /* copy alias */ 799: *s2++ = *s1++; 800: *s2++ = '\0'; 801: s1 = os1; 802: os1 = nbuf + (s2 - tbuf); 803: while (*s1++ != '\0') /* skip old group */ 804: ; 805: /* copy right part */ 806: tbufcpy(s2, s1); 807: /* copy back to original buffer */ 808: tbufcpy(nbuf, tbuf); 809: s1 = os1; 810: } else { 811: logerr("Unknown newsgroup '%s' removed", s1); 812: s2 = s1; 813: while (*s2++ != '\0') /* skip the bad one */ 814: ; 815: tbufcpy(s1, s2); 816: } 817: } else { /* It's in our active file */ 818: os1 = s1; 819: while (*s1++ != '\0') 820: ; 821: /* check for local only distribution on incoming 822: newsgroups. This might occur if someone posted to 823: general,net.unix */ 824: if(isproc && ngroups > 1 && index(os1, '.') == NULL 825: && index(header.nbuf, '.') != NULL) { 826: logerr("Local group '%s' removed", os1); 827: tbufcpy(os1, s1); 828: s1 = os1; 829: } 830: } 831: } 832: /* remove any duplicates */ 833: os1 = s1 = nbuf; 834: for(;;) { 835: if (*s1++ == '\0') { 836: if (*s1 == '\0') 837: break; 838: s2 = s1; 839: while (*s2 != '\0') { 840: if (strcmp(os1, s2) == 0) { 841: logerr("Duplicate '%s' removed",os1); 842: os1 = s2; 843: while (*s2++ != '\0') /* skip it */ 844: ; 845: tbufcpy(os1, s2); 846: } else 847: while (*s2++ != '\0') 848: ; 849: } 850: os1 = s1; 851: s1[-1] = '\0'; 852: } 853: } 854: if (nbuf[0] != '\0') { 855: s1 = header.nbuf; 856: s2 = nbuf; 857: do { 858: while (*s2 != '\0') 859: *s1++ = *s2++; 860: *s1++ = NGDELIM; 861: } while (*++s2 != '\0'); 862: *--s1 = '\0'; 863: (void) free(ngcheck); 864: return FALSE; 865: } 866: (void) free(ngcheck); 867: return TRUE; 868: } 869: 870: tbufcpy(s1, s2) 871: register char *s1, *s2; 872: { 873: do { 874: while (*s2 != '\0') 875: *s1++ = *s2++; 876: *s1++ = '\0'; 877: } while (*++s2 != '\0'); 878: *s1 = '\0'; 879: } 880: 881: 882: /* 883: * Figure out who posted the article (which is locally entered). 884: * The results are placed in the header structure hp. 885: */ 886: gensender(hp, logname) 887: struct hbuf *hp; 888: char *logname; 889: { 890: register char *fn, *p; 891: char buf[BUFLEN]; 892: char *fullname(), *getenv(); 893: int fd, n; 894: 895: fn = getenv("NAME"); 896: 897: if (fn == NULL) { 898: (void) sprintf(buf, "%s/%s", userhome, ".name"); 899: fd = open(buf, 0); 900: if (fd >= 0) { 901: n = read(fd, buf, sizeof buf); 902: (void) close(fd); 903: if (n > 0 && buf[0] >= 'A') { 904: fn = buf; 905: for (p=fn; *p; p++) 906: if (*p < ' ') 907: *p = '\0'; 908: } 909: } 910: } 911: 912: if (fn == NULL) 913: fn = fullname(logname); 914: 915: (void) sprintf(hp->path, "%s", logname); 916: (void) sprintf(hp->from, "%s@%s%s (%s)", logname, FULLSYSNAME, MYDOMAIN, fn); 917: } 918: 919: /* 920: * Trap interrupts. 921: */ 922: onsig(n) 923: int n; 924: { 925: static int numsigs = 0; 926: /* 927: * Most UNIX systems reset caught signals to SIG_DFL. 928: * This bad design requires that the trap be set again here. 929: * Unfortunately, if the signal recurs before the trap is set, 930: * the program will die, possibly leaving the lock in place. 931: */ 932: if (++numsigs > 100) { 933: logerr("inews ran away looping on signal %d", n); 934: xxit(1); 935: } 936: (void) signal(n, onsig); 937: SigTrap = n; 938: } 939: 940: #ifdef BATCH 941: /* 942: * If the stdin begins with "#", we assume we have been fed a batched 943: * shell script which looks like this: 944: * #! rnews 1234 945: * article with 1234 chars 946: * #! rnews 4321 947: * article with 4321 chars 948: * 949: * In this case we just exec the unbatcher and let it unpack and call us back. 950: * 951: * Note that there is a potential security hole here. If the batcher is 952: * /bin/sh, someone could ship you arbitrary stuff to run as shell commands. 953: * The main protection you have is that the effective uid will be news, not 954: * uucp and not the super user. (That, plus the fact that BATCH is set to 955: * "unbatch" as the system is distributed.) If you want to run a batched link 956: * and you are security conscious, do not use /bin/sh as the unbatcher. 957: * the thing to do is to change BATCH in your localize.sh file from /bin/sh 958: * to some restricted shell which can only run rnews. 959: */ 960: checkbatch() 961: { 962: int c; 963: 964: c = getc(stdin); 965: if (c != EOF) 966: (void) ungetc(c, stdin); 967: clearerr(stdin); 968: if (c == '#') { 969: char unbatcher[BUFLEN]; 970: 971: (void) sprintf(unbatcher, "%s/%s", LIB, BATCH); 972: reset_stdin(); 973: execl(unbatcher, "news-unpack", (char *)0); 974: xerror("Unable to exec shell to unpack news."); 975: } 976: } 977: 978: /* 979: * We've already done a read on stdin, and we want to seek back to the 980: * beginning. We want the real file descriptor (beyond buffers) to 981: * reflect the true beginning. Do whatever is necessary. 982: */ 983: reset_stdin() 984: { 985: register FILE *ofd; 986: register int c; 987: char *ofdname; 988: long lseek(); 989: 990: /* First try to seek back - if so, it's a cheap way back. */ 991: if (lseek(0, 0L, 0) == 0L) 992: return; 993: 994: /* Can't seek, so have to copy input to a file and use that. */ 995: ofdname = "/tmp/inewsXXXXXX"; 996: (void) mktemp(ofdname); 997: ofd = fopen(ofdname, "w"); 998: while ((c=getc(stdin)) != EOF) 999: putc(c, ofd); 1000: if (ferror(ofd)) 1001: xerror("write failed on temp file %s", ofdname); 1002: (void) fclose(stdin); 1003: (void) fclose(ofd); 1004: 1005: /* Now for a few lower level hacks to reopen stdin and make 1006: * absolutely sure that the right fd's are done for the exec. 1007: */ 1008: (void) close(0); /* make sure stdin is really closed. */ 1009: (void) open(ofdname, 0); /* should return zero */ 1010: (void) unlink(ofdname); /* to avoid cleaning it up later. */ 1011: } 1012: #endif /* BATCH */ 1013: 1014: /* 1015: * Exit and cleanup. 1016: */ 1017: xxit(status) 1018: int status; 1019: { 1020: (void) unlink(INFILE); 1021: (void) unlink(ARTICLE); 1022: while (lockcount > 0) 1023: unlock(); 1024: idunlock(); 1025: exit(status); 1026: } 1027: 1028: rwaccess(fname) 1029: char *fname; 1030: { 1031: int fd; 1032: 1033: fd = open(fname, 2); 1034: if (fd < 0) 1035: return 0; 1036: (void) close(fd); 1037: return 1; 1038: } 1039: 1040: exists(fname) 1041: char *fname; 1042: { 1043: int fd; 1044: 1045: fd = open(fname, 0); 1046: if (fd < 0) 1047: return 0; 1048: (void) close(fd); 1049: return 1; 1050: } 1051: 1052: int lockcount = 0; /* no. of times we've called lock */ 1053: 1054: #ifdef VMS 1055: 1056: #define SUBLOCK "/tmp/netnews.lck.1" 1057: 1058: /* 1059: * Newsystem locking. 1060: * These routines are different for VMS because we can not 1061: * effectively simulate links, and VMS supports multiple 1062: * version numbers of files 1063: */ 1064: lock() 1065: { 1066: register int i; 1067: register int fd; 1068: 1069: if (lockcount++ == 0) { 1070: i = DEADTIME; 1071: while ((fd = creat(SUBLOCK, 0444)) < 0) { 1072: if (--i < 0) { 1073: (void) unlink(SUBLOCK); 1074: logerr("News system locked up"); 1075: } 1076: if (i < -3) 1077: xerror("Unable to unlock news system"); 1078: sleep((unsigned)1); 1079: } 1080: (void) close(fd); 1081: } 1082: } 1083: 1084: unlock() 1085: { 1086: if (--lockcount == 0) 1087: (void) unlink(SUBLOCK); 1088: } 1089: 1090: #else /* !VMS */ 1091: 1092: /* 1093: * Newsystem locking. 1094: */ 1095: 1096: #ifdef BSD4_2 1097: #include <sys/file.h> 1098: static int LockFd = -1; 1099: lock() 1100: { 1101: LockFd = open(SUBFILE,0); 1102: /* This will sleep until the other program releases the lock */ 1103: /* We may need to alarm out of this, but I don't think so */ 1104: (void) flock(LockFd, LOCK_EX); 1105: } 1106: 1107: unlock() 1108: { 1109: (void) flock(LockFd, LOCK_UN); 1110: (void) close(LockFd); 1111: } 1112: #else /* !BSD4_2 */ 1113: /* Why doesn't USG unix have file locking????? */ 1114: lock() 1115: { 1116: register int i; 1117: extern int errno; 1118: 1119: if (lockcount++ == 0) { 1120: i = DEADTIME; 1121: while (link(SUBFILE, LOCKFILE)) { 1122: if (errno != EEXIST) 1123: break; 1124: if (--i < 0) 1125: xerror("News system locked up"); 1126: sleep((unsigned)1); 1127: } 1128: } 1129: } 1130: 1131: unlock() 1132: { 1133: if (--lockcount == 0) 1134: (void) unlink(LOCKFILE); 1135: } 1136: #endif /* !BSD4_2 */ 1137: #endif /* !VMS */ 1138: 1139: /* 1140: * Generate the name of the person responsible for posting this article, 1141: * in order to check that two articles were posted by the same person. 1142: */ 1143: char * 1144: senderof(hp) 1145: struct hbuf *hp; 1146: { 1147: char *q, *tp; 1148: char *tailpath(); 1149: 1150: if (hp->sender[0]) 1151: tp = hp->sender; 1152: else if (hp->from[0]) 1153: tp = hp->from; 1154: else 1155: tp = tailpath(hp); 1156: 1157: /* Remove full name */ 1158: q = index(tp, ' '); 1159: if (q) 1160: *q = '\0'; 1161: 1162: q = malloc((unsigned)(strlen(tp) + 1)); 1163: (void) strcpy(q, tp); 1164: return q; 1165: }