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 2006 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 <string.h>
     29 #include <stdlib.h>
     30 #include <bsm/devices.h>
     31 #include <bsm/devalloc.h>
     32 
     33 char *strtok_r(char *, const char *, char **);
     34 
     35 /* externs from getdaent.c */
     36 extern char *trim_white(char *);
     37 extern int pack_white(char *);
     38 extern char *getdadmfield(char *, char *);
     39 extern int getdadmline(char *, int, FILE *);
     40 
     41 static struct _dmapbuff {
     42 	FILE		*_dmapf;	/* for /etc/security/device_maps */
     43 	devmap_t	_interpdevmap;
     44 	char		_interpdmline[DA_BUFSIZE + 1];
     45 	char		*_DEVMAP;
     46 } *__dmapbuff;
     47 
     48 #define	dmapf	(_dmap->_dmapf)
     49 #define	interpdevmap	(_dmap->_interpdevmap)
     50 #define	interpdmline	(_dmap->_interpdmline)
     51 #define	DEVMAPS_FILE	(_dmap->_DEVMAP)
     52 
     53 devmap_t	*dmap_interpret(char *, devmap_t *);
     54 static devmap_t	*dmap_interpretf(char *, devmap_t *);
     55 static devmap_t *dmap_dlexpand(devmap_t *);
     56 
     57 int	dmap_matchdev(devmap_t *, char *);
     58 int	dmap_matchname(devmap_t *, char *);
     59 
     60 
     61 /*
     62  * _dmapalloc -
     63  *	allocates common buffers and structures.
     64  *	returns pointer to the new structure, else returns NULL on error.
     65  */
     66 static struct _dmapbuff *
     67 _dmapalloc(void)
     68 {
     69 	struct _dmapbuff *_dmap = __dmapbuff;
     70 
     71 	if (_dmap == NULL) {
     72 		_dmap = (struct _dmapbuff *)calloc((unsigned)1,
     73 		    (unsigned)sizeof (*__dmapbuff));
     74 		if (_dmap == NULL)
     75 			return (NULL);
     76 		DEVMAPS_FILE = "/etc/security/device_maps";
     77 		dmapf = NULL;
     78 		__dmapbuff = _dmap;
     79 	}
     80 
     81 	return (_dmap);
     82 }
     83 
     84 /*
     85  * setdmapent -
     86  *	rewinds the device_maps file to the beginning.
     87  */
     88 void
     89 setdmapent(void)
     90 {
     91 	struct _dmapbuff *_dmap = _dmapalloc();
     92 
     93 	if (_dmap == NULL)
     94 		return;
     95 	if (dmapf == NULL)
     96 		dmapf = fopen(DEVMAPS_FILE, "rF");
     97 	else
     98 		rewind(dmapf);
     99 }
    100 
    101 /*
    102  * enddmapent -
    103  *	closes device_maps file.
    104  */
    105 void
    106 enddmapent(void)
    107 {
    108 	struct _dmapbuff *_dmap = _dmapalloc();
    109 
    110 	if (_dmap == NULL)
    111 		return;
    112 	if (dmapf != NULL) {
    113 		(void) fclose(dmapf);
    114 		dmapf = NULL;
    115 	}
    116 }
    117 
    118 void
    119 freedmapent(devmap_t *dmap)
    120 {
    121 	char	**darp;
    122 
    123 	if ((darp = dmap->dmap_devarray) != NULL) {
    124 		while (*darp != NULL)
    125 			free(*darp++);
    126 		free(dmap->dmap_devarray);
    127 		dmap->dmap_devarray = NULL;
    128 	}
    129 }
    130 
    131 /*
    132  * setdmapfile -
    133  *	changes the default device_maps file to the one specified.
    134  *	It does not close the previous file. If this is desired, enddmapent
    135  *	should be called prior to setdampfile.
    136  */
    137 void
    138 setdmapfile(char *file)
    139 {
    140 	struct _dmapbuff *_dmap = _dmapalloc();
    141 
    142 	if (_dmap == NULL)
    143 		return;
    144 	if (dmapf != NULL) {
    145 		(void) fclose(dmapf);
    146 		dmapf = NULL;
    147 	}
    148 	DEVMAPS_FILE = file;
    149 }
    150 
    151 /*
    152  * getdmapent -
    153  * 	When first called, returns a pointer to the first devmap_t structure
    154  * 	in device_maps; thereafter, it returns a pointer to the next devmap_t
    155  *	structure in the file. Thus successive calls can be used to read the
    156  *	entire file.
    157  *	call to getdmapent should be bracketed by setdmapent and enddmapent.
    158  * 	returns pointer to devmap_t found, else returns NULL if no entry found
    159  * 	or on error.
    160  */
    161 devmap_t *
    162 getdmapent(void)
    163 {
    164 	devmap_t		*dmap;
    165 	struct _dmapbuff 	*_dmap = _dmapalloc();
    166 
    167 	if ((_dmap == 0) || (dmapf == NULL))
    168 		return (NULL);
    169 
    170 	while (getdadmline(interpdmline, (int)sizeof (interpdmline),
    171 	    dmapf) != 0) {
    172 		if ((dmap = dmap_interpret(interpdmline,
    173 		    &interpdevmap)) == NULL)
    174 			continue;
    175 		return (dmap);
    176 	}
    177 
    178 	return (NULL);
    179 }
    180 
    181 /*
    182  * getdmapnam -
    183  *	searches from the beginning of device_maps for the device specified by
    184  *	its name.
    185  *	call to getdmapnam should be bracketed by setdmapent and enddmapent.
    186  * 	returns pointer to devmapt_t for the device if it is found, else
    187  * 	returns NULL if device not found or in case of error.
    188  */
    189 devmap_t *
    190 getdmapnam(char *name)
    191 {
    192 	devmap_t		*dmap;
    193 	struct _dmapbuff	*_dmap = _dmapalloc();
    194 
    195 	if ((name == NULL) || (_dmap == 0) || (dmapf == NULL))
    196 		return (NULL);
    197 
    198 	while (getdadmline(interpdmline, (int)sizeof (interpdmline),
    199 	    dmapf) != 0) {
    200 		if (strstr(interpdmline, name) == NULL)
    201 			continue;
    202 		if ((dmap = dmap_interpretf(interpdmline,
    203 		    &interpdevmap)) == NULL)
    204 			continue;
    205 		if (dmap_matchname(dmap, name)) {
    206 			if ((dmap = dmap_dlexpand(dmap)) == NULL)
    207 				continue;
    208 			enddmapent();
    209 			return (dmap);
    210 		}
    211 		freedmapent(dmap);
    212 	}
    213 
    214 	return (NULL);
    215 }
    216 
    217 /*
    218  * getdmapdev -
    219  *	searches from the beginning of device_maps for the device specified by
    220  *	its logical name.
    221  *	call to getdmapdev should be bracketed by setdmapent and enddmapent.
    222  * 	returns  pointer to the devmap_t for the device if device is found,
    223  *	else returns NULL if device not found or on error.
    224  */
    225 devmap_t *
    226 getdmapdev(char *dev)
    227 {
    228 	devmap_t		*dmap;
    229 	struct _dmapbuff	*_dmap = _dmapalloc();
    230 
    231 	if ((dev == NULL) || (_dmap == 0) || (dmapf == NULL))
    232 		return (NULL);
    233 
    234 	while (getdadmline(interpdmline, (int)sizeof (interpdmline),
    235 	    dmapf) != 0) {
    236 		if ((dmap = dmap_interpret(interpdmline,
    237 		    &interpdevmap)) == NULL)
    238 			continue;
    239 		if (dmap_matchdev(dmap, dev)) {
    240 			enddmapent();
    241 			return (dmap);
    242 		}
    243 		freedmapent(dmap);
    244 	}
    245 
    246 	return (NULL);
    247 }
    248 
    249 /*
    250  * getdmaptype -
    251  *	searches from the beginning of device_maps for the device specified by
    252  *	its type.
    253  *	call to getdmaptype should be bracketed by setdmapent and enddmapent.
    254  * 	returns pointer to devmap_t found, else returns NULL if no entry found
    255  * 	or on error.
    256  */
    257 devmap_t *
    258 getdmaptype(char *type)
    259 {
    260 	devmap_t		*dmap;
    261 	struct _dmapbuff	*_dmap = _dmapalloc();
    262 
    263 	if ((type == NULL) || (_dmap == 0) || (dmapf == NULL))
    264 		return (NULL);
    265 
    266 	while (getdadmline(interpdmline, (int)sizeof (interpdmline),
    267 	    dmapf) != 0) {
    268 		if ((dmap = dmap_interpretf(interpdmline,
    269 		    &interpdevmap)) == NULL)
    270 			continue;
    271 		if (dmap->dmap_devtype != NULL &&
    272 		    strcmp(type, dmap->dmap_devtype) == 0) {
    273 			if ((dmap = dmap_dlexpand(dmap)) == NULL)
    274 				continue;
    275 			return (dmap);
    276 		}
    277 		freedmapent(dmap);
    278 	}
    279 
    280 	return (NULL);
    281 }
    282 
    283 /*
    284  * dmap_matchdev -
    285  * 	checks if the specified devmap_t is for the device specified.
    286  *	returns 1 if it is, else returns 0.
    287  */
    288 int
    289 dmap_matchdev(devmap_t *dmap, char *dev)
    290 {
    291 	char **dva;
    292 	char *dv;
    293 
    294 	if (dmap->dmap_devarray == NULL)
    295 		return (0);
    296 	for (dva = dmap->dmap_devarray; (dv = *dva) != NULL; dva ++) {
    297 		if (strcmp(dv, dev) == 0)
    298 			return (1);
    299 	}
    300 
    301 	return (0);
    302 }
    303 
    304 /*
    305  * dmap_matchtype -
    306  *	checks if the specified devmap_t is for the device specified.
    307  *	returns 1 if it is, else returns 0.
    308  */
    309 int
    310 dmap_matchtype(devmap_t *dmap, char *type)
    311 {
    312 	if ((dmap->dmap_devtype == NULL) || (type == NULL))
    313 		return (0);
    314 
    315 	return ((strcmp(dmap->dmap_devtype, type) == 0));
    316 }
    317 
    318 /*
    319  * dmap_matchname -
    320  * 	checks if the specified devmap_t is for the device specified.
    321  * 	returns 1 if it is, else returns 0.
    322  */
    323 int
    324 dmap_matchname(devmap_t *dmap, char *name)
    325 {
    326 	if (dmap->dmap_devname == NULL)
    327 		return (0);
    328 
    329 	return ((strcmp(dmap->dmap_devname, name) == 0));
    330 }
    331 
    332 /*
    333  * dm_match -
    334  *	calls dmap_matchname or dmap_matchtype as appropriate.
    335  */
    336 int
    337 dm_match(devmap_t *dmap, da_args *dargs)
    338 {
    339 	if (dargs->devinfo->devname)
    340 		return (dmap_matchname(dmap, dargs->devinfo->devname));
    341 	else if (dargs->devinfo->devtype)
    342 		return (dmap_matchtype(dmap, dargs->devinfo->devtype));
    343 
    344 	return (0);
    345 }
    346 
    347 /*
    348  * dmap_interpret -
    349  *	calls dmap_interpretf and dmap_dlexpand to parse devmap_t line.
    350  *	returns  pointer to parsed devmapt_t entry, else returns NULL on error.
    351  */
    352 devmap_t  *
    353 dmap_interpret(char *val, devmap_t *dm)
    354 {
    355 	if (dmap_interpretf(val, dm) == NULL)
    356 		return (NULL);
    357 
    358 	return (dmap_dlexpand(dm));
    359 }
    360 
    361 /*
    362  * dmap_interpretf -
    363  * 	parses string "val" and initializes pointers in the given devmap_t to
    364  * 	fields in "val".
    365  * 	returns pointer to updated devmap_t.
    366  */
    367 static devmap_t  *
    368 dmap_interpretf(char *val, devmap_t *dm)
    369 {
    370 	dm->dmap_devname = getdadmfield(val, KV_TOKEN_DELIMIT);
    371 	dm->dmap_devtype = getdadmfield(NULL, KV_TOKEN_DELIMIT);
    372 	dm->dmap_devlist = getdadmfield(NULL, KV_TOKEN_DELIMIT);
    373 	dm->dmap_devarray = NULL;
    374 	if (dm->dmap_devname == NULL ||
    375 	    dm->dmap_devtype == NULL ||
    376 	    dm->dmap_devlist == NULL)
    377 		return (NULL);
    378 
    379 	return (dm);
    380 }
    381 
    382 /*
    383  * dmap_dlexpand -
    384  * 	expands dmap_devlist of the form `devlist_generate`
    385  *	returns unexpanded form if there is no '\`' or in case of error.
    386  */
    387 static devmap_t *
    388 dmap_dlexpand(devmap_t *dmp)
    389 {
    390 	char	tmplist[DA_BUFSIZE + 1];
    391 	char	*cp, *cpl, **darp;
    392 	int	count;
    393 	FILE	*expansion;
    394 
    395 	dmp->dmap_devarray = NULL;
    396 	if (dmp->dmap_devlist == NULL)
    397 		return (NULL);
    398 	if (*(dmp->dmap_devlist) != '`') {
    399 		(void) strcpy(tmplist, dmp->dmap_devlist);
    400 	} else {
    401 		(void) strcpy(tmplist, dmp->dmap_devlist + 1);
    402 		if ((cp = strchr(tmplist, '`')) != NULL)
    403 			*cp = '\0';
    404 		if ((expansion = popen(tmplist, "rF")) == NULL)
    405 			return (NULL);
    406 		count = fread(tmplist, 1, sizeof (tmplist) - 1, expansion);
    407 		(void) pclose(expansion);
    408 		tmplist[count] = '\0';
    409 	}
    410 
    411 	/* cleanup the list */
    412 	count = pack_white(tmplist);
    413 	dmp->dmap_devarray = darp =
    414 	    (char **)malloc((count + 2) * sizeof (char *));
    415 	if (darp == NULL)
    416 		return (NULL);
    417 	cp = tmplist;
    418 	while ((cp = strtok_r(cp, " ", &cpl)) != NULL) {
    419 		*darp = strdup(cp);
    420 		if (*darp == NULL) {
    421 			freedmapent(dmp);
    422 			return (NULL);
    423 		}
    424 		darp++;
    425 		cp = NULL;
    426 	}
    427 	*darp = NULL;
    428 
    429 	return (dmp);
    430 }
    431 
    432 /*
    433  * dmapskip -
    434  * 	scans input string to find next colon or end of line.
    435  *	returns pointer to next char.
    436  */
    437 static char *
    438 dmapskip(char *p)
    439 {
    440 	while (*p && *p != ':' && *p != '\n')
    441 		++p;
    442 	if (*p == '\n')
    443 		*p = '\0';
    444 	else if (*p != '\0')
    445 		*p++ = '\0';
    446 
    447 	return (p);
    448 }
    449 
    450 /*
    451  * dmapdskip -
    452  * 	scans input string to find next space or end of line.
    453  *	returns pointer to next char.
    454  */
    455 static char *
    456 dmapdskip(p)
    457 	register char *p;
    458 {
    459 	while (*p && *p != ' ' && *p != '\n')
    460 		++p;
    461 	if (*p != '\0')
    462 		*p++ = '\0';
    463 
    464 	return (p);
    465 }
    466 
    467 char *
    468 getdmapfield(char *ptr)
    469 {
    470 	static	char	*tptr;
    471 
    472 	if (ptr == NULL)
    473 		ptr = tptr;
    474 	if (ptr == NULL)
    475 		return (NULL);
    476 	tptr = dmapskip(ptr);
    477 	ptr = trim_white(ptr);
    478 	if (ptr == NULL)
    479 		return (NULL);
    480 	if (*ptr == NULL)
    481 		return (NULL);
    482 
    483 	return (ptr);
    484 }
    485 
    486 char *
    487 getdmapdfield(char *ptr)
    488 {
    489 	static	char	*tptr;
    490 	if (ptr != NULL) {
    491 		ptr = trim_white(ptr);
    492 	} else {
    493 		ptr = tptr;
    494 	}
    495 	if (ptr == NULL)
    496 		return (NULL);
    497 	tptr = dmapdskip(ptr);
    498 	if (ptr == NULL)
    499 		return (NULL);
    500 	if (*ptr == NULL)
    501 		return (NULL);
    502 
    503 	return (ptr);
    504 }
    505