1 #pragma ident	"%Z%%M%	%I%	%E% SMI"
2 /*
3  * prof_get.c --- routines that expose the public interfaces for
4  * 	querying items from the profile.
5  *
6  */
7 
8 #include <stdio.h>
9 #include <string.h>
10 #ifdef HAVE_STDLIB_H
11 #include <stdlib.h>
12 #endif
13 #include <errno.h>
14 
15 #include "prof_int.h"
16 
17 /*
18  * These functions --- init_list(), end_list(), and add_to_list() are
19  * internal functions used to build up a null-terminated char ** list
20  * of strings to be returned by functions like profile_get_values.
21  *
22  * The profile_string_list structure is used for internal booking
23  * purposes to build up the list, which is returned in *ret_list by
24  * the end_list() function.
25  *
26  * The publicly exported interface for freeing char** list is
27  * profile_free_list().
28  */
29 
30 struct profile_string_list {
31 	char	**list;
32 	int	num;
33 	int	max;
34 };
35 
36 /*
37  * Initialize the string list abstraction.
38  */
39 static errcode_t init_list(list)
40 	struct profile_string_list *list;
41 {
42 	list->num = 0;
43 	list->max = 10;
44 	list->list = (char **) malloc(list->max * sizeof(char *));
45 	if (list->list == 0)
46 		return ENOMEM;
47 	list->list[0] = 0;
48 	return 0;
49 }
50 
51 /*
52  * Free any memory left over in the string abstraction, returning the
53  * built up list in *ret_list if it is non-null.
54  */
55 static void end_list(list, ret_list)
56     struct profile_string_list *list;
57     char ***ret_list;
58 {
59 	char	**cp;
60 
61 	if (list == 0)
62 		return;
63 
64 	if (ret_list) {
65 		*ret_list = list->list;
66 		return;
67 	} else {
68 		for (cp = list->list; *cp; cp++)
69 			free(*cp);
70 		free(list->list);
71 	}
72 	list->num = list->max = 0;
73 	list->list = 0;
74 }
75 
76 /*
77  * Add a string to the list.
78  */
79 static errcode_t add_to_list(list, str)
80 	struct profile_string_list *list;
81 	const char	*str;
82 {
83 	char 	*newstr, **newlist;
84 	int	newmax;
85 
86 	if (list->num+1 >= list->max) {
87 		newmax = list->max + 10;
88 		newlist = (char **)realloc(list->list, newmax * sizeof(char *));
89 		if (newlist == 0)
90 			return ENOMEM;
91 		list->max = newmax;
92 		list->list = newlist;
93 	}
94 	newstr = (char *) malloc(strlen(str)+1);
95 	if (newstr == 0)
96 		return ENOMEM;
97 	strcpy(newstr, str);
98 
99 	list->list[list->num++] = newstr;
100 	list->list[list->num] = 0;
101 	return 0;
102 }
103 
104 /*
105  * Return TRUE if the string is already a member of the list.
106  */
107 static int is_list_member(list, str)
108 	struct profile_string_list *list;
109 	const char	*str;
110 {
111 	char **cpp;
112 
113 	if (!list->list)
114 		return 0;
115 
116 	for (cpp = list->list; *cpp; cpp++) {
117 		if (!strcmp(*cpp, str))
118 			return 1;
119 	}
120 	return 0;
121 }
122 
123 /*
124  * This function frees a null-terminated list as returned by
125  * profile_get_values.
126  */
127 KRB5_DLLIMP void KRB5_CALLCONV profile_free_list(list)
128     char	**list;
129 {
130     char	**cp;
131 
132     if (list == 0)
133 	    return;
134 
135     for (cp = list; *cp; cp++)
136 	free(*cp);
137     free(list);
138 }
139 
140 KRB5_DLLIMP errcode_t KRB5_CALLCONV
141 profile_get_values(profile, names, ret_values)
142 	profile_t	profile;
143 	const char	**names;
144 	char	***ret_values;
145 {
146 	errcode_t		retval;
147 	void			*state;
148 	char			*value;
149 	struct profile_string_list values;
150 
151 	if ((retval = profile_node_iterator_create(profile, names,
152 						   PROFILE_ITER_RELATIONS_ONLY,
153 						   &state)))
154 		return retval;
155 
156 	if ((retval = init_list(&values)))
157 		return retval;
158 
159 	do {
160 		if ((retval = profile_node_iterator(&state, 0, 0, &value)))
161 			goto cleanup;
162 		if (value)
163 			add_to_list(&values, value);
164 	} while (state);
165 
166 	if (values.num == 0) {
167 		retval = PROF_NO_RELATION;
168 		goto cleanup;
169 	}
170 
171 	end_list(&values, ret_values);
172 	return 0;
173 
174 cleanup:
175 	end_list(&values, (char ***)NULL);
176 	return retval;
177 }
178 
179 /*
180  * This function only gets the first value from the file; it is a
181  * helper function for profile_get_string, profile_get_integer, etc.
182  */
183 errcode_t profile_get_value(profile, names, ret_value)
184 	profile_t	profile;
185 	const char	**names;
186 	const char	**ret_value;
187 {
188 	errcode_t		retval;
189 	void			*state;
190 	char			*value;
191 
192 	if ((retval = profile_node_iterator_create(profile, names,
193 						   PROFILE_ITER_RELATIONS_ONLY,
194 						   &state)))
195 		return retval;
196 
197 	if ((retval = profile_node_iterator(&state, 0, 0, &value)))
198 		goto cleanup;
199 
200 	if (value)
201 		*ret_value = value;
202 	else
203 		retval = PROF_NO_RELATION;
204 
205 cleanup:
206 	profile_node_iterator_free(&state);
207 	return retval;
208 }
209 
210 KRB5_DLLIMP errcode_t KRB5_CALLCONV
211 profile_get_string(profile, name, subname, subsubname,
212 			     def_val, ret_string)
213 	profile_t	profile;
214 	const char	*name, *subname, *subsubname;
215 	const char	*def_val;
216 	char 	**ret_string;
217 {
218 	const char	*value;
219 	errcode_t	retval;
220 	const char	*names[4];
221 
222 	if (profile) {
223 		names[0] = name;
224 		names[1] = subname;
225 		names[2] = subsubname;
226 		names[3] = 0;
227 		retval = profile_get_value(profile, names, &value);
228 		if (retval == PROF_NO_SECTION || retval == PROF_NO_RELATION)
229 			value = def_val;
230 		else if (retval)
231 			return retval;
232 	} else
233 		value = def_val;
234 
235 	if (value) {
236 		*ret_string = (char *) malloc(strlen(value)+1);
237 		if (*ret_string == 0)
238 			return ENOMEM;
239 		strcpy(*ret_string, value);
240 	} else
241 		*ret_string = 0;
242 	return 0;
243 }
244 
245 KRB5_DLLIMP errcode_t KRB5_CALLCONV
246 profile_get_integer(profile, name, subname, subsubname,
247 			      def_val, ret_int)
248 	profile_t	profile;
249 	const char	*name, *subname, *subsubname;
250 	int		def_val;
251 	int		*ret_int;
252 {
253 	const char	*value;
254 	errcode_t	retval;
255 	const char	*names[4];
256 
257 	if (profile == 0) {
258 		*ret_int = def_val;
259 		return 0;
260 	}
261 
262 	names[0] = name;
263 	names[1] = subname;
264 	names[2] = subsubname;
265 	names[3] = 0;
266 	retval = profile_get_value(profile, names, &value);
267 	if (retval == PROF_NO_SECTION || retval == PROF_NO_RELATION) {
268 		*ret_int = def_val;
269 		return 0;
270 	} else if (retval)
271 		return retval;
272 
273 	*ret_int = atoi(value);
274 	return 0;
275 }
276 
277 /*
278  * This function will return the list of the names of subections in the
279  * under the specified section name.
280  */
281 KRB5_DLLIMP errcode_t KRB5_CALLCONV
282 profile_get_subsection_names(profile, names, ret_names)
283 	profile_t	profile;
284 	const char	**names;
285 	char		***ret_names;
286 {
287 	errcode_t		retval;
288 	void			*state;
289 	char			*name;
290 	struct profile_string_list values;
291 
292 	if ((retval = profile_node_iterator_create(profile, names,
293 		   PROFILE_ITER_LIST_SECTION | PROFILE_ITER_SECTIONS_ONLY,
294 		   &state)))
295 		return retval;
296 
297 	if ((retval = init_list(&values)))
298 		return retval;
299 
300 	do {
301 		if ((retval = profile_node_iterator(&state, 0, &name, 0)))
302 			goto cleanup;
303 		if (name)
304 			add_to_list(&values, name);
305 	} while (state);
306 
307 	end_list(&values, ret_names);
308 	return 0;
309 
310 cleanup:
311 	end_list(&values, (char ***)NULL);
312 	return retval;
313 }
314 
315 /*
316  * This function will return the list of the names of relations in the
317  * under the specified section name.
318  */
319 KRB5_DLLIMP errcode_t KRB5_CALLCONV
320 profile_get_relation_names(profile, names, ret_names)
321 	profile_t	profile;
322 	const char	**names;
323 	char		***ret_names;
324 {
325 	errcode_t		retval;
326 	void			*state;
327 	char			*name;
328 	struct profile_string_list values;
329 
330 	if ((retval = profile_node_iterator_create(profile, names,
331 		   PROFILE_ITER_LIST_SECTION | PROFILE_ITER_RELATIONS_ONLY,
332 		   &state)))
333 		return retval;
334 
335 	if ((retval = init_list(&values)))
336 		return retval;
337 
338 	do {
339 		if ((retval = profile_node_iterator(&state, 0, &name, 0)))
340 			goto cleanup;
341 		if (name && !is_list_member(&values, name))
342 			add_to_list(&values, name);
343 	} while (state);
344 
345 	end_list(&values, ret_names);
346 	return 0;
347 
348 cleanup:
349 	end_list(&values, (char ***)NULL);
350 	return retval;
351 }
352 
353 KRB5_DLLIMP errcode_t KRB5_CALLCONV
354 profile_iterator_create(profile, names, flags, ret_iter)
355 	profile_t	profile;
356 	const char	**names;
357 	int		flags;
358 	void		**ret_iter;
359 {
360 	return profile_node_iterator_create(profile, names, flags, ret_iter);
361 }
362 
363 KRB5_DLLIMP void KRB5_CALLCONV
364 profile_iterator_free(iter_p)
365 	void	**iter_p;
366 {
367 	profile_node_iterator_free(iter_p);
368 }
369 
370 KRB5_DLLIMP errcode_t KRB5_CALLCONV
371 profile_iterator(iter_p, ret_name, ret_value)
372 	void	**iter_p;
373 	char **ret_name, **ret_value;
374 {
375 	char *name, *value;
376 	errcode_t	retval;
377 
378 	retval = profile_node_iterator(iter_p, 0, &name, &value);
379 	if (retval)
380 		return retval;
381 
382 	if (ret_name) {
383 		if (name) {
384 			*ret_name = (char *) malloc(strlen(name)+1);
385 			if (!*ret_name)
386 				return ENOMEM;
387 			strcpy(*ret_name, name);
388 		} else
389 			*ret_name = 0;
390 	}
391 	if (ret_value) {
392 		if (value) {
393 			*ret_value = (char *) malloc(strlen(value)+1);
394 			if (!*ret_value) {
395 				if (ret_name) {
396 					free(*ret_name);
397 					*ret_name = 0;
398 				}
399 				return ENOMEM;
400 			}
401 			strcpy(*ret_value, value);
402 		} else
403 			*ret_value = 0;
404 	}
405 	return 0;
406 }
407 
408 KRB5_DLLIMP void KRB5_CALLCONV
409 profile_release_string(str)
410 	char *str;
411 {
412 	free(str);
413 }
414