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
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.
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]
23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
27 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
28 /* All Rights Reserved */
30 * Copyright (c) 2016 by Delphix. All rights reserved.
33 #pragma ident "%Z%%M% %I% %E% SMI"
40 /* field array indexes for PERMISSIONS parameters */
48 #define U_NOREADPATH 7
49 #define U_NOWRITEPATH 8
57 /* NUMFLDS should be one more than the highest U_ value */
60 /* fields found in PERMISSIONS for requested system/login */
61 static char *_Flds
[NUMFLDS
];
63 /* keyword/value structure */
68 static struct keywords _Kwords
[] = {
69 {"LOGNAME", U_LOGNAME
},
70 {"MACHINE", U_MACHINE
},
71 {"CALLBACK", U_CALLBACK
},
72 {"REQUEST", U_REQUEST
},
73 {"SENDFILES", U_SENDFILES
},
75 {"WRITE", U_WRITEPATH
},
76 {"NOREAD", U_NOREADPATH
},
77 {"NOWRITE", U_NOWRITEPATH
},
79 {"COMMANDS", U_COMMANDS
},
80 {"VALIDATE", U_VALIDATE
},
90 /* for all options on paths - read, write, noread, nowrite */
91 /* NB: all pointers assumed to point to static data */
92 static char *_RPaths
[MAXPATHS
+1];
93 static char *_WPaths
[MAXPATHS
+1];
94 static char *_NoRPaths
[MAXPATHS
+1];
95 static char *_NoWPaths
[MAXPATHS
+1];
96 static char *_Commands
[MAXCMDS
+1];
97 static char _Cmd_defaults
[BUFSIZ
];
99 /* option variables */
100 static int _Request
; /* TRUE can request, FALSE can not request files */
101 static int _Switch
; /* FALSE requires a call back to send any files */
102 static int _CallBack
; /* TRUE for call back for any transaction */
103 static int _NoSpool
; /* TRUE if delivering directly to destination file */
104 static char _MyName
[MAXBASENAME
+1]; /* Myname from PERMISSIONS file */
105 /* NB: _Pubdir and _Path assumed to point to dynamic data */
106 static char *_Pubdir
= NULL
; /* PUBDIR from PERMISSIONS file */
107 static char *_Path
= NULL
; /* PATH from PERMISSIONS file */
115 /* file pointer for PERMISSIONS */
116 static FILE *Fp
= NULL
;
119 extern char *next_token(), *nextarg();
120 extern int parse_tokens(), canPath(), mkdirs();
121 static void fillFlds();
122 static void fillList();
123 static int cmdMatch(), listMatch(), nameMatch(),
124 userFind(), validateFind();
133 * fill in fields for login name
134 * name - the login id
135 * rmtname - remote system name
138 * 0 -> found login name
139 * FAIL -> did not find login
143 logFind(name
, rmtname
)
144 char *name
, *rmtname
;
147 DEBUG(5, "logFind called (name: %s, ", name
);
148 DEBUG(5, "rmtname: %s)\n", rmtname
);
150 ret
= validateFind (rmtname
);
151 if (ret
== SUCCESS
) { /* found VALIDATE entry */
152 ret
= userFind (name
, rmtname
, U_VALIDATE
);
154 DEBUG(5, "machine/login match failed%s", "");
159 ret
= userFind (name
, "", U_LOGNAME
);
161 DEBUG(7, "_Request (%s), ",
162 requestOK() ? "TRUE" : "FALSE");
163 DEBUG(7, "_Switch (%s), ",
164 switchRole() ? "TRUE" : "FALSE");
165 DEBUG(7, "_CallBack (%s), ",
166 callBack() ? "TRUE" : "FALSE");
167 DEBUG(7, "_MyName (%s), ", _MyName
);
168 DEBUG(7, "_NoSpool (%s), ",
169 noSpool() ? "TRUE" : "FALSE");
174 * fill in fields for machine name
176 * 0 -> found machine name
177 * FAIL -> did not find machine
185 DEBUG(5, "mchFind called (%s)\n", name
);
186 if ( (ret
= userFind (name
, "", U_MACHINE
)) == FAIL
)
187 /* see if there is a default line */
188 (void) userFind ("OTHER", "", U_MACHINE
);
190 /* mchFind is from MASTER mode - switch role is always ok */
193 DEBUG(7, "_Request (%s), ",
194 requestOK() ? "TRUE" : "FALSE");
195 DEBUG(7, "_Switch (%s), ",
196 switchRole() ? "TRUE" : "FALSE");
197 DEBUG(7, "_CallBack (%s), ",
198 callBack() ? "TRUE" : "FALSE");
199 DEBUG(7, "_MyName (%s), ", _MyName
);
200 DEBUG(7, "_NoSpool (%s), ",
201 noSpool() ? "TRUE" : "FALSE");
202 for (i
=0; _Commands
[i
] != NULL
; i
++)
203 DEBUG(7, "_Commands %s\n", _Commands
[i
]);
208 * this function will find a login name in the LOGNAME
211 * name -> who the remote says they are
226 fld
= nextarg(fld
, &arg
);
227 if (EQUALS(arg
, name
))
235 * interpret the _Flds options and set the option variables
241 if (_Flds
[U_REQUEST
] != NULL
) {
242 if (EQUALS(_Flds
[U_REQUEST
], "yes"))
248 if (_Flds
[U_SENDFILES
] != NULL
) {
249 if (EQUALS(_Flds
[U_SENDFILES
], "yes"))
255 if (_Flds
[U_CALLBACK
] != NULL
) {
256 if (EQUALS(_Flds
[U_CALLBACK
], "yes"))
262 if (_Flds
[U_DIRECT
] != NULL
) {
263 if (EQUALS(_Flds
[U_DIRECT
], "yes"))
269 if (_Flds
[U_MYNAME
] != NULL
) {
270 strncpy(_MyName
, _Flds
[U_MYNAME
], MAXBASENAME
);
271 _MyName
[MAXBASENAME
] = NULLCHAR
;
274 if (_Flds
[U_PUBDIR
] != NULL
) {
276 free(_Pubdir
); /* get rid of previous one */
277 _Pubdir
= strdup(_Flds
[U_PUBDIR
]);
279 ASSERT(_Pubdir
!= NULL
, Ct_ALLOCATE
, _Flds
[U_PUBDIR
], 0);
281 if (_Pubdir
== NULL
) {
282 perror(gettext("malloc() error"));
286 Pubdir
= _RPaths
[0] = _WPaths
[0] = _Pubdir
; /* reset default */
289 if (_Flds
[U_PATH
] != NULL
) {
291 free(_Path
); /* get rid of previous one */
292 _Path
= strdup(_Flds
[U_PATH
]);
294 ASSERT(_Path
!= NULL
, Ct_ALLOCATE
, _Flds
[U_PATH
], 0);
297 perror(gettext("malloc() error"));
307 * fill in the list vector for the system/login
309 * type - list type (read, write, noread, nowrite, command)
311 * list - filled in with items.
313 * number of items in list
326 /* find list limit */
327 if (type
== U_READPATH
|| type
== U_WRITEPATH
328 || type
== U_NOREADPATH
|| type
== U_NOWRITEPATH
)
330 else if (type
== U_COMMANDS
)
333 if (p
== NULL
|| !*p
) {
334 /* no names specified, default already setup */
339 while (*p
&& num
< maxlist
) {
341 if (*p
== ':') { /* null path */
345 while (*p
&& *p
!= ':')
349 DEBUG(7, "list (%s) ", list
[num
]);
352 DEBUG(7, "num = %d\n", num
);
358 * Find the line of PERMISSIONS for login.
359 * The search is determined by the type field
360 * (type=U_LOGNAME, U_MACHINE or U_VALIDATE)
362 * search for "name" in a LOGNAME= option
364 * search for "name" in a MACHINE= option
366 * search for "rmtname" in a VALIDATE= option and
367 * for the same entry see if "name" is in the LOGNAME= option
369 * name -> search name
370 * logname -> for validate entry
371 * type -> U_MACHINE or U_LOGNAME
373 * The global values of all options will be set
374 * (e.g. _RPaths, _WPaths, _Request, ...)
377 * FAIL -> no match found
380 userFind(name
, rmtname
, type
)
381 char *name
, *rmtname
;
384 char *p
, *arg
, *buf
= NULL
;
385 static char default_buf
[BUFSIZ
];
387 if (name
!= NULL
&& strcmp(name
, "DEFAULT") != 0) {
388 /* call ourself recursively to set defaults */
389 (void) userFind("DEFAULT", "", U_MACHINE
);
392 * Handle case where looking for DEFAULT entry.
393 * First initialize all defaults to their "base"
394 * values. Then the DEFAULT entry, if found,
395 * will override these settings.
401 _MyName
[0] = NULLCHAR
;
402 _RPaths
[0] = _WPaths
[0] = PUBDIR
; /* default is public */
403 _RPaths
[1] = _WPaths
[1] = NULLCHAR
;
404 _NoRPaths
[0] = NULLCHAR
;
405 _NoWPaths
[0] = NULLCHAR
;
408 Pubdir
= _Pubdir
= strdup(PUBDIR
);
411 _Path
= strdup(PATH
);
412 /* set up Commands defaults */
413 _Flds
[U_COMMANDS
] = strcpy(_Cmd_defaults
, DEFAULTCMDS
);
414 fillList(U_COMMANDS
, _Commands
);
416 * put defaults we read in in here so they're not overwritten
417 * by non-DEFAULT entries.
422 if (name
== NULL
) /* use defaults */
423 return(0); /* I don't think this will ever happen */
425 if ( (Fp
= fopen(PERMISSIONS
, "r")) == NULL
) {
426 DEBUG(5, "can't open %s\n", PERMISSIONS
);
431 if (parse_tokens (_Flds
, buf
) != 0) {
433 DEBUG(5, "name (%s) not found; return FAIL\n", name
);
439 p
= nextarg(p
, &arg
);
442 if (EQUALS(arg
, rmtname
)
443 && nameMatch(name
, _Flds
[U_LOGNAME
])==SUCCESS
)
448 if (EQUALS(arg
, name
))
453 if (EQUALSN(arg
, name
, MAXBASENAME
))
461 /* fill in path lists */
462 fillList(U_READPATH
, _RPaths
);
463 fillList(U_WRITEPATH
, _WPaths
);
465 _Flds
[U_NOREADPATH
] = "/";
466 fillList(U_NOREADPATH
, _NoRPaths
);
467 fillList(U_NOWRITEPATH
, _NoWPaths
);
469 /* fill in command list */
470 fillList(U_COMMANDS
, _Commands
);
478 * see if name is in a VALIDATE option
488 if ( (Fp
= fopen(PERMISSIONS
, "r")) == NULL
) {
489 DEBUG(5, "can't open %s\n", PERMISSIONS
);
494 if (parse_tokens (_Flds
, NULL
) != 0) {
495 DEBUG(5, "validateFind (%s) FAIL\n", name
);
500 if (_Flds
[U_VALIDATE
] == NULL
)
502 if (nameMatch(name
, _Flds
[U_VALIDATE
])==SUCCESS
) {
511 * see if name is in an ALIAS option
514 * otherwise -> machine name
521 if ( (Fp
= fopen(PERMISSIONS
, "r")) == NULL
) {
522 DEBUG(5, "can't open %s\n", PERMISSIONS
);
527 if (parse_tokens (_Flds
, NULL
) != 0) {
528 DEBUG(5, "aliasFind (%s) FAIL\n", name
);
533 if (_Flds
[U_ALIAS
] == NULL
)
535 if (nameMatch(name
, _Flds
[U_ALIAS
])==SUCCESS
) {
538 ASSERT(strchr(_Flds
[U_MACHINE
], ':') == NULL
,
539 "PERMISSIONS file: ALIAS is one-to-many:",
540 _Flds
[U_MACHINE
], 0);
542 if (strchr(_Flds
[U_MACHINE
], ':') != NULL
) {
543 printf(gettext("ALIAS is one-to-many: %s -> %s\n"),
544 name
, _Flds
[U_MACHINE
]);
548 return(_Flds
[U_MACHINE
]);
555 * parse a line in PERMISSIONS and return a vector
560 * EOF - at end of file
563 parse_tokens(flds
, buf
)
569 struct name_value pair
;
570 static char _line
[BUFSIZ
];
574 line
= _line
; /* if no buffer specified, use default */
575 /* initialize defaults in case parameter is not specified */
576 for (i
=0;i
<NUMFLDS
;i
++)
579 if (getuline(Fp
, line
) == 0)
582 for (p
=line
;p
&& *p
;) {
583 p
= next_token (p
, &pair
);
585 for (i
=0; i
<NUMFLDS
; i
++) {
586 if (EQUALS(pair
.name
, _Kwords
[i
].kword
)) {
587 flds
[i
] = pair
.value
;
592 ASSERT(i
<NUMFLDS
, "PERMISSIONS file: BAD OPTION--",
596 DEBUG(3, "bad option (%s) in PERMISSIONS\n",pair
.name
);
597 (void) printf("\n*****************************\n");
598 (void) printf(gettext("**BAD OPTION in PERMISSIONS file: %s\n"),
600 (void) printf("*****************************\n");
611 * return a name value pair
612 * string -> input pointer
613 * pair -> name value pair
615 * pointer to next character
618 next_token (string
, pair
)
620 struct name_value
*pair
;
622 char *prev
= _uu_setlocale(LC_ALL
, "C");
624 while ( (*string
) && ((*string
== '\t') || (*string
== ' ')) )
628 while ((*string
) && (*string
!= '='))
631 *string
++ = NULLCHAR
;
633 pair
->value
= string
;
634 while ((*string
) && (*string
!= '\t') && (*string
!= ' ')
635 && (*string
!= '\n'))
639 *string
++ = NULLCHAR
;
641 (void) _uu_resetlocale(LC_ALL
, prev
);
646 * get a line from the PERMISSIONS
647 * take care of comments (#) in col 1
648 * and continuations (\) in last col
662 for (;fgets(buf
, BUFSIZ
, fp
) != NULL
;) {
663 /* remove trailing white space */
664 c
= &buf
[strlen(buf
)-1];
665 while (c
>=buf
&& (*c
== '\n' || *c
== '\t' || *c
== ' ') )
668 if (buf
[0] == '#' || buf
[0] == '\n' || buf
[0] == NULLCHAR
)
670 (void) strcpy(p
, buf
);
685 * get the next colon separated argument from the list
687 * p -> pointer to next arg in string
689 * str -> pointer to input string
691 * name -> pointer to arg string
698 static char buf
[SMAX
+1];
700 for(b
=buf
,p
=str
; *p
!= ':' && *p
&& b
< buf
+SMAX
;)
710 * check if requesting files is permitted
712 * TRUE -> request permitted
713 * FALSE -> request denied
722 * myName - return my name from PERMISSIONS file
723 * or if not there, from uucpname()
732 strcpy(name
, _MyName
);
739 * check for callback required for any transaction
741 * TRUE -> callback required
742 * FALSE-> callback NOT required
751 * check for callback to send any files from here
752 * This means that the called (SLAVE) system will not switch roles.
754 * TRUE -> callback requried to send files
755 * FALSE-> callback NOT required to send files
764 * Check to see if command is valid for a specific machine.
765 * The PERMISSIONS file has an option COMMANDS=name1:name2:... for
766 * any machine that does not have the default list which is
768 * Note that the PERMISSIONS file is read once for each system
769 * at the time the Rmtname is set in xprocess().
778 DEBUG(7, "cmdOK(%s, )\n", cmd
);
779 return(cmdMatch(cmd
, fullcmd
));
784 * check a name against a list
787 * list -> list of names
793 listMatch(name
, list
)
799 dev_t _dev
[MAXPATHS
+1];
800 ino_t _ino
[MAXPATHS
+1];
802 /* ino set to 0 so stat is only done first time */
803 for (i
=0; list
[i
] != NULL
; i
++)
806 /* try to match inodes */
807 if ( (temp
= strdup(name
)) != NULL
) {
808 for ( tend
= temp
+ strlen(temp
) ; *temp
; ) {
809 if ( stat(temp
, &statbuf
) == 0 ) {
810 for (i
=0; list
[i
] != NULL
; i
++) {
811 if ( _ino
[i
] == 0 ) {
813 if ( stat(list
[i
], &tempbuf
) == 0 ) {
814 _dev
[i
] = tempbuf
.st_dev
;
815 _ino
[i
] = tempbuf
.st_ino
;
818 if ( _dev
[i
] == statbuf
.st_dev
819 && _ino
[i
] == statbuf
.st_ino
) {
826 if ( (tend
= strrchr(temp
, '/')) == NULL
) {
839 * Check "name" against a BASENAME or full name of _Commands list.
840 * If "name" specifies full path, check full, else check BASENAME.
841 * e.g. "name" rmail matches list item /usr/bin/rmail
845 * fullname -> copy full command name into fullname if
846 * a full path was specified in _Commands;
847 * if not, put name into fullname.
853 cmdMatch(name
, fullname
)
861 for (i
=0; _Commands
[i
] != NULL
; i
++) {
862 if (EQUALS(_Commands
[i
], "ALL")) {
863 /* if ALL specified in the list
864 * set allok and continue in case
865 * a full path name is specified for the command
871 bname
= BASENAME(_Commands
[i
], '/');
873 bname
= _Commands
[i
];
874 DEBUG(7, "bname=%s\n", bname
);
875 if (EQUALS(bname
, name
)) {
876 (void) strcpy(fullname
, _Commands
[i
]);
881 /* ALL was specified and the command was not found in list */
882 (void) strcpy(fullname
, name
);
885 (void) strcpy(fullname
, "NuLL"); /* this is a dummy command */
891 * check the paths for this login/machine
894 * flag CK_READ or CK_WRITE
896 * path may be modified to canonical form
897 * (../, ./, // will be interpreted/removed)
900 * FAIL -> failure - not a valid path for access
909 * this is probably redundant,
910 * because expfile did it, but that's ok
911 * Note - the /../ check is not required because of canPath
913 if (canPath(path
) == FAIL
)
917 if (listMatch(path
, _RPaths
)
918 && !listMatch(path
, _NoRPaths
))
920 if (flag
== CK_WRITE
)
921 if (listMatch(path
, _WPaths
)
922 && !listMatch(path
, _NoWPaths
))
926 /* ok if uucp generated D. or X. name for the spool directory */
927 if (PREFIX(RemSpool
, path
) ) {
928 s
= &path
[strlen(RemSpool
)];
930 && (*s
== DATAPRE
|| *s
== XQTPRE
)
932 && (strchr(s
, '/') == NULL
) )
936 /* path name not valid */
941 * check write permission of file.
942 * if mopt != NULL and permissions are ok,
943 * a side effect of this routine is to make
944 * directories up to the last part of the
945 * "to" ( if they do not exit).
947 * to - a path name of the destination file or directory
948 * from - full path name of source file
949 * opt - create directory option (NULL - don't create)
951 * to - will be the full path name of the destination file
957 chkperm(from
, to
, opt
)
958 char *from
, *to
, *opt
;
962 char dir
[MAXFULLNAME
];
964 if (*(p
= LASTCHAR(to
)) == '/') {
965 if (strlcpy(p
+1, BASENAME(from
, '/'), MAXFULLNAME
- strlen(to
)) >=
966 MAXFULLNAME
- strlen(to
)) {
969 } else if (DIRECTORY(to
)) {
971 if (strlcpy(p
+1, BASENAME(from
, '/'), MAXFULLNAME
- strlen(to
)) >=
972 MAXFULLNAME
- strlen(to
)) {
977 /* to is now the full path name of the destination file */
981 if (stat(to
, &s
) == 0)
982 return(FAIL
); /* file exists, but not writeable */
984 /* file does not exist--check directory and make when necessary */
986 (void) strcpy(dir
, to
);
987 if ( (lxp
=strrchr(dir
, '/')) == NULL
)
988 return(FAIL
); /* no directory part of name */
989 if (lxp
== dir
) /* at root */
993 /* should check WRITEANY on parent before mkdirs() */
994 if (!DIRECTORY(dir
)) {
996 return(FAIL
); /* no directory and no opt to make them */
997 else if (mkdirs(dir
, PUBMASK
) == FAIL
)
1001 /* the directory now exists--check for writability */
1002 if (EQUALS(RemSpool
, dir
) || WRITEANY(dir
))