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 #include <string.h>
27 #include <stdlib.h>
28 #include <bsm/devices.h>
29 #include <bsm/devalloc.h>
30 
31 char *strtok_r(char *, const char *, char **);
32 
33 /* externs from getdaent.c */
34 extern char *trim_white(char *);
35 extern int pack_white(char *);
36 extern char *getdadmfield(char *, char *);
37 extern int getdadmline(char *, int, FILE *);
38 
39 extern char *_strdup_null(char *);
40 
41 static struct _dadefbuff {
42 	FILE		*_dadeff;
43 			/* pointer into /etc/security/tsol/devalloc_defaults */
44 	da_defs_t	_interpdadefs;
45 	char		_interpdadefline[DA_BUFSIZE + 1];
46 	char		 *_DADEFS;
47 } *__dadefbuff;
48 
49 #define	dadeff		(_df->_dadeff)
50 #define	interpdadefs	(_df->_interpdadefs)
51 #define	interpdadefline	(_df->_interpdadefline)
52 #define	DADEFS_FILE	(_df->_DADEFS)
53 
54 static da_defs_t	*dadef_interpret(char *);
55 int dadef_matchtype(da_defs_t *, char *);
56 
57 /*
58  * _dadefalloc -
59  *	allocates common buffers and structures.
60  * 	returns pointer to the new structure, else returns NULL on error.
61  */
62 static struct _dadefbuff *
_dadefalloc(void)63 _dadefalloc(void)
64 {
65 	struct _dadefbuff *_df = __dadefbuff;
66 
67 	if (_df == NULL) {
68 		_df = (struct _dadefbuff *)calloc((unsigned)1,
69 		    (unsigned)sizeof (*__dadefbuff));
70 		if (_df == NULL)
71 			return (NULL);
72 		DADEFS_FILE = "/etc/security/tsol/devalloc_defaults";
73 		__dadefbuff = _df;
74 	}
75 
76 	return (__dadefbuff);
77 }
78 
79 /*
80  * setdadefent -
81  *	rewinds devalloc_defaults file to the begining.
82  */
83 
84 void
setdadefent(void)85 setdadefent(void)
86 {
87 	struct _dadefbuff *_df = _dadefalloc();
88 
89 	if (_df == NULL)
90 		return;
91 	if (dadeff == NULL)
92 		dadeff = fopen(DADEFS_FILE, "rF");
93 	else
94 		rewind(dadeff);
95 }
96 
97 /*
98  * enddadefent -
99  *	closes devalloc_defaults file.
100  */
101 
102 void
enddadefent(void)103 enddadefent(void)
104 {
105 	struct _dadefbuff *_df = _dadefalloc();
106 
107 	if (_df == NULL)
108 		return;
109 	if (dadeff != NULL) {
110 		(void) fclose(dadeff);
111 		dadeff = NULL;
112 	}
113 }
114 
115 void
freedadefent(da_defs_t * da_def)116 freedadefent(da_defs_t *da_def)
117 {
118 	if (da_def == NULL)
119 		return;
120 	_kva_free(da_def->devopts);
121 	da_def->devopts = NULL;
122 }
123 
124 /*
125  * getdadefent -
126  *	When first called, returns a pointer to the first da_defs_t
127  * 	structure in devalloc_defaults; thereafter, it returns a pointer to the
128  *	next da_defs_t structure in the file. Thus, successive calls can be
129  *	used to search the entire file.
130  *	call to getdadefent should be bracketed by setdadefent and enddadefent.
131  *	returns NULL on error.
132  */
133 da_defs_t *
getdadefent(void)134 getdadefent(void)
135 {
136 	char			line1[DA_BUFSIZE + 1];
137 	da_defs_t		*da_def;
138 	struct _dadefbuff	*_df = _dadefalloc();
139 
140 	if ((_df == 0) || (dadeff == NULL))
141 		return (NULL);
142 
143 	while (getdadmline(line1, (int)sizeof (line1), dadeff) != 0) {
144 		if ((da_def = dadef_interpret(line1)) == NULL)
145 			continue;
146 		return (da_def);
147 	}
148 
149 	return (NULL);
150 }
151 
152 /*
153  * getdadeftype -
154  * 	searches from the beginning of devalloc_defaults for the device
155  *	specified by its type.
156  *	call to getdadeftype should be bracketed by setdadefent and enddadefent.
157  * 	returns pointer to da_defs_t for the device if it is found, else
158  *	returns NULL if device not found or in case of error.
159  */
160 da_defs_t *
getdadeftype(char * type)161 getdadeftype(char *type)
162 {
163 	char			line1[DA_BUFSIZE + 1];
164 	da_defs_t		*da_def;
165 	struct _dadefbuff	*_df = _dadefalloc();
166 
167 	if ((type == NULL) || (_df == NULL) || (dadeff == NULL))
168 		return (NULL);
169 
170 	while (getdadmline(line1, (int)sizeof (line1), dadeff) != 0) {
171 		if (strstr(line1, type) == NULL)
172 			continue;
173 		if ((da_def = dadef_interpret(line1)) == NULL)
174 			continue;
175 		if (dadef_matchtype(da_def, type))
176 			return (da_def);
177 		freedadefent(da_def);
178 	}
179 
180 	return (NULL);
181 }
182 
183 /*
184  * dadef_matchtype -
185  *	checks if the specified da_defs_t is for the device type specified.
186  *	returns 1 if match found, else, returns 0.
187  */
188 int
dadef_matchtype(da_defs_t * da_def,char * type)189 dadef_matchtype(da_defs_t *da_def, char *type)
190 {
191 	if (da_def->devtype == NULL)
192 		return (0);
193 
194 	return ((strcmp(da_def->devtype, type) == 0));
195 }
196 
197 /*
198  * dadef_interpret -
199  *	parses val and initializes pointers in da_defs_t.
200  * 	returns pointer to parsed da_defs_t entry, else returns NULL on error.
201  */
202 static da_defs_t  *
dadef_interpret(char * val)203 dadef_interpret(char *val)
204 {
205 	struct _dadefbuff	*_df = _dadefalloc();
206 	int			i;
207 	char			*opts;
208 	kva_t			*kvap;
209 	kv_t			*kvp;
210 
211 	if (_df == NULL)
212 		return (NULL);
213 
214 	(void) strcpy(interpdadefline, val);
215 	interpdadefs.devtype = getdadmfield(interpdadefline, KV_TOKEN_DELIMIT);
216 	opts = getdadmfield(NULL, KV_TOKEN_DELIMIT);
217 	interpdadefs.devopts = NULL;
218 	if (interpdadefs.devtype == NULL)
219 		return (NULL);
220 	if (opts != NULL)
221 		interpdadefs.devopts =
222 		    _str2kva(opts, KV_ASSIGN, KV_DELIMITER);
223 	/* remove any extraneous whitespace in the options */
224 	if ((kvap = interpdadefs.devopts) != NULL) {
225 		for (i = 0, kvp = kvap->data; i < kvap->length; i++, kvp++) {
226 			(void) pack_white(kvp->key);
227 			(void) pack_white(kvp->value);
228 		}
229 	}
230 
231 	return (&interpdadefs);
232 }
233