|
DataMuseum.dkPresents historical artifacts from the history of: DKUUG/EUUG Conference tapes |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about DKUUG/EUUG Conference tapes Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - metrics - downloadIndex: T f
Length: 17661 (0x44fd) Types: TextFile Names: »funcs.c«
└─⟦9ae75bfbd⟧ Bits:30007242 EUUGD3: Starter Kit └─⟦373604645⟧ »EurOpenD3/news/bnews.2.11/src.tar.Z« └─⟦3beb569ac⟧ └─⟦this⟧ »src/funcs.c«
/* * This software is Copyright 1986, 1989 by Rick Adams. * * Permission is hereby granted to copy, reproduce, redistribute or * otherwise use this software as long as: there is no monetary * profit gained specifically from the use or reproduction or this * software, it is not sold, rented, traded or otherwise marketed, and * this copyright notice is included prominently in any copy * made. * * The author make no claims as to the fitness or correctness of * this software for any use whatsoever, and it is provided as is. * Any use of this software is at the user's own risk. * * funcs - functions used by many programs */ #ifdef SCCSID static char *SccsId = "@(#)funcs.c 2.39 1/15/89"; #endif /* SCCSID */ /*LINTLIBRARY*/ #include "params.h" #include <errno.h> #if defined(USG) || defined(BSD4_2) #include <fcntl.h> #endif /* !v7 */ #ifdef SYSLOG #include <sys/syslog.h> #ifndef LOG_NEWS LOG_NEWS is officially facility 7, please update your syslog.h #endif #endif extern char *Progname; /* * News group matching. * * nglist is a list of newsgroups. * sublist is a list of subscriptions. * sublist may have "meta newsgroups" in it. * All fields are NGDELIM separated, * and there is an NGDELIM at the end of each argument. * * Currently implemented glitches: * sublist uses 'all' like shell uses '*', and '.' like shell '/'. * If subscription X matches Y, it also matches Y.anything. */ ngmatch(nglist, sublist) register char *nglist, *sublist; { register char *n, *s; register int rc; rc = FALSE; for (n = nglist; *n != '\0' && rc == FALSE;) { for (s = sublist; *s != '\0';) { if (*s != NEGCHAR) rc = rc || ptrncmp(s, n); else rc = rc && !ptrncmp(s+1, n); while (*s++ != NGDELIM && *s != '\0') ; } while (*n++ != NGDELIM && *n != '\0') ; } return rc; } /* * Compare two newsgroups for equality. * The first one may be a "meta" newsgroup. */ ptrncmp(ng1, ng2) register char *ng1, *ng2; { while (*ng1 != NGDELIM && *ng1 != '\0') { if (ng1[0]=='a' && ng1[1]=='l' && ng1[2]=='l') { ng1 += 3; while (*ng2 != NGDELIM && *ng2 != '.' && *ng2 != '\0') if (ptrncmp(ng1, ng2++)) return(TRUE); return ptrncmp(ng1, ng2); } else if (*ng1++ != *ng2++) return FALSE; } return *ng2 == '.' || *ng2 == NGDELIM || *ng2 == '\0'; } /* * Exec the shell. * This version resets uid, gid, and umask. * Called with fsubr(ushell, s, NULL) */ /* ARGSUSED */ ushell(s, dummy) char *s, *dummy; { (void) umask(savmask); (void) setgid(gid); (void) setuid(uid); xshell(s); } /* * Exec the shell. */ #ifdef lint char **environ; #else /* !lint */ extern char **environ; #endif /* !lint */ xshell(s) char *s; { char *env[100], **envp; char a[BUFLEN + 2]; extern char filename[]; /* set $A */ (void) sprintf(a, "A=%s", filename); env[0] = a; for (envp = env + 1 ; *environ != NULL && envp < env + 98 ; environ++) if ((*environ)[0] != 'A' || (*environ)[1] != '=') *envp++ = *environ; *envp = NULL; execle(SHELL, SHELL, "-c", s, (char *)0, env); xerror("No shell!"); } /* * Fork and call a subroutine with two args. * Return pid without waiting. */ fsubr(f, s1, s2) int (*f)(); char *s1, *s2; { register int pid; /* this may NOT be a vfork */ while ((pid = fork()) == -1) sleep((unsigned)1); if (pid == 0) { (*f)(s1, s2); exit(0); } return pid; } /* * Wait on a child process. */ fwait(pid) register int pid; { register int w; int status; SIGNAL_TYPE onhup, onint; onint = (int (*)())signal(SIGINT, SIG_IGN); onhup = (int (*)())signal(SIGHUP, SIG_IGN); while ((w = wait(&status)) != pid && w != -1) ; if (w == -1) status = -1; (void) signal(SIGINT, onint); (void) signal(SIGHUP, onhup); return status; } /* * Strip trailing newlines, blanks, and tabs from 's'. * Return TRUE if newline was found, else FALSE. */ nstrip(s) register char *s; { register char *p; register int rc; rc = FALSE; p = s; while (*p) if (*p++ == '\n') rc = TRUE; while (--p >= s && (*p == '\n' || *p == ' ' || *p == '\t')); *++p = '\0'; return rc; } /* * Local open routine. */ FILE * xfopen(name, fmode) register char *name, *fmode; { register FILE *fp; char *fname; extern int errno; if ((fp = fopen(name, fmode)) == NULL) { #ifdef IHCC /* * IHCC users only see the "filename" that was in trouble, * not the whole path. (for security!) */ fname = rindex(name, '/') + 1; #else fname = name; #endif xerror("Cannot open %s (%s): %s", fname, fmode, errmsg(errno)); } /* kludge for setuid not being honored for root */ if ((uid == 0) && (duid != 0) && ((*fmode == 'a') || (*fmode == 'w'))) (void) chown(name, duid, dgid); return fp; } char * errmsg(code) int code; { extern int sys_nerr; extern char *sys_errlist[]; static char ebuf[6+5+1]; if (code > sys_nerr) { (void) sprintf(ebuf, "Error %d", code); return ebuf; } else return sys_errlist[code]; } /* From UC Berkeley @(#)strcasecmp.c 1.3 (Berkeley) 8/3/87 */ /* * This array is designed for mapping upper and lower case letter * together for a case independent comparison. The mappings are * based upon ascii character sequences. */ char charmap[] = { '\000', '\001', '\002', '\003', '\004', '\005', '\006', '\007', '\010', '\011', '\012', '\013', '\014', '\015', '\016', '\017', '\020', '\021', '\022', '\023', '\024', '\025', '\026', '\027', '\030', '\031', '\032', '\033', '\034', '\035', '\036', '\037', '\040', '\041', '\042', '\043', '\044', '\045', '\046', '\047', '\050', '\051', '\052', '\053', '\054', '\055', '\056', '\057', '\060', '\061', '\062', '\063', '\064', '\065', '\066', '\067', '\070', '\071', '\072', '\073', '\074', '\075', '\076', '\077', '\100', '\141', '\142', '\143', '\144', '\145', '\146', '\147', '\150', '\151', '\152', '\153', '\154', '\155', '\156', '\157', '\160', '\161', '\162', '\163', '\164', '\165', '\166', '\167', '\170', '\171', '\172', '\133', '\134', '\135', '\136', '\137', '\140', '\141', '\142', '\143', '\144', '\145', '\146', '\147', '\150', '\151', '\152', '\153', '\154', '\155', '\156', '\157', '\160', '\161', '\162', '\163', '\164', '\165', '\166', '\167', '\170', '\171', '\172', '\173', '\174', '\175', '\176', '\177', '\200', '\201', '\202', '\203', '\204', '\205', '\206', '\207', '\210', '\211', '\212', '\213', '\214', '\215', '\216', '\217', '\220', '\221', '\222', '\223', '\224', '\225', '\226', '\227', '\230', '\231', '\232', '\233', '\234', '\235', '\236', '\237', '\240', '\241', '\242', '\243', '\244', '\245', '\246', '\247', '\250', '\251', '\252', '\253', '\254', '\255', '\256', '\257', '\260', '\261', '\262', '\263', '\264', '\265', '\266', '\267', '\270', '\271', '\272', '\273', '\274', '\275', '\276', '\277', '\300', '\341', '\342', '\343', '\344', '\345', '\346', '\347', '\350', '\351', '\352', '\353', '\354', '\355', '\356', '\357', '\360', '\361', '\362', '\363', '\364', '\365', '\366', '\367', '\370', '\371', '\372', '\333', '\334', '\335', '\336', '\337', '\340', '\341', '\342', '\343', '\344', '\345', '\346', '\347', '\350', '\351', '\352', '\353', '\354', '\355', '\356', '\357', '\360', '\361', '\362', '\363', '\364', '\365', '\366', '\367', '\370', '\371', '\372', '\373', '\374', '\375', '\376', '\377', }; strcasecmp(s1, s2) register char *s1, *s2; { register char *cm = charmap; while (cm[*s1] == cm[*s2++]) if (*s1++ == '\0') return 0; return cm[*s1] - cm[*--s2]; } strncasecmp(s1, s2, n) register char *s1, *s2; register int n; { register char *cm = charmap; while (--n >= 0 && cm[*s1] == cm[*s2++]) if (*s1++ == '\0') return 0; return n < 0 ? 0 : cm[*s1] - cm[*--s2]; } prefix(full, pref) register char *full, *pref; { register char *cm = charmap; while (*pref != '\0') { if (cm[*full++] != cm[*pref++]) return FALSE; } return TRUE; } char * dirname(ngname) char *ngname; { static char rbuf[BUFLEN]; register char *p; (void) sprintf(rbuf, "%s/%s", SPOOL, ngname); for (p=rbuf+strlen(SPOOL); *p; p++) if (*p == '.') *p = '/'; return rbuf; } /* * Return TRUE iff ngname is a valid newsgroup name */ validng(ngname) char *ngname; { register FILE *fp; register char *p, *q; char abuf[BUFLEN]; fp = xfopen(ACTIVE, "r"); while(fgets(abuf, BUFLEN, fp) != NULL) { p = abuf; q = ngname; while (*p++ == *q++) ; if (*--q == '\0' && *--p == ' ') { (void) fclose(fp); return TRUE; } } (void) fclose(fp); return FALSE; } /* VARARGS1 */ xerror(message, arg1, arg2, arg3) char *message; long arg1, arg2, arg3; { char buffer[LBUFLEN]; fflush(stdout); (void) sprintf(buffer, message, arg1, arg2, arg3); logerr(buffer); xxit(1); } /* VARARGS1 */ log(fmt, a1, a2, a3, a4, a5, a6, a7, a8, a9) char *fmt; long a1, a2, a3, a4, a5, a6, a7, a8, a9; { _dolog(0, fmt, a1, a2, a3, a4, a5, a6, a7, a8, a9); } /* VARARGS1 */ logerr(fmt, a1, a2, a3, a4, a5, a6, a7, a8, a9) char *fmt; long a1, a2, a3, a4, a5, a6, a7, a8, a9; { _dolog(1, fmt, a1, a2, a3, a4, a5, a6, a7, a8, a9); } char *lfsuffix[] = { "log", "errlog", NULL, }; /* * Log the given message, with printf strings and parameters allowed, * on the log file, if it can be written. The date and an attempt at * figuring out the remote system name are also logged. */ /* VARARGS1 */ _dolog(which, fmt, a1, a2, a3, a4, a5, a6, a7, a8, a9) char *fmt; long a1, a2, a3, a4, a5, a6, a7, a8, a9; { FILE *logfile; register char *p, *logtime; int i; char logfname[BUFLEN]; /* the log file */ char rmtsys[BUFLEN]; char msg[LBUFLEN]; time_t t; (void) strcpy(rmtsys, header.path); p = index(rmtsys, '!'); if (p == NULL) p = index(rmtsys, ':'); if (p) *p = 0; else { p = rindex(rmtsys, '@'); if (p) (void) strcpy(rmtsys, p+1); else (void) strcpy(rmtsys, "local"); } (void) time(&t); logtime = ctime(&t); logtime[16] = 0; logtime += 4; (void) sprintf(msg, fmt, a1, a2, a3, a4, a5, a6, a7, a8, a9); #ifdef SYSLOG if (which ) { openlog(Progname, 0, LOG_NEWS); syslog(LOG_ERR, "%s %s\t%s", rmtsys, header.ident[0] ? header.ident : username, msg); } else { openlog(rmtsys, 0, LOG_NEWS); syslog(LOG_INFO, "%s\t%s", header.ident[0] ? header.ident : username, msg); } #else /* !SYSLOG */ if (which) fprintf(stderr,"%s: %s\n", Progname, msg); for (i=0; i<=which;i++) { (void) sprintf(logfname, "%s/%s", LIB, lfsuffix[i]); if (access(logfname, 0) == 0 && (logfile = fopen(logfname, "a")) != NULL) { #if defined(USG) || defined(BSD4_2) int flags; flags = fcntl(fileno(logfile), F_GETFL, 0); (void) fcntl(fileno(logfile), F_SETFL, flags|O_APPEND); #else /* v7 */ (void) lseek(fileno(logfile), 0L, 2); #endif /* v7 */ if (i) fprintf(logfile, "%s\t%s\t%s: %s\n", logtime, header.ident[0] ? header.ident : username, Progname, msg); else fprintf(logfile, "%s\t%s\t%s\n", logtime, rmtsys, msg); (void) fclose(logfile); } } #endif /* !SYSLOG */ } #ifdef VMS /* * vmslink allows simulation of file linking under VMS. */ vmslink(infile,outfile) char *infile, *outfile; { FILE *fp; if (access(outfile,0) == 0) { errno = EEXIST; return -1; } fp = fopen(outfile, "w"); if (fp == NULL) { errno = EACCES; return -1; } (void) fprintf(fp, "%s", infile); (void) fclose(fp); return 0; } /* * vmsdelete deletes all revisions of a file. It attempts to * appear as unlink(2) under conventional Unix in other respects. */ vmsdelete(file) char *file; { int i; i = unlink(file); if (i != 0) return i; i = errno; while (unlink(file) == 0) ; errno = i; return 0; } /* * Convert a Unix file to a VMS fixed record format file by * executing the 'unixtovms' command. */ unixtovms(file) char *file; { char buf[BUFLEN]; sprintf(buf, "exec /etc/unixtovms %s", file); return system(buf); } /* * Convert a VMS fixed record format file to a Unix file by * executing the 'vmstounix' command. */ vmstounix(file) char *file; { char buf[BUFLEN]; sprintf(buf,"exec /etc/vmstounix %s", file); return system(buf); } #endif /* VMS */ #ifndef MKDIRSUB /* * make a directory. Also make sure that the directory is owned * by the right userid */ mkdir(path, perm) char *path; int perm; { int pid, status; #ifdef USG char parent[200]; char *p; struct stat sbuf; /* * Make parent directory writable, because we will * be creating a directory owned by the real user, * rather than by news. */ (void) strcpy(parent, path); if (p = rindex(parent, '/')) { *p = '\0'; if (stat(parent, &sbuf) == 0) (void) chmod(parent, 0777); else return -1; } else return -1; #endif if (pid=vfork()) { status = fwait(pid); #if defined(USG) && !defined(CHEAP) if (pid=vfork()) (void) fwait(pid); else { setgid(gid); setuid(uid); if (chown(path, duid, dgid) == 0) (void) chmod(path, perm&(~N_UMASK)); _exit(0); } #endif /* USG && !CHEAP */ } else { (void) setgid(dgid); if (setuid(duid) < 0) (void) umask(0); else (void) umask(perm&N_UMASK); (void) execlp("mkdir", "mkdir", path, (char *)NULL); perror(path); _exit(1); } #ifdef USG (void) chmod(parent, sbuf.st_mode); /* Restore mode of parent */ #endif return status; } #endif /* !BSD4_2 */ #ifndef RENAMESUB rename(from,to) register char *from, *to; { (void) unlink(to); if (link(from, to) < 0) return -1; (void) unlink(from); return 0; } #endif /* !RENAMESUB */ #ifndef USG char * strpbrk(str, chars) register char *str, *chars; { register char *cp; do { cp = chars - 1; while (*++cp) { if (*str == *cp) return str; } } while (*str++); return NULL; } #endif /* !USG */ #ifdef FASCIST /* * This routine checks to see if the posting user is allowed to * post to the given newsgroup. If the username is not in the file * $LIBDIR/authorized then the default in the symbol FASCIST is used. * * Format of the call: * fascist(user, newgroups) * * Returns: * FALSE, if authorized * TRUE, if not * * Format of the file "authorized" is: * user:allowed groups * * Example: * root:net.all,mod.all * naughty_person:junk,net.politics * operator:!net.all,general,test,mod.unix * * An open environment could have FASCIST set to "all" * and then individual entries could be made in the authorized file * to prevent certain individuals from posting to such a wide * area. * * Note that a distribution of "all" does NOT mean to allow postings * only to local groups -- "all" includes "all.all". * Use "all,!all.all" to get this behavior * * Eugene Spafford spaf@gatech May 22, 1985 */ fascist(user, newsgroups) register char *user, *newsgroups; { FILE *facfd; char facuser[BUFLEN], facgroups[BUFLEN], factemp[BUFLEN]; char *getgrplist(); char *grplist = NULL; register char *facptr; /* First, open the necessary file...$LIBDIR/authorized and see if there * is an entry for this user */ (void) strncpy(facgroups, FASCIST, BUFLEN); sprintf(factemp, "%s/%s", LIB, "authorized"); facfd = fopen(factemp, "r"); if (facfd != NULL) { /* If no such file, use global default only */ while (fscanf(facfd, "%[^:]:%s\n", facuser, factemp) != EOF) { if (feof(facfd)) break; if (facuser[0] == '#') continue; if (facuser[0] == '\\') { if (!grplist) grplist = getgrplist(user); facptr = facuser; facptr++; if (ngmatch(facptr, grplist)) { (void) strcat(facgroups, ","); (void) strcat(facgroups, factemp); continue; } } else if (STRNCMP(facuser, user, BUFLEN) == 0) { (void) strcat(facgroups, ","); (void) strcat(facgroups, factemp); break; } } fclose (facfd); } #ifdef DEBUG fprintf(stderr, "facgroups = %s\n", facgroups); fprintf(stderr, "newsgroups = %s\n", newsgroups); #endif /* DEBUG */ /* We step through the newsgroups being posted to and check each against * the restriction list. *ALL* posted groups must match the restriction * list or we don't allow the posting. */ while (*newsgroups != '\0') { facptr = factemp; while (*newsgroups != '\0' && *newsgroups != NGDELIM) *facptr++ = *newsgroups++; *facptr = '\0'; if (*newsgroups == NGDELIM) newsgroups++; #ifdef DEBUG fprintf(stderr, "Checking newsgroup '%s'\n", factemp); #endif if (ngmatch(factemp, facgroups) == FALSE) return TRUE; } /* must be okay -- return */ #ifdef DEBUG fprintf (stderr, "Newsgroups approved for this poster.\n"); #endif /* DEBUG */ return FALSE; } #endif /* FASCIST */ /* This routine is meant to be called only once. On a system with a * large /etc/group file, this routine is a HOG!!!!! In order to save * ourselves from pain, this routine will look up groups for "user" * the first time. After that, it will always return the same results... */ char * getgrplist(user) register char *user; { register struct group *gr; register struct passwd *pw; register char **cp; register int len; static int grpdone = FALSE; static char grplist[LBUFLEN]; #ifdef DEBUG fprintf(stderr, "getgrplist entered...\n"); #endif /* DEBUG */ if (grpdone == FALSE) { #ifdef DEBUG fprintf(stderr, "... actually reading /etc/group...\n"); #endif /* DEBUG */ pw = getpwnam(user); setgrent(); while (gr = getgrent()) { if (pw) if (pw->pw_gid == gr->gr_gid) { strcat(grplist, gr->gr_name); strcat(grplist, ","); continue; } for (cp = gr->gr_mem; cp && *cp; cp++) if (STRCMP(*cp, user) == 0) { strcat(grplist, gr->gr_name); strcat(grplist, ","); break; } } if ((len = strlen(grplist))) grplist[len-1] = '\0'; grpdone = TRUE; } #ifdef DEBUG fprintf(stderr, "Group list - %s\n", grplist); #endif /* DEBUG */ return grplist; }