1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
7 * with the License.
8 *
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
13 *
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 *
20 * CDDL HEADER END
21 */
22 /*
23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
28 /* All Rights Reserved */
29 /*
30 * Copyright (c) 2016 by Delphix. All rights reserved.
31 */
32
33 #ifndef UUCHECK
34 #include "uucp.h"
35 #endif
36
37
38 /* field array indexes for PERMISSIONS parameters */
39 #define U_LOGNAME 0
40 #define U_MACHINE 1
41 #define U_CALLBACK 2
42 #define U_REQUEST 3
43 #define U_SENDFILES 4
44 #define U_READPATH 5
45 #define U_WRITEPATH 6
46 #define U_NOREADPATH 7
47 #define U_NOWRITEPATH 8
48 #define U_MYNAME 9
49 #define U_COMMANDS 10
50 #define U_VALIDATE 11
51 #define U_PUBDIR 12
52 #define U_DIRECT 13
53 #define U_ALIAS 14
54 #define U_PATH 15
55 /* NUMFLDS should be one more than the highest U_ value */
56 #define NUMFLDS 16
57
58 /* fields found in PERMISSIONS for requested system/login */
59 static char *_Flds[NUMFLDS];
60
61 /* keyword/value structure */
62 struct keywords {
63 char* kword;
64 int kvalue;
65 };
66 static struct keywords _Kwords[] = {
67 {"LOGNAME", U_LOGNAME},
68 {"MACHINE", U_MACHINE},
69 {"CALLBACK", U_CALLBACK},
70 {"REQUEST", U_REQUEST},
71 {"SENDFILES", U_SENDFILES},
72 {"READ", U_READPATH},
73 {"WRITE", U_WRITEPATH},
74 {"NOREAD", U_NOREADPATH},
75 {"NOWRITE", U_NOWRITEPATH},
76 {"MYNAME", U_MYNAME},
77 {"COMMANDS", U_COMMANDS},
78 {"VALIDATE", U_VALIDATE},
79 {"PUBDIR", U_PUBDIR},
80 {"DIRECT", U_DIRECT},
81 {"ALIAS", U_ALIAS},
82 {"PATH", U_PATH},
83 };
84
85 #define MAXCMDS 30
86 #define MAXPATHS 20
87
88 /* for all options on paths - read, write, noread, nowrite */
89 /* NB: all pointers assumed to point to static data */
90 static char *_RPaths[MAXPATHS+1];
91 static char *_WPaths[MAXPATHS+1];
92 static char *_NoRPaths[MAXPATHS+1];
93 static char *_NoWPaths[MAXPATHS+1];
94 static char *_Commands[MAXCMDS+1];
95 static char _Cmd_defaults[BUFSIZ];
96
97 /* option variables */
98 static int _Request; /* TRUE can request, FALSE can not request files */
99 static int _Switch; /* FALSE requires a call back to send any files */
100 static int _CallBack; /* TRUE for call back for any transaction */
101 static int _NoSpool; /* TRUE if delivering directly to destination file */
102 static char _MyName[MAXBASENAME+1]; /* Myname from PERMISSIONS file */
103 /* NB: _Pubdir and _Path assumed to point to dynamic data */
104 static char *_Pubdir = NULL; /* PUBDIR from PERMISSIONS file */
105 static char *_Path = NULL; /* PATH from PERMISSIONS file */
106
107 struct name_value
108 {
109 char *name;
110 char *value;
111 };
112
113 /* file pointer for PERMISSIONS */
114 static FILE *Fp = NULL;
115
116 /* functions */
117 extern char *next_token(), *nextarg();
118 extern int parse_tokens(), canPath(), mkdirs();
119 static void fillFlds();
120 static void fillList();
121 static int cmdMatch(), listMatch(), nameMatch(),
122 userFind(), validateFind();
123
124 int
noSpool()125 noSpool()
126 {
127 return(_NoSpool);
128 }
129
130 /*
131 * fill in fields for login name
132 * name - the login id
133 * rmtname - remote system name
134 *
135 * return:
136 * 0 -> found login name
137 * FAIL -> did not find login
138 */
139
140 int
logFind(name,rmtname)141 logFind(name, rmtname)
142 char *name, *rmtname;
143 {
144 int ret;
145 DEBUG(5, "logFind called (name: %s, ", name);
146 DEBUG(5, "rmtname: %s)\n", rmtname);
147
148 ret = validateFind (rmtname);
149 if (ret == SUCCESS) { /* found VALIDATE entry */
150 ret = userFind (name, rmtname, U_VALIDATE);
151 if (ret) {
152 DEBUG(5, "machine/login match failed%s", "");
153 return(FAIL);
154 }
155 }
156 else
157 ret = userFind (name, "", U_LOGNAME);
158
159 DEBUG(7, "_Request (%s), ",
160 requestOK() ? "TRUE" : "FALSE");
161 DEBUG(7, "_Switch (%s), ",
162 switchRole() ? "TRUE" : "FALSE");
163 DEBUG(7, "_CallBack (%s), ",
164 callBack() ? "TRUE" : "FALSE");
165 DEBUG(7, "_MyName (%s), ", _MyName);
166 DEBUG(7, "_NoSpool (%s), ",
167 noSpool() ? "TRUE" : "FALSE");
168 return(ret);
169 }
170
171 /*
172 * fill in fields for machine name
173 * return:
174 * 0 -> found machine name
175 * FAIL -> did not find machine
176 */
177
178 int
mchFind(name)179 mchFind(name)
180 char *name;
181 {
182 int i, ret;
183 DEBUG(5, "mchFind called (%s)\n", name);
184 if ( (ret = userFind (name, "", U_MACHINE)) == FAIL)
185 /* see if there is a default line */
186 (void) userFind ("OTHER", "", U_MACHINE);
187
188 /* mchFind is from MASTER mode - switch role is always ok */
189 _Switch = TRUE;
190
191 DEBUG(7, "_Request (%s), ",
192 requestOK() ? "TRUE" : "FALSE");
193 DEBUG(7, "_Switch (%s), ",
194 switchRole() ? "TRUE" : "FALSE");
195 DEBUG(7, "_CallBack (%s), ",
196 callBack() ? "TRUE" : "FALSE");
197 DEBUG(7, "_MyName (%s), ", _MyName);
198 DEBUG(7, "_NoSpool (%s), ",
199 noSpool() ? "TRUE" : "FALSE");
200 for (i=0; _Commands[i] != NULL; i++)
201 DEBUG(7, "_Commands %s\n", _Commands[i]);
202 return(ret);
203 }
204
205 /*
206 * this function will find a login name in the LOGNAME
207 * field.
208 * input:
209 * name -> who the remote says they are
210 * return:
211 * SUCCESS -> found
212 * FAIL -> not found
213 */
214 static int
nameMatch(name,fld)215 nameMatch(name, fld)
216 char *name, *fld;
217 {
218 char *arg;
219
220 if (fld == NULL)
221 return(FAIL);
222
223 while (*fld) {
224 fld = nextarg(fld, &arg);
225 if (EQUALS(arg, name))
226 return(SUCCESS);
227 }
228 return (FAIL);
229 }
230
231
232 /*
233 * interpret the _Flds options and set the option variables
234 */
235 static void
fillFlds()236 fillFlds()
237 {
238
239 if (_Flds[U_REQUEST] != NULL) {
240 if (EQUALS(_Flds[U_REQUEST], "yes"))
241 _Request = TRUE;
242 else
243 _Request = FALSE;
244 }
245
246 if (_Flds[U_SENDFILES] != NULL) {
247 if (EQUALS(_Flds[U_SENDFILES], "yes"))
248 _Switch = TRUE;
249 else
250 _Switch = FALSE;
251 }
252
253 if (_Flds[U_CALLBACK] != NULL) {
254 if (EQUALS(_Flds[U_CALLBACK], "yes"))
255 _CallBack = TRUE;
256 else
257 _CallBack = FALSE;
258 }
259
260 if (_Flds[U_DIRECT] != NULL) {
261 if (EQUALS(_Flds[U_DIRECT], "yes"))
262 _NoSpool = TRUE;
263 else
264 _NoSpool = FALSE;
265 }
266
267 if (_Flds[U_MYNAME] != NULL) {
268 strncpy(_MyName, _Flds[U_MYNAME], MAXBASENAME);
269 _MyName[MAXBASENAME] = NULLCHAR;
270 }
271
272 if (_Flds[U_PUBDIR] != NULL) {
273 if (_Pubdir != NULL)
274 free(_Pubdir); /* get rid of previous one */
275 _Pubdir = strdup(_Flds[U_PUBDIR]);
276 #ifndef UUCHECK
277 ASSERT(_Pubdir != NULL, Ct_ALLOCATE, _Flds[U_PUBDIR], 0);
278 #else /* UUCHECK */
279 if (_Pubdir == NULL) {
280 perror(gettext("malloc() error"));
281 exit(1);
282 }
283 #endif /* UUCHECK */
284 Pubdir = _RPaths[0] = _WPaths[0] = _Pubdir; /* reset default */
285 }
286
287 if (_Flds[U_PATH] != NULL) {
288 if (_Path != NULL)
289 free(_Path); /* get rid of previous one */
290 _Path = strdup(_Flds[U_PATH]);
291 #ifndef UUCHECK
292 ASSERT(_Path != NULL, Ct_ALLOCATE, _Flds[U_PATH], 0);
293 #else /* UUCHECK */
294 if (_Path == NULL) {
295 perror(gettext("malloc() error"));
296 exit(1);
297 }
298 #endif /* UUCHECK */
299 }
300
301 return;
302 }
303
304 /*
305 * fill in the list vector for the system/login
306 * input:
307 * type - list type (read, write, noread, nowrite, command)
308 * output:
309 * list - filled in with items.
310 * return:
311 * number of items in list
312 */
313 static void
fillList(type,list)314 fillList(type, list)
315 int type;
316 char *list[];
317 {
318 char *p;
319 int num;
320 int maxlist = 0;
321
322 p = _Flds[type];
323
324 /* find list limit */
325 if (type == U_READPATH || type == U_WRITEPATH
326 || type == U_NOREADPATH || type == U_NOWRITEPATH)
327 maxlist = MAXPATHS;
328 else if (type == U_COMMANDS)
329 maxlist = MAXCMDS;
330
331 if (p == NULL || !*p) {
332 /* no names specified, default already setup */
333 return;
334 }
335
336 num = 0;
337 while (*p && num < maxlist) {
338 list[num] = p;
339 if (*p == ':') { /* null path */
340 *p++ = NULLCHAR;
341 continue;
342 }
343 while (*p && *p != ':')
344 p++;
345 if (*p == ':')
346 *p++ = NULLCHAR;
347 DEBUG(7, "list (%s) ", list[num]);
348 num++;
349 }
350 DEBUG(7, "num = %d\n", num);
351 list[num] = NULL;
352 return;
353 }
354
355 /*
356 * Find the line of PERMISSIONS for login.
357 * The search is determined by the type field
358 * (type=U_LOGNAME, U_MACHINE or U_VALIDATE)
359 * For U_LOGNAME:
360 * search for "name" in a LOGNAME= option
361 * For U_MACHINE:
362 * search for "name" in a MACHINE= option
363 * For U_VALIDATE:
364 * search for "rmtname" in a VALIDATE= option and
365 * for the same entry see if "name" is in the LOGNAME= option
366 * input:
367 * name -> search name
368 * logname -> for validate entry
369 * type -> U_MACHINE or U_LOGNAME
370 * output:
371 * The global values of all options will be set
372 * (e.g. _RPaths, _WPaths, _Request, ...)
373 * return:
374 * 0 -> ok
375 * FAIL -> no match found
376 */
377 static int
userFind(name,rmtname,type)378 userFind(name, rmtname, type)
379 char *name, *rmtname;
380 int type;
381 {
382 char *p, *arg, *buf = NULL;
383 static char default_buf[BUFSIZ];
384
385 if (name != NULL && strcmp(name, "DEFAULT") != 0) {
386 /* call ourself recursively to set defaults */
387 (void) userFind("DEFAULT", "", U_MACHINE);
388 } else {
389 /*
390 * Handle case where looking for DEFAULT entry.
391 * First initialize all defaults to their "base"
392 * values. Then the DEFAULT entry, if found,
393 * will override these settings.
394 */
395 _Request = FALSE;
396 _CallBack = FALSE;
397 _Switch = FALSE;
398 _NoSpool = FALSE;
399 _MyName[0] = NULLCHAR;
400 _RPaths[0] = _WPaths[0] = PUBDIR; /* default is public */
401 _RPaths[1] = _WPaths[1] = NULLCHAR;
402 _NoRPaths[0] = NULLCHAR;
403 _NoWPaths[0] = NULLCHAR;
404 if (_Pubdir != NULL)
405 free(_Pubdir);
406 Pubdir = _Pubdir = strdup(PUBDIR);
407 if (_Path != NULL)
408 free(_Path);
409 _Path = strdup(PATH);
410 /* set up Commands defaults */
411 _Flds[U_COMMANDS] = strcpy(_Cmd_defaults, DEFAULTCMDS);
412 fillList(U_COMMANDS, _Commands);
413 /*
414 * put defaults we read in in here so they're not overwritten
415 * by non-DEFAULT entries.
416 */
417 buf = default_buf;
418 }
419
420 if (name == NULL) /* use defaults */
421 return(0); /* I don't think this will ever happen */
422
423 if ( (Fp = fopen(PERMISSIONS, "r")) == NULL) {
424 DEBUG(5, "can't open %s\n", PERMISSIONS);
425 return(FAIL);
426 }
427
428 for (;;) {
429 if (parse_tokens (_Flds, buf) != 0) {
430 (void) fclose(Fp);
431 DEBUG(5, "name (%s) not found; return FAIL\n", name);
432 return(FAIL);
433 }
434
435 p = _Flds[type];
436 while (p && *p) {
437 p = nextarg(p, &arg);
438 switch (type) {
439 case U_VALIDATE:
440 if (EQUALS(arg, rmtname)
441 && nameMatch(name, _Flds[U_LOGNAME])==SUCCESS)
442 break;
443 continue;
444
445 case U_LOGNAME:
446 if (EQUALS(arg, name))
447 break;
448 continue;
449
450 case U_MACHINE:
451 if (EQUALSN(arg, name, MAXBASENAME))
452 break;
453 continue;
454 }
455
456 (void) fclose(Fp);
457 fillFlds();
458
459 /* fill in path lists */
460 fillList(U_READPATH, _RPaths);
461 fillList(U_WRITEPATH, _WPaths);
462 if (!requestOK())
463 _Flds[U_NOREADPATH] = "/";
464 fillList(U_NOREADPATH, _NoRPaths);
465 fillList(U_NOWRITEPATH, _NoWPaths);
466
467 /* fill in command list */
468 fillList(U_COMMANDS, _Commands);
469
470 return(0);
471 }
472 }
473 }
474
475 /*
476 * see if name is in a VALIDATE option
477 * return:
478 * FAIL -> not found
479 * SUCCESS -> found
480 */
481 static int
validateFind(name)482 validateFind(name)
483 char *name;
484 {
485
486 if ( (Fp = fopen(PERMISSIONS, "r")) == NULL) {
487 DEBUG(5, "can't open %s\n", PERMISSIONS);
488 return(FAIL);
489 }
490
491 for (;;) {
492 if (parse_tokens (_Flds, NULL) != 0) {
493 DEBUG(5, "validateFind (%s) FAIL\n", name);
494 (void) fclose(Fp);
495 return(FAIL);
496 }
497
498 if (_Flds[U_VALIDATE] == NULL)
499 continue;
500 if (nameMatch(name, _Flds[U_VALIDATE])==SUCCESS) {
501 (void) fclose(Fp);
502 return (SUCCESS);
503 }
504 }
505
506 }
507
508 /*
509 * see if name is in an ALIAS option
510 * return:
511 * NULL -> not found
512 * otherwise -> machine name
513 */
514 char *
aliasFind(name)515 aliasFind(name)
516 char *name;
517 {
518
519 if ( (Fp = fopen(PERMISSIONS, "r")) == NULL) {
520 DEBUG(5, "can't open %s\n", PERMISSIONS);
521 return(NULL);
522 }
523
524 for (;;) {
525 if (parse_tokens (_Flds, NULL) != 0) {
526 DEBUG(5, "aliasFind (%s) FAIL\n", name);
527 (void) fclose(Fp);
528 return(NULL);
529 }
530
531 if (_Flds[U_ALIAS] == NULL)
532 continue;
533 if (nameMatch(name, _Flds[U_ALIAS])==SUCCESS) {
534 (void) fclose(Fp);
535 #ifndef UUCHECK
536 ASSERT(strchr(_Flds[U_MACHINE], ':') == NULL,
537 "PERMISSIONS file: ALIAS is one-to-many:",
538 _Flds[U_MACHINE], 0);
539 #else /* UUCHECK */
540 if (strchr(_Flds[U_MACHINE], ':') != NULL) {
541 printf(gettext("ALIAS is one-to-many: %s -> %s\n"),
542 name, _Flds[U_MACHINE]);
543 return(NULL);
544 }
545 #endif /* UUCHECK */
546 return(_Flds[U_MACHINE]);
547 }
548 }
549
550 }
551
552 /*
553 * parse a line in PERMISSIONS and return a vector
554 * of fields (flds)
555 *
556 * return:
557 * 0 - OK
558 * EOF - at end of file
559 */
560 int
parse_tokens(flds,buf)561 parse_tokens(flds, buf)
562 char *flds[];
563 char *buf;
564 {
565 int i;
566 char *p;
567 struct name_value pair;
568 static char _line[BUFSIZ];
569 char *line = buf;
570
571 if (buf == NULL)
572 line = _line; /* if no buffer specified, use default */
573 /* initialize defaults in case parameter is not specified */
574 for (i=0;i<NUMFLDS;i++)
575 flds[i] = NULL;
576
577 if (getuline(Fp, line) == 0)
578 return(EOF);
579
580 for (p=line;p && *p;) {
581 p = next_token (p, &pair);
582
583 for (i=0; i<NUMFLDS; i++) {
584 if (EQUALS(pair.name, _Kwords[i].kword)) {
585 flds[i] = pair.value;
586 break;
587 }
588 }
589 #ifndef UUCHECK
590 ASSERT(i<NUMFLDS, "PERMISSIONS file: BAD OPTION--",
591 pair.name, NUMFLDS);
592 #else /* UUCHECK */
593 if (i >= NUMFLDS) {
594 DEBUG(3, "bad option (%s) in PERMISSIONS\n",pair.name);
595 (void) printf("\n*****************************\n");
596 (void) printf(gettext("**BAD OPTION in PERMISSIONS file: %s\n"),
597 pair.name);
598 (void) printf("*****************************\n");
599 Uerrors++;
600 return(0);
601 }
602 #endif /* UUCHECK */
603
604 }
605 return(0);
606 }
607
608 /*
609 * return a name value pair
610 * string -> input pointer
611 * pair -> name value pair
612 * return:
613 * pointer to next character
614 */
615 char *
next_token(string,pair)616 next_token (string, pair)
617 char *string;
618 struct name_value *pair;
619 {
620 char *prev = _uu_setlocale(LC_ALL, "C");
621
622 while ( (*string) && ((*string == '\t') || (*string == ' ')) )
623 string++;
624
625 pair->name = string;
626 while ((*string) && (*string != '='))
627 string++;
628 if (*string)
629 *string++ = NULLCHAR;
630
631 pair->value = string;
632 while ((*string) && (*string != '\t') && (*string != ' ')
633 && (*string != '\n'))
634 string++;
635
636 if (*string)
637 *string++ = NULLCHAR;
638
639 (void) _uu_resetlocale(LC_ALL, prev);
640 return (string);
641 }
642
643 /*
644 * get a line from the PERMISSIONS
645 * take care of comments (#) in col 1
646 * and continuations (\) in last col
647 * return:
648 * len of line
649 * 0 -> end of file
650 */
651 int
getuline(fp,line)652 getuline(fp, line)
653 FILE *fp;
654 char *line;
655 {
656 char *p, *c;
657 char buf[BUFSIZ];
658
659 p = line;
660 for (;fgets(buf, BUFSIZ, fp) != NULL;) {
661 /* remove trailing white space */
662 c = &buf[strlen(buf)-1];
663 while (c>=buf && (*c == '\n' || *c == '\t' || *c == ' ') )
664 *c-- = NULLCHAR;
665
666 if (buf[0] == '#' || buf[0] == '\n' || buf[0] == NULLCHAR)
667 continue;
668 (void) strcpy(p, buf);
669 p += strlen(buf);
670 if ( *(p-1) == '\\')
671 p--;
672 else
673 break;
674 }
675
676 return(p-line);
677 }
678
679
680 #define SMAX 15
681
682 /*
683 * get the next colon separated argument from the list
684 * return:
685 * p -> pointer to next arg in string
686 * input:
687 * str -> pointer to input string
688 * output:
689 * name -> pointer to arg string
690 */
691 char *
nextarg(str,name)692 nextarg(str, name)
693 char *str, **name;
694 {
695 char *p, *b;
696 static char buf[SMAX+1];
697
698 for(b=buf,p=str; *p != ':' && *p && b < buf+SMAX;)
699 *b++ = *p++;
700 *b++ = NULLCHAR;
701 if (*p == ':')
702 p++;
703 *name = buf;
704 return(p);
705 }
706
707 /*
708 * check if requesting files is permitted
709 * return
710 * TRUE -> request permitted
711 * FALSE -> request denied
712 */
713 int
requestOK()714 requestOK()
715 {
716 return(_Request);
717 }
718
719 /*
720 * myName - return my name from PERMISSIONS file
721 * or if not there, from uucpname()
722 * return: none
723 */
724
725 void
myName(name)726 myName(name)
727 char *name;
728 {
729 if (*_MyName)
730 strcpy(name, _MyName);
731 else
732 uucpname(name);
733 return;
734 }
735
736 /*
737 * check for callback required for any transaction
738 * return:
739 * TRUE -> callback required
740 * FALSE-> callback NOT required
741 */
742 int
callBack()743 callBack()
744 {
745 return(_CallBack);
746 }
747
748 /*
749 * check for callback to send any files from here
750 * This means that the called (SLAVE) system will not switch roles.
751 * return:
752 * TRUE -> callback requried to send files
753 * FALSE-> callback NOT required to send files
754 */
755 int
switchRole()756 switchRole()
757 {
758 return(_Switch);
759 }
760
761 /*
762 * Check to see if command is valid for a specific machine.
763 * The PERMISSIONS file has an option COMMANDS=name1:name2:... for
764 * any machine that does not have the default list which is
765 * rmail
766 * Note that the PERMISSIONS file is read once for each system
767 * at the time the Rmtname is set in xprocess().
768 * Return codes:
769 * ok: TRUE
770 * fail: FALSE
771 */
772 int
cmdOK(cmd,fullcmd)773 cmdOK(cmd, fullcmd)
774 char *cmd, *fullcmd;
775 {
776 DEBUG(7, "cmdOK(%s, )\n", cmd);
777 return(cmdMatch(cmd, fullcmd));
778 }
779
780
781 /*
782 * check a name against a list
783 * input:
784 * name -> name
785 * list -> list of names
786 * return:
787 * TRUE -> found path
788 * FALSE -> not found
789 */
790 static int
listMatch(name,list)791 listMatch(name, list)
792 char *name, *list[];
793 {
794 int i;
795 char *temp, *tend;
796 struct stat statbuf;
797 dev_t _dev[MAXPATHS+1];
798 ino_t _ino[MAXPATHS+1];
799
800 /* ino set to 0 so stat is only done first time */
801 for (i=0; list[i] != NULL; i++)
802 _ino[i] = 0;
803
804 /* try to match inodes */
805 if ( (temp = strdup(name)) != NULL ) {
806 for ( tend = temp + strlen(temp) ; *temp; ) {
807 if ( stat(temp, &statbuf) == 0 ) {
808 for (i=0; list[i] != NULL; i++) {
809 if ( _ino[i] == 0 ) {
810 struct stat tempbuf;
811 if ( stat(list[i], &tempbuf) == 0 ) {
812 _dev[i] = tempbuf.st_dev;
813 _ino[i] = tempbuf.st_ino;
814 }
815 }
816 if ( _dev[i] == statbuf.st_dev
817 && _ino[i] == statbuf.st_ino ) {
818 free(temp);
819 return(TRUE);
820 }
821 }
822 }
823 *tend = '\0';
824 if ( (tend = strrchr(temp, '/')) == NULL ) {
825 free(temp);
826 break;
827 } else
828 *(tend+1) = '\0';
829 }
830 }
831
832 return(FALSE);
833 }
834
835
836 /*
837 * Check "name" against a BASENAME or full name of _Commands list.
838 * If "name" specifies full path, check full, else check BASENAME.
839 * e.g. "name" rmail matches list item /usr/bin/rmail
840 * input:
841 * name -> name
842 * output:
843 * fullname -> copy full command name into fullname if
844 * a full path was specified in _Commands;
845 * if not, put name into fullname.
846 * return:
847 * TRUE -> found path
848 * FALSE -> not found
849 */
850 static int
cmdMatch(name,fullname)851 cmdMatch(name, fullname)
852 char *name;
853 char *fullname;
854 {
855 int i;
856 char *bname;
857 int allok = FALSE;
858
859 for (i=0; _Commands[i] != NULL; i++) {
860 if (EQUALS(_Commands[i], "ALL")) {
861 /* if ALL specified in the list
862 * set allok and continue in case
863 * a full path name is specified for the command
864 */
865 allok = TRUE;
866 continue;
867 }
868 if (name[0] != '/')
869 bname = BASENAME(_Commands[i], '/');
870 else
871 bname = _Commands[i];
872 DEBUG(7, "bname=%s\n", bname);
873 if (EQUALS(bname, name)) {
874 (void) strcpy(fullname, _Commands[i]);
875 return(TRUE);
876 }
877 }
878 if (allok == TRUE) {
879 /* ALL was specified and the command was not found in list */
880 (void) strcpy(fullname, name);
881 return(TRUE);
882 }
883 (void) strcpy(fullname, "NuLL"); /* this is a dummy command */
884 return(FALSE);
885 }
886
887
888 /*
889 * check the paths for this login/machine
890 * input:
891 * path pathname
892 * flag CK_READ or CK_WRITE
893 * output:
894 * path may be modified to canonical form
895 * (../, ./, // will be interpreted/removed)
896 * returns:
897 * 0 -> success
898 * FAIL -> failure - not a valid path for access
899 */
900 int
chkpth(char * path,int flag)901 chkpth(char *path, int flag)
902 {
903 char *s;
904
905 /*
906 * this is probably redundant,
907 * because expfile did it, but that's ok
908 * Note - the /../ check is not required because of canPath
909 */
910 if (canPath(path) == FAIL)
911 return(FAIL);
912
913 if (flag == CK_READ)
914 if (listMatch(path, _RPaths)
915 && !listMatch(path, _NoRPaths))
916 return(0);
917 if (flag == CK_WRITE)
918 if (listMatch(path, _WPaths)
919 && !listMatch(path, _NoWPaths))
920 return(0);
921
922
923 /* ok if uucp generated D. or X. name for the spool directory */
924 if (PREFIX(RemSpool, path) ) {
925 s = &path[strlen(RemSpool)];
926 if ( (*s++ == '/')
927 && (*s == DATAPRE || *s == XQTPRE)
928 && (*(++s) == '.')
929 && (strchr(s, '/') == NULL) )
930 return(0);
931 }
932
933 /* path name not valid */
934 return(FAIL);
935 }
936
937 /*
938 * check write permission of file.
939 * if mopt != NULL and permissions are ok,
940 * a side effect of this routine is to make
941 * directories up to the last part of the
942 * "to" ( if they do not exit).
943 * Input:
944 * to - a path name of the destination file or directory
945 * from - full path name of source file
946 * opt - create directory option (NULL - don't create)
947 * Output:
948 * to - will be the full path name of the destination file
949 * returns:
950 * 0 ->success
951 * FAIL -> failure
952 */
953 int
chkperm(from,to,opt)954 chkperm(from, to, opt)
955 char *from, *to, *opt;
956 {
957 char *lxp, *p;
958 struct stat s;
959 char dir[MAXFULLNAME];
960
961 if (*(p = LASTCHAR(to)) == '/') {
962 if (strlcpy(p+1, BASENAME(from, '/'), MAXFULLNAME - strlen(to)) >=
963 MAXFULLNAME - strlen(to)) {
964 return(FAIL);
965 }
966 } else if (DIRECTORY(to)) {
967 *++p = '/';
968 if (strlcpy(p+1, BASENAME(from, '/'), MAXFULLNAME - strlen(to)) >=
969 MAXFULLNAME - strlen(to)) {
970 return(FAIL);
971 }
972 }
973
974 /* to is now the full path name of the destination file */
975
976 if (WRITEANY(to))
977 return(0);
978 if (stat(to, &s) == 0)
979 return(FAIL); /* file exists, but not writeable */
980
981 /* file does not exist--check directory and make when necessary */
982
983 (void) strcpy(dir, to);
984 if ( (lxp=strrchr(dir, '/')) == NULL)
985 return(FAIL); /* no directory part of name */
986 if (lxp == dir) /* at root */
987 lxp++;
988 *lxp = NULLCHAR;
989
990 /* should check WRITEANY on parent before mkdirs() */
991 if (!DIRECTORY(dir)) {
992 if (opt == NULL)
993 return(FAIL); /* no directory and no opt to make them */
994 else if (mkdirs(dir, PUBMASK) == FAIL)
995 return(FAIL);
996 }
997
998 /* the directory now exists--check for writability */
999 if (EQUALS(RemSpool, dir) || WRITEANY(dir))
1000 return(0);
1001
1002 return(FAIL);
1003 }
1004