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 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 22 * Use is subject to license terms. 23 */ 24 25 #include <locale.h> 26 #include <stdio.h> 27 #include <stdlib.h> 28 #include <string.h> 29 #include <string.h> 30 #include <unistd.h> 31 #include <malloc.h> 32 #include <memory.h> 33 #include <sys/param.h> 34 #include <sys/types.h> 35 #include <sys/file.h> 36 #include <fcntl.h> 37 #include <bsm/devices.h> 38 #define DMPFILE "/etc/security/device_maps" 39 #define RETRY_SLEEP 6 40 #define RETRY_COUNT 10 41 #define EINVOKE 2 42 #define EFAIL 1 43 44 #if !defined(TEXT_DOMAIN) 45 #define TEXT_DOMAIN "SUNW_BSM_DMINFO" 46 #endif 47 48 extern off_t lseek(); 49 50 char *getdmapfield(); 51 char *getdmapdfield(); 52 static void printdmapent(); 53 static void dmapi_err(); 54 55 static char *prog_name; 56 57 /* 58 * printdmapent(dmapp) prints a devmap_t structure pointed to by dmapp. 59 */ 60 static void 61 printdmapent(dmapp) 62 devmap_t *dmapp; 63 { 64 (void) printf("%s:", dmapp->dmap_devname); 65 (void) printf("%s:", dmapp->dmap_devtype); 66 (void) printf("%s", dmapp->dmap_devlist); 67 (void) printf("\n"); 68 } 69 70 71 /* 72 * dmapi_err(exit_code,err_msg) prints message pointed to by err_msg to 73 * stderr. Then prints usage message to stderr. Then exits program with 74 * exit_code. 75 * 76 */ 77 static void 78 dmapi_err(int exit_code, char *err_msg) 79 { 80 if (err_msg != NULL) { 81 (void) fprintf(stderr, "dmapinfo:%s\n", err_msg); 82 } 83 if (exit_code == EINVOKE) { 84 (void) fprintf(stderr, 85 "Usage: %s [-v] [-a] [-f filename] %s\n", 86 prog_name, 87 "[-d device ...]"); 88 (void) fprintf(stderr, 89 " %s [-v] [-a] [-f filename] %s\n", 90 prog_name, 91 "[-n name ...]"); 92 (void) fprintf(stderr, 93 " %s [-v] [-a] [-f filename] %s\n", 94 prog_name, 95 "[-t type ...]"); 96 (void) fprintf(stderr, 97 " %s [-v] [-a] [-f filename] %s\n", 98 prog_name, 99 "[-u Entry]"); 100 } 101 102 exit(exit_code); 103 } 104 105 int 106 main(int argc, char **argv) 107 { 108 devmap_t *dmapp; 109 devmap_t dmap; 110 char *mptr; 111 char *tptr; 112 char *nptr; 113 char *filename = DMPFILE; 114 int name = 0; 115 int device = 0; 116 int file = 0; 117 int verbose = 0; 118 int cntr = 0; 119 int any = 0; 120 int update = 0; 121 int tp = 0; 122 int des; 123 int status; 124 125 /* Internationalization */ 126 (void) setlocale(LC_ALL, ""); 127 (void) textdomain(TEXT_DOMAIN); 128 129 /* 130 * point prog_name to invocation name 131 */ 132 if ((tptr = strrchr(*argv, '/')) != NULL) 133 prog_name = ++tptr; 134 else 135 prog_name = *argv; 136 argc--; 137 argv++; 138 /* 139 * parse arguments 140 */ 141 while ((argc >= 1) && (argv[0][0] == '-')) { 142 switch (argv[0][1]) { 143 case 'a': 144 any++; 145 break; 146 case 'd': 147 if ((name) || (device) || (update) || (tp)) { 148 dmapi_err(EINVOKE, 149 gettext("option conflict")); 150 } 151 device++; 152 break; 153 case 'f': 154 argc--; 155 argv++; 156 if (argc <= 0) 157 dmapi_err(EINVOKE, 158 gettext("missing file name")); 159 filename = *argv; 160 file++; 161 break; 162 case 'n': 163 if ((name) || (device) || (update) || (tp)) { 164 dmapi_err(EINVOKE, 165 gettext("option conflict")); 166 } 167 name++; 168 break; 169 case 't': 170 if ((name) || (device) || (update) || (tp)) { 171 dmapi_err(EINVOKE, 172 gettext("option conflict")); 173 } 174 tp++; 175 break; 176 case 'u': 177 if ((name) || (device) || (update) || (tp)) { 178 dmapi_err(EINVOKE, 179 gettext("option conflict")); 180 } 181 update++; 182 break; 183 case 'v': 184 verbose++; 185 break; 186 default: 187 dmapi_err(EINVOKE, 188 gettext("bad option")); 189 break; 190 } 191 argc--; 192 argv++; 193 } 194 /* 195 * -d(device) -n(name) and -u(update) switches require at least one 196 * argument. 197 */ 198 if (file) 199 setdmapfile(filename); 200 if ((device) || (name) || (update) || (tp)) { 201 if (argc < 1) { 202 dmapi_err(EINVOKE, 203 gettext("insufficient args for this option")); 204 } 205 } 206 if (update) { 207 /* 208 * -u(update) switch requires only one argument 209 */ 210 if (argc != 1) { 211 dmapi_err(EINVOKE, 212 gettext("too many args for this option")); 213 } 214 /* 215 * read entry argument from stdin into a devmap_t known as dmap 216 */ 217 if ((dmap.dmap_devname = getdmapfield(*argv)) == NULL) { 218 dmapi_err(EINVOKE, 219 gettext("Bad dmap_devname in entry argument")); 220 } 221 if ((dmap.dmap_devtype = getdmapfield(NULL)) == 222 NULL) { 223 dmapi_err(EINVOKE, 224 gettext("Bad dmap_devtype in entry Argument")); 225 } 226 if ((dmap.dmap_devlist = getdmapfield(NULL)) == 227 NULL) { 228 dmapi_err(EINVOKE, 229 gettext("Bad dmap_devlist in entry argument")); 230 } 231 /* 232 * Find out how long device list is and create a buffer to 233 * hold it. Then copy it there. This is done since we do not 234 * want to corrupt the existing string. 235 */ 236 cntr = strlen(dmap.dmap_devlist) + 1; 237 mptr = calloc((unsigned)cntr, sizeof (char)); 238 if (mptr == NULL) { 239 if (verbose) { 240 (void) fprintf(stderr, 241 gettext( 242 "dmapinfo: Cannot calloc memory\n")); 243 } 244 exit(1); 245 } 246 (void) strcpy(mptr, dmap.dmap_devlist); 247 /* 248 * open the device maps file for read/ write. We are not 249 * sure we want to write to it yet but we may and this is a 250 * easy way to get the file descriptor. We want the file 251 * descriptor so we can lock the file. 252 */ 253 if ((des = open(filename, O_RDWR)) < 0) { 254 if (verbose) { 255 (void) fprintf(stderr, 256 gettext("dmapinfo: Cannot open %s\n"), 257 filename); 258 } 259 exit(1); 260 } 261 cntr = 0; 262 #ifdef CMW 263 while ((status = flock(des, LOCK_EX | LOCK_NB) == -1) && 264 (cntr++ < RETRY_COUNT)) { 265 (void) sleep(RETRY_SLEEP); 266 } 267 #else 268 while (((status = lockf(des, F_TLOCK, 0)) == -1) && 269 (cntr++ < RETRY_COUNT)) { 270 (void) sleep(RETRY_SLEEP); 271 } 272 #endif 273 if (status == -1) { 274 if (verbose) { 275 (void) fprintf(stderr, 276 gettext("dmapinfo: Cannot lock %s\n"), filename); 277 } 278 exit(1); 279 } 280 /* 281 * Now that we have the device_maps file then lets check 282 * for previous entrys with the same name. If it already 283 * exists then we will exit with status of 1. 284 */ 285 if (verbose) { 286 (void) fprintf(stderr, 287 gettext("dmapinfo: Checking %s for name (%s).\n"), 288 filename, dmap.dmap_devname); 289 } 290 if (getdmapnam(dmap.dmap_devname) != NULL) { 291 if (verbose) { 292 (void) fprintf(stderr, 293 gettext("dmapinfo: Device name (%s) found in %s.\n"), 294 dmap.dmap_devname, filename); 295 } 296 exit(1); 297 } 298 if (verbose) { 299 (void) fprintf(stderr, 300 gettext("dmapinfo: Device name (%s) not found in %s.\n"), 301 dmap.dmap_devname, filename); 302 } 303 /* 304 * We now Know name does not exist and now we need to check 305 * to see if any of the devices in the device list are in the 306 * device maps file. If the already exist then we will exit 307 * with a status of 1. 308 */ 309 nptr = mptr; 310 nptr = getdmapdfield(nptr); 311 while (nptr) { 312 if (verbose) { 313 (void) fprintf(stderr, 314 gettext("dmapinfo: " 315 "Check %s for device (%s).\n"), 316 filename, nptr); 317 } 318 if (getdmapdev(nptr) != NULL) { 319 if (verbose) { 320 (void) fprintf(stderr, 321 gettext("dmapinfo: " 322 "Device (%s) found in %s.\n"), 323 nptr, filename); 324 } 325 exit(1); 326 } 327 if (verbose) { 328 (void) fprintf(stderr, 329 gettext("dmapinfo: " 330 "Device (%s) not found in %s.\n"), 331 nptr, filename); 332 } 333 nptr = getdmapdfield(NULL); 334 } 335 /* 336 * Good the entry is uniq. So lets find out how long it is 337 * and add it to the end of device maps file in a pretty 338 * way. 339 */ 340 if (verbose) { 341 (void) fprintf(stderr, "dmapinfo: Adding entry to %s\n", 342 filename); 343 printdmapent(&dmap); 344 } 345 cntr = strlen(dmap.dmap_devname); 346 cntr += strlen(dmap.dmap_devtype); 347 cntr += strlen(dmap.dmap_devlist); 348 cntr += 15; 349 tptr = calloc((unsigned)cntr, sizeof (char)); 350 if (tptr == NULL) { 351 exit(1); 352 } 353 (void) strcat(tptr, dmap.dmap_devname); 354 (void) strcat(tptr, ":\\\n\t"); 355 (void) strcat(tptr, dmap.dmap_devtype); 356 (void) strcat(tptr, ":\\\n\t"); 357 (void) strcat(tptr, dmap.dmap_devlist); 358 (void) strcat(tptr, ":\\\n\t"); 359 (void) strcat(tptr, "\n"); 360 cntr = strlen(tptr); 361 #ifdef CMW 362 if (lseek(des, 0L, L_XTND) == -1L) { 363 exit(1); 364 } 365 #else 366 if (lseek(des, 0L, SEEK_END) == -1L) { 367 exit(1); 368 } 369 #endif 370 if (write(des, tptr, cntr) == -1) { 371 exit(1); 372 } 373 if (close(des) == -1) { 374 exit(1); 375 } 376 if (verbose) { 377 (void) fprintf(stderr, "dmapinfo: Entry added to %s\n", 378 filename); 379 } 380 exit(0); 381 } 382 /* 383 * Look for devices in device_maps file. If verbose switch is set 384 * then print entry(s) found. If "any" switch is set then, if any 385 * device is found will result in a exit status of 0. If "any" switch 386 * is not set then, if any device is not will result in a exit status 387 * of 1. 388 */ 389 if (device) { 390 setdmapent(); 391 while (argc >= 1) { 392 if ((dmapp = getdmapdev(*argv)) != NULL) { 393 if (verbose) { 394 printdmapent(dmapp); 395 } 396 cntr++; 397 } else if (any == 0) { 398 enddmapent(); 399 exit(1); 400 } 401 argc--; 402 argv++; 403 } 404 enddmapent(); 405 if (cntr != 0) 406 exit(0); 407 exit(1); 408 } 409 /* 410 * Look for names in device_maps file. If verbose switch is set 411 * then print entry(s) found. If "any" switch is set then, if any 412 * name is found will result in a exit status of 0. If "any" switch 413 * is not set then, if any name is not will result in a exit status 414 * of 1. 415 */ 416 if (name) { 417 setdmapent(); 418 while (argc >= 1) { 419 if ((dmapp = getdmapnam(*argv)) != NULL) { 420 if (verbose) { 421 printdmapent(dmapp); 422 } 423 cntr++; 424 } else if (any == 0) 425 exit(1); 426 argc--; 427 argv++; 428 } 429 enddmapent(); 430 if (cntr != 0) 431 exit(0); 432 exit(1); 433 } 434 /* 435 * Read all entrys from device maps file. If verbose flag is set 436 * then all the device maps files are printed. This is useful for 437 * piping to grep. Also this option used without the verbose option 438 * is useful to check for device maps file and for at least one 439 * entry. If the device maps file is found and there is one entry 440 * the return status is 0. 441 */ 442 if (tp) { 443 cntr = 0; 444 setdmapent(); 445 while (argc >= 1) { 446 while ((dmapp = getdmaptype(*argv)) != 0) { 447 cntr++; 448 if (verbose) { 449 printdmapent(dmapp); 450 } 451 } 452 if ((any == 0) && (cntr == 0)) { 453 enddmapent(); 454 exit(1); 455 } 456 argc--; 457 argv++; 458 } 459 enddmapent(); 460 if (cntr == 0) 461 exit(1); 462 exit(0); 463 } 464 /* 465 * Read all entrys from device maps file. If verbose flag is set 466 * then all the device maps files are printed. This is useful for 467 * piping to grep. Also this option used without the verbose option 468 * is useful to check for device maps file and for atleast one 469 * entry. If the device maps file is found and there is one entry 470 * the return status is 0. 471 */ 472 cntr = 0; 473 setdmapent(); 474 while ((dmapp = getdmapent()) != 0) { 475 cntr++; 476 if (verbose) { 477 printdmapent(dmapp); 478 } 479 } 480 enddmapent(); 481 if (cntr == 0) 482 exit(1); 483 return (0); 484 } 485