|
|
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: * funcs - functions used by many programs
16: */
17:
18: #ifdef SCCSID
19: static char *SccsId = "@(#)funcs.c 2.36 10/7/87";
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: /* this may NOT be a vfork */
141: while ((pid = fork()) == -1)
142: sleep((unsigned)1);
143: if (pid == 0) {
144: (*f)(s1, s2);
145: exit(0);
146: }
147: return pid;
148: }
149:
150: /*
151: * Wait on a child process.
152: */
153: fwait(pid)
154: register int pid;
155: {
156: register int w;
157: int status;
158: int (*onhup)(), (*onint)();
159:
160: onint = signal(SIGINT, SIG_IGN);
161: onhup = signal(SIGHUP, SIG_IGN);
162: while ((w = wait(&status)) != pid && w != -1)
163: ;
164: if (w == -1)
165: status = -1;
166: (void) signal(SIGINT, onint);
167: (void) signal(SIGHUP, onhup);
168: return status;
169: }
170:
171: /*
172: * Strip trailing newlines, blanks, and tabs from 's'.
173: * Return TRUE if newline was found, else FALSE.
174: */
175: nstrip(s)
176: register char *s;
177: {
178: register char *p;
179: register int rc;
180:
181: rc = FALSE;
182: p = s;
183: while (*p)
184: if (*p++ == '\n')
185: rc = TRUE;
186: while (--p >= s && (*p == '\n' || *p == ' ' || *p == '\t'));
187: *++p = '\0';
188: return rc;
189: }
190:
191: /*
192: * Local open routine.
193: */
194: FILE *
195: xfopen(name, fmode)
196: register char *name, *fmode;
197: {
198: register FILE *fp;
199: char *fname;
200: extern int errno;
201:
202: if ((fp = fopen(name, fmode)) == NULL) {
203: #ifdef IHCC
204: /*
205: * IHCC users only see the "filename" that was in trouble,
206: * not the whole path. (for security!)
207: */
208: fname = rindex(name, '/') + 1;
209: #else
210: fname = name;
211: #endif
212: xerror("Cannot open %s (%s): %s", fname, fmode, errmsg(errno));
213: }
214: /* kludge for setuid not being honored for root */
215: if ((uid == 0) && (duid != 0) && ((*fmode == 'a') || (*fmode == 'w')))
216: (void) chown(name, duid, dgid);
217: return fp;
218: }
219:
220: char *
221: errmsg(code)
222: int code;
223: {
224: extern int sys_nerr;
225: extern char *sys_errlist[];
226: static char ebuf[6+5+1];
227:
228: if (code > sys_nerr) {
229: (void) sprintf(ebuf, "Error %d", code);
230: return ebuf;
231: } else
232: return sys_errlist[code];
233: }
234: /* From UC Berkeley @(#)strcasecmp.c 1.3 (Berkeley) 8/3/87 */
235:
236: /*
237: * This array is designed for mapping upper and lower case letter
238: * together for a case independent comparison. The mappings are
239: * based upon ascii character sequences.
240: */
241: char charmap[] = {
242: '\000', '\001', '\002', '\003', '\004', '\005', '\006', '\007',
243: '\010', '\011', '\012', '\013', '\014', '\015', '\016', '\017',
244: '\020', '\021', '\022', '\023', '\024', '\025', '\026', '\027',
245: '\030', '\031', '\032', '\033', '\034', '\035', '\036', '\037',
246: '\040', '\041', '\042', '\043', '\044', '\045', '\046', '\047',
247: '\050', '\051', '\052', '\053', '\054', '\055', '\056', '\057',
248: '\060', '\061', '\062', '\063', '\064', '\065', '\066', '\067',
249: '\070', '\071', '\072', '\073', '\074', '\075', '\076', '\077',
250: '\100', '\141', '\142', '\143', '\144', '\145', '\146', '\147',
251: '\150', '\151', '\152', '\153', '\154', '\155', '\156', '\157',
252: '\160', '\161', '\162', '\163', '\164', '\165', '\166', '\167',
253: '\170', '\171', '\172', '\133', '\134', '\135', '\136', '\137',
254: '\140', '\141', '\142', '\143', '\144', '\145', '\146', '\147',
255: '\150', '\151', '\152', '\153', '\154', '\155', '\156', '\157',
256: '\160', '\161', '\162', '\163', '\164', '\165', '\166', '\167',
257: '\170', '\171', '\172', '\173', '\174', '\175', '\176', '\177',
258: '\200', '\201', '\202', '\203', '\204', '\205', '\206', '\207',
259: '\210', '\211', '\212', '\213', '\214', '\215', '\216', '\217',
260: '\220', '\221', '\222', '\223', '\224', '\225', '\226', '\227',
261: '\230', '\231', '\232', '\233', '\234', '\235', '\236', '\237',
262: '\240', '\241', '\242', '\243', '\244', '\245', '\246', '\247',
263: '\250', '\251', '\252', '\253', '\254', '\255', '\256', '\257',
264: '\260', '\261', '\262', '\263', '\264', '\265', '\266', '\267',
265: '\270', '\271', '\272', '\273', '\274', '\275', '\276', '\277',
266: '\300', '\341', '\342', '\343', '\344', '\345', '\346', '\347',
267: '\350', '\351', '\352', '\353', '\354', '\355', '\356', '\357',
268: '\360', '\361', '\362', '\363', '\364', '\365', '\366', '\367',
269: '\370', '\371', '\372', '\333', '\334', '\335', '\336', '\337',
270: '\340', '\341', '\342', '\343', '\344', '\345', '\346', '\347',
271: '\350', '\351', '\352', '\353', '\354', '\355', '\356', '\357',
272: '\360', '\361', '\362', '\363', '\364', '\365', '\366', '\367',
273: '\370', '\371', '\372', '\373', '\374', '\375', '\376', '\377',
274: };
275:
276: strcasecmp(s1, s2)
277: register char *s1, *s2;
278: {
279: register char *cm = charmap;
280:
281: while (cm[*s1] == cm[*s2++])
282: if (*s1++ == '\0')
283: return 0;
284: return cm[*s1] - cm[*--s2];
285: }
286:
287: strncasecmp(s1, s2, n)
288: register char *s1, *s2;
289: register int n;
290: {
291: register char *cm = charmap;
292:
293: while (--n >= 0 && cm[*s1] == cm[*s2++])
294: if (*s1++ == '\0')
295: return 0;
296: return n < 0 ? 0 : cm[*s1] - cm[*--s2];
297: }
298:
299: prefix(full, pref)
300: register char *full, *pref;
301: {
302: register char *cm = charmap;
303:
304: while (*pref != '\0') {
305: if (cm[*full++] != cm[*pref++])
306: return FALSE;
307: }
308: return TRUE;
309: }
310:
311: char *
312: dirname(ngname)
313: char *ngname;
314: {
315: static char rbuf[BUFLEN];
316: register char *p;
317:
318: (void) sprintf(rbuf, "%s/%s", SPOOL, ngname);
319:
320: for (p=rbuf+strlen(SPOOL); *p; p++)
321: if (*p == '.')
322: *p = '/';
323: return rbuf;
324: }
325:
326: /*
327: * Return TRUE iff ngname is a valid newsgroup name
328: */
329: validng(ngname)
330: char *ngname;
331: {
332: register FILE *fp;
333: register char *p, *q;
334: char abuf[BUFLEN];
335:
336: fp = xfopen(ACTIVE, "r");
337: while(fgets(abuf, BUFLEN, fp) != NULL) {
338: p = abuf;
339: q = ngname;
340: while (*p++ == *q++)
341: ;
342: if (*--q == '\0' && *--p == ' ') {
343: (void) fclose(fp);
344: return TRUE;
345: }
346: }
347: (void) fclose(fp);
348: return FALSE;
349: }
350:
351: /* VARARGS1 */
352: xerror(message, arg1, arg2, arg3)
353: char *message;
354: long arg1, arg2, arg3;
355: {
356: char buffer[LBUFLEN];
357:
358: fflush(stdout);
359: (void) sprintf(buffer, message, arg1, arg2, arg3);
360: logerr(buffer);
361: xxit(1);
362: }
363:
364: /* VARARGS1 */
365: log(fmt, a1, a2, a3, a4, a5, a6, a7, a8, a9)
366: char *fmt;
367: long a1, a2, a3, a4, a5, a6, a7, a8, a9;
368: {
369: _dolog(0, fmt, a1, a2, a3, a4, a5, a6, a7, a8, a9);
370: }
371:
372: /* VARARGS1 */
373: logerr(fmt, a1, a2, a3, a4, a5, a6, a7, a8, a9)
374: char *fmt;
375: long a1, a2, a3, a4, a5, a6, a7, a8, a9;
376: {
377: _dolog(1, fmt, a1, a2, a3, a4, a5, a6, a7, a8, a9);
378: }
379:
380: char *lfsuffix[] = {
381: "log",
382: "errlog",
383: NULL,
384: };
385:
386: /*
387: * Log the given message, with printf strings and parameters allowed,
388: * on the log file, if it can be written. The date and an attempt at
389: * figuring out the remote system name are also logged.
390: */
391: /* VARARGS1 */
392: _dolog(which, fmt, a1, a2, a3, a4, a5, a6, a7, a8, a9)
393: char *fmt;
394: long a1, a2, a3, a4, a5, a6, a7, a8, a9;
395: {
396: FILE *logfile;
397: register char *p, *logtime;
398: int i;
399: char logfname[BUFLEN]; /* the log file */
400: char rmtsys[BUFLEN];
401: char msg[LBUFLEN];
402: time_t t;
403:
404: (void) strcpy(rmtsys, header.path);
405: p = index(rmtsys, '!');
406: if (p == NULL)
407: p = index(rmtsys, ':');
408: if (p)
409: *p = 0;
410: else {
411: p = rindex(rmtsys, '@');
412: if (p)
413: (void) strcpy(rmtsys, p+1);
414: else
415: (void) strcpy(rmtsys, "local");
416: }
417:
418: (void) time(&t);
419: logtime = ctime(&t);
420: logtime[16] = 0;
421: logtime += 4;
422:
423:
424: (void) sprintf(msg, fmt, a1, a2, a3, a4, a5, a6, a7, a8, a9);
425:
426: if (which)
427: fprintf(stderr,"%s: %s\n", Progname, msg);
428:
429: for (i=0; i<=which;i++) {
430: (void) sprintf(logfname, "%s/%s", LIB, lfsuffix[i]);
431:
432: if (access(logfname, 0) == 0 && (logfile = fopen(logfname, "a")) != NULL) {
433: #if defined(USG) || defined(BSD4_2) || defined(BSD4_1C)
434: int flags;
435: flags = fcntl(fileno(logfile), F_GETFL, 0);
436: (void) fcntl(fileno(logfile), F_SETFL, flags|O_APPEND);
437: #else /* v7 */
438: (void) lseek(fileno(logfile), 0L, 2);
439: #endif /* v7 */
440: if (i)
441: fprintf(logfile, "%s\t%s\t%s: %s\n", logtime,
442: header.ident[0] ? header.ident : username, Progname, msg);
443: else
444: fprintf(logfile, "%s\t%s\t%s\n", logtime,
445: rmtsys, msg);
446: (void) fclose(logfile);
447: }
448: }
449: }
450: #ifdef VMS
451:
452: /*
453: * vmslink allows simulation of file linking under VMS.
454: */
455: vmslink(infile,outfile)
456: char *infile, *outfile;
457: {
458: FILE *fp;
459:
460: if (access(outfile,0) == 0) {
461: errno = EEXIST;
462: return -1;
463: }
464:
465: fp = fopen(outfile, "w");
466: if (fp == NULL) {
467: errno = EACCES;
468: return -1;
469: }
470:
471: (void) fprintf(fp, "%s", infile);
472: (void) fclose(fp);
473:
474: return 0;
475: }
476:
477: /*
478: * vmsdelete deletes all revisions of a file. It attempts to
479: * appear as unlink(2) under conventional Unix in other respects.
480: */
481: vmsdelete(file)
482: char *file;
483: {
484: int i;
485:
486: i = unlink(file);
487: if (i != 0)
488: return i;
489:
490: i = errno;
491: while (unlink(file) == 0)
492: ;
493: errno = i;
494:
495: return 0;
496: }
497:
498: /*
499: * Convert a Unix file to a VMS fixed record format file by
500: * executing the 'unixtovms' command.
501: */
502: unixtovms(file)
503: char *file;
504: {
505: char buf[BUFLEN];
506: sprintf(buf, "exec /etc/unixtovms %s", file);
507: return system(buf);
508: }
509:
510: /*
511: * Convert a VMS fixed record format file to a Unix file by
512: * executing the 'vmstounix' command.
513: */
514: vmstounix(file)
515: char *file;
516: {
517: char buf[BUFLEN];
518: sprintf(buf,"exec /etc/vmstounix %s", file);
519: return system(buf);
520: }
521: #endif /* VMS */
522:
523: #if !defined(BSD4_2) && !defined(BSD4_1C)
524: /*
525: * make a directory. Also make sure that the directory is owned
526: * by the right userid
527: */
528: mkdir(path, perm)
529: char *path;
530: int perm;
531: {
532: int pid, status;
533: #ifdef USG
534: char parent[200];
535: char *p;
536: struct stat sbuf;
537:
538: /*
539: * Make parent directory writable, because we will
540: * be creating a directory owned by the real user,
541: * rather than by news.
542: */
543: (void) strcpy(parent, path);
544: if (p = rindex(parent, '/')) {
545: *p = '\0';
546: if (stat(parent, &sbuf) == 0)
547: (void) chmod(parent, 0777);
548: else
549: return -1;
550: } else
551: return -1;
552: #endif
553:
554: if (pid=vfork()) {
555: status = fwait(pid);
556: #if defined(USG) && !defined(CHEAP)
557: if (pid=vfork())
558: (void) fwait(pid);
559: else {
560: setgid(gid);
561: setuid(uid);
562: if (chown(path, duid, dgid) == 0)
563: (void) chmod(path, perm&(~N_UMASK));
564: _exit(0);
565: }
566: #endif /* USG && !CHEAP */
567: } else {
568: (void) setgid(dgid);
569: if (setuid(duid) < 0)
570: (void) umask(0);
571: else
572: (void) umask(perm&N_UMASK);
573: (void) execlp("mkdir", "mkdir", path, (char *)NULL);
574: perror(path);
575: _exit(1);
576: }
577: #ifdef USG
578: (void) chmod(parent, sbuf.st_mode); /* Restore mode of parent */
579: #endif
580: return status;
581: }
582: #endif /* !BSD4_2 && ! BSD4_1C */
583: #ifndef USG
584: char *
585: strpbrk(str, chars)
586: register char *str, *chars;
587: {
588: register char *cp;
589:
590: do {
591: cp = chars - 1;
592: while (*++cp) {
593: if (*str == *cp)
594: return str;
595: }
596: } while (*str++);
597: return NULL;
598: }
599: #endif /* !USG */
600:
601: #ifdef FASCIST
602: /*
603: * This routine checks to see if the posting user is allowed to
604: * post to the given newsgroup. If the username is not in the file
605: * $LIBDIR/authorized then the default in the symbol FASCIST is used.
606: *
607: * Format of the call:
608: * fascist(user, newgroups)
609: *
610: * Returns:
611: * FALSE, if authorized
612: * TRUE, if not
613: *
614: * Format of the file "authorized" is:
615: * user:allowed groups
616: *
617: * Example:
618: * root:net.all,mod.all
619: * naughty_person:junk,net.politics
620: * operator:!net.all,general,test,mod.unix
621: *
622: * An open environment could have FASCIST set to "all"
623: * and then individual entries could be made in the authorized file
624: * to prevent certain individuals from posting to such a wide
625: * area.
626: *
627: * Note that a distribution of "all" does NOT mean to allow postings
628: * only to local groups -- "all" includes "all.all".
629: * Use "all,!all.all" to get this behavior
630: *
631: * Eugene Spafford spaf@gatech May 22, 1985
632: */
633:
634: fascist(user, newsgroups)
635: register char *user, *newsgroups;
636: {
637: FILE *facfd;
638: char facuser[BUFLEN], facgroups[BUFLEN], factemp[BUFLEN];
639: register char *facptr;
640:
641: /* First, open the necessary file...$LIBDIR/authorized and see if there
642: * is an entry for this user
643: */
644:
645: (void) strncpy(facgroups, FASCIST, BUFLEN);
646: sprintf(factemp, "%s/%s", LIB, "authorized");
647: facfd = fopen(factemp, "r");
648:
649: if (facfd != NULL) { /* If no such file, we go with the global default */
650: while (fscanf(facfd, "%[^:]:%s\n", facuser, factemp) != EOF)
651: {
652: if (feof(facfd))
653: break;
654: if (strncmp(facuser, user, BUFLEN) == 0) {
655: (void) strcat(facgroups, ",");
656: (void) strcat(facgroups, factemp);
657: break;
658: }
659: }
660: fclose (facfd);
661: }
662: #ifdef DEBUG
663: fprintf(stderr, "facgroups = %s\n", facgroups);
664: fprintf(stderr, "newsgroups = %s\n", newsgroups);
665: #endif /* DEBUG */
666:
667: /* We step through the newsgroups being posted to and check each against
668: * the restriction list. *ALL* posted groups must match the restriction
669: * list or we don't allow the posting.
670: */
671:
672: while (*newsgroups != '\0') {
673: facptr = factemp;
674: while (*newsgroups != '\0' && *newsgroups != NGDELIM)
675: *facptr++ = *newsgroups++;
676: *facptr = '\0';
677: if (*newsgroups == NGDELIM)
678: newsgroups++;
679:
680: #ifdef DEBUG
681: fprintf(stderr, "Checking newsgroup '%s'\n", factemp);
682: #endif
683:
684: if (ngmatch(factemp, facgroups) == FALSE)
685: return TRUE;
686: }
687:
688: /* must be okay -- return */
689: #ifdef DEBUG
690: fprintf (stderr, "Newsgroups approved for this poster.\n");
691: #endif /* DEBUG */
692: return FALSE;
693: }
694: #endif /* FASCIST */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.