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