Home | History | Annotate | Download | only in bnu
      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
    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
    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
    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
    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
    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
    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
    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
    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 *
    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
    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 *
    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
    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 *
    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
    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
    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
    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
    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
    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
    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
    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
    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
    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