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