#include <string.h>
#include <strings.h>
#include <stdlib.h>
#include <unistd.h>
#include <limits.h>
#include <bsm/devices.h>
#include <bsm/devalloc.h>
char *strtok_r(char *, const char *, char **);
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;
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 *);
static int dmap_resolve_link(char *devpath, char **devfs_path);
int dmap_matchdev(devmap_t *, char *);
int dmap_matchname(devmap_t *, char *);
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);
}
void
setdmapent(void)
{
struct _dmapbuff *_dmap = _dmapalloc();
if (_dmap == NULL)
return;
if (dmapf == NULL)
dmapf = fopen(DEVMAPS_FILE, "rF");
else
rewind(dmapf);
}
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;
}
}
void
setdmapfile(char *file)
{
struct _dmapbuff *_dmap = _dmapalloc();
if (_dmap == NULL)
return;
if (dmapf != NULL) {
(void) fclose(dmapf);
dmapf = NULL;
}
DEVMAPS_FILE = file;
}
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);
}
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);
}
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);
}
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);
}
static int
dmap_match_one_dev(devmap_t *dmap, char *dev)
{
char **dva;
char *dv;
char *dmap_link;
char *dev_link;
char stage_link[PATH_MAX + 1];
if (dmap->dmap_devarray == NULL)
return (0);
for (dva = dmap->dmap_devarray; (dv = *dva) != NULL; dva++) {
if (strstr(dev, dv) != NULL)
return (1);
}
(void) strncpy(stage_link, dmap->dmap_devarray[0], sizeof (stage_link));
if (dmap_resolve_link(stage_link, &dmap_link) != 0)
return (0);
(void) strncpy(stage_link, dev, sizeof (stage_link));
if (dmap_resolve_link(stage_link, &dev_link) != 0) {
free(dmap_link);
return (0);
}
if (strcmp(dev_link, dmap_link) == 0) {
free(dmap_link);
free(dev_link);
return (1);
}
free(dmap_link);
free(dev_link);
return (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);
}
int
dmap_exact_dev(devmap_t *dmap, char *dev, int *num)
{
char *dv;
if ((dev == NULL) || (dmap->dmap_devname == NULL))
return (2);
dv = dmap->dmap_devname;
dv += strcspn(dmap->dmap_devname, "0123456789");
if (sscanf(dv, "%d", num) != 1)
*num = -1;
return (dmap_match_one_dev(dmap, dev));
}
int
dmap_matchtype(devmap_t *dmap, char *type)
{
if ((dmap->dmap_devtype == NULL) || (type == NULL))
return (0);
return ((strcmp(dmap->dmap_devtype, type) == 0));
}
int
dmap_matchname(devmap_t *dmap, char *name)
{
if (dmap->dmap_devname == NULL)
return (0);
return ((strcmp(dmap->dmap_devname, name) == 0));
}
static int
dmap_minor_root(const char *contents, const char **mn_root)
{
char *ptr, *prefix;
prefix = "../devices/";
if ((ptr = strstr(contents, prefix)) != NULL) {
if (mn_root != NULL) {
*mn_root = ptr += strlen(prefix) - 1;
}
return (1);
}
prefix = "/devices/";
if (strncmp(contents, prefix, strlen(prefix)) == 0) {
if (mn_root != NULL) {
*mn_root = contents + strlen(prefix) - 1;
}
return (1);
}
if (mn_root != NULL) {
*mn_root = contents;
}
return (0);
}
static int
dmap_resolve_link(char *devpath, char **devfs_path)
{
char contents[PATH_MAX + 1];
char stage_link[PATH_MAX + 1];
char *ptr;
int linksize;
char *slashdev = "/dev/";
if (devfs_path) {
*devfs_path = NULL;
}
linksize = readlink(devpath, contents, PATH_MAX);
if (linksize <= 0) {
return (-1);
} else {
contents[linksize] = '\0';
}
if (dmap_minor_root((const char *)contents, (const char **)&ptr) !=
1) {
if (strncmp(contents, slashdev, strlen(slashdev)) == 0) {
(void) strcpy(stage_link, contents);
} else {
if ((ptr = strrchr(devpath, '/')) == NULL) {
return (-1);
}
*ptr = '\0';
(void) strcpy(stage_link, devpath);
*ptr = '/';
(void) strcat(stage_link, "/");
(void) strcat(stage_link, contents);
}
return (dmap_resolve_link(stage_link, devfs_path));
}
if (devfs_path) {
*devfs_path = strdup(ptr);
if (*devfs_path == NULL) {
return (-1);
}
}
return (0);
}
char *
dmap_physname(devmap_t *dmap)
{
char *oldlink;
char stage_link[PATH_MAX + 1];
if ((dmap == NULL) || (dmap->dmap_devarray == NULL) ||
(dmap->dmap_devarray[0] == NULL))
return (NULL);
(void) strncpy(stage_link, dmap->dmap_devarray[0], sizeof (stage_link));
if (dmap_resolve_link(stage_link, &oldlink) == 0)
return (oldlink);
return (NULL);
}
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);
}
devmap_t *
dmap_interpret(char *val, devmap_t *dm)
{
if (dmap_interpretf(val, dm) == NULL)
return (NULL);
return (dmap_dlexpand(dm));
}
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);
}
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, "rF")) == NULL)
return (NULL);
count = fread(tmplist, 1, sizeof (tmplist) - 1, expansion);
(void) pclose(expansion);
tmplist[count] = '\0';
}
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);
}
static char *
dmapskip(char *p)
{
while (*p && *p != ':' && *p != '\n')
++p;
if (*p == '\n')
*p = '\0';
else if (*p != '\0')
*p++ = '\0';
return (p);
}
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 == '\0')
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 == '\0')
return (NULL);
return (ptr);
}