xref: /illumos-gate/usr/src/lib/libbsm/common/getdment.c (revision 3d393ee6c37fa10ac512ed6d36109ad616dc7c1a)
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 /*
22  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
27 
28 #include <string.h>
29 #include <stdlib.h>
30 #include <bsm/devices.h>
31 #include <bsm/devalloc.h>
32 
33 char *strtok_r(char *, const char *, char **);
34 
35 /* externs from getdaent.c */
36 extern char *trim_white(char *);
37 extern int pack_white(char *);
38 extern char *getdadmfield(char *, char *);
39 extern int getdadmline(char *, int, FILE *);
40 
41 static struct _dmapbuff {
42 	FILE		*_dmapf;	/* for /etc/security/device_maps */
43 	devmap_t	_interpdevmap;
44 	char		_interpdmline[DA_BUFSIZE + 1];
45 	char		*_DEVMAP;
46 } *__dmapbuff;
47 
48 #define	dmapf	(_dmap->_dmapf)
49 #define	interpdevmap	(_dmap->_interpdevmap)
50 #define	interpdmline	(_dmap->_interpdmline)
51 #define	DEVMAPS_FILE	(_dmap->_DEVMAP)
52 
53 devmap_t	*dmap_interpret(char *, devmap_t *);
54 static devmap_t	*dmap_interpretf(char *, devmap_t *);
55 static devmap_t *dmap_dlexpand(devmap_t *);
56 
57 int	dmap_matchdev(devmap_t *, char *);
58 int	dmap_matchname(devmap_t *, char *);
59 
60 
61 /*
62  * _dmapalloc -
63  *	allocates common buffers and structures.
64  *	returns pointer to the new structure, else returns NULL on error.
65  */
66 static struct _dmapbuff *
67 _dmapalloc(void)
68 {
69 	struct _dmapbuff *_dmap = __dmapbuff;
70 
71 	if (_dmap == NULL) {
72 		_dmap = (struct _dmapbuff *)calloc((unsigned)1,
73 		    (unsigned)sizeof (*__dmapbuff));
74 		if (_dmap == NULL)
75 			return (NULL);
76 		DEVMAPS_FILE = "/etc/security/device_maps";
77 		dmapf = NULL;
78 		__dmapbuff = _dmap;
79 	}
80 
81 	return (_dmap);
82 }
83 
84 /*
85  * setdmapent -
86  *	rewinds the device_maps file to the beginning.
87  */
88 void
89 setdmapent(void)
90 {
91 	struct _dmapbuff *_dmap = _dmapalloc();
92 
93 	if (_dmap == NULL)
94 		return;
95 	if (dmapf == NULL)
96 		dmapf = fopen(DEVMAPS_FILE, "rF");
97 	else
98 		rewind(dmapf);
99 }
100 
101 /*
102  * enddmapent -
103  *	closes device_maps file.
104  */
105 void
106 enddmapent(void)
107 {
108 	struct _dmapbuff *_dmap = _dmapalloc();
109 
110 	if (_dmap == NULL)
111 		return;
112 	if (dmapf != NULL) {
113 		(void) fclose(dmapf);
114 		dmapf = NULL;
115 	}
116 }
117 
118 void
119 freedmapent(devmap_t *dmap)
120 {
121 	char	**darp;
122 
123 	if ((darp = dmap->dmap_devarray) != NULL) {
124 		while (*darp != NULL)
125 			free(*darp++);
126 		free(dmap->dmap_devarray);
127 		dmap->dmap_devarray = NULL;
128 	}
129 }
130 
131 /*
132  * setdmapfile -
133  *	changes the default device_maps file to the one specified.
134  *	It does not close the previous file. If this is desired, enddmapent
135  *	should be called prior to setdampfile.
136  */
137 void
138 setdmapfile(char *file)
139 {
140 	struct _dmapbuff *_dmap = _dmapalloc();
141 
142 	if (_dmap == NULL)
143 		return;
144 	if (dmapf != NULL) {
145 		(void) fclose(dmapf);
146 		dmapf = NULL;
147 	}
148 	DEVMAPS_FILE = file;
149 }
150 
151 /*
152  * getdmapent -
153  * 	When first called, returns a pointer to the first devmap_t structure
154  * 	in device_maps; thereafter, it returns a pointer to the next devmap_t
155  *	structure in the file. Thus successive calls can be used to read the
156  *	entire file.
157  *	call to getdmapent should be bracketed by setdmapent and enddmapent.
158  * 	returns pointer to devmap_t found, else returns NULL if no entry found
159  * 	or on error.
160  */
161 devmap_t *
162 getdmapent(void)
163 {
164 	devmap_t		*dmap;
165 	struct _dmapbuff 	*_dmap = _dmapalloc();
166 
167 	if ((_dmap == 0) || (dmapf == NULL))
168 		return (NULL);
169 
170 	while (getdadmline(interpdmline, (int)sizeof (interpdmline),
171 	    dmapf) != 0) {
172 		if ((dmap = dmap_interpret(interpdmline,
173 		    &interpdevmap)) == NULL)
174 			continue;
175 		return (dmap);
176 	}
177 
178 	return (NULL);
179 }
180 
181 /*
182  * getdmapnam -
183  *	searches from the beginning of device_maps for the device specified by
184  *	its name.
185  *	call to getdmapnam should be bracketed by setdmapent and enddmapent.
186  * 	returns pointer to devmapt_t for the device if it is found, else
187  * 	returns NULL if device not found or in case of error.
188  */
189 devmap_t *
190 getdmapnam(char *name)
191 {
192 	devmap_t		*dmap;
193 	struct _dmapbuff	*_dmap = _dmapalloc();
194 
195 	if ((name == NULL) || (_dmap == 0) || (dmapf == NULL))
196 		return (NULL);
197 
198 	while (getdadmline(interpdmline, (int)sizeof (interpdmline),
199 	    dmapf) != 0) {
200 		if (strstr(interpdmline, name) == NULL)
201 			continue;
202 		if ((dmap = dmap_interpretf(interpdmline,
203 		    &interpdevmap)) == NULL)
204 			continue;
205 		if (dmap_matchname(dmap, name)) {
206 			if ((dmap = dmap_dlexpand(dmap)) == NULL)
207 				continue;
208 			enddmapent();
209 			return (dmap);
210 		}
211 		freedmapent(dmap);
212 	}
213 
214 	return (NULL);
215 }
216 
217 /*
218  * getdmapdev -
219  *	searches from the beginning of device_maps for the device specified by
220  *	its logical name.
221  *	call to getdmapdev should be bracketed by setdmapent and enddmapent.
222  * 	returns  pointer to the devmap_t for the device if device is found,
223  *	else returns NULL if device not found or on error.
224  */
225 devmap_t *
226 getdmapdev(char *dev)
227 {
228 	devmap_t		*dmap;
229 	struct _dmapbuff	*_dmap = _dmapalloc();
230 
231 	if ((dev == NULL) || (_dmap == 0) || (dmapf == NULL))
232 		return (NULL);
233 
234 	while (getdadmline(interpdmline, (int)sizeof (interpdmline),
235 	    dmapf) != 0) {
236 		if ((dmap = dmap_interpret(interpdmline,
237 		    &interpdevmap)) == NULL)
238 			continue;
239 		if (dmap_matchdev(dmap, dev)) {
240 			enddmapent();
241 			return (dmap);
242 		}
243 		freedmapent(dmap);
244 	}
245 
246 	return (NULL);
247 }
248 
249 /*
250  * getdmaptype -
251  *	searches from the beginning of device_maps for the device specified by
252  *	its type.
253  *	call to getdmaptype should be bracketed by setdmapent and enddmapent.
254  * 	returns pointer to devmap_t found, else returns NULL if no entry found
255  * 	or on error.
256  */
257 devmap_t *
258 getdmaptype(char *type)
259 {
260 	devmap_t		*dmap;
261 	struct _dmapbuff	*_dmap = _dmapalloc();
262 
263 	if ((type == NULL) || (_dmap == 0) || (dmapf == NULL))
264 		return (NULL);
265 
266 	while (getdadmline(interpdmline, (int)sizeof (interpdmline),
267 	    dmapf) != 0) {
268 		if ((dmap = dmap_interpretf(interpdmline,
269 		    &interpdevmap)) == NULL)
270 			continue;
271 		if (dmap->dmap_devtype != NULL &&
272 		    strcmp(type, dmap->dmap_devtype) == 0) {
273 			if ((dmap = dmap_dlexpand(dmap)) == NULL)
274 				continue;
275 			return (dmap);
276 		}
277 		freedmapent(dmap);
278 	}
279 
280 	return (NULL);
281 }
282 
283 /*
284  * dmap_matchdev -
285  * 	checks if the specified devmap_t is for the device specified.
286  *	returns 1 if it is, else returns 0.
287  */
288 int
289 dmap_matchdev(devmap_t *dmap, char *dev)
290 {
291 	char **dva;
292 	char *dv;
293 
294 	if (dmap->dmap_devarray == NULL)
295 		return (0);
296 	for (dva = dmap->dmap_devarray; (dv = *dva) != NULL; dva ++) {
297 		if (strcmp(dv, dev) == 0)
298 			return (1);
299 	}
300 
301 	return (0);
302 }
303 
304 /*
305  * dmap_matchtype -
306  *	checks if the specified devmap_t is for the device specified.
307  *	returns 1 if it is, else returns 0.
308  */
309 int
310 dmap_matchtype(devmap_t *dmap, char *type)
311 {
312 	if ((dmap->dmap_devtype == NULL) || (type == NULL))
313 		return (0);
314 
315 	return ((strcmp(dmap->dmap_devtype, type) == 0));
316 }
317 
318 /*
319  * dmap_matchname -
320  * 	checks if the specified devmap_t is for the device specified.
321  * 	returns 1 if it is, else returns 0.
322  */
323 int
324 dmap_matchname(devmap_t *dmap, char *name)
325 {
326 	if (dmap->dmap_devname == NULL)
327 		return (0);
328 
329 	return ((strcmp(dmap->dmap_devname, name) == 0));
330 }
331 
332 /*
333  * dm_match -
334  *	calls dmap_matchname or dmap_matchtype as appropriate.
335  */
336 int
337 dm_match(devmap_t *dmap, da_args *dargs)
338 {
339 	if (dargs->devinfo->devname)
340 		return (dmap_matchname(dmap, dargs->devinfo->devname));
341 	else if (dargs->devinfo->devtype)
342 		return (dmap_matchtype(dmap, dargs->devinfo->devtype));
343 
344 	return (0);
345 }
346 
347 /*
348  * dmap_interpret -
349  *	calls dmap_interpretf and dmap_dlexpand to parse devmap_t line.
350  *	returns  pointer to parsed devmapt_t entry, else returns NULL on error.
351  */
352 devmap_t  *
353 dmap_interpret(char *val, devmap_t *dm)
354 {
355 	if (dmap_interpretf(val, dm) == NULL)
356 		return (NULL);
357 
358 	return (dmap_dlexpand(dm));
359 }
360 
361 /*
362  * dmap_interpretf -
363  * 	parses string "val" and initializes pointers in the given devmap_t to
364  * 	fields in "val".
365  * 	returns pointer to updated devmap_t.
366  */
367 static devmap_t  *
368 dmap_interpretf(char *val, devmap_t *dm)
369 {
370 	dm->dmap_devname = getdadmfield(val, KV_TOKEN_DELIMIT);
371 	dm->dmap_devtype = getdadmfield(NULL, KV_TOKEN_DELIMIT);
372 	dm->dmap_devlist = getdadmfield(NULL, KV_TOKEN_DELIMIT);
373 	dm->dmap_devarray = NULL;
374 	if (dm->dmap_devname == NULL ||
375 	    dm->dmap_devtype == NULL ||
376 	    dm->dmap_devlist == NULL)
377 		return (NULL);
378 
379 	return (dm);
380 }
381 
382 /*
383  * dmap_dlexpand -
384  * 	expands dmap_devlist of the form `devlist_generate`
385  *	returns unexpanded form if there is no '\`' or in case of error.
386  */
387 static devmap_t *
388 dmap_dlexpand(devmap_t *dmp)
389 {
390 	char	tmplist[DA_BUFSIZE + 1];
391 	char	*cp, *cpl, **darp;
392 	int	count;
393 	FILE	*expansion;
394 
395 	dmp->dmap_devarray = NULL;
396 	if (dmp->dmap_devlist == NULL)
397 		return (NULL);
398 	if (*(dmp->dmap_devlist) != '`') {
399 		(void) strcpy(tmplist, dmp->dmap_devlist);
400 	} else {
401 		(void) strcpy(tmplist, dmp->dmap_devlist + 1);
402 		if ((cp = strchr(tmplist, '`')) != NULL)
403 			*cp = '\0';
404 		if ((expansion = popen(tmplist, "rF")) == NULL)
405 			return (NULL);
406 		count = fread(tmplist, 1, sizeof (tmplist) - 1, expansion);
407 		(void) pclose(expansion);
408 		tmplist[count] = '\0';
409 	}
410 
411 	/* cleanup the list */
412 	count = pack_white(tmplist);
413 	dmp->dmap_devarray = darp =
414 	    (char **)malloc((count + 2) * sizeof (char *));
415 	if (darp == NULL)
416 		return (NULL);
417 	cp = tmplist;
418 	while ((cp = strtok_r(cp, " ", &cpl)) != NULL) {
419 		*darp = strdup(cp);
420 		if (*darp == NULL) {
421 			freedmapent(dmp);
422 			return (NULL);
423 		}
424 		darp++;
425 		cp = NULL;
426 	}
427 	*darp = NULL;
428 
429 	return (dmp);
430 }
431 
432 /*
433  * dmapskip -
434  * 	scans input string to find next colon or end of line.
435  *	returns pointer to next char.
436  */
437 static char *
438 dmapskip(char *p)
439 {
440 	while (*p && *p != ':' && *p != '\n')
441 		++p;
442 	if (*p == '\n')
443 		*p = '\0';
444 	else if (*p != '\0')
445 		*p++ = '\0';
446 
447 	return (p);
448 }
449 
450 /*
451  * dmapdskip -
452  * 	scans input string to find next space or end of line.
453  *	returns pointer to next char.
454  */
455 static char *
456 dmapdskip(p)
457 	register char *p;
458 {
459 	while (*p && *p != ' ' && *p != '\n')
460 		++p;
461 	if (*p != '\0')
462 		*p++ = '\0';
463 
464 	return (p);
465 }
466 
467 char *
468 getdmapfield(char *ptr)
469 {
470 	static	char	*tptr;
471 
472 	if (ptr == NULL)
473 		ptr = tptr;
474 	if (ptr == NULL)
475 		return (NULL);
476 	tptr = dmapskip(ptr);
477 	ptr = trim_white(ptr);
478 	if (ptr == NULL)
479 		return (NULL);
480 	if (*ptr == NULL)
481 		return (NULL);
482 
483 	return (ptr);
484 }
485 
486 char *
487 getdmapdfield(char *ptr)
488 {
489 	static	char	*tptr;
490 	if (ptr != NULL) {
491 		ptr = trim_white(ptr);
492 	} else {
493 		ptr = tptr;
494 	}
495 	if (ptr == NULL)
496 		return (NULL);
497 	tptr = dmapdskip(ptr);
498 	if (ptr == NULL)
499 		return (NULL);
500 	if (*ptr == NULL)
501 		return (NULL);
502 
503 	return (ptr);
504 }
505