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
printdmapent(dmapp)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
dmapi_err(int exit_code,char * err_msg)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
main(int argc,char ** argv)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