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: * funcs - functions used by many programs 16: */ 17: 18: #ifdef SCCSID 19: static char *SccsId = "@(#)funcs.c 2.31 1/17/86"; 20: #endif /* SCCSID */ 21: 22: /*LINTLIBRARY*/ 23: 24: #include "params.h" 25: #include <errno.h> 26: #if defined(USG) || defined(BSD4_2) || defined(BSD4_1C) 27: #include <fcntl.h> 28: #endif /* !v7 */ 29: 30: extern char *Progname; 31: 32: /* 33: * News group matching. 34: * 35: * nglist is a list of newsgroups. 36: * sublist is a list of subscriptions. 37: * sublist may have "meta newsgroups" in it. 38: * All fields are NGDELIM separated, 39: * and there is an NGDELIM at the end of each argument. 40: * 41: * Currently implemented glitches: 42: * sublist uses 'all' like shell uses '*', and '.' like shell '/'. 43: * If subscription X matches Y, it also matches Y.anything. 44: */ 45: ngmatch(nglist, sublist) 46: register char *nglist, *sublist; 47: { 48: register char *n, *s; 49: register int rc; 50: 51: rc = FALSE; 52: for (n = nglist; *n != '\0' && rc == FALSE;) { 53: for (s = sublist; *s != '\0';) { 54: if (*s != NEGCHAR) 55: rc = rc || ptrncmp(s, n); 56: else 57: rc = rc && !ptrncmp(s+1, n); 58: while (*s++ != NGDELIM && *s != '\0') 59: ; 60: } 61: while (*n++ != NGDELIM && *n != '\0') 62: ; 63: } 64: return rc; 65: } 66: 67: /* 68: * Compare two newsgroups for equality. 69: * The first one may be a "meta" newsgroup. 70: */ 71: ptrncmp(ng1, ng2) 72: register char *ng1, *ng2; 73: { 74: while (*ng1 != NGDELIM && *ng1 != '\0') { 75: if (ng1[0]=='a' && ng1[1]=='l' && ng1[2]=='l') { 76: ng1 += 3; 77: while (*ng2 != NGDELIM && *ng2 != '.' && *ng2 != '\0') 78: if (ptrncmp(ng1, ng2++)) 79: return(TRUE); 80: return ptrncmp(ng1, ng2); 81: } else if (*ng1++ != *ng2++) 82: return FALSE; 83: } 84: return *ng2 == '.' || *ng2 == NGDELIM || *ng2 == '\0'; 85: } 86: 87: /* 88: * Exec the shell. 89: * This version resets uid, gid, and umask. 90: * Called with fsubr(ushell, s, NULL) 91: */ 92: /* ARGSUSED */ 93: ushell(s, dummy) 94: char *s, *dummy; 95: { 96: (void) umask(savmask); 97: (void) setgid(gid); 98: (void) setuid(uid); 99: xshell(s); 100: } 101: 102: /* 103: * Exec the shell. 104: */ 105: 106: #ifdef lint 107: char **environ; 108: #else /* !lint */ 109: extern char **environ; 110: #endif /* !lint */ 111: 112: xshell(s) 113: char *s; 114: { 115: char *env[100], **envp; 116: char a[BUFLEN + 2]; 117: extern char filename[]; 118: /* set $A */ 119: (void) sprintf(a, "A=%s", filename); 120: env[0] = a; 121: for (envp = env + 1 ; *environ != NULL && envp < env + 98 ; environ++) 122: if ((*environ)[0] != 'A' || (*environ)[1] != '=') 123: *envp++ = *environ; 124: *envp = NULL; 125: 126: execle(SHELL, SHELL, "-c", s, (char *)0, env); 127: xerror("No shell!"); 128: } 129: 130: /* 131: * Fork and call a subroutine with two args. 132: * Return pid without waiting. 133: */ 134: fsubr(f, s1, s2) 135: int (*f)(); 136: char *s1, *s2; 137: { 138: register int pid; 139: 140: while ((pid = fork()) == -1) 141: sleep((unsigned)1); 142: if (pid == 0) { 143: (*f)(s1, s2); 144: exit(0); 145: } 146: return pid; 147: } 148: 149: /* 150: * Wait on a child process. 151: */ 152: fwait(pid) 153: register int pid; 154: { 155: register int w; 156: int status; 157: int (*onhup)(), (*onint)(); 158: 159: onint = signal(SIGINT, SIG_IGN); 160: onhup = signal(SIGHUP, SIG_IGN); 161: while ((w = wait(&status)) != pid && w != -1) 162: ; 163: if (w == -1) 164: status = -1; 165: (void) signal(SIGINT, onint); 166: (void) signal(SIGHUP, onhup); 167: return status; 168: } 169: 170: /* 171: * Strip trailing newlines, blanks, and tabs from 's'. 172: * Return TRUE if newline was found, else FALSE. 173: */ 174: nstrip(s) 175: register char *s; 176: { 177: register char *p; 178: register int rc; 179: 180: rc = FALSE; 181: p = s; 182: while (*p) 183: if (*p++ == '\n') 184: rc = TRUE; 185: while (--p >= s && (*p == '\n' || *p == ' ' || *p == '\t')); 186: *++p = '\0'; 187: return rc; 188: } 189: 190: /* 191: * Local open routine. 192: */ 193: FILE * 194: xfopen(name, fmode) 195: register char *name, *fmode; 196: { 197: register FILE *fp; 198: char *fname; 199: extern int errno; 200: 201: if ((fp = fopen(name, fmode)) == NULL) { 202: #ifdef IHCC 203: /* 204: * IHCC users only see the "filename" that was in trouble, 205: * not the whole path. (for security!) 206: */ 207: fname = rindex(name, '/') + 1; 208: #else 209: fname = name; 210: #endif 211: xerror("Cannot open %s (%s): %s", fname, fmode, errmsg(errno)); 212: } 213: /* kludge for setuid not being honored for root */ 214: if ((uid == 0) && (duid != 0) && ((*fmode == 'a') || (*fmode == 'w'))) 215: (void) chown(name, duid, dgid); 216: return fp; 217: } 218: 219: char * 220: errmsg(code) 221: int code; 222: { 223: extern int sys_nerr; 224: extern char *sys_errlist[]; 225: static char ebuf[6+5+1]; 226: 227: if (code > sys_nerr) { 228: (void) sprintf(ebuf, "Error %d", code); 229: return ebuf; 230: } else 231: return sys_errlist[code]; 232: } 233: 234: prefix(full, pref) 235: register char *full, *pref; 236: { 237: register char fc, pc; 238: 239: while ((pc = *pref++) != '\0') { 240: fc = *full++; 241: if (isupper(fc)) 242: fc = tolower(fc); 243: if (isupper(pc)) 244: pc = tolower(pc); 245: if (fc != pc) 246: return FALSE; 247: } 248: return TRUE; 249: } 250: 251: char * 252: dirname(ngname) 253: char *ngname; 254: { 255: static char rbuf[BUFLEN]; 256: register char *p; 257: 258: (void) sprintf(rbuf, "%s/%s", SPOOL, ngname); 259: 260: for (p=rbuf+strlen(SPOOL); *p; p++) 261: if (*p == '.') 262: *p = '/'; 263: return rbuf; 264: } 265: 266: /* 267: * Return TRUE iff ngname is a valid newsgroup name 268: */ 269: validng(ngname) 270: char *ngname; 271: { 272: register FILE *fp; 273: register char *p, *q; 274: char abuf[BUFLEN]; 275: 276: fp = xfopen(ACTIVE, "r"); 277: while(fgets(abuf, BUFLEN, fp) != NULL) { 278: p = abuf; 279: q = ngname; 280: while (*p++ == *q++) 281: ; 282: if (*--q == '\0' && *--p == ' ') { 283: (void) fclose(fp); 284: return TRUE; 285: } 286: } 287: (void) fclose(fp); 288: return FALSE; 289: } 290: 291: /* VARARGS1 */ 292: xerror(message, arg1, arg2, arg3) 293: char *message; 294: int arg1, arg2, arg3; 295: { 296: char buffer[128]; 297: 298: fflush(stdout); 299: (void) sprintf(buffer, message, arg1, arg2, arg3); 300: logerr(buffer); 301: xxit(1); 302: } 303: 304: /* VARARGS1 */ 305: log(fmt, a1, a2, a3, a4, a5, a6, a7, a8, a9) 306: char *fmt; 307: { 308: _dolog(0, fmt, a1, a2, a3, a4, a5, a6, a7, a8, a9); 309: } 310: 311: /* VARARGS1 */ 312: logerr(fmt, a1, a2, a3, a4, a5, a6, a7, a8, a9) 313: char *fmt; 314: { 315: _dolog(1, fmt, a1, a2, a3, a4, a5, a6, a7, a8, a9); 316: } 317: 318: char *lfsuffix[] = { 319: "log", 320: "errlog", 321: 0 322: }; 323: 324: /* 325: * Log the given message, with printf strings and parameters allowed, 326: * on the log file, if it can be written. The date and an attempt at 327: * figuring out the remote system name are also logged. 328: */ 329: /* VARARGS1 */ 330: _dolog(which, fmt, a1, a2, a3, a4, a5, a6, a7, a8, a9) 331: char *fmt; 332: { 333: FILE *logfile; 334: register char *p, *logtime; 335: int i; 336: char logfname[BUFLEN]; /* the log file */ 337: char rmtsys[BUFLEN]; 338: char msg[BUFLEN]; 339: time_t t; 340: 341: (void) strcpy(rmtsys, header.path); 342: p = index(rmtsys, '!'); 343: if (p == NULL) 344: p = index(rmtsys, ':'); 345: if (p) 346: *p = 0; 347: else { 348: p = rindex(rmtsys, '@'); 349: if (p) 350: (void) strcpy(rmtsys, p+1); 351: else 352: (void) strcpy(rmtsys, "local"); 353: } 354: 355: (void) time(&t); 356: logtime = ctime(&t); 357: logtime[16] = 0; 358: logtime += 4; 359: 360: 361: (void) sprintf(msg, fmt, a1, a2, a3, a4, a5, a6, a7, a8, a9); 362: 363: if (which) 364: fprintf(stderr,"%s: %s\n", Progname, msg); 365: 366: for (i=0; i<=which;i++) { 367: (void) sprintf(logfname, "%s/%s", LIB, lfsuffix[i]); 368: 369: if (access(logfname, 0) == 0 && (logfile = fopen(logfname, "a")) != NULL) { 370: #if defined(USG) || defined(BSD4_2) || defined(BSD4_1C) 371: int flags; 372: flags = fcntl(fileno(logfile), F_GETFL, 0); 373: (void) fcntl(fileno(logfile), F_SETFL, flags|O_APPEND); 374: #else /* v7 */ 375: (void) lseek(fileno(logfile), 0L, 2); 376: #endif /* v7 */ 377: if (i) 378: fprintf(logfile, "%s\t%s\t%s: %s\n", logtime, 379: header.ident[0] ? header.ident : username, Progname, msg); 380: else 381: fprintf(logfile, "%s\t%s\t%s\n", logtime, 382: rmtsys, msg); 383: (void) fclose(logfile); 384: } 385: } 386: } 387: #ifdef VMS 388: 389: /* 390: * vmslink allows simulation of file linking under VMS. 391: */ 392: vmslink(infile,outfile) 393: char *infile, *outfile; 394: { 395: FILE *fp; 396: 397: if (access(outfile,0) == 0) { 398: errno = EEXIST; 399: return -1; 400: } 401: 402: fp = fopen(outfile, "w"); 403: if (fp == NULL) { 404: errno = EACCES; 405: return -1; 406: } 407: 408: (void) fprintf(fp, "%s", infile); 409: (void) fclose(fp); 410: 411: return 0; 412: } 413: 414: /* 415: * vmsdelete deletes all revisions of a file. It attempts to 416: * appear as unlink(2) under conventional Unix in other respects. 417: */ 418: vmsdelete(file) 419: char *file; 420: { 421: int i; 422: 423: i = unlink(file); 424: if (i != 0) 425: return i; 426: 427: i = errno; 428: while (unlink(file) == 0) 429: ; 430: errno = i; 431: 432: return 0; 433: } 434: 435: /* 436: * Convert a Unix file to a VMS fixed record format file by 437: * executing the 'unixtovms' command. 438: */ 439: unixtovms(file) 440: char *file; 441: { 442: char buf[BUFLEN]; 443: sprintf(buf, "exec /etc/unixtovms %s", file); 444: return system(buf); 445: } 446: 447: /* 448: * Convert a VMS fixed record format file to a Unix file by 449: * executing the 'vmstounix' command. 450: */ 451: vmstounix(file) 452: char *file; 453: { 454: char buf[BUFLEN]; 455: sprintf(buf,"exec /etc/vmstounix %s", file); 456: return system(buf); 457: } 458: #endif /* VMS */ 459: 460: #if !defined(BSD4_2) && !defined(BSD4_1C) 461: /* 462: * make a directory. Also make sure that the directory is owned 463: * by the right userid 464: */ 465: mkdir(path, perm) 466: char *path; 467: int perm; 468: { 469: int pid, status; 470: 471: if (pid=fork()) { 472: status = fwait(pid); 473: #if defined(USG) && !defined(CHEAP) 474: if (pid=fork()) 475: (void) fwait(pid); 476: else { 477: setgid(gid); 478: setuid(uid); 479: if (chown(path, duid, dgid) == 0) 480: (void) chmod(path, perm&(~N_UMASK)); 481: _exit(0); 482: } 483: #endif /* USG && !CHEAP */ 484: } else { 485: (void) setgid(dgid); 486: if (setuid(duid) < 0) 487: (void) umask(0); 488: else 489: (void) umask(perm&N_UMASK); 490: (void) execlp("mkdir", "mkdir", path, (char *)NULL); 491: perror(path); 492: _exit(1); 493: } 494: return status; 495: } 496: #endif /* !BSD4_2 && ! BSD4_1C */ 497: #ifndef USG 498: char * 499: strpbrk(str, chars) 500: register char *str, *chars; 501: { 502: register char *cp; 503: 504: do { 505: cp = chars - 1; 506: while (*++cp) { 507: if (*str == *cp) 508: return str; 509: } 510: } while (*str++); 511: return NULL; 512: } 513: #endif /* !USG */ 514: 515: #ifdef FASCIST 516: /* 517: * This routine checks to see if the posting user is allowed to 518: * post to the given newsgroup. If the username is not in the file 519: * $LIBDIR/authorized then the default in the symbol FASCIST is used. 520: * 521: * Format of the call: 522: * fascist(user, newgroups) 523: * 524: * Returns: 525: * FALSE, if authorized 526: * TRUE, if not 527: * 528: * Format of the file "authorized" is: 529: * user:allowed groups 530: * 531: * Example: 532: * root:net.all,mod.all 533: * naughty_person:junk,net.politics 534: * operator:!net.all,general,test,mod.unix 535: * 536: * An open environment could have FASCIST set to "all" 537: * and then individual entries could be made in the authorized file 538: * to prevent certain individuals from posting to such a wide 539: * area. 540: * 541: * Note that a distribution of "all" does NOT mean to allow postings 542: * only to local groups -- "all" includes "all.all". 543: * Use "all,!all.all" to get this behavior 544: * 545: * Eugene Spafford spaf@gatech May 22, 1985 546: */ 547: 548: fascist(user, newsgroups) 549: register char *user, *newsgroups; 550: { 551: FILE *facfd; 552: char facuser[BUFLEN], facgroups[BUFLEN], factemp[BUFLEN]; 553: register char *facptr; 554: 555: /* First, open the necessary file...$LIBDIR/authorized and see if there 556: * is an entry for this user 557: */ 558: 559: (void) strncpy(facgroups, FASCIST, BUFLEN); 560: sprintf(factemp, "%s/%s", LIBDIR, "authorized"); 561: facfd = fopen(factemp, "r"); 562: 563: if (facfd != NULL) { /* If no such file, we go with the global default */ 564: while (fscanf(facfd, "%[^:]:%s\n", facuser, factemp) != EOF) 565: if (strncmp(facuser, user, BUFLEN) == 0) { 566: (void) strcat(facgroups, ","); 567: (void) strcat(facgroups, factemp); 568: break; 569: } 570: fclose (facfd); 571: } 572: #ifdef DEBUG 573: fprintf(stderr, "facgroups = %s\n", facgroups); 574: fprintf(stderr, "newsgroups = %s\n", newsgroups); 575: #endif DEBUG 576: 577: /* We step through the newsgroups being posted to and check each against 578: * the restriction list. *ALL* posted groups must match the restriction 579: * list or we don't allow the posting. 580: */ 581: 582: while (*newsgroups != '\0') { 583: facptr = factemp; 584: while (*newsgroups != '\0' && *newsgroups != NGDELIM) 585: *facptr++ = *newsgroups++; 586: *facptr = '\0'; 587: if (*newsgroups == NGDELIM) 588: newsgroups++; 589: 590: #ifdef DEBUG 591: fprintf(stderr, "Checking newsgroup '%s'\n", factemp); 592: #endif 593: 594: if (ngmatch(factemp, facgroups) == FALSE) 595: return TRUE; 596: } 597: 598: /* must be okay -- return */ 599: #ifdef DEBUG 600: fprintf (stderr, "Newsgroups approved for this poster.\n"); 601: #endif DEBUG 602: return FALSE; 603: } 604: #endif FASCIST