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, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #include <stdio.h> 30 #include <string.h> 31 #include <malloc.h> 32 #include <bsm/devices.h> 33 #include <sys/errno.h> 34 35 #define MAXINT 0x7fffffff; 36 37 static struct _dmapbuff { 38 devmap_t _NULLDM; 39 FILE *_dmapf; /* pointer into /etc/security/device_maps */ 40 devmap_t _interpdevmap; 41 char _interpline[BUFSIZ + 1]; 42 char *_DEVMAP; 43 } *__dmapbuff; 44 45 #define NULLDM (_dmap->_NULLDM) 46 #define dmapf (_dmap->_dmapf) 47 #define interpdevmap (_dmap->_interpdevmap) 48 #define interpline (_dmap->_interpline) 49 #define DEVMAP (_dmap->_DEVMAP) 50 static devmap_t *interpret(); 51 static int matchdev(); 52 static int matchname(); 53 /* 54 * trim_white(ptr) trims off leading and trailing white space from a NULL 55 * terminated string pointed to by "ptr". The leading white space is skipped 56 * by moving the pointer forward. The trailing white space is removed by 57 * nulling the white space characters. The pointer is returned to the white 58 * string. If the resulting string is null in length then a NULL pointer is 59 * returned. If "ptr" is NULL then a NULL pointer is returned. 60 */ 61 static char * 62 trim_white(char *ptr) 63 { 64 register char *tptr; 65 register int cnt; 66 if (ptr == NULL) 67 return (NULL); 68 while ((*ptr == ' ') || (*ptr == '\t')) { 69 ptr++; 70 } 71 cnt = strlen(ptr); 72 if (cnt != 0) { 73 tptr = ptr + cnt - 1; 74 while ((*tptr == ' ') || (*tptr == '\t')) { 75 *tptr = '\0'; 76 tptr--; 77 } 78 } 79 if (*ptr == NULL) 80 return (NULL); 81 return (ptr); 82 } 83 /* 84 * scan string pointed to by pointer "p" 85 * find next colin or end of line. Null it and 86 * return pointer to next char. 87 */ 88 static char * 89 dmapskip(register char *p) 90 { 91 while (*p && *p != ':' && *p != '\n') 92 ++p; 93 if (*p == '\n') 94 *p = '\0'; 95 else if (*p != '\0') 96 *p++ = '\0'; 97 return (p); 98 } 99 /* 100 * scan string pointed to by pointer "p" 101 * find next colin or end of line. Null it and 102 * return pointer to next char. 103 */ 104 static char * 105 dmapdskip(register char *p) 106 { 107 while (*p && *p != ' ' && *p != '\n') 108 ++p; 109 if (*p != '\0') 110 *p++ = '\0'; 111 return (p); 112 } 113 114 /* 115 * _dmapalloc() allocates common buffers and structures used by the device 116 * maps library routines. Then returns a pointer to a structure. The 117 * returned pointer will be null if there is an error condition. 118 */ 119 static struct _dmapbuff * 120 _dmapalloc(void) 121 { 122 register struct _dmapbuff *_dmap = __dmapbuff; 123 124 if (_dmap == 0) { 125 _dmap = (struct _dmapbuff *) 126 calloc((unsigned)1, (unsigned)sizeof (*__dmapbuff)); 127 if (_dmap == 0) 128 return (0); 129 DEVMAP = "/etc/security/device_maps"; 130 __dmapbuff = _dmap; 131 } 132 return (__dmapbuff); 133 } 134 /* 135 * getdmapline(buff,len,stream) reads one device maps line from "stream" into 136 * "buff" on "len" bytes. Continued lines from "stream" are concatinated 137 * into one line in "buff". Comments are removed from "buff". The number of 138 * characters in "buff" is returned. If no characters are read or an error 139 * occured then "0" is returned 140 */ 141 static int 142 getdmapline(char *buff, int len, FILE *stream) 143 { 144 register struct _dmapbuff *_dmap = _dmapalloc(); 145 char *cp; 146 char *ccp; 147 size_t tmpcnt; 148 int charcnt = 0; 149 int fileerr = 0; 150 int contline; 151 if (_dmap == 0) 152 return (0); 153 do { 154 cp = buff; 155 *cp = NULL; 156 do { 157 if ((len - charcnt <= 1) || 158 (fgets(cp, len - charcnt, stream) == NULL)) { 159 fileerr = 1; 160 break; 161 } 162 ccp = strpbrk(cp, "\\\n"); 163 if (ccp != NULL) { 164 if (*ccp == '\\') 165 contline = 1; 166 else 167 contline = 0; 168 *ccp = NULL; 169 } 170 tmpcnt = strlen(cp); 171 if (tmpcnt != 0) { 172 cp += tmpcnt; 173 charcnt += tmpcnt; 174 } 175 } while ((contline) || (charcnt == 0)); 176 ccp = strpbrk(buff, "#"); 177 if (ccp != NULL) 178 *ccp = NULL; 179 charcnt = strlen(buff); 180 } while ((fileerr == 0) && (charcnt == 0)); 181 if (fileerr && !charcnt) 182 return (0); 183 else 184 return (charcnt); 185 } 186 char 187 *getdmapfield(char *ptr) 188 { 189 static char *tptr; 190 if (ptr == NULL) 191 ptr = tptr; 192 if (ptr == NULL) 193 return (NULL); 194 tptr = dmapskip(ptr); 195 ptr = trim_white(ptr); 196 if (ptr == NULL) 197 return (NULL); 198 if (*ptr == NULL) 199 return (NULL); 200 return (ptr); 201 } 202 char 203 *getdmapdfield(char *ptr) 204 { 205 static char *tptr; 206 if (ptr != NULL) { 207 ptr = trim_white(ptr); 208 } else { 209 ptr = tptr; 210 } 211 if (ptr == NULL) 212 return (NULL); 213 tptr = dmapdskip(ptr); 214 if (ptr == NULL) 215 return (NULL); 216 if (*ptr == NULL) 217 return (NULL); 218 return (ptr); 219 } 220 /* 221 * getdmapdev(dev) searches from the beginning of the file until a logical 222 * device matching "dev" is found and returns a pointer to the particular 223 * structure in which it was found. If an EOF or an error is encountered on 224 * reading, these functions return a NULL pointer. 225 */ 226 devmap_t * 227 getdmapdev(register char *name) 228 { 229 register struct _dmapbuff *_dmap = _dmapalloc(); 230 devmap_t *dmap; 231 char line[BUFSIZ + 1]; 232 233 if (_dmap == 0) 234 return (0); 235 setdmapent(); 236 if (!dmapf) 237 return (NULL); 238 while (getdmapline(line, (int)sizeof (line), dmapf) != 0) { 239 if ((dmap = interpret(line)) == NULL) 240 continue; 241 if (matchdev(&dmap, name)) { 242 enddmapent(); 243 return (dmap); 244 } 245 } 246 enddmapent(); 247 return (NULL); 248 } 249 /* 250 * getdmapnam(name) searches from the beginning of the file until a audit-name 251 * matching "name" is found and returns a pointer to the particular structure 252 * in which it was found. If an EOF or an error is encountered on reading, 253 * these functions return a NULL pointer. 254 */ 255 devmap_t * 256 getdmapnam(register char *name) 257 { 258 register struct _dmapbuff *_dmap = _dmapalloc(); 259 devmap_t *dmap; 260 char line[BUFSIZ + 1]; 261 262 if (_dmap == 0) 263 return (0); 264 setdmapent(); 265 if (!dmapf) 266 return (NULL); 267 while (getdmapline(line, (int)sizeof (line), dmapf) != 0) { 268 if ((dmap = interpret(line)) == NULL) 269 continue; 270 if (matchname(&dmap, name)) { 271 enddmapent(); 272 return (dmap); 273 } 274 } 275 enddmapent(); 276 return (NULL); 277 } 278 279 /* 280 * setdmapent() essentially rewinds the device_maps file to the begining. 281 */ 282 283 void 284 setdmapent(void) 285 { 286 register struct _dmapbuff *_dmap = _dmapalloc(); 287 288 289 if (_dmap == 0) 290 return; 291 292 if (dmapf == NULL) { 293 dmapf = fopen(DEVMAP, "r"); 294 } else 295 rewind(dmapf); 296 } 297 298 299 /* 300 * enddmapent() may be called to close the device_maps file when processing 301 * is complete. 302 */ 303 304 void 305 enddmapent(void) 306 { 307 register struct _dmapbuff *_dmap = _dmapalloc(); 308 309 if (_dmap == 0) 310 return; 311 if (dmapf != NULL) { 312 (void) fclose(dmapf); 313 dmapf = NULL; 314 } 315 } 316 317 318 /* 319 * setdmapfile(name) changes the default device_maps file to "name" thus 320 * allowing alternate device_maps files to be used. Note: it does not 321 * close the previous file . If this is desired, enddmapent should be called 322 * prior to it. 323 */ 324 void 325 setdmapfile(char *file) 326 { 327 register struct _dmapbuff *_dmap = _dmapalloc(); 328 329 if (_dmap == 0) 330 return; 331 if (dmapf != NULL) { 332 (void) fclose(dmapf); 333 dmapf = NULL; 334 } 335 DEVMAP = file; 336 } 337 /* 338 * getdmaptype(tp) When first called, returns a pointer to the 339 * first devmap_t structure in the file with device-type matching 340 * "tp"; thereafter, it returns a pointer to the next devmap_t 341 * structure in the file with device-type matching "tp". 342 * Thus successive calls can be used to search the 343 * entire file for entries having device-type matching "tp". 344 * A null pointer is returned on error. 345 */ 346 devmap_t * 347 getdmaptype(char *tp) 348 { 349 register struct _dmapbuff *_dmap = _dmapalloc(); 350 char line1[BUFSIZ + 1]; 351 devmap_t *dmap; 352 353 if (_dmap == 0) 354 return (0); 355 if (dmapf == NULL && (dmapf = fopen(DEVMAP, "r")) == NULL) { 356 return (NULL); 357 } 358 do { 359 if (getdmapline(line1, (int)sizeof (line1), dmapf) == 0) 360 return (NULL); 361 362 if ((dmap = interpret(line1)) == NULL) 363 return (NULL); 364 } while (strcmp(tp, dmap->dmap_devtype) != 0); 365 return (dmap); 366 } 367 368 /* 369 * getdmapent() When first called, returns a pointer to the first devmap_t 370 * structure in the file; thereafter, it returns a pointer to the next devmap_t 371 * structure in the file. Thus successive calls can be used to search the 372 * entire file. A null pointer is returned on error. 373 */ 374 devmap_t * 375 getdmapent(void) 376 { 377 register struct _dmapbuff *_dmap = _dmapalloc(); 378 char line1[BUFSIZ + 1]; 379 devmap_t *dmap; 380 381 if (_dmap == 0) 382 return (0); 383 if (dmapf == NULL && (dmapf = fopen(DEVMAP, "r")) == NULL) { 384 return (NULL); 385 } 386 if (getdmapline(line1, (int)sizeof (line1), dmapf) == 0) 387 return (NULL); 388 389 if ((dmap = interpret(line1)) == NULL) 390 return (NULL); 391 return (dmap); 392 } 393 /* 394 * matchdev(dmapp,dev) The dev_list in the structure pointed to by "dmapp" is 395 * searched for string "dev". If a match occures then a "1" is returned 396 * otherwise a "0" is returned. 397 */ 398 static int 399 matchdev(devmap_t **dmapp, char *dev) 400 { 401 register struct _dmapbuff *_dmap = _dmapalloc(); 402 devmap_t *dmap = *dmapp; 403 char tmpdev[BUFSIZ + 1]; 404 int charcnt; 405 int tmpcnt; 406 char *cp; 407 char *tcp; 408 char *last; 409 charcnt = strlen(dev); 410 if (_dmap == 0) 411 return (0); 412 if (dmap->dmap_devlist == NULL) 413 return (0); 414 (void) strcpy(tmpdev, dmap->dmap_devlist); 415 tcp = tmpdev; 416 while ((cp = strtok_r(tcp, " ", &last)) != NULL) { 417 tcp = NULL; 418 tmpcnt = strlen(cp); 419 if (tmpcnt != charcnt) 420 continue; 421 if (strcmp(cp, dev) == 0) 422 return (1); 423 } 424 return (0); 425 } 426 /* 427 * matchname(dmapp,name) The audit-name in the structure pointed to by "dmapp" 428 * is searched for string "name". If a match occures then a "1" is returned 429 * otherwise a "0" is returned. 430 */ 431 static int 432 matchname(devmap_t **dmapp, char *name) 433 { 434 register struct _dmapbuff *_dmap = _dmapalloc(); 435 devmap_t *dmap = *dmapp; 436 437 if (_dmap == 0) 438 return (0); 439 if (dmap->dmap_devname == NULL) 440 return (0); 441 if (strlen(dmap->dmap_devname) != strlen(name)) 442 return (0); 443 if (strcmp(dmap->dmap_devname, name) == 0) 444 return (1); 445 return (0); 446 } 447 /* 448 * interpret(val) string "val" is parsed and the pointers in a devmap_t 449 * structure are initialized to point to fields in "val". A pointer to this 450 * structure is returned. 451 */ 452 static devmap_t * 453 interpret(char *val) 454 { 455 register struct _dmapbuff *_dmap = _dmapalloc(); 456 457 if (_dmap == 0) 458 return (0); 459 (void) strcpy(interpline, val); 460 interpdevmap.dmap_devname = getdmapfield(interpline); 461 interpdevmap.dmap_devtype = getdmapfield((char *)NULL); 462 interpdevmap.dmap_devlist = getdmapfield((char *)NULL); 463 464 return (&interpdevmap); 465 } 466