Path: blob/main/crypto/heimdal/lib/krb5/config_file.c
34878 views
/*1* Copyright (c) 1997 - 2004 Kungliga Tekniska Högskolan2* (Royal Institute of Technology, Stockholm, Sweden).3* All rights reserved.4*5* Portions Copyright (c) 2009 Apple Inc. All rights reserved.6*7* Redistribution and use in source and binary forms, with or without8* modification, are permitted provided that the following conditions9* are met:10*11* 1. Redistributions of source code must retain the above copyright12* notice, this list of conditions and the following disclaimer.13*14* 2. Redistributions in binary form must reproduce the above copyright15* notice, this list of conditions and the following disclaimer in the16* documentation and/or other materials provided with the distribution.17*18* 3. Neither the name of the Institute nor the names of its contributors19* may be used to endorse or promote products derived from this software20* without specific prior written permission.21*22* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND23* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE24* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE25* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE26* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL27* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS28* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)29* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT30* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY31* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF32* SUCH DAMAGE.33*/3435#include "krb5_locl.h"3637#ifdef __APPLE__38#include <CoreFoundation/CoreFoundation.h>39#endif4041/* Gaah! I want a portable funopen */42struct fileptr {43const char *s;44FILE *f;45};4647static char *48config_fgets(char *str, size_t len, struct fileptr *ptr)49{50/* XXX this is not correct, in that they don't do the same if the51line is longer than len */52if(ptr->f != NULL)53return fgets(str, len, ptr->f);54else {55/* this is almost strsep_copy */56const char *p;57ssize_t l;58if(*ptr->s == '\0')59return NULL;60p = ptr->s + strcspn(ptr->s, "\n");61if(*p == '\n')62p++;63l = min(len, (size_t)(p - ptr->s));64if(len > 0) {65memcpy(str, ptr->s, l);66str[l] = '\0';67}68ptr->s = p;69return str;70}71}7273static krb5_error_code parse_section(char *p, krb5_config_section **s,74krb5_config_section **res,75const char **err_message);76static krb5_error_code parse_binding(struct fileptr *f, unsigned *lineno, char *p,77krb5_config_binding **b,78krb5_config_binding **parent,79const char **err_message);80static krb5_error_code parse_list(struct fileptr *f, unsigned *lineno,81krb5_config_binding **parent,82const char **err_message);8384krb5_config_section *85_krb5_config_get_entry(krb5_config_section **parent, const char *name, int type)86{87krb5_config_section **q;8889for(q = parent; *q != NULL; q = &(*q)->next)90if(type == krb5_config_list &&91(unsigned)type == (*q)->type &&92strcmp(name, (*q)->name) == 0)93return *q;94*q = calloc(1, sizeof(**q));95if(*q == NULL)96return NULL;97(*q)->name = strdup(name);98(*q)->type = type;99if((*q)->name == NULL) {100free(*q);101*q = NULL;102return NULL;103}104return *q;105}106107/*108* Parse a section:109*110* [section]111* foo = bar112* b = {113* a114* }115* ...116*117* starting at the line in `p', storing the resulting structure in118* `s' and hooking it into `parent'.119* Store the error message in `err_message'.120*/121122static krb5_error_code123parse_section(char *p, krb5_config_section **s, krb5_config_section **parent,124const char **err_message)125{126char *p1;127krb5_config_section *tmp;128129p1 = strchr (p + 1, ']');130if (p1 == NULL) {131*err_message = "missing ]";132return KRB5_CONFIG_BADFORMAT;133}134*p1 = '\0';135tmp = _krb5_config_get_entry(parent, p + 1, krb5_config_list);136if(tmp == NULL) {137*err_message = "out of memory";138return KRB5_CONFIG_BADFORMAT;139}140*s = tmp;141return 0;142}143144/*145* Parse a brace-enclosed list from `f', hooking in the structure at146* `parent'.147* Store the error message in `err_message'.148*/149150static krb5_error_code151parse_list(struct fileptr *f, unsigned *lineno, krb5_config_binding **parent,152const char **err_message)153{154char buf[KRB5_BUFSIZ];155krb5_error_code ret;156krb5_config_binding *b = NULL;157unsigned beg_lineno = *lineno;158159while(config_fgets(buf, sizeof(buf), f) != NULL) {160char *p;161162++*lineno;163buf[strcspn(buf, "\r\n")] = '\0';164p = buf;165while(isspace((unsigned char)*p))166++p;167if (*p == '#' || *p == ';' || *p == '\0')168continue;169while(isspace((unsigned char)*p))170++p;171if (*p == '}')172return 0;173if (*p == '\0')174continue;175ret = parse_binding (f, lineno, p, &b, parent, err_message);176if (ret)177return ret;178}179*lineno = beg_lineno;180*err_message = "unclosed {";181return KRB5_CONFIG_BADFORMAT;182}183184/*185*186*/187188static krb5_error_code189parse_binding(struct fileptr *f, unsigned *lineno, char *p,190krb5_config_binding **b, krb5_config_binding **parent,191const char **err_message)192{193krb5_config_binding *tmp;194char *p1, *p2;195krb5_error_code ret = 0;196197p1 = p;198while (*p && *p != '=' && !isspace((unsigned char)*p))199++p;200if (*p == '\0') {201*err_message = "missing =";202return KRB5_CONFIG_BADFORMAT;203}204p2 = p;205while (isspace((unsigned char)*p))206++p;207if (*p != '=') {208*err_message = "missing =";209return KRB5_CONFIG_BADFORMAT;210}211++p;212while(isspace((unsigned char)*p))213++p;214*p2 = '\0';215if (*p == '{') {216tmp = _krb5_config_get_entry(parent, p1, krb5_config_list);217if (tmp == NULL) {218*err_message = "out of memory";219return KRB5_CONFIG_BADFORMAT;220}221ret = parse_list (f, lineno, &tmp->u.list, err_message);222} else {223tmp = _krb5_config_get_entry(parent, p1, krb5_config_string);224if (tmp == NULL) {225*err_message = "out of memory";226return KRB5_CONFIG_BADFORMAT;227}228p1 = p;229p = p1 + strlen(p1);230while(p > p1 && isspace((unsigned char)*(p-1)))231--p;232*p = '\0';233tmp->u.string = strdup(p1);234}235*b = tmp;236return ret;237}238239#if defined(__APPLE__)240241#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1060242#define HAVE_CFPROPERTYLISTCREATEWITHSTREAM 1243#endif244245static char *246cfstring2cstring(CFStringRef string)247{248CFIndex len;249char *str;250251str = (char *) CFStringGetCStringPtr(string, kCFStringEncodingUTF8);252if (str)253return strdup(str);254255len = CFStringGetLength(string);256len = 1 + CFStringGetMaximumSizeForEncoding(len, kCFStringEncodingUTF8);257str = malloc(len);258if (str == NULL)259return NULL;260261if (!CFStringGetCString (string, str, len, kCFStringEncodingUTF8)) {262free (str);263return NULL;264}265return str;266}267268static void269convert_content(const void *key, const void *value, void *context)270{271krb5_config_section *tmp, **parent = context;272char *k;273274if (CFGetTypeID(key) != CFStringGetTypeID())275return;276277k = cfstring2cstring(key);278if (k == NULL)279return;280281if (CFGetTypeID(value) == CFStringGetTypeID()) {282tmp = _krb5_config_get_entry(parent, k, krb5_config_string);283tmp->u.string = cfstring2cstring(value);284} else if (CFGetTypeID(value) == CFDictionaryGetTypeID()) {285tmp = _krb5_config_get_entry(parent, k, krb5_config_list);286CFDictionaryApplyFunction(value, convert_content, &tmp->u.list);287} else {288/* log */289}290free(k);291}292293static krb5_error_code294parse_plist_config(krb5_context context, const char *path, krb5_config_section **parent)295{296CFReadStreamRef s;297CFDictionaryRef d;298CFURLRef url;299300url = CFURLCreateFromFileSystemRepresentation(kCFAllocatorDefault, (UInt8 *)path, strlen(path), FALSE);301if (url == NULL) {302krb5_clear_error_message(context);303return ENOMEM;304}305306s = CFReadStreamCreateWithFile(kCFAllocatorDefault, url);307CFRelease(url);308if (s == NULL) {309krb5_clear_error_message(context);310return ENOMEM;311}312313if (!CFReadStreamOpen(s)) {314CFRelease(s);315krb5_clear_error_message(context);316return ENOENT;317}318319#ifdef HAVE_CFPROPERTYLISTCREATEWITHSTREAM320d = (CFDictionaryRef)CFPropertyListCreateWithStream(NULL, s, 0, kCFPropertyListImmutable, NULL, NULL);321#else322d = (CFDictionaryRef)CFPropertyListCreateFromStream(NULL, s, 0, kCFPropertyListImmutable, NULL, NULL);323#endif324CFRelease(s);325if (d == NULL) {326krb5_clear_error_message(context);327return ENOENT;328}329330CFDictionaryApplyFunction(d, convert_content, parent);331CFRelease(d);332333return 0;334}335336#endif337338339/*340* Parse the config file `fname', generating the structures into `res'341* returning error messages in `err_message'342*/343344static krb5_error_code345krb5_config_parse_debug (struct fileptr *f,346krb5_config_section **res,347unsigned *lineno,348const char **err_message)349{350krb5_config_section *s = NULL;351krb5_config_binding *b = NULL;352char buf[KRB5_BUFSIZ];353krb5_error_code ret;354355while (config_fgets(buf, sizeof(buf), f) != NULL) {356char *p;357358++*lineno;359buf[strcspn(buf, "\r\n")] = '\0';360p = buf;361while(isspace((unsigned char)*p))362++p;363if (*p == '#' || *p == ';')364continue;365if (*p == '[') {366ret = parse_section(p, &s, res, err_message);367if (ret)368return ret;369b = NULL;370} else if (*p == '}') {371*err_message = "unmatched }";372return EINVAL; /* XXX */373} else if(*p != '\0') {374if (s == NULL) {375*err_message = "binding before section";376return EINVAL;377}378ret = parse_binding(f, lineno, p, &b, &s->u.list, err_message);379if (ret)380return ret;381}382}383return 0;384}385386static int387is_plist_file(const char *fname)388{389size_t len = strlen(fname);390char suffix[] = ".plist";391if (len < sizeof(suffix))392return 0;393if (strcasecmp(&fname[len - (sizeof(suffix) - 1)], suffix) != 0)394return 0;395return 1;396}397398/**399* Parse a configuration file and add the result into res. This400* interface can be used to parse several configuration files into one401* resulting krb5_config_section by calling it repeatably.402*403* @param context a Kerberos 5 context.404* @param fname a file name to a Kerberos configuration file405* @param res the returned result, must be free with krb5_free_config_files().406* @return Return an error code or 0, see krb5_get_error_message().407*408* @ingroup krb5_support409*/410411KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL412krb5_config_parse_file_multi (krb5_context context,413const char *fname,414krb5_config_section **res)415{416const char *str;417char *newfname = NULL;418unsigned lineno = 0;419krb5_error_code ret;420struct fileptr f;421422/**423* If the fname starts with "~/" parse configuration file in the424* current users home directory. The behavior can be disabled and425* enabled by calling krb5_set_home_dir_access().426*/427if (fname[0] == '~' && fname[1] == '/') {428#ifndef KRB5_USE_PATH_TOKENS429const char *home = NULL;430431if (!_krb5_homedir_access(context)) {432krb5_set_error_message(context, EPERM,433"Access to home directory not allowed");434return EPERM;435}436437if(!issuid())438home = getenv("HOME");439440if (home == NULL) {441struct passwd *pw = getpwuid(getuid());442if(pw != NULL)443home = pw->pw_dir;444}445if (home) {446asprintf(&newfname, "%s%s", home, &fname[1]);447if (newfname == NULL) {448krb5_set_error_message(context, ENOMEM,449N_("malloc: out of memory", ""));450return ENOMEM;451}452fname = newfname;453}454#else /* KRB5_USE_PATH_TOKENS */455if (asprintf(&newfname, "%%{USERCONFIG}%s", &fname[1]) < 0 ||456newfname == NULL)457{458krb5_set_error_message(context, ENOMEM,459N_("malloc: out of memory", ""));460return ENOMEM;461}462fname = newfname;463#endif464}465466if (is_plist_file(fname)) {467#ifdef __APPLE__468ret = parse_plist_config(context, fname, res);469if (ret) {470krb5_set_error_message(context, ret,471"Failed to parse plist %s", fname);472if (newfname)473free(newfname);474return ret;475}476#else477krb5_set_error_message(context, ENOENT,478"no support for plist configuration files");479return ENOENT;480#endif481} else {482#ifdef KRB5_USE_PATH_TOKENS483char * exp_fname = NULL;484485ret = _krb5_expand_path_tokens(context, fname, &exp_fname);486if (ret) {487if (newfname)488free(newfname);489return ret;490}491492if (newfname)493free(newfname);494fname = newfname = exp_fname;495#endif496497f.f = fopen(fname, "r");498f.s = NULL;499if(f.f == NULL) {500ret = errno;501krb5_set_error_message (context, ret, "open %s: %s",502fname, strerror(ret));503if (newfname)504free(newfname);505return ret;506}507508ret = krb5_config_parse_debug (&f, res, &lineno, &str);509fclose(f.f);510if (ret) {511krb5_set_error_message (context, ret, "%s:%u: %s",512fname, lineno, str);513if (newfname)514free(newfname);515return ret;516}517}518return 0;519}520521KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL522krb5_config_parse_file (krb5_context context,523const char *fname,524krb5_config_section **res)525{526*res = NULL;527return krb5_config_parse_file_multi(context, fname, res);528}529530static void531free_binding (krb5_context context, krb5_config_binding *b)532{533krb5_config_binding *next_b;534535while (b) {536free (b->name);537if (b->type == krb5_config_string)538free (b->u.string);539else if (b->type == krb5_config_list)540free_binding (context, b->u.list);541else542krb5_abortx(context, "unknown binding type (%d) in free_binding",543b->type);544next_b = b->next;545free (b);546b = next_b;547}548}549550/**551* Free configuration file section, the result of552* krb5_config_parse_file() and krb5_config_parse_file_multi().553*554* @param context A Kerberos 5 context555* @param s the configuration section to free556*557* @return returns 0 on successes, otherwise an error code, see558* krb5_get_error_message()559*560* @ingroup krb5_support561*/562563KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL564krb5_config_file_free (krb5_context context, krb5_config_section *s)565{566free_binding (context, s);567return 0;568}569570#ifndef HEIMDAL_SMALLER571572KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL573_krb5_config_copy(krb5_context context,574krb5_config_section *c,575krb5_config_section **head)576{577krb5_config_binding *d, *previous = NULL;578579*head = NULL;580581while (c) {582d = calloc(1, sizeof(*d));583584if (*head == NULL)585*head = d;586587d->name = strdup(c->name);588d->type = c->type;589if (d->type == krb5_config_string)590d->u.string = strdup(c->u.string);591else if (d->type == krb5_config_list)592_krb5_config_copy (context, c->u.list, &d->u.list);593else594krb5_abortx(context,595"unknown binding type (%d) in krb5_config_copy",596d->type);597if (previous)598previous->next = d;599600previous = d;601c = c->next;602}603return 0;604}605606#endif /* HEIMDAL_SMALLER */607608KRB5_LIB_FUNCTION const void * KRB5_LIB_CALL609_krb5_config_get_next (krb5_context context,610const krb5_config_section *c,611const krb5_config_binding **pointer,612int type,613...)614{615const char *ret;616va_list args;617618va_start(args, type);619ret = _krb5_config_vget_next (context, c, pointer, type, args);620va_end(args);621return ret;622}623624static const void *625vget_next(krb5_context context,626const krb5_config_binding *b,627const krb5_config_binding **pointer,628int type,629const char *name,630va_list args)631{632const char *p = va_arg(args, const char *);633while(b != NULL) {634if(strcmp(b->name, name) == 0) {635if(b->type == (unsigned)type && p == NULL) {636*pointer = b;637return b->u.generic;638} else if(b->type == krb5_config_list && p != NULL) {639return vget_next(context, b->u.list, pointer, type, p, args);640}641}642b = b->next;643}644return NULL;645}646647KRB5_LIB_FUNCTION const void * KRB5_LIB_CALL648_krb5_config_vget_next (krb5_context context,649const krb5_config_section *c,650const krb5_config_binding **pointer,651int type,652va_list args)653{654const krb5_config_binding *b;655const char *p;656657if(c == NULL)658c = context->cf;659660if (c == NULL)661return NULL;662663if (*pointer == NULL) {664/* first time here, walk down the tree looking for the right665section */666p = va_arg(args, const char *);667if (p == NULL)668return NULL;669return vget_next(context, c, pointer, type, p, args);670}671672/* we were called again, so just look for more entries with the673same name and type */674for (b = (*pointer)->next; b != NULL; b = b->next) {675if(strcmp(b->name, (*pointer)->name) == 0 && b->type == (unsigned)type) {676*pointer = b;677return b->u.generic;678}679}680return NULL;681}682683KRB5_LIB_FUNCTION const void * KRB5_LIB_CALL684_krb5_config_get (krb5_context context,685const krb5_config_section *c,686int type,687...)688{689const void *ret;690va_list args;691692va_start(args, type);693ret = _krb5_config_vget (context, c, type, args);694va_end(args);695return ret;696}697698699const void *700_krb5_config_vget (krb5_context context,701const krb5_config_section *c,702int type,703va_list args)704{705const krb5_config_binding *foo = NULL;706707return _krb5_config_vget_next (context, c, &foo, type, args);708}709710/**711* Get a list of configuration binding list for more processing712*713* @param context A Kerberos 5 context.714* @param c a configuration section, or NULL to use the section from context715* @param ... a list of names, terminated with NULL.716*717* @return NULL if configuration list is not found, a list otherwise718*719* @ingroup krb5_support720*/721722KRB5_LIB_FUNCTION const krb5_config_binding * KRB5_LIB_CALL723krb5_config_get_list (krb5_context context,724const krb5_config_section *c,725...)726{727const krb5_config_binding *ret;728va_list args;729730va_start(args, c);731ret = krb5_config_vget_list (context, c, args);732va_end(args);733return ret;734}735736/**737* Get a list of configuration binding list for more processing738*739* @param context A Kerberos 5 context.740* @param c a configuration section, or NULL to use the section from context741* @param args a va_list of arguments742*743* @return NULL if configuration list is not found, a list otherwise744*745* @ingroup krb5_support746*/747748KRB5_LIB_FUNCTION const krb5_config_binding * KRB5_LIB_CALL749krb5_config_vget_list (krb5_context context,750const krb5_config_section *c,751va_list args)752{753return _krb5_config_vget (context, c, krb5_config_list, args);754}755756/**757* Returns a "const char *" to a string in the configuration database.758* The string may not be valid after a reload of the configuration759* database so a caller should make a local copy if it needs to keep760* the string.761*762* @param context A Kerberos 5 context.763* @param c a configuration section, or NULL to use the section from context764* @param ... a list of names, terminated with NULL.765*766* @return NULL if configuration string not found, a string otherwise767*768* @ingroup krb5_support769*/770771KRB5_LIB_FUNCTION const char* KRB5_LIB_CALL772krb5_config_get_string (krb5_context context,773const krb5_config_section *c,774...)775{776const char *ret;777va_list args;778779va_start(args, c);780ret = krb5_config_vget_string (context, c, args);781va_end(args);782return ret;783}784785/**786* Like krb5_config_get_string(), but uses a va_list instead of ...787*788* @param context A Kerberos 5 context.789* @param c a configuration section, or NULL to use the section from context790* @param args a va_list of arguments791*792* @return NULL if configuration string not found, a string otherwise793*794* @ingroup krb5_support795*/796797KRB5_LIB_FUNCTION const char* KRB5_LIB_CALL798krb5_config_vget_string (krb5_context context,799const krb5_config_section *c,800va_list args)801{802return _krb5_config_vget (context, c, krb5_config_string, args);803}804805/**806* Like krb5_config_vget_string(), but instead of returning NULL,807* instead return a default value.808*809* @param context A Kerberos 5 context.810* @param c a configuration section, or NULL to use the section from context811* @param def_value the default value to return if no configuration812* found in the database.813* @param args a va_list of arguments814*815* @return a configuration string816*817* @ingroup krb5_support818*/819820KRB5_LIB_FUNCTION const char* KRB5_LIB_CALL821krb5_config_vget_string_default (krb5_context context,822const krb5_config_section *c,823const char *def_value,824va_list args)825{826const char *ret;827828ret = krb5_config_vget_string (context, c, args);829if (ret == NULL)830ret = def_value;831return ret;832}833834/**835* Like krb5_config_get_string(), but instead of returning NULL,836* instead return a default value.837*838* @param context A Kerberos 5 context.839* @param c a configuration section, or NULL to use the section from context840* @param def_value the default value to return if no configuration841* found in the database.842* @param ... a list of names, terminated with NULL.843*844* @return a configuration string845*846* @ingroup krb5_support847*/848849KRB5_LIB_FUNCTION const char* KRB5_LIB_CALL850krb5_config_get_string_default (krb5_context context,851const krb5_config_section *c,852const char *def_value,853...)854{855const char *ret;856va_list args;857858va_start(args, def_value);859ret = krb5_config_vget_string_default (context, c, def_value, args);860va_end(args);861return ret;862}863864static char *865next_component_string(char * begin, const char * delims, char **state)866{867char * end;868869if (begin == NULL)870begin = *state;871872if (*begin == '\0')873return NULL;874875end = begin;876while (*end == '"') {877char * t = strchr(end + 1, '"');878879if (t)880end = ++t;881else882end += strlen(end);883}884885if (*end != '\0') {886size_t pos;887888pos = strcspn(end, delims);889end = end + pos;890}891892if (*end != '\0') {893*end = '\0';894*state = end + 1;895if (*begin == '"' && *(end - 1) == '"' && begin + 1 < end) {896begin++; *(end - 1) = '\0';897}898return begin;899}900901*state = end;902if (*begin == '"' && *(end - 1) == '"' && begin + 1 < end) {903begin++; *(end - 1) = '\0';904}905return begin;906}907908/**909* Get a list of configuration strings, free the result with910* krb5_config_free_strings().911*912* @param context A Kerberos 5 context.913* @param c a configuration section, or NULL to use the section from context914* @param args a va_list of arguments915*916* @return TRUE or FALSE917*918* @ingroup krb5_support919*/920921KRB5_LIB_FUNCTION char ** KRB5_LIB_CALL922krb5_config_vget_strings(krb5_context context,923const krb5_config_section *c,924va_list args)925{926char **strings = NULL;927int nstr = 0;928const krb5_config_binding *b = NULL;929const char *p;930931while((p = _krb5_config_vget_next(context, c, &b,932krb5_config_string, args))) {933char *tmp = strdup(p);934char *pos = NULL;935char *s;936if(tmp == NULL)937goto cleanup;938s = next_component_string(tmp, " \t", &pos);939while(s){940char **tmp2 = realloc(strings, (nstr + 1) * sizeof(*strings));941if(tmp2 == NULL)942goto cleanup;943strings = tmp2;944strings[nstr] = strdup(s);945nstr++;946if(strings[nstr-1] == NULL)947goto cleanup;948s = next_component_string(NULL, " \t", &pos);949}950free(tmp);951}952if(nstr){953char **tmp = realloc(strings, (nstr + 1) * sizeof(*strings));954if(tmp == NULL)955goto cleanup;956strings = tmp;957strings[nstr] = NULL;958}959return strings;960cleanup:961while(nstr--)962free(strings[nstr]);963free(strings);964return NULL;965966}967968/**969* Get a list of configuration strings, free the result with970* krb5_config_free_strings().971*972* @param context A Kerberos 5 context.973* @param c a configuration section, or NULL to use the section from context974* @param ... a list of names, terminated with NULL.975*976* @return TRUE or FALSE977*978* @ingroup krb5_support979*/980981KRB5_LIB_FUNCTION char** KRB5_LIB_CALL982krb5_config_get_strings(krb5_context context,983const krb5_config_section *c,984...)985{986va_list ap;987char **ret;988va_start(ap, c);989ret = krb5_config_vget_strings(context, c, ap);990va_end(ap);991return ret;992}993994/**995* Free the resulting strings from krb5_config-get_strings() and996* krb5_config_vget_strings().997*998* @param strings strings to free999*1000* @ingroup krb5_support1001*/10021003KRB5_LIB_FUNCTION void KRB5_LIB_CALL1004krb5_config_free_strings(char **strings)1005{1006char **s = strings;1007while(s && *s){1008free(*s);1009s++;1010}1011free(strings);1012}10131014/**1015* Like krb5_config_get_bool_default() but with a va_list list of1016* configuration selection.1017*1018* Configuration value to a boolean value, where yes/true and any1019* non-zero number means TRUE and other value is FALSE.1020*1021* @param context A Kerberos 5 context.1022* @param c a configuration section, or NULL to use the section from context1023* @param def_value the default value to return if no configuration1024* found in the database.1025* @param args a va_list of arguments1026*1027* @return TRUE or FALSE1028*1029* @ingroup krb5_support1030*/10311032KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL1033krb5_config_vget_bool_default (krb5_context context,1034const krb5_config_section *c,1035krb5_boolean def_value,1036va_list args)1037{1038const char *str;1039str = krb5_config_vget_string (context, c, args);1040if(str == NULL)1041return def_value;1042if(strcasecmp(str, "yes") == 0 ||1043strcasecmp(str, "true") == 0 ||1044atoi(str)) return TRUE;1045return FALSE;1046}10471048/**1049* krb5_config_get_bool() will convert the configuration1050* option value to a boolean value, where yes/true and any non-zero1051* number means TRUE and other value is FALSE.1052*1053* @param context A Kerberos 5 context.1054* @param c a configuration section, or NULL to use the section from context1055* @param args a va_list of arguments1056*1057* @return TRUE or FALSE1058*1059* @ingroup krb5_support1060*/10611062KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL1063krb5_config_vget_bool (krb5_context context,1064const krb5_config_section *c,1065va_list args)1066{1067return krb5_config_vget_bool_default (context, c, FALSE, args);1068}10691070/**1071* krb5_config_get_bool_default() will convert the configuration1072* option value to a boolean value, where yes/true and any non-zero1073* number means TRUE and other value is FALSE.1074*1075* @param context A Kerberos 5 context.1076* @param c a configuration section, or NULL to use the section from context1077* @param def_value the default value to return if no configuration1078* found in the database.1079* @param ... a list of names, terminated with NULL.1080*1081* @return TRUE or FALSE1082*1083* @ingroup krb5_support1084*/10851086KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL1087krb5_config_get_bool_default (krb5_context context,1088const krb5_config_section *c,1089krb5_boolean def_value,1090...)1091{1092va_list ap;1093krb5_boolean ret;1094va_start(ap, def_value);1095ret = krb5_config_vget_bool_default(context, c, def_value, ap);1096va_end(ap);1097return ret;1098}10991100/**1101* Like krb5_config_get_bool() but with a va_list list of1102* configuration selection.1103*1104* Configuration value to a boolean value, where yes/true and any1105* non-zero number means TRUE and other value is FALSE.1106*1107* @param context A Kerberos 5 context.1108* @param c a configuration section, or NULL to use the section from context1109* @param ... a list of names, terminated with NULL.1110*1111* @return TRUE or FALSE1112*1113* @ingroup krb5_support1114*/11151116KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL1117krb5_config_get_bool (krb5_context context,1118const krb5_config_section *c,1119...)1120{1121va_list ap;1122krb5_boolean ret;1123va_start(ap, c);1124ret = krb5_config_vget_bool (context, c, ap);1125va_end(ap);1126return ret;1127}11281129/**1130* Get the time from the configuration file using a relative time.1131*1132* Like krb5_config_get_time_default() but with a va_list list of1133* configuration selection.1134*1135* @param context A Kerberos 5 context.1136* @param c a configuration section, or NULL to use the section from context1137* @param def_value the default value to return if no configuration1138* found in the database.1139* @param args a va_list of arguments1140*1141* @return parsed the time (or def_value on parse error)1142*1143* @ingroup krb5_support1144*/11451146KRB5_LIB_FUNCTION int KRB5_LIB_CALL1147krb5_config_vget_time_default (krb5_context context,1148const krb5_config_section *c,1149int def_value,1150va_list args)1151{1152const char *str;1153krb5_deltat t;11541155str = krb5_config_vget_string (context, c, args);1156if(str == NULL)1157return def_value;1158if (krb5_string_to_deltat(str, &t))1159return def_value;1160return t;1161}11621163/**1164* Get the time from the configuration file using a relative time, for example: 1h30s1165*1166* @param context A Kerberos 5 context.1167* @param c a configuration section, or NULL to use the section from context1168* @param args a va_list of arguments1169*1170* @return parsed the time or -1 on error1171*1172* @ingroup krb5_support1173*/11741175KRB5_LIB_FUNCTION int KRB5_LIB_CALL1176krb5_config_vget_time (krb5_context context,1177const krb5_config_section *c,1178va_list args)1179{1180return krb5_config_vget_time_default (context, c, -1, args);1181}11821183/**1184* Get the time from the configuration file using a relative time, for example: 1h30s1185*1186* @param context A Kerberos 5 context.1187* @param c a configuration section, or NULL to use the section from context1188* @param def_value the default value to return if no configuration1189* found in the database.1190* @param ... a list of names, terminated with NULL.1191*1192* @return parsed the time (or def_value on parse error)1193*1194* @ingroup krb5_support1195*/11961197KRB5_LIB_FUNCTION int KRB5_LIB_CALL1198krb5_config_get_time_default (krb5_context context,1199const krb5_config_section *c,1200int def_value,1201...)1202{1203va_list ap;1204int ret;1205va_start(ap, def_value);1206ret = krb5_config_vget_time_default(context, c, def_value, ap);1207va_end(ap);1208return ret;1209}12101211/**1212* Get the time from the configuration file using a relative time, for example: 1h30s1213*1214* @param context A Kerberos 5 context.1215* @param c a configuration section, or NULL to use the section from context1216* @param ... a list of names, terminated with NULL.1217*1218* @return parsed the time or -1 on error1219*1220* @ingroup krb5_support1221*/12221223KRB5_LIB_FUNCTION int KRB5_LIB_CALL1224krb5_config_get_time (krb5_context context,1225const krb5_config_section *c,1226...)1227{1228va_list ap;1229int ret;1230va_start(ap, c);1231ret = krb5_config_vget_time (context, c, ap);1232va_end(ap);1233return ret;1234}123512361237KRB5_LIB_FUNCTION int KRB5_LIB_CALL1238krb5_config_vget_int_default (krb5_context context,1239const krb5_config_section *c,1240int def_value,1241va_list args)1242{1243const char *str;1244str = krb5_config_vget_string (context, c, args);1245if(str == NULL)1246return def_value;1247else {1248char *endptr;1249long l;1250l = strtol(str, &endptr, 0);1251if (endptr == str)1252return def_value;1253else1254return l;1255}1256}12571258KRB5_LIB_FUNCTION int KRB5_LIB_CALL1259krb5_config_vget_int (krb5_context context,1260const krb5_config_section *c,1261va_list args)1262{1263return krb5_config_vget_int_default (context, c, -1, args);1264}12651266KRB5_LIB_FUNCTION int KRB5_LIB_CALL1267krb5_config_get_int_default (krb5_context context,1268const krb5_config_section *c,1269int def_value,1270...)1271{1272va_list ap;1273int ret;1274va_start(ap, def_value);1275ret = krb5_config_vget_int_default(context, c, def_value, ap);1276va_end(ap);1277return ret;1278}12791280KRB5_LIB_FUNCTION int KRB5_LIB_CALL1281krb5_config_get_int (krb5_context context,1282const krb5_config_section *c,1283...)1284{1285va_list ap;1286int ret;1287va_start(ap, c);1288ret = krb5_config_vget_int (context, c, ap);1289va_end(ap);1290return ret;1291}129212931294#ifndef HEIMDAL_SMALLER12951296/**1297* Deprecated: configuration files are not strings1298*1299* @ingroup krb5_deprecated1300*/13011302KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL1303krb5_config_parse_string_multi(krb5_context context,1304const char *string,1305krb5_config_section **res)1306KRB5_DEPRECATED_FUNCTION("Use X instead")1307{1308const char *str;1309unsigned lineno = 0;1310krb5_error_code ret;1311struct fileptr f;1312f.f = NULL;1313f.s = string;13141315ret = krb5_config_parse_debug (&f, res, &lineno, &str);1316if (ret) {1317krb5_set_error_message (context, ret, "%s:%u: %s",1318"<constant>", lineno, str);1319return ret;1320}1321return 0;1322}13231324#endif132513261327