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