Home | History | Annotate | Download | only in common
      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 (the "License").
      6  * You may not use this file except in compliance with the License.
      7  *
      8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9  * or http://www.opensolaris.org/os/licensing.
     10  * See the License for the specific language governing permissions
     11  * and limitations under the License.
     12  *
     13  * When distributing Covered Code, include this CDDL HEADER in each
     14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15  * If applicable, add the following below this CDDL HEADER, with the
     16  * fields enclosed by brackets "[]" replaced with your own identifying
     17  * information: Portions Copyright [yyyy] [name of copyright owner]
     18  *
     19  * CDDL HEADER END
     20  */
     21 /*
     22  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
     23  * Use is subject to license terms.
     24  */
     25 
     26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
     27 
     28 #include <ctype.h>
     29 #include <string.h>
     30 #include <stdlib.h>
     31 #include <tsol/label.h>
     32 #include <bsm/devices.h>
     33 #include <bsm/devalloc.h>
     34 
     35 extern char *_strdup_null(char *);
     36 
     37 static struct _dabuff {
     38 	FILE		*_daf;	/* pointer into /etc/security/device_allocate */
     39 	devalloc_t	_interpdevalloc;
     40 	char		_interpdaline[DA_BUFSIZE + 1];
     41 	char		 *_DEVALLOC;
     42 } *__dabuff;
     43 
     44 #define	daf	(_da->_daf)
     45 #define	interpdevalloc	(_da->_interpdevalloc)
     46 #define	interpdaline	(_da->_interpdaline)
     47 #define	DEVALLOC_FILE	(_da->_DEVALLOC)
     48 static devalloc_t	*da_interpret(char *);
     49 
     50 int da_matchname(devalloc_t *, char *);
     51 int da_matchtype(devalloc_t *, char *);
     52 
     53 static int system_labeled = 0;
     54 
     55 /*
     56  * trim_white -
     57  *	trims off leading and trailing white space from input string.
     58  * 	The leading white space is skipped by moving the pointer forward.
     59  * 	The trailing white space is removed by nulling the white space
     60  *	characters.
     61  *	returns pointer to non-white string, else returns NULL if input string
     62  *	is null or if the resulting string has zero length.
     63  */
     64 char *
     65 trim_white(char *ptr)
     66 {
     67 	char	*tptr;
     68 
     69 	if (ptr == NULL)
     70 		return (NULL);
     71 	while (isspace(*ptr))
     72 		ptr++;
     73 	tptr = ptr + strlen(ptr);
     74 	while (tptr != ptr && isspace(tptr[-1]))
     75 		--tptr;
     76 	*tptr = '\0';
     77 	if (*ptr == '\0')
     78 		return (NULL);
     79 
     80 	return (ptr);
     81 }
     82 
     83 /*
     84  * pack_white -
     85  *	trims off multiple occurrences of white space from input string.
     86  * 	returns the number of spaces retained
     87  */
     88 int
     89 pack_white(char *ptr)
     90 {
     91 	int	cnt = 0;
     92 	char	*tptr, ch;
     93 
     94 	if (ptr == NULL)
     95 		return (0);
     96 	tptr = ptr;
     97 	while (isspace(*tptr))
     98 		tptr++;
     99 	for (;;) {
    100 		while ((ch = *tptr) != '\0' && !isspace(ch)) {
    101 			*ptr++ = ch;
    102 			tptr++;
    103 		}
    104 		while (isspace(*tptr))
    105 			tptr++;
    106 		if (*tptr == '\0')
    107 			break;
    108 		*ptr++ = ' ';
    109 		cnt++;
    110 	}
    111 	*ptr = '\0';
    112 
    113 	return (cnt);
    114 }
    115 
    116 /*
    117  * getdadmline -
    118  *	reads one device_alloc/device_maps line from stream into buff of len
    119  *	bytes. Continued lines from stream are concatenated into one line in
    120  *	buff. Comments are removed from buff.
    121  *	returns the number of characters in buff, else returns 0 if no
    122  * 	characters are read or an error occurred.
    123  */
    124 int
    125 getdadmline(char *buff, int len, FILE *stream)
    126 {
    127 	int 	tmpcnt;
    128 	int 	charcnt = 0;
    129 	int 	fileerr = 0;
    130 	int 	contline = 0;
    131 	char 	*cp;
    132 	char 	*ccp;
    133 
    134 	do {
    135 		cp = buff;
    136 		*cp = NULL;
    137 		do {
    138 			contline = 0;
    139 			if (fgets(cp, len - charcnt, stream) == NULL) {
    140 				fileerr = 1;
    141 				break;
    142 			}
    143 			ccp = strchr(cp, '\n');
    144 			if (ccp != NULL) {
    145 				if (ccp != cp && ccp[-1] == '\\') {
    146 					ccp--;
    147 					contline = 1;
    148 				}
    149 				else
    150 					contline = 0;
    151 				*ccp = NULL;
    152 			}
    153 			tmpcnt = strlen(cp);
    154 			cp += tmpcnt;
    155 			charcnt += tmpcnt;
    156 		} while ((contline) || (charcnt == 0));
    157 		ccp = strpbrk(buff, "#");
    158 		if (ccp != NULL)
    159 			*ccp = NULL;
    160 		charcnt = strlen(buff);
    161 	} while ((fileerr == 0) && (charcnt == 0));
    162 
    163 	if (fileerr && !charcnt)
    164 		return (0);
    165 	else
    166 		return (charcnt);
    167 }
    168 
    169 /*
    170  * _daalloc -
    171  *	allocates common buffers and structures.
    172  * 	returns pointer to the new structure, else returns NULL on error.
    173  */
    174 static struct _dabuff *
    175 _daalloc(void)
    176 {
    177 	struct _dabuff	*_da = __dabuff;
    178 
    179 	if (_da == NULL) {
    180 		_da = (struct _dabuff *)calloc((unsigned)1,
    181 		    (unsigned)sizeof (*__dabuff));
    182 		if (_da == NULL)
    183 			return (NULL);
    184 		DEVALLOC_FILE = "/etc/security/device_allocate";
    185 		daf = NULL;
    186 		__dabuff = _da;
    187 		system_labeled = is_system_labeled();
    188 	}
    189 
    190 	return (__dabuff);
    191 }
    192 
    193 /*
    194  * getdadmfield -
    195  *	gets individual fields separated by skip in ptr.
    196  */
    197 char *
    198 getdadmfield(char *ptr, char *skip)
    199 {
    200 	static char	*tptr = NULL;
    201 	char		*pend;
    202 
    203 	/* check for a continuing search */
    204 	if (ptr == NULL)
    205 		ptr = tptr;
    206 	/* check for source end */
    207 	if (ptr == NULL || *ptr == '\0')
    208 		return (NULL);
    209 	/* find terminator */
    210 	pend = strpbrk(ptr, skip);
    211 	/* terminate and set continuation pointer */
    212 	if (pend != NULL) {
    213 		*pend++ = '\0';
    214 		tptr = pend;
    215 	} else
    216 		tptr = NULL;
    217 	/*
    218 	 * trim off any surrounding white space, return what's left
    219 	 */
    220 
    221 	return (trim_white(ptr));
    222 }
    223 
    224 /*
    225  * setdaent -
    226  *	rewinds the device_allocate file to the begining.
    227  */
    228 
    229 void
    230 setdaent(void)
    231 {
    232 	struct _dabuff	*_da = _daalloc();
    233 
    234 	if (_da == NULL)
    235 		return;
    236 	if (daf == NULL)
    237 		daf = fopen(DEVALLOC_FILE, "rF");
    238 	else
    239 		rewind(daf);
    240 }
    241 
    242 /*
    243  * enddaent -
    244  *	closes device_allocate file.
    245  */
    246 
    247 void
    248 enddaent(void)
    249 {
    250 	struct _dabuff	*_da = _daalloc();
    251 
    252 	if (_da == NULL)
    253 		return;
    254 	if (daf != NULL) {
    255 		(void) fclose(daf);
    256 		daf = NULL;
    257 	}
    258 }
    259 
    260 /*
    261  * setdafile -
    262  *	changes the default device_allocate file to the one specified.
    263  * 	It does not close the previous file. If this is desired, enddaent
    264  *	should be called prior to setdafile.
    265  */
    266 void
    267 setdafile(char *file)
    268 {
    269 	struct _dabuff	*_da = _daalloc();
    270 
    271 	if (_da == NULL)
    272 		return;
    273 	if (daf != NULL) {
    274 		(void) fclose(daf);
    275 		daf = NULL;
    276 	}
    277 	DEVALLOC_FILE = file;
    278 }
    279 
    280 void
    281 freedaent(devalloc_t *dap)
    282 {
    283 	if (dap == NULL)
    284 		return;
    285 	_kva_free(dap->da_devopts);
    286 	dap->da_devopts = NULL;
    287 }
    288 
    289 /*
    290  * getdaon -
    291  *	checks if device_allocate has string DEVICE_ALLOCATION=ON or
    292  *	DEVICE_ALLOCATION=OFF string in it.
    293  *	returns 1 if the string is DEVICE_ALLOCATION=ON, 0 if it is
    294  *	DEVICE_ALLOCATION=OFF, -1 if neither string present.
    295  */
    296 int
    297 getdaon()
    298 {
    299 	int		is_on = -1;
    300 	char		line1[DA_BUFSIZE + 1];
    301 	struct _dabuff *_da = _daalloc();
    302 
    303 	setdaent();
    304 	if ((_da == NULL) || (daf == NULL)) {
    305 		enddaent();
    306 		return (is_on);
    307 	}
    308 	while (getdadmline(line1, (int)sizeof (line1), daf) != 0) {
    309 		if (strncmp(line1, DA_ON_STR, (strlen(DA_ON_STR) - 1)) == 0) {
    310 			is_on = 1;
    311 			break;
    312 		} else if (strncmp(line1, DA_OFF_STR,
    313 		    (strlen(DA_OFF_STR) - 1)) == 0) {
    314 			is_on = 0;
    315 			break;
    316 		}
    317 	}
    318 	enddaent();
    319 
    320 	return (is_on);
    321 }
    322 
    323 /*
    324  * getdaent -
    325  *	When first called, returns a pointer to the first devalloc_t
    326  * 	structure in device_allocate; thereafter, it returns a pointer to the
    327  *	next devalloc_t structure in the file. Thus, successive calls can be
    328  *	used to search the entire file.
    329  *	call to getdaent should be bracketed by setdaent and enddaent.
    330  *	returns NULL on error.
    331  */
    332 devalloc_t *
    333 getdaent(void)
    334 {
    335 	char		line1[DA_BUFSIZE + 1];
    336 	devalloc_t	*da;
    337 	struct _dabuff	*_da = _daalloc();
    338 
    339 	if ((_da == 0) || (daf == NULL))
    340 		return (NULL);
    341 
    342 	while (getdadmline(line1, (int)sizeof (line1), daf) != 0) {
    343 		if ((strncmp(line1, DA_ON_STR, (strlen(DA_ON_STR) - 1)) == 0) ||
    344 		    (strncmp(line1, DA_OFF_STR, (strlen(DA_OFF_STR) - 1)) == 0))
    345 			continue;
    346 		if ((da = da_interpret(line1)) == NULL)
    347 			continue;
    348 		return (da);
    349 	}
    350 
    351 	return (NULL);
    352 }
    353 
    354 /*
    355  * getdanam
    356  * 	searches from the beginning of device_allocate for the device specified
    357  * 	by its name.
    358  *	call to getdanam should be bracketed by setdaent and enddaent.
    359  * 	returns pointer to devalloc_t for the device if it is found, else
    360  *	returns NULL if device not found or in case of error.
    361  */
    362 devalloc_t *
    363 getdanam(char *name)
    364 {
    365 	char		line[DA_BUFSIZE + 1];
    366 	devalloc_t	*da;
    367 	struct _dabuff	*_da = _daalloc();
    368 
    369 	if ((name == NULL) || (_da == 0) || (daf == NULL))
    370 		return (NULL);
    371 
    372 	while (getdadmline(line, (int)sizeof (line), daf) != 0) {
    373 		if (strstr(line, name) == NULL)
    374 			continue;
    375 		if ((da = da_interpret(line)) == NULL)
    376 			continue;
    377 		if (da_matchname(da, name)) {
    378 			enddaent();
    379 			return (da);
    380 		}
    381 		freedaent(da);
    382 	}
    383 
    384 	return (NULL);
    385 }
    386 
    387 /*
    388  * getdatype -
    389  * 	searches from the beginning of device_allocate for the device specified
    390  * 	by its type.
    391  *	call to getdatype should be bracketed by setdaent and enddaent.
    392  * 	returns pointer to devalloc_t for the device if it is found, else
    393  *	returns NULL if device not found or in case of error.
    394  */
    395 devalloc_t *
    396 getdatype(char *type)
    397 {
    398 	char		line1[DA_BUFSIZE + 1];
    399 	devalloc_t	*da;
    400 	struct _dabuff	*_da = _daalloc();
    401 
    402 	if ((type == NULL) || (_da == NULL) || (daf == NULL))
    403 		return (NULL);
    404 
    405 	while (getdadmline(line1, (int)sizeof (line1), daf) != 0) {
    406 		if (strstr(line1, type) == NULL)
    407 			continue;
    408 		if ((da = da_interpret(line1)) == NULL)
    409 			continue;
    410 		if (da_matchtype(da, type))
    411 			return (da);
    412 		freedaent(da);
    413 	}
    414 
    415 	return (NULL);
    416 }
    417 
    418 /*
    419  * da_matchname -
    420  *	checks if the specified devalloc_t is for the device specified.
    421  * 	returns 1 if it is, else returns 0.
    422  */
    423 int
    424 da_matchname(devalloc_t *dap, char *name)
    425 {
    426 	if (dap->da_devname == NULL)
    427 		return (0);
    428 
    429 	return ((strcmp(dap->da_devname, name) == 0));
    430 }
    431 
    432 /*
    433  * da_matchtype -
    434  *	checks if the specified devalloc_t is for the device type specified.
    435  *	returns 1 if match found, else, returns 0.
    436  */
    437 int
    438 da_matchtype(devalloc_t *da, char *type)
    439 {
    440 	if (da->da_devtype == NULL)
    441 		return (0);
    442 
    443 	return ((strcmp(da->da_devtype, type) == 0));
    444 }
    445 
    446 /*
    447  * da_match -
    448  * 	calls da_matchname or da_matchdev as appropriate.
    449  */
    450 int
    451 da_match(devalloc_t *dap, da_args *dargs)
    452 {
    453 	if (dargs->devinfo->devname)
    454 		return (da_matchname(dap, dargs->devinfo->devname));
    455 	else if (dargs->devinfo->devtype)
    456 		return (da_matchtype(dap, dargs->devinfo->devtype));
    457 
    458 	return (0);
    459 }
    460 
    461 /*
    462  * da_interpret -
    463  *	parses val and initializes pointers in devalloc_t.
    464  * 	returns pointer to parsed devalloc_t entry, else returns NULL on error.
    465  */
    466 static devalloc_t  *
    467 da_interpret(char *val)
    468 {
    469 	struct _dabuff	*_da = _daalloc();
    470 	char	*opts;
    471 	int	i;
    472 	kva_t	*kvap;
    473 	kv_t	*kvp;
    474 
    475 	if (_da == NULL)
    476 		return (NULL);
    477 
    478 	(void) strcpy(interpdaline, val);
    479 	interpdevalloc.da_devname = getdadmfield(interpdaline, KV_DELIMITER);
    480 	interpdevalloc.da_devtype = getdadmfield(NULL, KV_DELIMITER);
    481 	opts = getdadmfield(NULL, KV_DELIMITER);
    482 	(void) getdadmfield(NULL, KV_DELIMITER);	/* reserved field */
    483 	interpdevalloc.da_devauth = getdadmfield(NULL, KV_DELIMITER);
    484 	interpdevalloc.da_devexec = getdadmfield(NULL, KV_DELIMITER);
    485 	interpdevalloc.da_devopts = NULL;
    486 	if (interpdevalloc.da_devname == NULL ||
    487 	    interpdevalloc.da_devtype == NULL)
    488 		return (NULL);
    489 	if ((opts != NULL) &&
    490 	    (strncmp(opts, DA_RESERVED, strlen(DA_RESERVED)) != 0)) {
    491 		interpdevalloc.da_devopts =
    492 		    _str2kva(opts, KV_ASSIGN, KV_TOKEN_DELIMIT);
    493 	}
    494 	/* remove any extraneous whitespace in the options */
    495 	if ((kvap = interpdevalloc.da_devopts) != NULL) {
    496 		for (i = 0, kvp = kvap->data; i < kvap->length; i++, kvp++) {
    497 			(void) pack_white(kvp->key);
    498 			(void) pack_white(kvp->value);
    499 		}
    500 	}
    501 
    502 	if (system_labeled) {
    503 		/* if label range is not defined, use the default range. */
    504 		int		i = 0, nlen = 0;
    505 		char		*minstr = NULL, *maxstr = NULL;
    506 		kva_t		*nkvap = NULL;
    507 		kv_t		*ndata = NULL, *odata = NULL;
    508 
    509 		if (kvap == NULL) {
    510 			nlen = 2;	/* minlabel, maxlabel */
    511 		} else {
    512 			nlen += kvap->length;
    513 			if ((minstr = kva_match(kvap, DAOPT_MINLABEL)) == NULL)
    514 				nlen++;
    515 			if ((maxstr = kva_match(kvap, DAOPT_MAXLABEL)) == NULL)
    516 				nlen++;
    517 		}
    518 		if ((minstr != NULL) && (maxstr != NULL))
    519 			/*
    520 			 * label range provided; we don't need to construct
    521 			 * default range.
    522 			 */
    523 			goto out;
    524 		nkvap = _new_kva(nlen);
    525 		ndata = nkvap->data;
    526 		if (kvap != NULL) {
    527 			for (i = 0; i < kvap->length; i++) {
    528 				odata = kvap->data;
    529 				ndata[i].key = _strdup_null(odata[i].key);
    530 				ndata[i].value = _strdup_null(odata[i].value);
    531 				nkvap->length++;
    532 			}
    533 		}
    534 		if (minstr == NULL) {
    535 			ndata[i].key = strdup(DAOPT_MINLABEL);
    536 			ndata[i].value = strdup(DA_DEFAULT_MIN);
    537 			nkvap->length++;
    538 			i++;
    539 		}
    540 		if (maxstr == NULL) {
    541 			ndata[i].key = strdup(DAOPT_MAXLABEL);
    542 			ndata[i].value = strdup(DA_DEFAULT_MAX);
    543 			nkvap->length++;
    544 		}
    545 		interpdevalloc.da_devopts = nkvap;
    546 	}
    547 
    548 out:
    549 	return (&interpdevalloc);
    550 }
    551