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