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