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