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 "prof_int.h"
9 #include <stdio.h>
10 #include <string.h>
11 #ifdef HAVE_STDLIB_H
12 #include <stdlib.h>
13 #endif
14 #include <errno.h>
15 #include <limits.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(struct profile_string_list *list)
40 {
41 	list->num = 0;
42 	list->max = 10;
43 	list->list = (char **) malloc(list->max * sizeof(char *));
44 	if (list->list == 0)
45 		return ENOMEM;
46 	list->list[0] = 0;
47 	return 0;
48 }
49 
50 /*
51  * Free any memory left over in the string abstraction, returning the
52  * built up list in *ret_list if it is non-null.
53  */
54 static void end_list(struct profile_string_list *list, char ***ret_list)
55 {
56 	char	**cp;
57 
58 	if (list == 0)
59 		return;
60 
61 	if (ret_list) {
62 		*ret_list = list->list;
63 		return;
64 	} else {
65 		for (cp = list->list; *cp; cp++)
66 			free(*cp);
67 		free(list->list);
68 	}
69 	list->num = list->max = 0;
70 	list->list = 0;
71 }
72 
73 /*
74  * Add a string to the list.
75  */
76 static errcode_t add_to_list(struct profile_string_list *list, const char *str)
77 {
78 	char 	*newstr, **newlist;
79 	int	newmax;
80 
81 	if (list->num+1 >= list->max) {
82 		newmax = list->max + 10;
83 		newlist = (char **) realloc(list->list, newmax * sizeof(char *));
84 		if (newlist == 0)
85 			return ENOMEM;
86 		list->max = newmax;
87 		list->list = newlist;
88 	}
89 	newstr = (char *) malloc(strlen(str)+1);
90 	if (newstr == 0)
91 		return ENOMEM;
92 	strcpy(newstr, str);
93 
94 	list->list[list->num++] = newstr;
95 	list->list[list->num] = 0;
96 	return 0;
97 }
98 
99 /*
100  * Return TRUE if the string is already a member of the list.
101  */
102 static int is_list_member(struct profile_string_list *list, const char *str)
103 {
104 	char **cpp;
105 
106 	if (!list->list)
107 		return 0;
108 
109 	for (cpp = list->list; *cpp; cpp++) {
110 		if (!strcmp(*cpp, str))
111 			return 1;
112 	}
113 	return 0;
114 }
115 
116 /*
117  * This function frees a null-terminated list as returned by
118  * profile_get_values.
119  */
120 void KRB5_CALLCONV profile_free_list(char **list)
121 {
122     char	**cp;
123 
124     if (list == 0)
125 	    return;
126 
127     for (cp = list; *cp; cp++)
128 	free(*cp);
129     free(list);
130 }
131 
132 errcode_t KRB5_CALLCONV
133 profile_get_values(profile_t profile, const char *const *names,
134 		   char ***ret_values)
135 {
136 	errcode_t		retval;
137 	void			*state;
138 	char			*value;
139 	struct profile_string_list values;
140 
141 	if ((retval = profile_node_iterator_create(profile, names,
142 						   PROFILE_ITER_RELATIONS_ONLY,
143 						   &state)))
144 		return retval;
145 
146 	if ((retval = init_list(&values)))
147 		return retval;
148 
149 	do {
150 		if ((retval = profile_node_iterator(&state, 0, 0, &value)))
151 			goto cleanup;
152 		if (value)
153 			add_to_list(&values, value);
154 	} while (state);
155 
156 	if (values.num == 0) {
157 		retval = PROF_NO_RELATION;
158 		goto cleanup;
159 	}
160 
161 	end_list(&values, ret_values);
162 	return 0;
163 
164 cleanup:
165 	end_list(&values, (char ***)NULL);
166 	return retval;
167 }
168 
169 /*
170  * This function only gets the first value from the file; it is a
171  * helper function for profile_get_string, profile_get_integer, etc.
172  */
173 errcode_t profile_get_value(profile_t profile, const char **names,
174 			    const char **ret_value)
175 {
176 	errcode_t		retval;
177 	void			*state;
178 	char			*value;
179 
180 	if ((retval = profile_node_iterator_create(profile, names,
181 						   PROFILE_ITER_RELATIONS_ONLY,
182 						   &state)))
183 		return retval;
184 
185 	if ((retval = profile_node_iterator(&state, 0, 0, &value)))
186 		goto cleanup;
187 
188 	if (value)
189 		*ret_value = value;
190 	else
191 		retval = PROF_NO_RELATION;
192 
193 cleanup:
194 	profile_node_iterator_free(&state);
195 	return retval;
196 }
197 
198 errcode_t KRB5_CALLCONV
199 profile_get_string(profile_t profile, const char *name, const char *subname,
200 		   const char *subsubname, const char *def_val,
201 		   char **ret_string)
202 {
203 	const char	*value;
204 	errcode_t	retval;
205 	const char	*names[4];
206 
207 	if (profile) {
208 		names[0] = name;
209 		names[1] = subname;
210 		names[2] = subsubname;
211 		names[3] = 0;
212 		retval = profile_get_value(profile, names, &value);
213 		if (retval == PROF_NO_SECTION || retval == PROF_NO_RELATION)
214 			value = def_val;
215 		else if (retval)
216 			return retval;
217 	} else
218 		value = def_val;
219 
220 	if (value) {
221 	  *ret_string = (char *) malloc(strlen(value)+1);
222 		if (*ret_string == 0)
223 			return ENOMEM;
224 		strcpy(*ret_string, value);
225 	} else
226 		*ret_string = 0;
227 	return 0;
228 }
229 
230 errcode_t KRB5_CALLCONV
231 profile_get_integer(profile_t profile, const char *name, const char *subname,
232 		    const char *subsubname, int def_val, int *ret_int)
233 {
234 	const char	*value;
235 	errcode_t	retval;
236 	const char	*names[4];
237 	char            *end_value;
238 	long		ret_long;
239 
240 	*ret_int = def_val;
241 	if (profile == 0)
242 		return 0;
243 
244 	names[0] = name;
245 	names[1] = subname;
246 	names[2] = subsubname;
247 	names[3] = 0;
248 	retval = profile_get_value(profile, names, &value);
249 	if (retval == PROF_NO_SECTION || retval == PROF_NO_RELATION) {
250 		*ret_int = def_val;
251 		return 0;
252 	} else if (retval)
253 		return retval;
254 
255 	if (value[0] == 0)
256 	    /* Empty string is no good.  */
257 	    return PROF_BAD_INTEGER;
258 	errno = 0;
259 	ret_long = strtol (value, &end_value, 10);
260 
261 	/* Overflow or underflow.  */
262 	if ((ret_long == LONG_MIN || ret_long == LONG_MAX) && errno != 0)
263 	    return PROF_BAD_INTEGER;
264 	/* Value outside "int" range.  */
265 	if ((long) (int) ret_long != ret_long)
266 	    return PROF_BAD_INTEGER;
267 	/* Garbage in string.  */
268 	if (end_value != value + strlen (value))
269 	    return PROF_BAD_INTEGER;
270 
271 
272 	*ret_int = ret_long;
273 	return 0;
274 }
275 
276 static const char *const conf_yes[] = {
277     "y", "yes", "true", "t", "1", "on",
278     0,
279 };
280 
281 static const char *const conf_no[] = {
282     "n", "no", "false", "nil", "0", "off",
283     0,
284 };
285 
286 static errcode_t
287 profile_parse_boolean(const char *s, int *ret_boolean)
288 {
289     const char *const *p;
290 
291     if (ret_boolean == NULL)
292     	return PROF_EINVAL;
293 
294     for(p=conf_yes; *p; p++) {
295 		if (!strcasecmp(*p,s)) {
296 			*ret_boolean = 1;
297 	    	return 0;
298 		}
299     }
300 
301     for(p=conf_no; *p; p++) {
302 		if (!strcasecmp(*p,s)) {
303 			*ret_boolean = 0;
304 			return 0;
305 		}
306     }
307 
308 	return PROF_BAD_BOOLEAN;
309 }
310 
311 errcode_t KRB5_CALLCONV
312 profile_get_boolean(profile_t profile, const char *name, const char *subname,
313 		    const char *subsubname, int def_val, int *ret_boolean)
314 {
315 	const char	*value;
316 	errcode_t	retval;
317 	const char	*names[4];
318 
319 	if (profile == 0) {
320 		*ret_boolean = def_val;
321 		return 0;
322 	}
323 
324 	names[0] = name;
325 	names[1] = subname;
326 	names[2] = subsubname;
327 	names[3] = 0;
328 	retval = profile_get_value(profile, names, &value);
329 	if (retval == PROF_NO_SECTION || retval == PROF_NO_RELATION) {
330 		*ret_boolean = def_val;
331 		return 0;
332 	} else if (retval)
333 		return retval;
334 
335 	return profile_parse_boolean (value, ret_boolean);
336 }
337 
338 /*
339  * This function will return the list of the names of subections in the
340  * under the specified section name.
341  */
342 errcode_t KRB5_CALLCONV
343 profile_get_subsection_names(profile_t profile, const char **names,
344 			     char ***ret_names)
345 {
346 	errcode_t		retval;
347 	void			*state;
348 	char			*name;
349 	struct profile_string_list values;
350 
351 	if ((retval = profile_node_iterator_create(profile, names,
352 		   PROFILE_ITER_LIST_SECTION | PROFILE_ITER_SECTIONS_ONLY,
353 		   &state)))
354 		return retval;
355 
356 	if ((retval = init_list(&values)))
357 		return retval;
358 
359 	do {
360 		if ((retval = profile_node_iterator(&state, 0, &name, 0)))
361 			goto cleanup;
362 		if (name)
363 			add_to_list(&values, name);
364 	} while (state);
365 
366 	end_list(&values, ret_names);
367 	return 0;
368 
369 cleanup:
370 	end_list(&values, (char ***)NULL);
371 	return retval;
372 }
373 
374 /*
375  * This function will return the list of the names of relations in the
376  * under the specified section name.
377  */
378 errcode_t KRB5_CALLCONV
379 profile_get_relation_names(profile_t profile, const char **names,
380 			   char ***ret_names)
381 {
382 	errcode_t		retval;
383 	void			*state;
384 	char			*name;
385 	struct profile_string_list values;
386 
387 	if ((retval = profile_node_iterator_create(profile, names,
388 		   PROFILE_ITER_LIST_SECTION | PROFILE_ITER_RELATIONS_ONLY,
389 		   &state)))
390 		return retval;
391 
392 	if ((retval = init_list(&values)))
393 		return retval;
394 
395 	do {
396 		if ((retval = profile_node_iterator(&state, 0, &name, 0)))
397 			goto cleanup;
398 		if (name && !is_list_member(&values, name))
399 			add_to_list(&values, name);
400 	} while (state);
401 
402 	end_list(&values, ret_names);
403 	return 0;
404 
405 cleanup:
406 	end_list(&values, (char ***)NULL);
407 	return retval;
408 }
409 
410 errcode_t KRB5_CALLCONV
411 profile_iterator_create(profile_t profile, const char *const *names, int flags,
412 			void **ret_iter)
413 {
414 	return profile_node_iterator_create(profile, names, flags, ret_iter);
415 }
416 
417 void KRB5_CALLCONV
418 profile_iterator_free(void **iter_p)
419 {
420 	profile_node_iterator_free(iter_p);
421 }
422 
423 errcode_t KRB5_CALLCONV
424 profile_iterator(void **iter_p, char **ret_name, char **ret_value)
425 {
426 	char *name, *value;
427 	errcode_t	retval;
428 
429 	retval = profile_node_iterator(iter_p, 0, &name, &value);
430 	if (retval)
431 		return retval;
432 
433 	if (ret_name) {
434 		if (name) {
435 		  *ret_name = (char *) malloc(strlen(name)+1);
436 			if (!*ret_name)
437 				return ENOMEM;
438 			strcpy(*ret_name, name);
439 		} else
440 			*ret_name = 0;
441 	}
442 	if (ret_value) {
443 		if (value) {
444 		  *ret_value = (char *) malloc(strlen(value)+1);
445 			if (!*ret_value) {
446 				if (ret_name) {
447 					free(*ret_name);
448 					*ret_name = 0;
449 				}
450 				return ENOMEM;
451 			}
452 			strcpy(*ret_value, value);
453 		} else
454 			*ret_value = 0;
455 	}
456 	return 0;
457 }
458 
459 void KRB5_CALLCONV
460 profile_release_string(char *str)
461 {
462 	free(str);
463 }
464