| /* |
| * CDDL HEADER START |
| * |
| * The contents of this file are subject to the terms of the |
| * Common Development and Distribution License (the "License"). |
| * You may not use this file except in compliance with the License. |
| * |
| * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE |
| * or http://www.opensolaris.org/os/licensing. |
| * See the License for the specific language governing permissions |
| * and limitations under the License. |
| * |
| * When distributing Covered Code, include this CDDL HEADER in each |
| * file and include the License file at usr/src/OPENSOLARIS.LICENSE. |
| * If applicable, add the following below this CDDL HEADER, with the |
| * fields enclosed by brackets "[]" replaced with your own identifying |
| * information: Portions Copyright [yyyy] [name of copyright owner] |
| * |
| * CDDL HEADER END |
| */ |
| /* |
| * Copyright 2006 Sun Microsystems, Inc. All rights reserved. |
| * Use is subject to license terms. |
| */ |
| |
| #pragma ident "%Z%%M% %I% %E% SMI" |
| |
| #include <string.h> |
| #include <stdlib.h> |
| #include <bsm/devices.h> |
| #include <bsm/devalloc.h> |
| |
| char *strtok_r(char *, const char *, char **); |
| |
| /* externs from getdaent.c */ |
| extern char *trim_white(char *); |
| extern int pack_white(char *); |
| extern char *getdadmfield(char *, char *); |
| extern int getdadmline(char *, int, FILE *); |
| |
| static struct _dmapbuff { |
| FILE *_dmapf; /* for /etc/security/device_maps */ |
| devmap_t _interpdevmap; |
| char _interpdmline[DA_BUFSIZE + 1]; |
| char *_DEVMAP; |
| } *__dmapbuff; |
| |
| #define dmapf (_dmap->_dmapf) |
| #define interpdevmap (_dmap->_interpdevmap) |
| #define interpdmline (_dmap->_interpdmline) |
| #define DEVMAPS_FILE (_dmap->_DEVMAP) |
| |
| devmap_t *dmap_interpret(char *, devmap_t *); |
| static devmap_t *dmap_interpretf(char *, devmap_t *); |
| static devmap_t *dmap_dlexpand(devmap_t *); |
| |
| int dmap_matchdev(devmap_t *, char *); |
| int dmap_matchname(devmap_t *, char *); |
| |
| |
| /* |
| * _dmapalloc - |
| * allocates common buffers and structures. |
| * returns pointer to the new structure, else returns NULL on error. |
| */ |
| static struct _dmapbuff * |
| _dmapalloc(void) |
| { |
| struct _dmapbuff *_dmap = __dmapbuff; |
| |
| if (_dmap == NULL) { |
| _dmap = (struct _dmapbuff *)calloc((unsigned)1, |
| (unsigned)sizeof (*__dmapbuff)); |
| if (_dmap == NULL) |
| return (NULL); |
| DEVMAPS_FILE = "/etc/security/device_maps"; |
| dmapf = NULL; |
| __dmapbuff = _dmap; |
| } |
| |
| return (_dmap); |
| } |
| |
| /* |
| * setdmapent - |
| * rewinds the device_maps file to the beginning. |
| */ |
| void |
| setdmapent(void) |
| { |
| struct _dmapbuff *_dmap = _dmapalloc(); |
| |
| if (_dmap == NULL) |
| return; |
| if (dmapf == NULL) |
| dmapf = fopen(DEVMAPS_FILE, "r"); |
| else |
| rewind(dmapf); |
| } |
| |
| /* |
| * enddmapent - |
| * closes device_maps file. |
| */ |
| void |
| enddmapent(void) |
| { |
| struct _dmapbuff *_dmap = _dmapalloc(); |
| |
| if (_dmap == NULL) |
| return; |
| if (dmapf != NULL) { |
| (void) fclose(dmapf); |
| dmapf = NULL; |
| } |
| } |
| |
| void |
| freedmapent(devmap_t *dmap) |
| { |
| char **darp; |
| |
| if ((darp = dmap->dmap_devarray) != NULL) { |
| while (*darp != NULL) |
| free(*darp++); |
| free(dmap->dmap_devarray); |
| dmap->dmap_devarray = NULL; |
| } |
| } |
| |
| /* |
| * setdmapfile - |
| * changes the default device_maps file to the one specified. |
| * It does not close the previous file. If this is desired, enddmapent |
| * should be called prior to setdampfile. |
| */ |
| void |
| setdmapfile(char *file) |
| { |
| struct _dmapbuff *_dmap = _dmapalloc(); |
| |
| if (_dmap == NULL) |
| return; |
| if (dmapf != NULL) { |
| (void) fclose(dmapf); |
| dmapf = NULL; |
| } |
| DEVMAPS_FILE = file; |
| } |
| |
| /* |
| * getdmapent - |
| * When first called, returns a pointer to the first devmap_t structure |
| * in device_maps; thereafter, it returns a pointer to the next devmap_t |
| * structure in the file. Thus successive calls can be used to read the |
| * entire file. |
| * call to getdmapent should be bracketed by setdmapent and enddmapent. |
| * returns pointer to devmap_t found, else returns NULL if no entry found |
| * or on error. |
| */ |
| devmap_t * |
| getdmapent(void) |
| { |
| devmap_t *dmap; |
| struct _dmapbuff *_dmap = _dmapalloc(); |
| |
| if ((_dmap == 0) || (dmapf == NULL)) |
| return (NULL); |
| |
| while (getdadmline(interpdmline, (int)sizeof (interpdmline), |
| dmapf) != 0) { |
| if ((dmap = dmap_interpret(interpdmline, |
| &interpdevmap)) == NULL) |
| continue; |
| return (dmap); |
| } |
| |
| return (NULL); |
| } |
| |
| /* |
| * getdmapnam - |
| * searches from the beginning of device_maps for the device specified by |
| * its name. |
| * call to getdmapnam should be bracketed by setdmapent and enddmapent. |
| * returns pointer to devmapt_t for the device if it is found, else |
| * returns NULL if device not found or in case of error. |
| */ |
| devmap_t * |
| getdmapnam(char *name) |
| { |
| devmap_t *dmap; |
| struct _dmapbuff *_dmap = _dmapalloc(); |
| |
| if ((name == NULL) || (_dmap == 0) || (dmapf == NULL)) |
| return (NULL); |
| |
| while (getdadmline(interpdmline, (int)sizeof (interpdmline), |
| dmapf) != 0) { |
| if (strstr(interpdmline, name) == NULL) |
| continue; |
| if ((dmap = dmap_interpretf(interpdmline, |
| &interpdevmap)) == NULL) |
| continue; |
| if (dmap_matchname(dmap, name)) { |
| if ((dmap = dmap_dlexpand(dmap)) == NULL) |
| continue; |
| enddmapent(); |
| return (dmap); |
| } |
| freedmapent(dmap); |
| } |
| |
| return (NULL); |
| } |
| |
| /* |
| * getdmapdev - |
| * searches from the beginning of device_maps for the device specified by |
| * its logical name. |
| * call to getdmapdev should be bracketed by setdmapent and enddmapent. |
| * returns pointer to the devmap_t for the device if device is found, |
| * else returns NULL if device not found or on error. |
| */ |
| devmap_t * |
| getdmapdev(char *dev) |
| { |
| devmap_t *dmap; |
| struct _dmapbuff *_dmap = _dmapalloc(); |
| |
| if ((dev == NULL) || (_dmap == 0) || (dmapf == NULL)) |
| return (NULL); |
| |
| while (getdadmline(interpdmline, (int)sizeof (interpdmline), |
| dmapf) != 0) { |
| if ((dmap = dmap_interpret(interpdmline, |
| &interpdevmap)) == NULL) |
| continue; |
| if (dmap_matchdev(dmap, dev)) { |
| enddmapent(); |
| return (dmap); |
| } |
| freedmapent(dmap); |
| } |
| |
| return (NULL); |
| } |
| |
| /* |
| * getdmaptype - |
| * searches from the beginning of device_maps for the device specified by |
| * its type. |
| * call to getdmaptype should be bracketed by setdmapent and enddmapent. |
| * returns pointer to devmap_t found, else returns NULL if no entry found |
| * or on error. |
| */ |
| devmap_t * |
| getdmaptype(char *type) |
| { |
| devmap_t *dmap; |
| struct _dmapbuff *_dmap = _dmapalloc(); |
| |
| if ((type == NULL) || (_dmap == 0) || (dmapf == NULL)) |
| return (NULL); |
| |
| while (getdadmline(interpdmline, (int)sizeof (interpdmline), |
| dmapf) != 0) { |
| if ((dmap = dmap_interpretf(interpdmline, |
| &interpdevmap)) == NULL) |
| continue; |
| if (dmap->dmap_devtype != NULL && |
| strcmp(type, dmap->dmap_devtype) == 0) { |
| if ((dmap = dmap_dlexpand(dmap)) == NULL) |
| continue; |
| return (dmap); |
| } |
| freedmapent(dmap); |
| } |
| |
| return (NULL); |
| } |
| |
| /* |
| * dmap_matchdev - |
| * checks if the specified devmap_t is for the device specified. |
| * returns 1 if it is, else returns 0. |
| */ |
| int |
| dmap_matchdev(devmap_t *dmap, char *dev) |
| { |
| char **dva; |
| char *dv; |
| |
| if (dmap->dmap_devarray == NULL) |
| return (0); |
| for (dva = dmap->dmap_devarray; (dv = *dva) != NULL; dva ++) { |
| if (strcmp(dv, dev) == 0) |
| return (1); |
| } |
| |
| return (0); |
| } |
| |
| /* |
| * dmap_matchtype - |
| * checks if the specified devmap_t is for the device specified. |
| * returns 1 if it is, else returns 0. |
| */ |
| int |
| dmap_matchtype(devmap_t *dmap, char *type) |
| { |
| if ((dmap->dmap_devtype == NULL) || (type == NULL)) |
| return (0); |
| |
| return ((strcmp(dmap->dmap_devtype, type) == 0)); |
| } |
| |
| /* |
| * dmap_matchname - |
| * checks if the specified devmap_t is for the device specified. |
| * returns 1 if it is, else returns 0. |
| */ |
| int |
| dmap_matchname(devmap_t *dmap, char *name) |
| { |
| if (dmap->dmap_devname == NULL) |
| return (0); |
| |
| return ((strcmp(dmap->dmap_devname, name) == 0)); |
| } |
| |
| /* |
| * dm_match - |
| * calls dmap_matchname or dmap_matchtype as appropriate. |
| */ |
| int |
| dm_match(devmap_t *dmap, da_args *dargs) |
| { |
| if (dargs->devinfo->devname) |
| return (dmap_matchname(dmap, dargs->devinfo->devname)); |
| else if (dargs->devinfo->devtype) |
| return (dmap_matchtype(dmap, dargs->devinfo->devtype)); |
| |
| return (0); |
| } |
| |
| /* |
| * dmap_interpret - |
| * calls dmap_interpretf and dmap_dlexpand to parse devmap_t line. |
| * returns pointer to parsed devmapt_t entry, else returns NULL on error. |
| */ |
| devmap_t * |
| dmap_interpret(char *val, devmap_t *dm) |
| { |
| if (dmap_interpretf(val, dm) == NULL) |
| return (NULL); |
| |
| return (dmap_dlexpand(dm)); |
| } |
| |
| /* |
| * dmap_interpretf - |
| * parses string "val" and initializes pointers in the given devmap_t to |
| * fields in "val". |
| * returns pointer to updated devmap_t. |
| */ |
| static devmap_t * |
| dmap_interpretf(char *val, devmap_t *dm) |
| { |
| dm->dmap_devname = getdadmfield(val, KV_TOKEN_DELIMIT); |
| dm->dmap_devtype = getdadmfield(NULL, KV_TOKEN_DELIMIT); |
| dm->dmap_devlist = getdadmfield(NULL, KV_TOKEN_DELIMIT); |
| dm->dmap_devarray = NULL; |
| if (dm->dmap_devname == NULL || |
| dm->dmap_devtype == NULL || |
| dm->dmap_devlist == NULL) |
| return (NULL); |
| |
| return (dm); |
| } |
| |
| /* |
| * dmap_dlexpand - |
| * expands dmap_devlist of the form `devlist_generate` |
| * returns unexpanded form if there is no '\`' or in case of error. |
| */ |
| static devmap_t * |
| dmap_dlexpand(devmap_t *dmp) |
| { |
| char tmplist[DA_BUFSIZE + 1]; |
| char *cp, *cpl, **darp; |
| int count; |
| FILE *expansion; |
| |
| dmp->dmap_devarray = NULL; |
| if (dmp->dmap_devlist == NULL) |
| return (NULL); |
| if (*(dmp->dmap_devlist) != '`') { |
| (void) strcpy(tmplist, dmp->dmap_devlist); |
| } else { |
| (void) strcpy(tmplist, dmp->dmap_devlist + 1); |
| if ((cp = strchr(tmplist, '`')) != NULL) |
| *cp = '\0'; |
| if ((expansion = popen(tmplist, "r")) == NULL) |
| return (NULL); |
| count = fread(tmplist, 1, sizeof (tmplist) - 1, expansion); |
| (void) pclose(expansion); |
| tmplist[count] = '\0'; |
| } |
| |
| /* cleanup the list */ |
| count = pack_white(tmplist); |
| dmp->dmap_devarray = darp = |
| (char **)malloc((count + 2) * sizeof (char *)); |
| if (darp == NULL) |
| return (NULL); |
| cp = tmplist; |
| while ((cp = strtok_r(cp, " ", &cpl)) != NULL) { |
| *darp = strdup(cp); |
| if (*darp == NULL) { |
| freedmapent(dmp); |
| return (NULL); |
| } |
| darp++; |
| cp = NULL; |
| } |
| *darp = NULL; |
| |
| return (dmp); |
| } |
| |
| /* |
| * dmapskip - |
| * scans input string to find next colon or end of line. |
| * returns pointer to next char. |
| */ |
| static char * |
| dmapskip(char *p) |
| { |
| while (*p && *p != ':' && *p != '\n') |
| ++p; |
| if (*p == '\n') |
| *p = '\0'; |
| else if (*p != '\0') |
| *p++ = '\0'; |
| |
| return (p); |
| } |
| |
| /* |
| * dmapdskip - |
| * scans input string to find next space or end of line. |
| * returns pointer to next char. |
| */ |
| static char * |
| dmapdskip(p) |
| register char *p; |
| { |
| while (*p && *p != ' ' && *p != '\n') |
| ++p; |
| if (*p != '\0') |
| *p++ = '\0'; |
| |
| return (p); |
| } |
| |
| char * |
| getdmapfield(char *ptr) |
| { |
| static char *tptr; |
| |
| if (ptr == NULL) |
| ptr = tptr; |
| if (ptr == NULL) |
| return (NULL); |
| tptr = dmapskip(ptr); |
| ptr = trim_white(ptr); |
| if (ptr == NULL) |
| return (NULL); |
| if (*ptr == NULL) |
| return (NULL); |
| |
| return (ptr); |
| } |
| |
| char * |
| getdmapdfield(char *ptr) |
| { |
| static char *tptr; |
| if (ptr != NULL) { |
| ptr = trim_white(ptr); |
| } else { |
| ptr = tptr; |
| } |
| if (ptr == NULL) |
| return (NULL); |
| tptr = dmapdskip(ptr); |
| if (ptr == NULL) |
| return (NULL); |
| if (*ptr == NULL) |
| return (NULL); |
| |
| return (ptr); |
| } |