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