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, "r"); 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, "r")) == 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