|
|
1.1 root 1: /* /sccs/src/cmd/uucp/s.permission.c
2: permission.c 1.3 8/30/84 17:37:34
3: */
4: #ifndef UUCHECK
5: #include "uucp.h"
6: VERSION(@(#)permission.c 1.3);
7: #endif
8:
9:
10: /* field array indexes for PERMISSIONS parameters */
11: #define U_LOGNAME 0
12: #define U_MACHINE 1
13: #define U_CALLBACK 2
14: #define U_REQUEST 3
15: #define U_SENDFILES 4
16: #define U_READPATH 5
17: #define U_WRITEPATH 6
18: #define U_NOREADPATH 7
19: #define U_NOWRITEPATH 8
20: #define U_MYNAME 9
21: #define U_COMMANDS 10
22: #define U_VALIDATE 11
23: #define U_PUBDIR 12
24: /* NUMFLDS should be one more than the highest U_ value */
25: #define NUMFLDS 13
26:
27: /* fields found in PERMISSIONS for requested system/login */
28: static char *_Flds[NUMFLDS];
29:
30: /* keyword/value structure */
31: struct keywords {
32: char* kword;
33: int kvalue;
34: };
35: static struct keywords _Kwords[] = {
36: {"LOGNAME", U_LOGNAME},
37: {"MACHINE", U_MACHINE},
38: {"CALLBACK", U_CALLBACK},
39: {"REQUEST", U_REQUEST},
40: {"SENDFILES", U_SENDFILES},
41: {"READ", U_READPATH},
42: {"WRITE", U_WRITEPATH},
43: {"NOREAD", U_NOREADPATH},
44: {"NOWRITE", U_NOWRITEPATH},
45: {"MYNAME", U_MYNAME},
46: {"COMMANDS", U_COMMANDS},
47: {"VALIDATE", U_VALIDATE},
48: {"PUBDIR", U_PUBDIR},
49: };
50:
51: #define MAXCMDS 30
52: #define MAXPATHS 20
53:
54: /* for all options on paths - read, write, noread, nowrite */
55: static char *_RPaths[MAXPATHS+1];
56: static char *_WPaths[MAXPATHS+1];
57: static char *_NoRPaths[MAXPATHS+1];
58: static char *_NoWPaths[MAXPATHS+1];
59: static char *_Commands[MAXCMDS+1];
60: static char _Cmd_defaults[BUFSIZ];
61:
62: /* option variables */
63: static int _Request; /* TRUE can request, FALSE can not request files */
64: static int _Switch; /* FALSE requires a call back to send any files */
65: static int _CallBack; /* TRUE for call back for any transaction */
66: static char _MyName[MAXBASENAME+1]; /* Myname from PERMISSIONS file */
67: static char *_Pubdir = NULL; /* PUBDIR from PERMISSIONS file */
68:
69: struct name_value
70: {
71: char *name;
72: char *value;
73: };
74:
75: /* file pointer for PERMISSIONS */
76: static FILE *Fp = NULL;
77:
78: /* functions */
79: static char *next_token(), *nextarg();
80: static void fillFlds();
81: static int fillList();
82:
83: /*
84: * fill in fields for login name
85: * name - the login id
86: * rmtname - remote system name
87: *
88: * return:
89: * 0 -> found login name
90: * FAIL -> did not find login
91: */
92:
93: logFind(name, rmtname)
94: char *name, *rmtname;
95: {
96: int ret;
97: DEBUG(5, "logFind called (name: %s, ", name);
98: DEBUG(5, "rmtname: %s)\n", rmtname);
99:
100: ret = validateFind (rmtname);
101: if (ret == SUCCESS) { /* found VALIDATE entry */
102: ret = userFind (name, rmtname, U_VALIDATE);
103: if (ret) {
104: DEBUG(5, "machine/login match failed", "");
105: return(FAIL);
106: }
107: }
108: else
109: ret = userFind (name, "", U_LOGNAME);
110:
111: DEBUG(7, "_Request (%s), ",
112: requestOK() ? "TRUE" : "FALSE");
113: DEBUG(7, "_Switch (%s), ",
114: switchRole() ? "TRUE" : "FALSE");
115: DEBUG(7, "_CallBack (%s), ",
116: callBack() ? "TRUE" : "FALSE");
117: DEBUG(7, "_MyName (%s), ", _MyName);
118: return(ret);
119: }
120:
121: /*
122: * fill in fields for machine name
123: * return:
124: * 0 -> found machine name
125: * FAIL -> did not find machine
126: */
127:
128: mchFind(name)
129: char *name;
130: {
131: register i, ret;
132: DEBUG(5, "mchFind called (%s)\n", name);
133: if ( (ret = userFind (name, "", U_MACHINE)) == FAIL)
134: /* see if there is a default line */
135: (void) userFind ("OTHER", "", U_MACHINE);
136:
137: /* mchFind is from MASTER mode - switch role is always ok */
138: _Switch = TRUE;
139:
140: DEBUG(7, "_Request (%s), ",
141: requestOK() ? "TRUE" : "FALSE");
142: DEBUG(7, "_Switch (%s), ",
143: switchRole() ? "TRUE" : "FALSE");
144: DEBUG(7, "_CallBack (%s), ",
145: callBack() ? "TRUE" : "FALSE");
146: DEBUG(7, "_MyName (%s), ", _MyName);
147: for (i=0; _Commands[i] != NULL; i++)
148: DEBUG(7, "_Commands %s\n", _Commands[i]);
149: return(ret);
150: }
151:
152: /*
153: * this function will find a login name in the LOGNAME
154: * field.
155: * input:
156: * name -> who the remote says he/she is
157: * return:
158: * SUCCESS -> found
159: * FAIL -> not found
160: */
161: static
162: int
163: nameMatch(name, fld)
164: char *name, *fld;
165: {
166: char *arg;
167:
168: if (fld == NULL)
169: return(FAIL);
170:
171: while (*fld) {
172: fld = nextarg(fld, &arg);
173: if (EQUALS(arg, name))
174: return(SUCCESS);
175: }
176: return (FAIL);
177: }
178:
179:
180: /*
181: * interpret the _Flds options and set the option variables
182: */
183: static
184: void
185: fillFlds()
186: {
187:
188: if (EQUALS(_Flds[U_REQUEST], "yes"))
189: _Request = TRUE;
190: else
191: _Request = FALSE;
192:
193: if (EQUALS(_Flds[U_SENDFILES], "yes"))
194: _Switch = TRUE;
195: else
196: _Switch = FALSE;
197:
198: if (EQUALS(_Flds[U_CALLBACK], "yes"))
199: _CallBack = TRUE;
200: else
201: _CallBack = FALSE;
202:
203: if (_Flds[U_MYNAME] != NULL) {
204: strncpy(_MyName, _Flds[U_MYNAME], MAXBASENAME);
205: _MyName[MAXBASENAME] = NULLCHAR;
206: }
207: else
208: *_MyName = NULLCHAR;
209:
210: if (_Flds[U_PUBDIR] != NULL) {
211: if (_Pubdir != NULL)
212: free(_Pubdir); /* get rid of previous one */
213: _Pubdir = malloc(strlen(_Flds[U_PUBDIR])+1);
214: #ifndef UUCHECK
215: ASSERT(_Pubdir != NULL, Ct_ALLOCATE, _Flds[U_PUBDIR], 0);
216: #else
217: if (_Pubdir == NULL) {
218: (void) fprintf(stderr, "malloc() error\n");
219: exit(1);
220: }
221: #endif
222: strcpy(_Pubdir, _Flds[U_PUBDIR]);
223: Pubdir = _RPaths[0] = _WPaths[0] = _Pubdir; /* reset default */
224: }
225: else
226: Pubdir = PUBDIR;
227:
228: return;
229: }
230:
231: /*
232: * fill in the list vector for the system/login
233: * input:
234: * type - list type (read, write, noread, nowrite, command)
235: * output:
236: * list - filled in with items.
237: * return:
238: * number of items in list
239: */
240: static
241: fillList(type, list)
242: int type;
243: char *list[];
244: {
245: register char *p;
246: register num;
247: int maxlist = 0;
248:
249: p = _Flds[type];
250:
251: /* find list limit */
252: if (type == U_READPATH || type == U_WRITEPATH
253: || type == U_NOREADPATH || type == U_NOWRITEPATH)
254: maxlist = MAXPATHS;
255: else if (type == U_COMMANDS)
256: maxlist = MAXCMDS;
257:
258: if (p == NULL || !*p) {
259: /* no names specified, default already setup */
260: return(0);
261: }
262:
263: num = 0;
264: while (*p && num < maxlist) {
265: list[num] = p;
266: if (*p == ':') { /* null path */
267: *p++ = NULLCHAR;
268: continue;
269: }
270: while (*p && *p != ':')
271: p++;
272: if (*p == ':')
273: *p++ = NULLCHAR;
274: DEBUG(7, "list (%s) ", list[num]);
275: num++;
276: }
277: DEBUG(7, "num = %d\n", num);
278: list[num] = NULL;
279: return(num);
280: }
281:
282: /*
283: * Find the line of PERMISSIONS for login.
284: * The search is determined by the type field
285: * (type=U_LOGNAME, U_MACHINE or U_VALIDATE)
286: * For U_LOGNAME:
287: * search for "name" in a LOGNAME= option
288: * For U_MACHINE:
289: * search for "name" in a MACHINE= option
290: * For U_VALIDATE:
291: * search for "rmtname" in a VALIDATE= option and
292: * for the same entry see if "name" is in the LOGNAME= option
293: * input:
294: * name -> search name
295: * logname -> for validate entry
296: * type -> U_MACHINE or U_LOGNAME
297: * output:
298: * The global values of all options will be set
299: * (e.g. _RPaths, _WPaths, _Request, ...)
300: * return:
301: * 0 -> ok
302: * FAIL -> no match found
303: */
304: static
305: userFind(name, rmtname, type)
306: char *name, *rmtname;
307: int type;
308: {
309: char *p, *arg;
310:
311: /* initialize permission variables in case line is not found */
312: _Request = FALSE;
313: _CallBack = FALSE;
314: _Switch = FALSE;
315: _MyName[0] = NULLCHAR;
316: _RPaths[0] = _WPaths[0] = PUBDIR; /* default is public */
317: _RPaths[1] = _WPaths[1] = NULLCHAR;
318: /* set up Commands defaults */
319: _Flds[U_COMMANDS] = strcpy(_Cmd_defaults, DEFAULTCMDS);
320: fillList(U_COMMANDS, _Commands);
321:
322: if (name == NULL) /* use defaults */
323: return(0); /* I don't think this will ever happen */
324:
325: if ( (Fp = fopen(PFILE, "r")) == NULL) {
326: DEBUG(5, "can't open %s\n", PFILE);
327: return(FAIL);
328: }
329:
330: for (;;) {
331: if (parse_tokens (_Flds) != 0) {
332: (void) fclose(Fp);
333: DEBUG(5, "name (%s) not found; return FAIL\n", name);
334: return(FAIL);
335: }
336:
337: p = _Flds[type];
338: while (p && *p) {
339: p = nextarg(p, &arg);
340: switch (type) {
341: case U_VALIDATE:
342: if (EQUALS(arg, rmtname)
343: && nameMatch(name, _Flds[U_LOGNAME])==SUCCESS)
344: break;
345: continue;
346:
347: case U_LOGNAME:
348: if (EQUALS(arg, name))
349: break;
350: continue;
351:
352: case U_MACHINE:
353: if (EQUALSN(arg, name, SYSNSIZE))
354: break;
355: continue;
356: }
357:
358: (void) fclose(Fp);
359: fillFlds();
360:
361: /* fill in path lists */
362: fillList(U_READPATH, _RPaths);
363: fillList(U_WRITEPATH, _WPaths);
364: if (!requestOK())
365: _Flds[U_NOREADPATH] = "/";
366: fillList(U_NOREADPATH, _NoRPaths);
367: fillList(U_NOWRITEPATH, _NoWPaths);
368:
369: /* fill in command list */
370: fillList(U_COMMANDS, _Commands);
371:
372: return(0);
373: }
374: }
375: }
376:
377: /*
378: * see if name is in a VALIDATE option
379: * return:
380: * FAIL -> not found
381: * SUCCESS -> found
382: */
383: static
384: int
385: validateFind(name)
386: char *name;
387: {
388:
389: if ( (Fp = fopen(PFILE, "r")) == NULL) {
390: DEBUG(5, "can't open %s\n", PFILE);
391: return(FAIL);
392: }
393:
394: for (;;) {
395: if (parse_tokens (_Flds) != 0) {
396: DEBUG(5, "validateFind (%s) FAIL\n", name);
397: (void) fclose(Fp);
398: return(FAIL);
399: }
400:
401: if (_Flds[U_VALIDATE] == NULL)
402: continue;
403: if (nameMatch(name, _Flds[U_VALIDATE])==SUCCESS) {
404: (void) fclose(Fp);
405: return (SUCCESS);
406: }
407: }
408:
409: }
410:
411:
412: /*
413: * parse a line in PERMISSIONS and return a vector
414: * of fields (flds)
415: *
416: * return:
417: * 0 - OK
418: * EOF - at end of file
419: */
420: parse_tokens (flds)
421: char *flds[];
422: {
423: register i;
424: register char *p;
425: struct name_value pair;
426: static char line[BUFSIZ];
427:
428: /* initialize defaults in case parameter is not specified */
429: for (i=0;i<NUMFLDS;i++)
430: flds[i] = NULL;
431:
432: if (getuline(line) == 0)
433: return(EOF);
434:
435: for (p=line;p && *p;) {
436: p = next_token (p, &pair);
437:
438: for (i=0; i<NUMFLDS; i++) {
439: if (EQUALS(pair.name, _Kwords[i].kword)) {
440: flds[i] = pair.value;
441: break;
442: }
443: }
444: #ifndef UUCHECK
445: ASSERT(i<NUMFLDS, "PERMISSIONS file: BAD OPTION--",
446: pair.name, NUMFLDS);
447: #else
448: if (i >= NUMFLDS) {
449: DEBUG(3, "bad option (%s) in PERMISSIONS\n",pair.name);
450: (void) printf("\n*****************************\n");
451: (void) printf("**BAD OPTION in PERMISSIONS file: %s\n",
452: pair.name);
453: (void) printf("*****************************\n");
454: Uerrors++;
455: return(0);
456: }
457: #endif
458:
459: }
460: return(0);
461: }
462:
463: /*
464: * return a name value pair
465: * string -> input pointer
466: * pair -> name value pair
467: * return:
468: * pointer to next character
469: */
470: static
471: char *
472: next_token (string, pair)
473: register char *string;
474: struct name_value *pair;
475: {
476:
477: while ( (*string) && ((*string == '\t') || (*string == ' ')) )
478: string++;
479:
480: pair->name = string;
481: while ((*string) && (*string != '='))
482: string++;
483: if (*string)
484: *string++ = NULLCHAR;
485:
486: pair->value = string;
487: while ((*string) && (*string != '\t') && (*string != ' ')
488: && (*string != '\n'))
489: string++;
490:
491: if (*string)
492: *string++ = NULLCHAR;
493:
494: return (string);
495: }
496:
497: /*
498: * get a line from the PERMISSIONS
499: * take care of comments (#) in col 1
500: * and continuations (\) in last col
501: * return:
502: * len of line
503: * 0 -> end of file
504: */
505: getuline(line)
506: char *line;
507: {
508: register char *p, *c;
509: char buf[BUFSIZ];
510:
511: p = line;
512: for (;fgets(buf, BUFSIZ, Fp) != NULL;) {
513: /* remove trailing white space */
514: c = &buf[strlen(buf)-1];
515: while (c>=buf && (*c == '\n' || *c == '\t' || *c == ' ') )
516: *c-- = NULLCHAR;
517:
518: if (buf[0] == '#' || buf[0] == '\n' || buf[0] == NULLCHAR)
519: continue;
520: (void) strcpy(p, buf);
521: p += strlen(buf);
522: if ( *(p-1) == '\\')
523: p--;
524: else
525: break;
526: }
527:
528: return(p-line);
529: }
530:
531:
532: #define SMAX 15
533:
534: /*
535: * get the next colon separated argument from the list
536: * return:
537: * p -> pointer to next arg in string
538: * input:
539: * str -> pointer to input string
540: * output:
541: * name -> pointer to arg string
542: */
543: static
544: char *
545: nextarg(str, name)
546: char *str, **name;
547: {
548: register char *p, *b;
549: static char buf[SMAX+1];
550:
551: for(b=buf,p=str; *p != ':' && *p && b < buf+SMAX;)
552: *b++ = *p++;
553: *b++ = NULLCHAR;
554: if (*p == ':')
555: p++;
556: *name = buf;
557: return(p);
558: }
559:
560: /*
561: * check if requesting files is permitted
562: * return
563: * TRUE -> request permitted
564: * FALSE -> request denied
565: */
566: requestOK()
567: {
568: return(_Request);
569: }
570:
571: /*
572: * myName - return my name from PERMISSIONS file
573: * or if not there, from uucpname()
574: * return: none
575: */
576:
577: void
578: myName(name)
579: char *name;
580: {
581: if (*_MyName)
582: strcpy(name, _MyName);
583: else
584: uucpname(name);
585: return;
586: }
587:
588: /*
589: * check for callback required for any transaction
590: * return:
591: * TRUE -> callback required
592: * FALSE-> callback NOT required
593: */
594: callBack()
595: {
596: return(_CallBack);
597: }
598:
599: /*
600: * check for callback to send any files from here
601: * This means that the called (SLAVE) system will not switch roles.
602: * return:
603: * TRUE -> callback requried to send files
604: * FALSE-> callback NOT required to send files
605: */
606: switchRole()
607: {
608: return(_Switch);
609: }
610:
611: /*
612: * Check to see if command is valid for a specific machine.
613: * The PERMISSIONS file has an option XQT=name1:name2:... for
614: * any machine that does not have the default list which is
615: * rmail:rnews
616: * Note that the PERMISSIONS file is read once for each system
617: * at the time the Rmtname is set in xprocess().
618: * Return codes:
619: * ok: TRUE
620: * fail: FALSE
621: */
622: cmdOK(cmd, fullcmd)
623: char *cmd, *fullcmd;
624: {
625: DEBUG(7, "cmdOK(%s, )\n", cmd);
626: return(cmdMatch(cmd, fullcmd));
627: }
628:
629:
630: /*
631: * check a name against a list
632: * input:
633: * name -> name
634: * list -> list of names
635: * return:
636: * TRUE -> found path
637: * FALSE -> not found
638: */
639: static
640: int
641: listMatch(name, list)
642: register char *name, *list[];
643: {
644: register i;
645:
646: for (i=0; list[i] != NULL; i++)
647: if (PREFIX(list[i], name))
648: return(TRUE);
649: return(FALSE);
650: }
651:
652:
653: /*
654: * Check "name" against a BASENAME or full name of _Commands list.
655: * If "name" specifies full path, check full, else check BASENAME.
656: * e.g. "name" rmail matches list item /usr/bin/rmail
657: * input:
658: * name -> name
659: * output:
660: * fullname -> copy full command name into fullname if
661: * a full path was specified in _Commands;
662: * if not, put name into fullname.
663: * return:
664: * TRUE -> found path
665: * FALSE -> not found
666: */
667: static
668: cmdMatch(name, fullname)
669: register char *name;
670: char *fullname;
671: {
672: register i;
673: char *bname;
674: int allok = FALSE;
675:
676: for (i=0; _Commands[i] != NULL; i++) {
677: if (EQUALS(_Commands[i], "ALL")) {
678: /* if ALL specified in the list
679: * set allok and continue in case
680: * a full path name is specified for the command
681: */
682: allok = TRUE;
683: continue;
684: }
685: if (name[0] != '/')
686: bname = BASENAME(_Commands[i], '/');
687: else
688: bname = _Commands[i];
689: DEBUG(7, "bname=%s\n", bname);
690: if (EQUALS(bname, name)) {
691: (void) strcpy(fullname, _Commands[i]);
692: return(TRUE);
693: }
694: }
695: if (allok == TRUE) {
696: /* ALL was specified and the command was not found in list */
697: (void) strcpy(fullname, name);
698: return(TRUE);
699: }
700: (void) strcpy(fullname, "NuLL"); /* this is a dummy command */
701: return(FALSE);
702: }
703:
704:
705: /*
706: * check the paths for this login/machine
707: * input:
708: * path pathname
709: * flag CK_READ or CK_WRITE
710: * output:
711: * path may be modified to canonical form
712: * (../, ./, // will be interpreted/removed)
713: * returns:
714: * 0 -> success
715: * FAIL -> failure - not a valid path for access
716: */
717: chkpth(path, flag)
718: char *path;
719: {
720: register char *s;
721:
722: /*
723: * this is probably redundant,
724: * because expfile did it, but that's ok
725: * Note - the /../ check is not required because of canPath
726: */
727: if (canPath(path) == FAIL)
728: return(FAIL);
729:
730: if (flag == CK_READ)
731: if (listMatch(path, _RPaths)
732: && !listMatch(path, _NoRPaths))
733: return(0);
734: if (flag == CK_WRITE)
735: if (listMatch(path, _WPaths)
736: && !listMatch(path, _NoWPaths))
737: return(0);
738:
739:
740: /* ok if uucp generated D. or X. name for the spool directory */
741: if (PREFIX(RemSpool, path) ) {
742: s = &path[strlen(RemSpool)];
743: if ( (*s++ == '/')
744: && (*s == DATAPRE || *s == XQTPRE)
745: && (*(++s) == '.')
746: && (strchr(s, '/') == NULL) )
747: return(0);
748: }
749:
750: /* path name not valid */
751: return(FAIL);
752: }
753:
754: /*
755: * check write permission of file.
756: * if mopt != NULL and permissions are ok,
757: * a side effect of this routine is to make
758: * directories up to the last part of the
759: * "to" ( if they do not exit).
760: * Input:
761: * to - a path name of the destination file or directory
762: * from - full path name of source file
763: * opt - create directory option (NULL - don't create)
764: * Output:
765: * to - will be the full path name of the destination file
766: * returns:
767: * 0 ->success
768: * FAIL -> failure
769: */
770: chkperm(from, to, opt)
771: char *from, *to, *opt;
772: {
773: register char *lxp, *p;
774: struct stat s;
775: char dir[MAXFULLNAME];
776:
777: if ( *(p = LASTCHAR(to)) == '/')
778: (void) strcpy(p+1, BASENAME(from, '/'));
779: else
780: if (DIRECTORY(to)) {
781: *++p = '/';
782: (void) strcpy(p+1, BASENAME(from, '/'));
783: }
784:
785: /* to is now the full path name of the destination file */
786:
787: if (WRITEANY(to))
788: return(0);
789: if (stat(to, &s) == 0)
790: return(FAIL); /* file exists, but not writeable */
791:
792: /* file does not exist--check directory and make when necessary */
793:
794: (void) strcpy(dir, to);
795: if ( (lxp=strrchr(dir, '/')) == NULL)
796: return(FAIL); /* no directory part of name */
797: if (lxp == dir) /* at root */
798: lxp++;
799: *lxp = NULLCHAR;
800:
801: if (!DIRECTORY(dir)) {
802: if (opt == NULL)
803: return(FAIL); /* no directory and no opt to make them */
804: else if (mkdirs(dir) == FAIL)
805: return(FAIL);
806: }
807:
808: /* the directory now exists--check for writability */
809: if (EQUALS(RemSpool, dir) || WRITEANY(dir))
810: return(0);
811:
812: return(FAIL);
813: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.