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