389 lines
		
	
	
		
			9.3 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			389 lines
		
	
	
		
			9.3 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/*
 | 
						|
 * Copyright (c) 2020 Kungliga Tekniska Högskolan
 | 
						|
 * (Royal Institute of Technology, Stockholm, Sweden).
 | 
						|
 * All rights reserved.
 | 
						|
 *
 | 
						|
 * Redistribution and use in source and binary forms, with or without
 | 
						|
 * modification, are permitted provided that the following conditions
 | 
						|
 * are met:
 | 
						|
 *
 | 
						|
 * 1. Redistributions of source code must retain the above copyright
 | 
						|
 *    notice, this list of conditions and the following disclaimer.
 | 
						|
 *
 | 
						|
 * 2. Redistributions in binary form must reproduce the above copyright
 | 
						|
 *    notice, this list of conditions and the following disclaimer in the
 | 
						|
 *    documentation and/or other materials provided with the distribution.
 | 
						|
 *
 | 
						|
 * 3. Neither the name of the Institute nor the names of its contributors
 | 
						|
 *    may be used to endorse or promote products derived from this software
 | 
						|
 *    without specific prior written permission.
 | 
						|
 *
 | 
						|
 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
 | 
						|
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 | 
						|
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 | 
						|
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
 | 
						|
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 | 
						|
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 | 
						|
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 | 
						|
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 | 
						|
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 | 
						|
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 | 
						|
 * SUCH DAMAGE.
 | 
						|
 */
 | 
						|
 | 
						|
#include "baselocl.h"
 | 
						|
 | 
						|
#undef __attribute__
 | 
						|
#define __attribute__(X)
 | 
						|
 | 
						|
heim_context
 | 
						|
heim_context_init(void)
 | 
						|
{
 | 
						|
    heim_context context;
 | 
						|
 | 
						|
    if ((context = calloc(1, sizeof(*context))) == NULL)
 | 
						|
        return NULL;
 | 
						|
 | 
						|
    context->homedir_access = !issuid();
 | 
						|
    context->log_utc = 1;
 | 
						|
    context->error_string = NULL;
 | 
						|
    context->debug_dest = NULL;
 | 
						|
    context->warn_dest = NULL;
 | 
						|
    context->log_dest = NULL;
 | 
						|
    context->time_fmt = NULL;
 | 
						|
    context->et_list = NULL;
 | 
						|
    return context;
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
heim_context_free(heim_context *contextp)
 | 
						|
{
 | 
						|
    heim_context context = *contextp;
 | 
						|
 | 
						|
    *contextp = NULL;
 | 
						|
    if (!context)
 | 
						|
        return;
 | 
						|
    heim_closelog(context, context->debug_dest);
 | 
						|
    heim_closelog(context, context->warn_dest);
 | 
						|
    heim_closelog(context, context->log_dest);
 | 
						|
    free_error_table(context->et_list);
 | 
						|
    free(context->time_fmt);
 | 
						|
    free(context->error_string);
 | 
						|
    free(context);
 | 
						|
}
 | 
						|
 | 
						|
heim_error_code
 | 
						|
heim_add_et_list(heim_context context, void (*func)(struct et_list **))
 | 
						|
{
 | 
						|
    (*func)(&context->et_list);
 | 
						|
    return 0;
 | 
						|
}
 | 
						|
 | 
						|
heim_error_code
 | 
						|
heim_context_set_time_fmt(heim_context context, const char *fmt)
 | 
						|
{
 | 
						|
    char *s;
 | 
						|
 | 
						|
    if (fmt == NULL) {
 | 
						|
        free(context->time_fmt);
 | 
						|
        return 0;
 | 
						|
    }
 | 
						|
    if ((s = strdup(fmt)) == NULL)
 | 
						|
        return heim_enomem(context);
 | 
						|
    free(context->time_fmt);
 | 
						|
    context->time_fmt = s;
 | 
						|
    return 0;
 | 
						|
}
 | 
						|
 | 
						|
const char *
 | 
						|
heim_context_get_time_fmt(heim_context context)
 | 
						|
{
 | 
						|
    return context->time_fmt ? context->time_fmt : "%Y-%m-%dT%H:%M:%S";
 | 
						|
}
 | 
						|
 | 
						|
unsigned int
 | 
						|
heim_context_set_log_utc(heim_context context, unsigned int log_utc)
 | 
						|
{
 | 
						|
    unsigned int old = context->log_utc;
 | 
						|
 | 
						|
    context->log_utc = log_utc ? 1 : 0;
 | 
						|
    return old;
 | 
						|
}
 | 
						|
 | 
						|
int
 | 
						|
heim_context_get_log_utc(heim_context context)
 | 
						|
{
 | 
						|
    return context->log_utc;
 | 
						|
}
 | 
						|
 | 
						|
unsigned int
 | 
						|
heim_context_set_homedir_access(heim_context context, unsigned int homedir_access)
 | 
						|
{
 | 
						|
    unsigned int old = context->homedir_access;
 | 
						|
 | 
						|
    context->homedir_access = homedir_access ? 1 : 0;
 | 
						|
    return old;
 | 
						|
}
 | 
						|
 | 
						|
unsigned int
 | 
						|
heim_context_get_homedir_access(heim_context context)
 | 
						|
{
 | 
						|
    return context->homedir_access;
 | 
						|
}
 | 
						|
 | 
						|
heim_error_code
 | 
						|
heim_enomem(heim_context context)
 | 
						|
{
 | 
						|
    heim_set_error_message(context, ENOMEM, "malloc: out of memory");
 | 
						|
    return ENOMEM;
 | 
						|
}
 | 
						|
 | 
						|
heim_log_facility *
 | 
						|
heim_get_log_dest(heim_context context)
 | 
						|
{
 | 
						|
    return context->log_dest;
 | 
						|
}
 | 
						|
 | 
						|
heim_log_facility *
 | 
						|
heim_get_warn_dest(heim_context context)
 | 
						|
{
 | 
						|
    return context->warn_dest;
 | 
						|
}
 | 
						|
 | 
						|
heim_log_facility *
 | 
						|
heim_get_debug_dest(heim_context context)
 | 
						|
{
 | 
						|
    return context->debug_dest;
 | 
						|
}
 | 
						|
 | 
						|
heim_error_code
 | 
						|
heim_set_log_dest(heim_context context, heim_log_facility *fac)
 | 
						|
{
 | 
						|
    context->log_dest = fac;
 | 
						|
    return 0;
 | 
						|
}
 | 
						|
 | 
						|
heim_error_code
 | 
						|
heim_set_warn_dest(heim_context context, heim_log_facility *fac)
 | 
						|
{
 | 
						|
    context->warn_dest = fac;
 | 
						|
    return 0;
 | 
						|
}
 | 
						|
 | 
						|
heim_error_code
 | 
						|
heim_set_debug_dest(heim_context context, heim_log_facility *fac)
 | 
						|
{
 | 
						|
    context->debug_dest = fac;
 | 
						|
    return 0;
 | 
						|
}
 | 
						|
 | 
						|
#ifndef PATH_SEP
 | 
						|
# define PATH_SEP ":"
 | 
						|
#endif
 | 
						|
 | 
						|
static heim_error_code
 | 
						|
add_file(char ***pfilenames, int *len, char *file)
 | 
						|
{
 | 
						|
    char **pp = *pfilenames;
 | 
						|
    int i;
 | 
						|
 | 
						|
    for(i = 0; i < *len; i++) {
 | 
						|
        if(strcmp(pp[i], file) == 0) {
 | 
						|
            free(file);
 | 
						|
            return 0;
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    pp = realloc(*pfilenames, (*len + 2) * sizeof(*pp));
 | 
						|
    if (pp == NULL) {
 | 
						|
        free(file);
 | 
						|
        return ENOMEM;
 | 
						|
    }
 | 
						|
 | 
						|
    pp[*len] = file;
 | 
						|
    pp[*len + 1] = NULL;
 | 
						|
    *pfilenames = pp;
 | 
						|
    *len += 1;
 | 
						|
    return 0;
 | 
						|
}
 | 
						|
 | 
						|
#ifdef WIN32
 | 
						|
static char *
 | 
						|
get_default_config_config_files_from_registry(void)
 | 
						|
{
 | 
						|
    static const char *KeyName = "Software\\Heimdal"; /* XXX #define this */
 | 
						|
    char *config_file = NULL;
 | 
						|
    LONG rcode;
 | 
						|
    HKEY key;
 | 
						|
 | 
						|
    rcode = RegOpenKeyEx(HKEY_CURRENT_USER, KeyName, 0, KEY_READ, &key);
 | 
						|
    if (rcode == ERROR_SUCCESS) {
 | 
						|
        config_file = heim_parse_reg_value_as_multi_string(NULL, key, "config",
 | 
						|
                                                           REG_NONE, 0, PATH_SEP);
 | 
						|
        RegCloseKey(key);
 | 
						|
    }
 | 
						|
 | 
						|
    if (config_file)
 | 
						|
        return config_file;
 | 
						|
 | 
						|
    rcode = RegOpenKeyEx(HKEY_LOCAL_MACHINE, KeyName, 0, KEY_READ, &key);
 | 
						|
    if (rcode == ERROR_SUCCESS) {
 | 
						|
        config_file = heim_parse_reg_value_as_multi_string(NULL, key, "config",
 | 
						|
                                                           REG_NONE, 0, PATH_SEP);
 | 
						|
        RegCloseKey(key);
 | 
						|
    }
 | 
						|
 | 
						|
    return config_file;
 | 
						|
}
 | 
						|
#endif
 | 
						|
 | 
						|
heim_error_code
 | 
						|
heim_prepend_config_files(const char *filelist,
 | 
						|
                          char **pq,
 | 
						|
                          char ***ret_pp)
 | 
						|
{
 | 
						|
    heim_error_code ret;
 | 
						|
    const char *p, *q;
 | 
						|
    char **pp;
 | 
						|
    int len;
 | 
						|
    char *fn;
 | 
						|
 | 
						|
    pp = NULL;
 | 
						|
 | 
						|
    len = 0;
 | 
						|
    p = filelist;
 | 
						|
    while(1) {
 | 
						|
        ssize_t l;
 | 
						|
        q = p;
 | 
						|
        l = strsep_copy(&q, PATH_SEP, NULL, 0);
 | 
						|
        if(l == -1)
 | 
						|
            break;
 | 
						|
        fn = malloc(l + 1);
 | 
						|
        if(fn == NULL) {
 | 
						|
            heim_free_config_files(pp);
 | 
						|
            return ENOMEM;
 | 
						|
        }
 | 
						|
        (void) strsep_copy(&p, PATH_SEP, fn, l + 1);
 | 
						|
        ret = add_file(&pp, &len, fn);
 | 
						|
        if (ret) {
 | 
						|
            heim_free_config_files(pp);
 | 
						|
            return ret;
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    if (pq != NULL) {
 | 
						|
        int i;
 | 
						|
 | 
						|
        for (i = 0; pq[i] != NULL; i++) {
 | 
						|
            fn = strdup(pq[i]);
 | 
						|
            if (fn == NULL) {
 | 
						|
                heim_free_config_files(pp);
 | 
						|
                return ENOMEM;
 | 
						|
            }
 | 
						|
            ret = add_file(&pp, &len, fn);
 | 
						|
            if (ret) {
 | 
						|
                heim_free_config_files(pp);
 | 
						|
                return ret;
 | 
						|
            }
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    *ret_pp = pp;
 | 
						|
    return 0;
 | 
						|
}
 | 
						|
 | 
						|
heim_error_code
 | 
						|
heim_prepend_config_files_default(const char *prepend,
 | 
						|
                                  const char *def,
 | 
						|
                                  const char *envvar,
 | 
						|
                                  char ***pfilenames)
 | 
						|
{
 | 
						|
    heim_error_code ret;
 | 
						|
    char **defpp, **pp = NULL;
 | 
						|
 | 
						|
    ret = heim_get_default_config_files(def, envvar, &defpp);
 | 
						|
    if (ret)
 | 
						|
        return ret;
 | 
						|
 | 
						|
    ret = heim_prepend_config_files(prepend, defpp, &pp);
 | 
						|
    heim_free_config_files(defpp);
 | 
						|
    if (ret) {
 | 
						|
        return ret;
 | 
						|
    }
 | 
						|
    *pfilenames = pp;
 | 
						|
    return 0;
 | 
						|
}
 | 
						|
 | 
						|
heim_error_code
 | 
						|
heim_get_default_config_files(const char *def,
 | 
						|
                              const char *envvar,
 | 
						|
                              char ***pfilenames)
 | 
						|
{
 | 
						|
    const char *files = NULL;
 | 
						|
 | 
						|
    files = secure_getenv(envvar);
 | 
						|
 | 
						|
#ifdef _WIN32
 | 
						|
    if (files == NULL) {
 | 
						|
        char * reg_files;
 | 
						|
        reg_files = get_default_config_config_files_from_registry();
 | 
						|
        if (reg_files != NULL) {
 | 
						|
            heim_error_code code;
 | 
						|
 | 
						|
            code = heim_prepend_config_files(reg_files, NULL, pfilenames);
 | 
						|
            free(reg_files);
 | 
						|
 | 
						|
            return code;
 | 
						|
        }
 | 
						|
    }
 | 
						|
#endif
 | 
						|
 | 
						|
    if (files == NULL)
 | 
						|
        files = def;
 | 
						|
    return heim_prepend_config_files(files, NULL, pfilenames);
 | 
						|
}
 | 
						|
 | 
						|
#ifdef _WIN32
 | 
						|
#define REGPATH_KERBEROS "SOFTWARE\\Kerberos"
 | 
						|
#define REGPATH_HEIMDAL  "SOFTWARE\\Heimdal"
 | 
						|
#endif
 | 
						|
 | 
						|
heim_error_code
 | 
						|
heim_set_config_files(heim_context context, char **filenames,
 | 
						|
                      heim_config_binding **res)
 | 
						|
{
 | 
						|
    heim_error_code ret = 0;
 | 
						|
 | 
						|
    *res = NULL;
 | 
						|
    while (filenames != NULL && *filenames != NULL && **filenames != '\0') {
 | 
						|
        ret = heim_config_parse_file_multi(context, *filenames, res);
 | 
						|
        if (ret != 0 && ret != ENOENT && ret != EACCES && ret != EPERM
 | 
						|
            && ret != HEIM_ERR_CONFIG_BADFORMAT) {
 | 
						|
            heim_config_file_free(context, *res);
 | 
						|
            *res = NULL;
 | 
						|
            return ret;
 | 
						|
        }
 | 
						|
        filenames++;
 | 
						|
    }
 | 
						|
 | 
						|
#ifdef _WIN32
 | 
						|
    /*
 | 
						|
     * We always ignored errors from loading from the registry, so we still do.
 | 
						|
     */
 | 
						|
    heim_load_config_from_registry(context, REGPATH_KERBEROS,
 | 
						|
                                   REGPATH_HEIMDAL, res);
 | 
						|
 | 
						|
#endif
 | 
						|
    return 0;
 | 
						|
}
 | 
						|
 | 
						|
void
 | 
						|
heim_free_config_files(char **filenames)
 | 
						|
{
 | 
						|
    char **p;
 | 
						|
 | 
						|
    for (p = filenames; p && *p != NULL; p++)
 | 
						|
        free(*p);
 | 
						|
    free(filenames);
 | 
						|
}
 |