Path: blob/main/crypto/krb5/src/util/profile/prof_get.c
34879 views
/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */1/*2* prof_get.c --- routines that expose the public interfaces for3* querying items from the profile.4*5*/67#include "prof_int.h"8#include <stdio.h>9#include <string.h>10#ifdef HAVE_STDLIB_H11#include <stdlib.h>12#endif13#include <errno.h>14#include <limits.h>1516/*17* These functions --- init_list(), end_list(), and add_to_list() are18* internal functions used to build up a null-terminated char ** list19* of strings to be returned by functions like profile_get_values.20*21* The profile_string_list structure is used for internal booking22* purposes to build up the list, which is returned in *ret_list by23* the end_list() function.24*25* The publicly exported interface for freeing char** list is26* profile_free_list().27*/2829struct profile_string_list {30char **list;31unsigned int num;32unsigned int max;33};3435/*36* Initialize the string list abstraction.37*/38static errcode_t init_list(struct profile_string_list *list)39{40list->num = 0;41list->max = 10;42list->list = malloc(list->max * sizeof(char *));43if (list->list == 0)44return ENOMEM;45list->list[0] = 0;46return 0;47}4849/*50* Free any memory left over in the string abstraction, returning the51* built up list in *ret_list if it is non-null.52*/53static void end_list(struct profile_string_list *list, char ***ret_list)54{55char **cp;5657if (list == 0)58return;5960if (ret_list) {61*ret_list = list->list;62return;63} else {64for (cp = list->list; cp && *cp; cp++)65free(*cp);66free(list->list);67}68list->num = list->max = 0;69list->list = 0;70}7172/*73* Add a string to the list.74*/75static errcode_t add_to_list(struct profile_string_list *list, const char *str)76{77char *newstr, **newlist;78unsigned int newmax;7980if (list->num+1 >= list->max) {81newmax = list->max + 10;82newlist = realloc(list->list, newmax * sizeof(char *));83if (newlist == 0)84return ENOMEM;85list->max = newmax;86list->list = newlist;87}88newstr = strdup(str);89if (newstr == 0)90return ENOMEM;9192list->list[list->num++] = newstr;93list->list[list->num] = 0;94return 0;95}9697/*98* Return TRUE if the string is already a member of the list.99*/100static int is_list_member(struct profile_string_list *list, const char *str)101{102char **cpp;103104if (!list->list)105return 0;106107for (cpp = list->list; *cpp; cpp++) {108if (!strcmp(*cpp, str))109return 1;110}111return 0;112}113114/*115* This function frees a null-terminated list as returned by116* profile_get_values.117*/118void KRB5_CALLCONV profile_free_list(char **list)119{120char **cp;121122if (list == 0)123return;124125for (cp = list; *cp; cp++)126free(*cp);127free(list);128}129130/* Look up a relation in a vtable profile. */131static errcode_t132get_values_vt(profile_t profile, const char *const *names, char ***ret_values)133{134errcode_t retval;135char **vtvalues, **val;136struct profile_string_list values;137138retval = profile->vt->get_values(profile->cbdata, names, &vtvalues);139if (retval)140return retval;141142/* Copy the result into memory we can free. */143retval = init_list(&values);144if (retval == 0) {145for (val = vtvalues; *val; val++)146add_to_list(&values, *val);147end_list(&values, ret_values);148}149150profile->vt->free_values(profile->cbdata, vtvalues);151return retval;152}153154errcode_t KRB5_CALLCONV155profile_get_values(profile_t profile, const char *const *names,156char ***ret_values)157{158errcode_t retval;159void *state = NULL;160char *value;161struct profile_string_list values;162163*ret_values = NULL;164if (!profile)165return PROF_NO_PROFILE;166if (profile->vt)167return get_values_vt(profile, names, ret_values);168169if ((retval = profile_node_iterator_create(profile, names,170PROFILE_ITER_RELATIONS_ONLY,171&state)))172return retval;173174retval = init_list(&values);175if (retval)176goto cleanup;177178do {179if ((retval = profile_node_iterator(&state, 0, 0, &value)))180goto cleanup;181if (value)182add_to_list(&values, value);183} while (state);184185if (values.num == 0) {186retval = PROF_NO_RELATION;187goto cleanup;188}189190cleanup:191end_list(&values, retval ? NULL : ret_values);192profile_node_iterator_free(&state);193return retval;194}195196/* Look up a relation in a vtable profile and return the first value in the197* result. */198static errcode_t199get_value_vt(profile_t profile, const char *const *names, char **ret_value)200{201errcode_t retval;202char **vtvalues;203204retval = profile->vt->get_values(profile->cbdata, names, &vtvalues);205if (retval)206return retval;207*ret_value = strdup(*vtvalues);208if (*ret_value == NULL)209retval = ENOMEM;210profile->vt->free_values(profile->cbdata, vtvalues);211return retval;212}213214/*215* This function only gets the first value from the file; it is a216* helper function for profile_get_string, profile_get_integer, etc.217*/218errcode_t profile_get_value(profile_t profile, const char **names,219char **ret_value)220{221errcode_t retval;222void *state;223char *value;224225*ret_value = NULL;226if (!profile)227return PROF_NO_PROFILE;228if (profile->vt)229return get_value_vt(profile, names, ret_value);230231retval = profile_iterator_create(profile, names,232PROFILE_ITER_RELATIONS_ONLY, &state);233if (retval)234return retval;235236retval = profile_iterator(&state, NULL, &value);237if (retval)238goto cleanup;239240if (value)241*ret_value = value;242else243retval = PROF_NO_RELATION;244245cleanup:246profile_iterator_free(&state);247return retval;248}249250errcode_t KRB5_CALLCONV251profile_get_string(profile_t profile, const char *name, const char *subname,252const char *subsubname, const char *def_val,253char **ret_string)254{255char *value;256errcode_t retval;257const char *names[4];258259if (profile) {260names[0] = name;261names[1] = subname;262names[2] = subsubname;263names[3] = 0;264retval = profile_get_value(profile, names, &value);265if (retval == 0) {266*ret_string = value;267return 0;268} else if (retval != PROF_NO_SECTION && retval != PROF_NO_RELATION)269return retval;270}271272if (def_val) {273*ret_string = strdup(def_val);274if (*ret_string == NULL)275return ENOMEM;276} else277*ret_string = NULL;278return 0;279}280281static errcode_t282parse_int(const char *value, int *ret_int)283{284char *end_value;285long ret_long;286287if (value[0] == 0)288/* Empty string is no good. */289return PROF_BAD_INTEGER;290errno = 0;291ret_long = strtol(value, &end_value, 10);292293/* Overflow or underflow. */294if ((ret_long == LONG_MIN || ret_long == LONG_MAX) && errno != 0)295return PROF_BAD_INTEGER;296/* Value outside "int" range. */297if ((long) (int) ret_long != ret_long)298return PROF_BAD_INTEGER;299/* Garbage in string. */300if (end_value != value + strlen (value))301return PROF_BAD_INTEGER;302303*ret_int = ret_long;304return 0;305}306307errcode_t KRB5_CALLCONV308profile_get_integer(profile_t profile, const char *name, const char *subname,309const char *subsubname, int def_val, int *ret_int)310{311char *value;312errcode_t retval;313const char *names[4];314315*ret_int = def_val;316if (profile == 0)317return 0;318319names[0] = name;320names[1] = subname;321names[2] = subsubname;322names[3] = 0;323retval = profile_get_value(profile, names, &value);324if (retval == PROF_NO_SECTION || retval == PROF_NO_RELATION) {325*ret_int = def_val;326return 0;327} else if (retval)328return retval;329330retval = parse_int(value, ret_int);331free(value);332return retval;333}334335static const char *const conf_yes[] = {336"y", "yes", "true", "t", "1", "on",3370,338};339340static const char *const conf_no[] = {341"n", "no", "false", "nil", "0", "off",3420,343};344345static errcode_t346profile_parse_boolean(const char *s, int *ret_boolean)347{348const char *const *p;349350if (ret_boolean == NULL)351return PROF_EINVAL;352353for(p=conf_yes; *p; p++) {354if (!strcasecmp(*p,s)) {355*ret_boolean = 1;356return 0;357}358}359360for(p=conf_no; *p; p++) {361if (!strcasecmp(*p,s)) {362*ret_boolean = 0;363return 0;364}365}366367return PROF_BAD_BOOLEAN;368}369370errcode_t KRB5_CALLCONV371profile_get_boolean(profile_t profile, const char *name, const char *subname,372const char *subsubname, int def_val, int *ret_boolean)373{374char *value;375errcode_t retval;376const char *names[4];377378if (profile == 0) {379*ret_boolean = def_val;380return 0;381}382383names[0] = name;384names[1] = subname;385names[2] = subsubname;386names[3] = 0;387retval = profile_get_value(profile, names, &value);388if (retval == PROF_NO_SECTION || retval == PROF_NO_RELATION) {389*ret_boolean = def_val;390return 0;391} else if (retval)392return retval;393394retval = profile_parse_boolean(value, ret_boolean);395free(value);396return retval;397}398399/*400* This function will return the list of the names of subections in the401* under the specified section name.402*/403errcode_t KRB5_CALLCONV404profile_get_subsection_names(profile_t profile, const char **names,405char ***ret_names)406{407errcode_t retval;408void *state;409char *name;410struct profile_string_list values;411412if ((retval = profile_iterator_create(profile, names,413PROFILE_ITER_LIST_SECTION |414PROFILE_ITER_SECTIONS_ONLY,415&state)))416return retval;417418if ((retval = init_list(&values)))419return retval;420421do {422if ((retval = profile_iterator(&state, &name, NULL)))423goto cleanup;424if (name)425add_to_list(&values, name);426free(name);427} while (state);428429end_list(&values, ret_names);430return 0;431432cleanup:433end_list(&values, 0);434return retval;435}436437/*438* This function will return the list of the names of relations in the439* under the specified section name.440*/441errcode_t KRB5_CALLCONV442profile_get_relation_names(profile_t profile, const char **names,443char ***ret_names)444{445errcode_t retval;446void *state;447char *name;448struct profile_string_list values;449450if ((retval = profile_iterator_create(profile, names,451PROFILE_ITER_LIST_SECTION |452PROFILE_ITER_RELATIONS_ONLY,453&state)))454return retval;455456if ((retval = init_list(&values)))457return retval;458459do {460if ((retval = profile_iterator(&state, &name, NULL)))461goto cleanup;462if (name && !is_list_member(&values, name))463add_to_list(&values, name);464free(name);465} while (state);466467end_list(&values, ret_names);468return 0;469470cleanup:471end_list(&values, 0);472return retval;473}474475struct profile_iterator {476prf_magic_t magic;477profile_t profile;478void *idata;479};480481errcode_t KRB5_CALLCONV482profile_iterator_create(profile_t profile, const char *const *names, int flags,483void **ret_iter)484{485struct profile_iterator *iter;486errcode_t retval;487488*ret_iter = NULL;489if (!profile)490return PROF_NO_PROFILE;491492iter = malloc(sizeof(*iter));493if (iter == NULL)494return ENOMEM;495iter->magic = PROF_MAGIC_ITERATOR;496iter->profile = profile;497498/* Create the underlying iterator representation using the vtable or the499* built-in node iterator. */500if (profile->vt) {501if (!profile->vt->iterator_create)502retval = PROF_UNSUPPORTED;503else504retval = profile->vt->iterator_create(profile->cbdata, names,505flags, &iter->idata);506} else {507retval = profile_node_iterator_create(profile, names, flags,508&iter->idata);509}510if (retval) {511free(iter);512return retval;513}514515*ret_iter = iter;516return 0;517}518519void KRB5_CALLCONV520profile_iterator_free(void **iter_p)521{522struct profile_iterator *iter;523profile_t profile;524525if (!iter_p)526return;527iter = *iter_p;528if (!iter || iter->magic != PROF_MAGIC_ITERATOR)529return;530profile = iter->profile;531if (profile->vt)532profile->vt->iterator_free(profile->cbdata, iter->idata);533else534profile_node_iterator_free(&iter->idata);535free(iter);536*iter_p = NULL;537}538539/* Make copies of name and value into *ret_name and *ret_value. Handle null540* values of any argument. */541static errcode_t542set_results(const char *name, const char *value, char **ret_name,543char **ret_value)544{545char *name_copy = NULL, *value_copy = NULL;546547if (ret_name && name) {548name_copy = strdup(name);549if (name_copy == NULL)550goto oom;551}552if (ret_value && value) {553value_copy = strdup(value);554if (value_copy == NULL)555goto oom;556}557if (ret_name)558*ret_name = name_copy;559if (ret_value)560*ret_value = value_copy;561return 0;562oom:563free(name_copy);564free(value_copy);565return ENOMEM;566}567568errcode_t KRB5_CALLCONV569profile_iterator(void **iter_p, char **ret_name, char **ret_value)570{571char *name, *value;572errcode_t retval;573struct profile_iterator *iter = *iter_p;574profile_t profile;575576if (ret_name)577*ret_name = NULL;578if (ret_value)579*ret_value = NULL;580if (iter == NULL || iter->magic != PROF_MAGIC_ITERATOR)581return PROF_MAGIC_ITERATOR;582profile = iter->profile;583584if (profile->vt) {585retval = profile->vt->iterator(profile->cbdata, iter->idata, &name,586&value);587if (retval)588return retval;589if (name == NULL) {590profile->vt->iterator_free(profile->cbdata, iter->idata);591free(iter);592*iter_p = NULL;593}594retval = set_results(name, value, ret_name, ret_value);595if (name)596profile->vt->free_string(profile->cbdata, name);597if (value)598profile->vt->free_string(profile->cbdata, value);599return retval;600}601602retval = profile_node_iterator(&iter->idata, 0, &name, &value);603if (iter->idata == NULL) {604free(iter);605*iter_p = NULL;606}607if (retval)608return retval;609return set_results(name, value, ret_name, ret_value);610}611612void KRB5_CALLCONV613profile_release_string(char *str)614{615free(str);616}617618619