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