Blame src/gp_config.c

Packit Service 9f2c4a
/* Copyright (C) 2011 the GSS-PROXY contributors, see COPYING for license */
Packit Service 9f2c4a
Packit Service 9f2c4a
#include "config.h"
Packit Service 9f2c4a
#include <stdio.h>
Packit Service 9f2c4a
#include <stdlib.h>
Packit Service 9f2c4a
#include <string.h>
Packit Service 9f2c4a
#include <errno.h>
Packit Service 9f2c4a
#include <pwd.h>
Packit Service 9f2c4a
#include "gp_proxy.h"
Packit Service 9f2c4a
#include "gp_config.h"
Packit Service 9f2c4a
#include "gp_selinux.h"
Packit Service 9f2c4a
Packit Service 9f2c4a
#include <gssapi/gssapi.h>
Packit Service 9f2c4a
Packit Service 9f2c4a
#include <ini_configobj.h>
Packit Service 9f2c4a
Packit Service 9f2c4a
struct gp_flag_def {
Packit Service 9f2c4a
    const char *name;
Packit Service 9f2c4a
    uint32_t value;
Packit Service 9f2c4a
};
Packit Service 9f2c4a
Packit Service 9f2c4a
struct gp_flag_def flag_names[] = {
Packit Service 9f2c4a
    { "DELEGATE", GSS_C_DELEG_FLAG },
Packit Service 9f2c4a
    { "MUTUAL_AUTH", GSS_C_MUTUAL_FLAG },
Packit Service 9f2c4a
    { "REPLAY_DETECT", GSS_C_REPLAY_FLAG },
Packit Service 9f2c4a
    { "SEQUENCE", GSS_C_SEQUENCE_FLAG },
Packit Service 9f2c4a
    { "CONFIDENTIALITY", GSS_C_CONF_FLAG },
Packit Service 9f2c4a
    { "INTEGRITIY", GSS_C_INTEG_FLAG },
Packit Service 9f2c4a
    { "ANONYMOUS", GSS_C_ANON_FLAG },
Packit Service 9f2c4a
    { NULL, 0 }
Packit Service 9f2c4a
};
Packit Service 9f2c4a
Packit Service 9f2c4a
#define DEFAULT_FILTERED_FLAGS GSS_C_DELEG_FLAG
Packit Service 9f2c4a
#define DEFAULT_ENFORCED_FLAGS 0
Packit Service 9f2c4a
Packit Service 9f2c4a
static void free_str_array(const char ***a, int *count)
Packit Service 9f2c4a
{
Packit Service 9f2c4a
    const char **array;
Packit Service 9f2c4a
    int i;
Packit Service 9f2c4a
Packit Service 9f2c4a
    if (!a) {
Packit Service 9f2c4a
        return;
Packit Service 9f2c4a
    }
Packit Service 9f2c4a
    array = *a;
Packit Service 9f2c4a
Packit Service 9f2c4a
    if (count) {
Packit Service 9f2c4a
        for (i = 0; i < *count; i++) {
Packit Service 9f2c4a
            safefree(array[i]);
Packit Service 9f2c4a
        }
Packit Service 9f2c4a
    } else {
Packit Service 9f2c4a
        for (i = 0; array[i]; i++) {
Packit Service 9f2c4a
            safefree(array[i]);
Packit Service 9f2c4a
        }
Packit Service 9f2c4a
    }
Packit Service 9f2c4a
    safefree(*a);
Packit Service 9f2c4a
}
Packit Service 9f2c4a
Packit Service 9f2c4a
void free_cred_store_elements(gss_key_value_set_desc *cs)
Packit Service 9f2c4a
{
Packit Service 9f2c4a
    if (!cs->elements) return;
Packit Service 9f2c4a
Packit Service 9f2c4a
    for (unsigned i = 0; i < cs->count; i++) {
Packit Service 9f2c4a
        safefree(cs->elements[i].key);
Packit Service 9f2c4a
        safefree(cs->elements[i].value);
Packit Service 9f2c4a
    }
Packit Service 9f2c4a
    safefree(cs->elements);
Packit Service 9f2c4a
    cs->count = 0;
Packit Service 9f2c4a
}
Packit Service 9f2c4a
Packit Service 9f2c4a
static void gp_service_free(struct gp_service *svc)
Packit Service 9f2c4a
{
Packit Service 9f2c4a
    free(svc->name);
Packit Service 9f2c4a
    if (svc->mechs & GP_CRED_KRB5) {
Packit Service 9f2c4a
        free(svc->krb5.principal);
Packit Service 9f2c4a
        free_cred_store_elements(&svc->krb5.store);
Packit Service 9f2c4a
        gp_free_creds_handle(&svc->krb5.creds_handle);
Packit Service 9f2c4a
    }
Packit Service 9f2c4a
    free(svc->socket);
Packit Service 9f2c4a
    free(svc->program);
Packit Service 9f2c4a
    SELINUX_context_free(svc->selinux_ctx);
Packit Service 9f2c4a
    memset(svc, 0, sizeof(struct gp_service));
Packit Service 9f2c4a
}
Packit Service 9f2c4a
Packit Service 9f2c4a
static int setup_krb5_creds_handle(struct gp_service *svc)
Packit Service 9f2c4a
{
Packit Service 9f2c4a
    uint32_t ret_maj, ret_min;
Packit Service 9f2c4a
    const char *keytab = NULL;
Packit Service 9f2c4a
Packit Service 9f2c4a
    for (unsigned i = 0; i < svc->krb5.store.count; i++) {
Packit Service 9f2c4a
        if (strcmp(svc->krb5.store.elements[i].key, "keytab") == 0) {
Packit Service 9f2c4a
            keytab = svc->krb5.store.elements[i].value;
Packit Service 9f2c4a
            break;
Packit Service 9f2c4a
        }
Packit Service 9f2c4a
    }
Packit Service 9f2c4a
Packit Service 9f2c4a
    ret_maj = gp_init_creds_handle(&ret_min, svc->name, keytab,
Packit Service 9f2c4a
                                   &svc->krb5.creds_handle);
Packit Service 9f2c4a
    if (ret_maj) {
Packit Service 9f2c4a
        return ret_min;
Packit Service 9f2c4a
    }
Packit Service 9f2c4a
Packit Service 9f2c4a
    return 0;
Packit Service 9f2c4a
}
Packit Service 9f2c4a
Packit Service 9f2c4a
static int get_krb5_mech_cfg(struct gp_service *svc,
Packit Service 9f2c4a
                             struct gp_ini_context *ctx,
Packit Service 9f2c4a
                             const char *secname)
Packit Service 9f2c4a
{
Packit Service 9f2c4a
    struct { const char *a; const char *b; } deprecated_vals[] = {
Packit Service 9f2c4a
        {"krb5_keytab", "keytab" },
Packit Service 9f2c4a
        {"krb5_ccache", "ccache" },
Packit Service 9f2c4a
        {"krb5_client_keytab", "client_keytab" }
Packit Service 9f2c4a
    };
Packit Service 9f2c4a
    const char *value;
Packit Service 9f2c4a
    const char **strings = NULL;
Packit Service 9f2c4a
    int count = 0;
Packit Service 9f2c4a
    int i;
Packit Service 9f2c4a
    int ret;
Packit Service 9f2c4a
Packit Service 9f2c4a
    ret = gp_config_get_string(ctx, secname, "krb5_principal", &value);
Packit Service 9f2c4a
    if (ret == 0) {
Packit Service 9f2c4a
        svc->krb5.principal = strdup(value);
Packit Service 9f2c4a
        if (!svc->krb5.principal) {
Packit Service 9f2c4a
            return ENOMEM;
Packit Service 9f2c4a
        }
Packit Service 9f2c4a
    } else if (ret != ENOENT) {
Packit Service 9f2c4a
        return ret;
Packit Service 9f2c4a
    }
Packit Service 9f2c4a
Packit Service 9f2c4a
    /* check for deprecated options */
Packit Service 9f2c4a
    for (i = 0; i < 3; i++) {
Packit Service 9f2c4a
        ret = gp_config_get_string(ctx, secname, deprecated_vals[i].a, &value);
Packit Service 9f2c4a
        if (ret == 0) {
Packit Service 9f2c4a
            GPERROR("\"%s = %s\" is deprecated, "
Packit Service 9f2c4a
                    "please use \"cred_store = %s:%s\"\n",
Packit Service 9f2c4a
                    deprecated_vals[i].a, value,
Packit Service 9f2c4a
                    deprecated_vals[i].b, value);
Packit Service 9f2c4a
            return EINVAL;
Packit Service 9f2c4a
        } else if (ret != ENOENT) {
Packit Service 9f2c4a
            return ret;
Packit Service 9f2c4a
        }
Packit Service 9f2c4a
    }
Packit Service 9f2c4a
Packit Service 9f2c4a
    /* instead look for the cred_store parameter */
Packit Service 9f2c4a
    ret = gp_config_get_string_array(ctx, secname, "cred_store",
Packit Service 9f2c4a
                                     &count, &strings);
Packit Service 9f2c4a
    if (ret == 0) {
Packit Service 9f2c4a
        const char *p;
Packit Service 9f2c4a
        ssize_t len;
Packit Service 9f2c4a
        char *key;
Packit Service 9f2c4a
Packit Service 9f2c4a
        svc->krb5.store.elements =
Packit Service 9f2c4a
            calloc(count, sizeof(gss_key_value_element_desc));
Packit Service 9f2c4a
        if (!svc->krb5.store.elements) {
Packit Service 9f2c4a
            ret = ENOMEM;
Packit Service 9f2c4a
            goto done;
Packit Service 9f2c4a
        }
Packit Service 9f2c4a
        svc->krb5.store.count = count;
Packit Service 9f2c4a
Packit Service 9f2c4a
        for (int c = 0; c < count; c++) {
Packit Service 9f2c4a
            p = strchr(strings[c], ':');
Packit Service 9f2c4a
            if (!p) {
Packit Service 9f2c4a
                GPERROR("Invalid cred_store value, no ':' separator found in"
Packit Service 9f2c4a
                        " [%s].\n", strings[c]);
Packit Service 9f2c4a
                ret = EINVAL;
Packit Service 9f2c4a
                goto done;
Packit Service 9f2c4a
            }
Packit Service 9f2c4a
            len = asprintf(&key, "%.*s", (int)(p - strings[c]), strings[c]);
Packit Service 9f2c4a
            if (len == -1) {
Packit Service 9f2c4a
                ret = ENOMEM;
Packit Service 9f2c4a
                goto done;
Packit Service 9f2c4a
            }
Packit Service 9f2c4a
            svc->krb5.store.elements[c].key = key;
Packit Service 9f2c4a
            svc->krb5.store.elements[c].value = strdup(p + 1);
Packit Service 9f2c4a
            if (!svc->krb5.store.elements[c].value) {
Packit Service 9f2c4a
                ret = ENOMEM;
Packit Service 9f2c4a
                goto done;
Packit Service 9f2c4a
            }
Packit Service 9f2c4a
        }
Packit Service 9f2c4a
Packit Service 9f2c4a
    } else if (ret == ENOENT) {
Packit Service 9f2c4a
        /* when not there we ignore */
Packit Service 9f2c4a
        ret = 0;
Packit Service 9f2c4a
    }
Packit Service 9f2c4a
Packit Service 9f2c4a
    if (ret == 0) {
Packit Service 9f2c4a
        ret = setup_krb5_creds_handle(svc);
Packit Service 9f2c4a
    }
Packit Service 9f2c4a
Packit Service 9f2c4a
done:
Packit Service 9f2c4a
    free_str_array(&strings, &count);
Packit Service 9f2c4a
    return ret;
Packit Service 9f2c4a
}
Packit Service 9f2c4a
Packit Service 9f2c4a
static int parse_flags(const char *value, uint32_t *storage)
Packit Service 9f2c4a
{
Packit Service 9f2c4a
    char *handle;
Packit Service 9f2c4a
    char *token;
Packit Service 9f2c4a
    char *str;
Packit Service 9f2c4a
    bool add;
Packit Service 9f2c4a
    unsigned long int conv;
Packit Service 9f2c4a
    uint32_t flagval;
Packit Service 9f2c4a
    int i;
Packit Service 9f2c4a
Packit Service 9f2c4a
    str = strdup(value);
Packit Service 9f2c4a
    if (!str) {
Packit Service 9f2c4a
        return ENOMEM;
Packit Service 9f2c4a
    }
Packit Service 9f2c4a
Packit Service 9f2c4a
    for (token = strtok_r(str, ", ", &handle);
Packit Service 9f2c4a
         token != NULL;
Packit Service 9f2c4a
         token = strtok_r(NULL, ", ", &handle)) {
Packit Service 9f2c4a
        switch (token[0]) {
Packit Service 9f2c4a
        case '+':
Packit Service 9f2c4a
            add = true;
Packit Service 9f2c4a
            break;
Packit Service 9f2c4a
        case '-':
Packit Service 9f2c4a
            add = false;
Packit Service 9f2c4a
            break;
Packit Service 9f2c4a
        default:
Packit Service 9f2c4a
            GPERROR("Ignoring flag [%s], missing +/- qualifier.\n", token);
Packit Service 9f2c4a
            continue;
Packit Service 9f2c4a
        }
Packit Service 9f2c4a
        token++;
Packit Service 9f2c4a
        for (i = 0; flag_names[i].name != NULL; i++) {
Packit Service 9f2c4a
            if (strcasecmp(token, flag_names[i].name) == 0) {
Packit Service 9f2c4a
                flagval = flag_names[i].value;
Packit Service 9f2c4a
                break;
Packit Service 9f2c4a
            }
Packit Service 9f2c4a
        }
Packit Service 9f2c4a
        if (flag_names[i].name == NULL) {
Packit Service 9f2c4a
            conv = strtoul(token, &handle, 0);
Packit Service 9f2c4a
            if (conv == 0 || conv == ULONG_MAX || *handle != '\0') {
Packit Service 9f2c4a
                GPERROR("Ignoring flag [%s], unrecognized value.\n", token);
Packit Service 9f2c4a
                continue;
Packit Service 9f2c4a
            }
Packit Service 9f2c4a
            flagval = conv;
Packit Service 9f2c4a
        }
Packit Service 9f2c4a
        GPDEBUG("%s Flag %s (%u).\n", add?"Add":"Remove", token, flagval);
Packit Service 9f2c4a
        if (add) *storage |= flagval;
Packit Service 9f2c4a
        else *storage &= ~flagval;
Packit Service 9f2c4a
    }
Packit Service 9f2c4a
    safefree(str);
Packit Service 9f2c4a
Packit Service 9f2c4a
    return 0;
Packit Service 9f2c4a
}
Packit Service 9f2c4a
Packit Service 9f2c4a
static int check_services(const struct gp_config *cfg)
Packit Service 9f2c4a
{
Packit Service 9f2c4a
    int i, j;
Packit Service 9f2c4a
    struct gp_service *isvc, *jsvc;
Packit Service 9f2c4a
    const char *isock, *jsock;
Packit Service 9f2c4a
    int ret = 0;
Packit Service 9f2c4a
Packit Service 9f2c4a
    /* [gssproxy] section does not get placed in svcs */
Packit Service 9f2c4a
    for (i = 0; i < cfg->num_svcs; i++) {
Packit Service 9f2c4a
        isvc = cfg->svcs[i];
Packit Service 9f2c4a
        isock = isvc->socket;
Packit Service 9f2c4a
        if (!isock) {
Packit Service 9f2c4a
            isock = GP_SOCKET_NAME;
Packit Service 9f2c4a
        }
Packit Service 9f2c4a
Packit Service 9f2c4a
        if (isvc->program) {
Packit Service 9f2c4a
            if (isvc->program[0] != '/') {
Packit Service 9f2c4a
                ret = 1;
Packit Service 9f2c4a
                GPERROR("Program paths must be absolute!\n");
Packit Service 9f2c4a
            } else if (strchr(isvc->program, '|')) {
Packit Service 9f2c4a
                ret = 1;
Packit Service 9f2c4a
                GPERROR("The character '|' is invalid in program paths!\n");
Packit Service 9f2c4a
            }
Packit Service 9f2c4a
        }
Packit Service 9f2c4a
Packit Service 9f2c4a
        for (j = 0; j < i; j++) {
Packit Service 9f2c4a
            jsvc = cfg->svcs[j];
Packit Service 9f2c4a
            jsock = jsvc->socket;
Packit Service 9f2c4a
            if (!jsock) {
Packit Service 9f2c4a
                jsock = GP_SOCKET_NAME;
Packit Service 9f2c4a
            }
Packit Service 9f2c4a
Packit Service 9f2c4a
            if (!gp_same(isock, jsock) ||
Packit Service 9f2c4a
                !gp_same(isvc->program, jsvc->program) ||
Packit Service 9f2c4a
                !gp_selinux_ctx_equal(isvc->selinux_ctx, jsvc->selinux_ctx)) {
Packit Service 9f2c4a
                continue;
Packit Service 9f2c4a
            }
Packit Service 9f2c4a
Packit Service 9f2c4a
            if (jsvc->any_uid) {
Packit Service 9f2c4a
                ret = 1;
Packit Service 9f2c4a
                GPERROR("%s sets allow_any_uid with the same socket, "
Packit Service 9f2c4a
                        "selinux_context, and program as %s!\n",
Packit Service 9f2c4a
                        jsvc->name, isvc->name);
Packit Service 9f2c4a
            } else if (jsvc->euid == isvc->euid) {
Packit Service 9f2c4a
                ret = 1;
Packit Service 9f2c4a
                GPERROR("socket, selinux_context, euid, and program for "
Packit Service 9f2c4a
                        "%s and %s should not match!\n",
Packit Service 9f2c4a
                        isvc->name, jsvc->name);
Packit Service 9f2c4a
            }
Packit Service 9f2c4a
        }
Packit Service 9f2c4a
    }
Packit Service 9f2c4a
Packit Service 9f2c4a
    return ret;
Packit Service 9f2c4a
}
Packit Service 9f2c4a
Packit Service 9f2c4a
static int load_services(struct gp_config *cfg, struct gp_ini_context *ctx)
Packit Service 9f2c4a
{
Packit Service 9f2c4a
    int num_sec;
Packit Service 9f2c4a
    char *secname = NULL;
Packit Service 9f2c4a
    const char *value;
Packit Service 9f2c4a
    char *vcopy;
Packit Service 9f2c4a
    char *token;
Packit Service 9f2c4a
    char *handle;
Packit Service 9f2c4a
    int valnum;
Packit Service 9f2c4a
    int ret;
Packit Service 9f2c4a
    int i, n;
Packit Service 9f2c4a
Packit Service 9f2c4a
    num_sec = gp_config_get_nsec(ctx);
Packit Service 9f2c4a
Packit Service 9f2c4a
    /* allocate enough space for num_sec services,
Packit Service 9f2c4a
     * we won't waste too much space by overallocating */
Packit Service 9f2c4a
    cfg->svcs = calloc(num_sec, sizeof(struct gp_service *));
Packit Service 9f2c4a
    if (!cfg->svcs) {
Packit Service 9f2c4a
        ret = ENOMEM;
Packit Service 9f2c4a
        goto done;
Packit Service 9f2c4a
    }
Packit Service 9f2c4a
Packit Service 9f2c4a
    for (i = 0; i < num_sec; i++) {
Packit Service 9f2c4a
        secname = gp_config_get_secname(ctx, i);
Packit Service 9f2c4a
Packit Service 9f2c4a
        ret = strncmp(secname, "service/", 8);
Packit Service 9f2c4a
        if (ret == 0) {
Packit Service 9f2c4a
            n = cfg->num_svcs;
Packit Service 9f2c4a
            cfg->svcs[n] = calloc(1, sizeof(struct gp_service));
Packit Service 9f2c4a
            if (!cfg->svcs[n]) {
Packit Service 9f2c4a
                ret = ENOMEM;
Packit Service 9f2c4a
                goto done;
Packit Service 9f2c4a
            }
Packit Service 9f2c4a
            cfg->num_svcs++;
Packit Service 9f2c4a
Packit Service 9f2c4a
            /* by default allow both */
Packit Service 9f2c4a
            cfg->svcs[n]->cred_usage = GSS_C_BOTH;
Packit Service 9f2c4a
Packit Service 9f2c4a
            cfg->svcs[n]->name = strdup(secname + 8);
Packit Service 9f2c4a
            if (!cfg->svcs[n]->name) {
Packit Service 9f2c4a
                ret = ENOMEM;
Packit Service 9f2c4a
                goto done;
Packit Service 9f2c4a
            }
Packit Service 9f2c4a
Packit Service 9f2c4a
            /* euid can be a string or an int */
Packit Service 9f2c4a
            ret = gp_config_get_int(ctx, secname, "euid", &valnum);
Packit Service 9f2c4a
            if (ret != 0) {
Packit Service 9f2c4a
                ret = gp_config_get_string(ctx, secname, "euid", &value);
Packit Service 9f2c4a
                if (ret == 0) {
Packit Service 9f2c4a
                    struct passwd *eu_passwd; /* static; do not free */
Packit Service 9f2c4a
Packit Service 9f2c4a
                    errno = 0; /* needs to be 0; otherwise it won't be set */
Packit Service 9f2c4a
                    eu_passwd = getpwnam(value);
Packit Service 9f2c4a
                    if (!eu_passwd) {
Packit Service 9f2c4a
                        ret = errno;
Packit Service 9f2c4a
                        if (ret == 0) { /* not that it gets set anyway... */
Packit Service 9f2c4a
                            ret = ENOENT;
Packit Service 9f2c4a
                        }
Packit Service 9f2c4a
                    } else {
Packit Service 9f2c4a
                        valnum = eu_passwd->pw_uid;
Packit Service 9f2c4a
                    }
Packit Service 9f2c4a
                }
Packit Service 9f2c4a
                if (ret != 0) {
Packit Service 9f2c4a
                    /* if euid is missing or there is an error retrieving it
Packit Service 9f2c4a
                     * return an error and end. This is a fatal condition. */
Packit Service 9f2c4a
                    if (ret == ENOENT) {
Packit Service 9f2c4a
                        GPERROR("Option 'euid' is missing from [%s].\n", secname);
Packit Service 9f2c4a
                        ret = EINVAL;
Packit Service 9f2c4a
                    }
Packit Service 9f2c4a
                    gp_service_free(cfg->svcs[n]);
Packit Service 9f2c4a
                    cfg->num_svcs--;
Packit Service 9f2c4a
                    safefree(secname);
Packit Service 9f2c4a
                    goto done;
Packit Service 9f2c4a
                }
Packit Service 9f2c4a
            }
Packit Service 9f2c4a
            cfg->svcs[n]->euid = valnum;
Packit Service 9f2c4a
Packit Service 9f2c4a
            ret = gp_config_get_string(ctx, secname, "allow_any_uid", &value);
Packit Service 9f2c4a
            if (ret == 0) {
Packit Service 9f2c4a
                if (gp_boolean_is_true(value)) {
Packit Service 9f2c4a
                    cfg->svcs[n]->any_uid = true;
Packit Service 9f2c4a
                }
Packit Service 9f2c4a
            }
Packit Service 9f2c4a
Packit Service 9f2c4a
            ret = gp_config_get_string(ctx, secname,
Packit Service 9f2c4a
                                       "allow_protocol_transition", &value);
Packit Service 9f2c4a
            if (ret == 0) {
Packit Service 9f2c4a
                if (gp_boolean_is_true(value)) {
Packit Service 9f2c4a
                    cfg->svcs[n]->allow_proto_trans = true;
Packit Service 9f2c4a
                }
Packit Service 9f2c4a
            }
Packit Service 9f2c4a
Packit Service 9f2c4a
            ret = gp_config_get_string(ctx, secname,
Packit Service 9f2c4a
                                       "allow_constrained_delegation", &value);
Packit Service 9f2c4a
            if (ret == 0) {
Packit Service 9f2c4a
                if (gp_boolean_is_true(value)) {
Packit Service 9f2c4a
                    cfg->svcs[n]->allow_const_deleg = true;
Packit Service 9f2c4a
                }
Packit Service 9f2c4a
            }
Packit Service 9f2c4a
Packit Service 9f2c4a
            ret = gp_config_get_string(ctx, secname,
Packit Service 9f2c4a
                                       "allow_client_ccache_sync", &value);
Packit Service 9f2c4a
            if (ret == 0) {
Packit Service 9f2c4a
                if (gp_boolean_is_true(value)) {
Packit Service 9f2c4a
                    cfg->svcs[n]->allow_cc_sync = true;
Packit Service 9f2c4a
                }
Packit Service 9f2c4a
            }
Packit Service 9f2c4a
Packit Service 9f2c4a
            ret = gp_config_get_string(ctx, secname, "trusted", &value);
Packit Service 9f2c4a
            if (ret == 0) {
Packit Service 9f2c4a
                if (gp_boolean_is_true(value)) {
Packit Service 9f2c4a
                    cfg->svcs[n]->trusted = true;
Packit Service 9f2c4a
                }
Packit Service 9f2c4a
            }
Packit Service 9f2c4a
Packit Service 9f2c4a
            ret = gp_config_get_string(ctx, secname, "kernel_nfsd", &value);
Packit Service 9f2c4a
            if (ret == 0) {
Packit Service 9f2c4a
                if (gp_boolean_is_true(value)) {
Packit Service 9f2c4a
                    cfg->svcs[n]->kernel_nfsd = true;
Packit Service 9f2c4a
                }
Packit Service 9f2c4a
            }
Packit Service 9f2c4a
Packit Service 9f2c4a
            ret = gp_config_get_string(ctx, secname, "impersonate", &value);
Packit Service 9f2c4a
            if (ret == 0) {
Packit Service 9f2c4a
                if (gp_boolean_is_true(value)) {
Packit Service 9f2c4a
                    cfg->svcs[n]->impersonate = true;
Packit Service 9f2c4a
                }
Packit Service 9f2c4a
            }
Packit Service 9f2c4a
Packit Service 9f2c4a
            ret = gp_config_get_string(ctx, secname, "socket", &value);
Packit Service 9f2c4a
            if (ret == 0) {
Packit Service 9f2c4a
                cfg->svcs[n]->socket = strdup(value);
Packit Service 9f2c4a
                if (!cfg->svcs[n]->socket) {
Packit Service 9f2c4a
                    ret = ENOMEM;
Packit Service 9f2c4a
                    goto done;
Packit Service 9f2c4a
                }
Packit Service 9f2c4a
            }
Packit Service 9f2c4a
Packit Service 9f2c4a
            ret = gp_config_get_string(ctx, secname, "mechs", &value);
Packit Service 9f2c4a
            if (ret != 0) {
Packit Service 9f2c4a
                /* if mechs is missing or there is an error retrieving it
Packit Service 9f2c4a
                 * return an error and end. This is a fatal condition. */
Packit Service 9f2c4a
                if (ret == ENOENT) {
Packit Service 9f2c4a
                    GPERROR("Option 'mechs' is missing from [%s].\n", secname);
Packit Service 9f2c4a
                    ret = EINVAL;
Packit Service 9f2c4a
                }
Packit Service 9f2c4a
                gp_service_free(cfg->svcs[n]);
Packit Service 9f2c4a
                cfg->num_svcs--;
Packit Service 9f2c4a
                safefree(secname);
Packit Service 9f2c4a
                goto done;
Packit Service 9f2c4a
            }
Packit Service 9f2c4a
Packit Service 9f2c4a
            vcopy = strdup(value);
Packit Service 9f2c4a
            if (!vcopy) {
Packit Service 9f2c4a
                ret = ENOMEM;
Packit Service 9f2c4a
                goto done;
Packit Service 9f2c4a
            }
Packit Service 9f2c4a
            token = strtok_r(vcopy, ", ", &handle);
Packit Service 9f2c4a
            do {
Packit Service 9f2c4a
Packit Service 9f2c4a
                ret = strcmp(value, "krb5");
Packit Service 9f2c4a
                if (ret == 0) {
Packit Service 9f2c4a
                    ret = get_krb5_mech_cfg(cfg->svcs[n], ctx, secname);
Packit Service 9f2c4a
                    if (ret == 0) {
Packit Service 9f2c4a
                        cfg->svcs[n]->mechs |= GP_CRED_KRB5;
Packit Service 9f2c4a
                    } else {
Packit Service 9f2c4a
                        GPERROR("Failed to read krb5 config for %s.\n",
Packit Service 9f2c4a
                                secname);
Packit Service 9f2c4a
                        safefree(vcopy);
Packit Service 9f2c4a
                        return ret;
Packit Service 9f2c4a
                    }
Packit Service 9f2c4a
Packit Service 9f2c4a
                } else {
Packit Service 9f2c4a
                    GPERROR("Unknown mech: %s in [%s], ignoring.\n",
Packit Service 9f2c4a
                            token, secname);
Packit Service 9f2c4a
                }
Packit Service 9f2c4a
Packit Service 9f2c4a
                token = strtok_r(NULL, ", ", &handle);
Packit Service 9f2c4a
            } while (token != NULL);
Packit Service 9f2c4a
            safefree(vcopy);
Packit Service 9f2c4a
Packit Service 9f2c4a
            if (cfg->svcs[n]->mechs == 0) {
Packit Service 9f2c4a
                GPDEBUG("No mechs found for [%s], ignoring.\n", secname);
Packit Service 9f2c4a
                gp_service_free(cfg->svcs[n]);
Packit Service 9f2c4a
                cfg->num_svcs--;
Packit Service 9f2c4a
                safefree(secname);
Packit Service 9f2c4a
                continue;
Packit Service 9f2c4a
            }
Packit Service 9f2c4a
Packit Service 9f2c4a
            ret = gp_config_get_string(ctx, secname,
Packit Service 9f2c4a
                                       "selinux_context", &value);
Packit Service 9f2c4a
            if (ret == 0) {
Packit Service 9f2c4a
                GPDEBUG(
Packit Service 9f2c4a
                    "selinux_ctx is deprecated; use euid/socket instead.\n");
Packit Service 9f2c4a
                cfg->svcs[n]->selinux_ctx = SELINUX_context_new(value);
Packit Service 9f2c4a
                if (!cfg->svcs[n]->selinux_ctx) {
Packit Service 9f2c4a
                    ret = EINVAL;
Packit Service 9f2c4a
                    goto done;
Packit Service 9f2c4a
                }
Packit Service 9f2c4a
            }
Packit Service 9f2c4a
Packit Service 9f2c4a
            ret = gp_config_get_string(ctx, secname, "cred_usage", &value);
Packit Service 9f2c4a
            if (ret == 0) {
Packit Service 9f2c4a
                if (strcasecmp(value, "initiate") == 0) {
Packit Service 9f2c4a
                    cfg->svcs[n]->cred_usage = GSS_C_INITIATE;
Packit Service 9f2c4a
                } else if (strcasecmp(value, "accept") == 0) {
Packit Service 9f2c4a
                    cfg->svcs[n]->cred_usage = GSS_C_ACCEPT;
Packit Service 9f2c4a
                } else if (strcasecmp(value, "both") == 0) {
Packit Service 9f2c4a
                    cfg->svcs[n]->cred_usage = GSS_C_BOTH;
Packit Service 9f2c4a
                } else {
Packit Service 9f2c4a
                    GPDEBUG("Invalid value '%s' for cred_usage in [%s].\n",
Packit Service 9f2c4a
                            value, secname);
Packit Service 9f2c4a
                    ret = EINVAL;
Packit Service 9f2c4a
                    goto done;
Packit Service 9f2c4a
                }
Packit Service 9f2c4a
            }
Packit Service 9f2c4a
Packit Service 9f2c4a
            cfg->svcs[n]->filter_flags = DEFAULT_FILTERED_FLAGS;
Packit Service 9f2c4a
            ret = gp_config_get_string(ctx, secname, "filter_flags", &value);
Packit Service 9f2c4a
            if (ret == 0) {
Packit Service 9f2c4a
                parse_flags(value, &cfg->svcs[n]->filter_flags);
Packit Service 9f2c4a
            }
Packit Service 9f2c4a
Packit Service 9f2c4a
            cfg->svcs[n]->enforce_flags = DEFAULT_ENFORCED_FLAGS;
Packit Service 9f2c4a
            ret = gp_config_get_string(ctx, secname, "enforce_flags", &value);
Packit Service 9f2c4a
            if (ret == 0) {
Packit Service 9f2c4a
                ret = parse_flags(value, &cfg->svcs[n]->enforce_flags);
Packit Service 9f2c4a
                if (ret) goto done;
Packit Service 9f2c4a
            }
Packit Service 9f2c4a
Packit Service 9f2c4a
            ret = gp_config_get_string(ctx, secname, "program", &value);
Packit Service 9f2c4a
            if (ret == 0) {
Packit Service 9f2c4a
                cfg->svcs[n]->program = strdup(value);
Packit Service 9f2c4a
                if (!cfg->svcs[n]->program) {
Packit Service 9f2c4a
                    ret = ENOMEM;
Packit Service 9f2c4a
                    goto done;
Packit Service 9f2c4a
                }
Packit Service 9f2c4a
            }
Packit Service 9f2c4a
        }
Packit Service 9f2c4a
        safefree(secname);
Packit Service 9f2c4a
    }
Packit Service 9f2c4a
Packit Service 9f2c4a
    if (cfg->num_svcs == 0) {
Packit Service 9f2c4a
        GPERROR("No service sections configured!\n");
Packit Service 9f2c4a
        return ENOENT;
Packit Service 9f2c4a
    }
Packit Service 9f2c4a
Packit Service 9f2c4a
    ret = check_services(cfg);
Packit Service 9f2c4a
Packit Service 9f2c4a
done:
Packit Service 9f2c4a
    safefree(secname);
Packit Service 9f2c4a
    return ret;
Packit Service 9f2c4a
}
Packit Service 9f2c4a
Packit Service 9f2c4a
static int gp_init_ini_context(const char *config_file,
Packit Service 9f2c4a
                               const char *config_dir,
Packit Service 9f2c4a
                               struct gp_ini_context **ctxp)
Packit Service 9f2c4a
{
Packit Service 9f2c4a
    struct gp_ini_context *ctx;
Packit Service 9f2c4a
    int ret;
Packit Service 9f2c4a
Packit Service 9f2c4a
    if (!ctxp) {
Packit Service 9f2c4a
        return EINVAL;
Packit Service 9f2c4a
    }
Packit Service 9f2c4a
Packit Service 9f2c4a
    ctx = calloc(1, sizeof(struct gp_ini_context));
Packit Service 9f2c4a
    if (!ctx) {
Packit Service 9f2c4a
        return ENOENT;
Packit Service 9f2c4a
    }
Packit Service 9f2c4a
Packit Service 9f2c4a
    ret = gp_config_init(config_file, config_dir, ctx);
Packit Service 9f2c4a
Packit Service 9f2c4a
    if (ret) {
Packit Service 9f2c4a
        free(ctx);
Packit Service 9f2c4a
    } else {
Packit Service 9f2c4a
        *ctxp = ctx;
Packit Service 9f2c4a
    }
Packit Service 9f2c4a
    return ret;
Packit Service 9f2c4a
}
Packit Service 9f2c4a
Packit Service 9f2c4a
int load_config(struct gp_config *cfg)
Packit Service 9f2c4a
{
Packit Service 9f2c4a
    struct gp_ini_context *ctx;
Packit Service 9f2c4a
    const char *tmpstr;
Packit Service 9f2c4a
    int tmp_dbg_lvl = 0;
Packit Service 9f2c4a
    int tmpint = 0;
Packit Service 9f2c4a
    int ret;
Packit Service 9f2c4a
Packit Service 9f2c4a
    ret = gp_init_ini_context(cfg->config_file, cfg->config_dir, &ctx;;
Packit Service 9f2c4a
    if (ret) {
Packit Service 9f2c4a
        return ret;
Packit Service 9f2c4a
    }
Packit Service 9f2c4a
Packit Service 9f2c4a
    ret = gp_config_get_string(ctx, "gssproxy", "debug", &tmpstr);
Packit Service 9f2c4a
    if (ret == 0) {
Packit Service 9f2c4a
        if (gp_boolean_is_true(tmpstr)) {
Packit Service 9f2c4a
            if (tmp_dbg_lvl == 0) {
Packit Service 9f2c4a
                tmp_dbg_lvl = 1;
Packit Service 9f2c4a
            }
Packit Service 9f2c4a
        }
Packit Service 9f2c4a
    } else if (ret != ENOENT) {
Packit Service 9f2c4a
        goto done;
Packit Service 9f2c4a
    }
Packit Service 9f2c4a
Packit Service 9f2c4a
    ret = gp_config_get_int(ctx, "gssproxy", "debug_level", &tmpint);
Packit Service 9f2c4a
    if (ret == 0) {
Packit Service 9f2c4a
        tmp_dbg_lvl = tmpint;
Packit Service 9f2c4a
    } else if (ret != ENOENT) {
Packit Service 9f2c4a
        goto done;
Packit Service 9f2c4a
    }
Packit Service 9f2c4a
Packit Service 9f2c4a
    ret = gp_config_get_string(ctx, "gssproxy", "run_as_user", &tmpstr);
Packit Service 9f2c4a
    if (ret == 0) {
Packit Service 9f2c4a
        cfg->proxy_user = strdup(tmpstr);
Packit Service 9f2c4a
        if (!cfg->proxy_user) {
Packit Service 9f2c4a
            ret = ENOMEM;
Packit Service 9f2c4a
            goto done;
Packit Service 9f2c4a
        }
Packit Service 9f2c4a
    } else if (ret != ENOENT) {
Packit Service 9f2c4a
        goto done;
Packit Service 9f2c4a
    }
Packit Service 9f2c4a
Packit Service 9f2c4a
    ret = gp_config_get_int(ctx, "gssproxy", "worker threads",
Packit Service 9f2c4a
                            &cfg->num_workers);
Packit Service 9f2c4a
    if (ret != 0 && ret != ENOENT) {
Packit Service 9f2c4a
        goto done;
Packit Service 9f2c4a
    }
Packit Service 9f2c4a
Packit Service 9f2c4a
    ret = load_services(cfg, ctx);
Packit Service 9f2c4a
Packit Service 9f2c4a
done:
Packit Service 9f2c4a
    if (ret != 0) {
Packit Service 9f2c4a
        GPERROR("Error reading configuration %d: %s", ret, gp_strerror(ret));
Packit Service 9f2c4a
    }
Packit Service 9f2c4a
    gp_debug_toggle(tmp_dbg_lvl);
Packit Service 9f2c4a
    gp_config_close(ctx);
Packit Service 9f2c4a
    safefree(ctx);
Packit Service 9f2c4a
    return ret;
Packit Service 9f2c4a
}
Packit Service 9f2c4a
Packit Service 9f2c4a
struct gp_config *read_config(char *config_file, char *config_dir,
Packit Service 9f2c4a
                              char *socket_name, int opt_daemonize)
Packit Service 9f2c4a
{
Packit Service 9f2c4a
    const char *socket = GP_SOCKET_NAME;
Packit Service 9f2c4a
    const char *dir = NULL;
Packit Service 9f2c4a
    struct gp_config *cfg;
Packit Service 9f2c4a
    int ret;
Packit Service 9f2c4a
Packit Service 9f2c4a
    cfg = calloc(1, sizeof(struct gp_config));
Packit Service 9f2c4a
    if (!cfg) {
Packit Service 9f2c4a
        return NULL;
Packit Service 9f2c4a
    }
Packit Service 9f2c4a
Packit Service 9f2c4a
    if (config_file) {
Packit Service 9f2c4a
        cfg->config_file = strdup(config_file);
Packit Service 9f2c4a
        if (!cfg->config_file) {
Packit Service 9f2c4a
            ret = ENOMEM;
Packit Service 9f2c4a
            goto done;
Packit Service 9f2c4a
        }
Packit Service 9f2c4a
    } else {
Packit Service 9f2c4a
        ret = asprintf(&cfg->config_file, "%s/gssproxy.conf", PUBCONF_PATH);
Packit Service 9f2c4a
        if (ret == -1) {
Packit Service 9f2c4a
            goto done;
Packit Service 9f2c4a
        }
Packit Service 9f2c4a
    }
Packit Service 9f2c4a
Packit Service 9f2c4a
    if (config_dir) {
Packit Service 9f2c4a
        dir = config_dir;
Packit Service 9f2c4a
    } else if (!config_file) {
Packit Service 9f2c4a
        dir = PUBCONF_PATH;
Packit Service 9f2c4a
    }
Packit Service 9f2c4a
Packit Service 9f2c4a
    if (dir) {
Packit Service 9f2c4a
        cfg->config_dir = strdup(dir);
Packit Service 9f2c4a
        if (!cfg->config_dir) {
Packit Service 9f2c4a
            ret = ENOMEM;
Packit Service 9f2c4a
            goto done;
Packit Service 9f2c4a
        }
Packit Service 9f2c4a
    }
Packit Service 9f2c4a
Packit Service 9f2c4a
    if (socket_name) socket = socket_name;
Packit Service 9f2c4a
Packit Service 9f2c4a
    cfg->socket_name = strdup(socket);
Packit Service 9f2c4a
    if (cfg->socket_name == NULL) {
Packit Service 9f2c4a
        ret = ENOMEM;
Packit Service 9f2c4a
        goto done;
Packit Service 9f2c4a
    }
Packit Service 9f2c4a
Packit Service 9f2c4a
    switch (opt_daemonize) {
Packit Service 9f2c4a
    case 0:
Packit Service 9f2c4a
        /* daemonize by default */
Packit Service 9f2c4a
    case 1:
Packit Service 9f2c4a
        cfg->daemonize = true;
Packit Service 9f2c4a
        break;
Packit Service 9f2c4a
    case 2:
Packit Service 9f2c4a
        cfg->daemonize = false;
Packit Service 9f2c4a
        break;
Packit Service 9f2c4a
    }
Packit Service 9f2c4a
Packit Service 9f2c4a
    ret = load_config(cfg);
Packit Service 9f2c4a
    if (ret) {
Packit Service 9f2c4a
        GPDEBUG("Config file(s) not found!\n");
Packit Service 9f2c4a
    }
Packit Service 9f2c4a
Packit Service 9f2c4a
done:
Packit Service 9f2c4a
    if (ret) {
Packit Service 9f2c4a
        /* recursively frees cfg */
Packit Service 9f2c4a
        free_config(&cfg;;
Packit Service 9f2c4a
        return NULL;
Packit Service 9f2c4a
    }
Packit Service 9f2c4a
Packit Service 9f2c4a
    return cfg;
Packit Service 9f2c4a
}
Packit Service 9f2c4a
Packit Service 9f2c4a
struct gp_creds_handle *gp_service_get_creds_handle(struct gp_service *svc)
Packit Service 9f2c4a
{
Packit Service 9f2c4a
    return svc->krb5.creds_handle;
Packit Service 9f2c4a
}
Packit Service 9f2c4a
Packit Service 9f2c4a
void free_config(struct gp_config **cfg)
Packit Service 9f2c4a
{
Packit Service 9f2c4a
    struct gp_config *config = *cfg;
Packit Service 9f2c4a
Packit Service 9f2c4a
    if (!config) {
Packit Service 9f2c4a
        return;
Packit Service 9f2c4a
    }
Packit Service 9f2c4a
Packit Service 9f2c4a
    free(config->config_file);
Packit Service 9f2c4a
    free(config->config_dir);
Packit Service 9f2c4a
    free(config->socket_name);
Packit Service 9f2c4a
    free(config->proxy_user);
Packit Service 9f2c4a
Packit Service 9f2c4a
    for (int i = 0; i < config->num_svcs; i++) {
Packit Service 9f2c4a
        gp_service_free(config->svcs[i]);
Packit Service 9f2c4a
        safefree(config->svcs[i]);
Packit Service 9f2c4a
    }
Packit Service 9f2c4a
Packit Service 9f2c4a
    free(config->svcs);
Packit Service 9f2c4a
    free(config);
Packit Service 9f2c4a
    *cfg = NULL;
Packit Service 9f2c4a
}
Packit Service 9f2c4a
Packit Service 9f2c4a
static int gp_config_from_file(const char *config_file,
Packit Service 9f2c4a
                               struct ini_cfgobj *ini_config,
Packit Service 9f2c4a
                               const uint32_t collision_flags)
Packit Service 9f2c4a
{
Packit Service 9f2c4a
    struct ini_cfgfile *file_ctx = NULL;
Packit Service 9f2c4a
    int ret;
Packit Service 9f2c4a
Packit Service 9f2c4a
    ret = ini_config_file_open(config_file,
Packit Service 9f2c4a
                               0, /* metadata_flags, FIXME */
Packit Service 9f2c4a
                               &file_ctx);
Packit Service 9f2c4a
    if (ret) {
Packit Service 9f2c4a
        GPERROR("Failed to open config file: %d (%s)\n",
Packit Service 9f2c4a
                ret, gp_strerror(ret));
Packit Service 9f2c4a
        ini_config_destroy(ini_config);
Packit Service 9f2c4a
        return ret;
Packit Service 9f2c4a
    }
Packit Service 9f2c4a
Packit Service 9f2c4a
    ret = ini_config_parse(file_ctx,
Packit Service 9f2c4a
                           INI_STOP_ON_ANY, /* error_level */
Packit Service 9f2c4a
                           collision_flags,
Packit Service 9f2c4a
                           INI_PARSE_NOWRAP, /* parse_flags */
Packit Service 9f2c4a
                           ini_config);
Packit Service 9f2c4a
    if (ret) {
Packit Service 9f2c4a
        char **errors = NULL;
Packit Service 9f2c4a
        /* we had a parsing failure */
Packit Service 9f2c4a
        GPERROR("Failed to parse config file: %d (%s)\n",
Packit Service 9f2c4a
                ret, gp_strerror(ret));
Packit Service 9f2c4a
        if (ini_config_error_count(ini_config)) {
Packit Service 9f2c4a
            ini_config_get_errors(ini_config, &errors);
Packit Service 9f2c4a
            if (errors) {
Packit Service 9f2c4a
                ini_config_print_errors(stderr, errors);
Packit Service 9f2c4a
                ini_config_free_errors(errors);
Packit Service 9f2c4a
            }
Packit Service 9f2c4a
        }
Packit Service 9f2c4a
        ini_config_file_destroy(file_ctx);
Packit Service 9f2c4a
        ini_config_destroy(ini_config);
Packit Service 9f2c4a
        return ret;
Packit Service 9f2c4a
    }
Packit Service 9f2c4a
Packit Service 9f2c4a
    ini_config_file_destroy(file_ctx);
Packit Service 9f2c4a
    return 0;
Packit Service 9f2c4a
}
Packit Service 9f2c4a
Packit Service 9f2c4a
static int gp_config_from_dir(const char *config_dir,
Packit Service 9f2c4a
                              struct ini_cfgobj **ini_config,
Packit Service 9f2c4a
                              const uint32_t collision_flags)
Packit Service 9f2c4a
{
Packit Service 9f2c4a
    struct ini_cfgobj *result_cfg = NULL;
Packit Service 9f2c4a
    struct ref_array *error_list = NULL;
Packit Service 9f2c4a
    int ret;
Packit Service 9f2c4a
Packit Service 9f2c4a
    const char *patterns[] = {
Packit Service 9f2c4a
        /* match only files starting with "##-" and ending in ".conf" */
Packit Service 9f2c4a
        "^[0-9]\\{2\\}-.\\{1,\\}\\.conf$",
Packit Service 9f2c4a
        NULL,
Packit Service 9f2c4a
    };
Packit Service 9f2c4a
Packit Service 9f2c4a
    const char *sections[] = {
Packit Service 9f2c4a
        /* match either "gssproxy" or sections that start with "service/" */
Packit Service 9f2c4a
        "^gssproxy$",
Packit Service 9f2c4a
        "^service/.*$",
Packit Service 9f2c4a
        NULL,
Packit Service 9f2c4a
    };
Packit Service 9f2c4a
Packit Service 9f2c4a
    /* Permission check failures silently skip the file, so they are not
Packit Service 9f2c4a
     * useful to us. */
Packit Service 9f2c4a
    ret = ini_config_augment(*ini_config,
Packit Service 9f2c4a
                             config_dir,
Packit Service 9f2c4a
                             patterns,
Packit Service 9f2c4a
                             sections,
Packit Service 9f2c4a
                             NULL, /* check_perm */
Packit Service 9f2c4a
                             INI_STOP_ON_ANY, /* error_level */
Packit Service 9f2c4a
                             collision_flags,
Packit Service 9f2c4a
                             INI_PARSE_NOWRAP,
Packit Service 9f2c4a
                             /* allow sections with the same name in
Packit Service 9f2c4a
                              * different files, but log warnings */
Packit Service 9f2c4a
                             INI_MS_DETECT | INI_MS_PRESERVE,
Packit Service 9f2c4a
                             &result_cfg,
Packit Service 9f2c4a
                             &error_list,
Packit Service 9f2c4a
                             NULL);
Packit Service 9f2c4a
    if (error_list) {
Packit Service 9f2c4a
        uint32_t len;
Packit Service 9f2c4a
        len = ref_array_len(error_list);
Packit Service 9f2c4a
        for (uint32_t i = 0; i < len; i++) {
Packit Service 9f2c4a
            /* libini has an unfixable bug where error strings are (char **) */
Packit Service 9f2c4a
            GPAUDIT("Error when reading config directory: %s\n",
Packit Service 9f2c4a
                    *(char **)ref_array_get(error_list, i, NULL));
Packit Service 9f2c4a
        }
Packit Service 9f2c4a
        ref_array_destroy(error_list);
Packit Service 9f2c4a
    }
Packit Service 9f2c4a
Packit Service 9f2c4a
    if (ret && ret != EEXIST) {
Packit Service 9f2c4a
        GPERROR("Error when reading config directory number: %d\n", ret);
Packit Service 9f2c4a
Packit Service 9f2c4a
        ref_array_destroy(error_list);
Packit Service 9f2c4a
        return ret;
Packit Service 9f2c4a
    }
Packit Service 9f2c4a
Packit Service 9f2c4a
    /* if we read no new files, result_cfg will be NULL */
Packit Service 9f2c4a
    if (result_cfg) {
Packit Service 9f2c4a
        ini_config_destroy(*ini_config);
Packit Service 9f2c4a
        *ini_config = result_cfg;
Packit Service 9f2c4a
    }
Packit Service 9f2c4a
Packit Service 9f2c4a
    return 0;
Packit Service 9f2c4a
}
Packit Service 9f2c4a
Packit Service 9f2c4a
int gp_config_init(const char *config_file, const char *config_dir,
Packit Service 9f2c4a
                   struct gp_ini_context *ctx)
Packit Service 9f2c4a
{
Packit Service 9f2c4a
    struct ini_cfgobj *ini_config = NULL;
Packit Service 9f2c4a
    int ret;
Packit Service 9f2c4a
Packit Service 9f2c4a
    /* Within a single file, merge all collisions */
Packit Service 9f2c4a
    const uint32_t collision_flags =
Packit Service 9f2c4a
      INI_MS_MERGE | INI_MV1S_ALLOW | INI_MV2S_ALLOW;
Packit Service 9f2c4a
Packit Service 9f2c4a
    if (!ctx) {
Packit Service 9f2c4a
        return EINVAL;
Packit Service 9f2c4a
    }
Packit Service 9f2c4a
Packit Service 9f2c4a
    ret = ini_config_create(&ini_config);
Packit Service 9f2c4a
    if (ret) {
Packit Service 9f2c4a
        return ENOENT;
Packit Service 9f2c4a
    }
Packit Service 9f2c4a
Packit Service 9f2c4a
    if (config_file) {
Packit Service 9f2c4a
        ret = gp_config_from_file(config_file, ini_config, collision_flags);
Packit Service 9f2c4a
        if (ret) {
Packit Service 9f2c4a
            GPDEBUG("Error when trying to read config file %s.\n",
Packit Service 9f2c4a
                    config_file);
Packit Service 9f2c4a
            return ret;
Packit Service 9f2c4a
        }
Packit Service 9f2c4a
    }
Packit Service 9f2c4a
    if (config_dir) {
Packit Service 9f2c4a
        ret = gp_config_from_dir(config_dir, &ini_config, collision_flags);
Packit Service 9f2c4a
        if (ret) {
Packit Service 9f2c4a
            GPDEBUG("Error when trying to read config directory %s.\n",
Packit Service 9f2c4a
                    config_dir);
Packit Service 9f2c4a
            return ret;
Packit Service 9f2c4a
        }
Packit Service 9f2c4a
    }
Packit Service 9f2c4a
Packit Service 9f2c4a
    ctx->private_data = ini_config;
Packit Service 9f2c4a
Packit Service 9f2c4a
    return 0;
Packit Service 9f2c4a
}
Packit Service 9f2c4a
Packit Service 9f2c4a
int gp_config_get_string(struct gp_ini_context *ctx,
Packit Service 9f2c4a
                         const char *secname,
Packit Service 9f2c4a
                         const char *keyname,
Packit Service 9f2c4a
                         const char **value)
Packit Service 9f2c4a
{
Packit Service 9f2c4a
    struct ini_cfgobj *ini_config = (struct ini_cfgobj *)ctx->private_data;
Packit Service 9f2c4a
    struct value_obj *vo = NULL;
Packit Service 9f2c4a
    int ret;
Packit Service 9f2c4a
    const char *val;
Packit Service 9f2c4a
Packit Service 9f2c4a
    if (!value) {
Packit Service 9f2c4a
        return -1;
Packit Service 9f2c4a
    }
Packit Service 9f2c4a
Packit Service 9f2c4a
    *value = NULL;
Packit Service 9f2c4a
Packit Service 9f2c4a
    ret = ini_get_config_valueobj(secname,
Packit Service 9f2c4a
                                  keyname,
Packit Service 9f2c4a
                                  ini_config,
Packit Service 9f2c4a
                                  INI_GET_FIRST_VALUE,
Packit Service 9f2c4a
                                  &vo);
Packit Service 9f2c4a
    if (ret) {
Packit Service 9f2c4a
        return ret;
Packit Service 9f2c4a
    }
Packit Service 9f2c4a
    if (!vo) {
Packit Service 9f2c4a
        return ENOENT;
Packit Service 9f2c4a
    }
Packit Service 9f2c4a
Packit Service 9f2c4a
    val = ini_get_const_string_config_value(vo, &ret;;
Packit Service 9f2c4a
    if (ret) {
Packit Service 9f2c4a
        return ret;
Packit Service 9f2c4a
    }
Packit Service 9f2c4a
Packit Service 9f2c4a
    *value = val;
Packit Service 9f2c4a
Packit Service 9f2c4a
    return 0;
Packit Service 9f2c4a
}
Packit Service 9f2c4a
Packit Service 9f2c4a
int gp_config_get_string_array(struct gp_ini_context *ctx,
Packit Service 9f2c4a
                               const char *secname,
Packit Service 9f2c4a
                               const char *keyname,
Packit Service 9f2c4a
                               int *num_values,
Packit Service 9f2c4a
                               const char ***values)
Packit Service 9f2c4a
{
Packit Service 9f2c4a
    struct ini_cfgobj *ini_config = (struct ini_cfgobj *)ctx->private_data;
Packit Service 9f2c4a
    struct value_obj *vo = NULL;
Packit Service 9f2c4a
    const char *value;
Packit Service 9f2c4a
    int ret;
Packit Service 9f2c4a
    int i, count = 0;
Packit Service 9f2c4a
    const char **array = NULL;
Packit Service 9f2c4a
    const char **t_array;
Packit Service 9f2c4a
Packit Service 9f2c4a
    if (!values || !num_values) {
Packit Service 9f2c4a
        return EINVAL;
Packit Service 9f2c4a
    }
Packit Service 9f2c4a
Packit Service 9f2c4a
    *num_values = 0;
Packit Service 9f2c4a
    *values = NULL;
Packit Service 9f2c4a
Packit Service 9f2c4a
    ret = ini_get_config_valueobj(secname,
Packit Service 9f2c4a
                                  keyname,
Packit Service 9f2c4a
                                  ini_config,
Packit Service 9f2c4a
                                  INI_GET_FIRST_VALUE,
Packit Service 9f2c4a
                                  &vo);
Packit Service 9f2c4a
    if (ret) {
Packit Service 9f2c4a
        return ret;
Packit Service 9f2c4a
    }
Packit Service 9f2c4a
    if (!vo) {
Packit Service 9f2c4a
        return ENOENT;
Packit Service 9f2c4a
    }
Packit Service 9f2c4a
Packit Service 9f2c4a
    value = ini_get_const_string_config_value(vo, &ret;;
Packit Service 9f2c4a
    if (ret) {
Packit Service 9f2c4a
        return ret;
Packit Service 9f2c4a
    }
Packit Service 9f2c4a
Packit Service 9f2c4a
    array = calloc(1, sizeof(char *));
Packit Service 9f2c4a
    if (array == NULL) {
Packit Service 9f2c4a
        ret = ENOMEM;
Packit Service 9f2c4a
        goto done;
Packit Service 9f2c4a
    }
Packit Service 9f2c4a
Packit Service 9f2c4a
    array[count] = strdup(value);
Packit Service 9f2c4a
    if (array[count] == NULL) {
Packit Service 9f2c4a
        ret = ENOMEM;
Packit Service 9f2c4a
        goto done;
Packit Service 9f2c4a
    }
Packit Service 9f2c4a
Packit Service 9f2c4a
    count++;
Packit Service 9f2c4a
Packit Service 9f2c4a
    do {
Packit Service 9f2c4a
        ret = ini_get_config_valueobj(secname,
Packit Service 9f2c4a
                                      keyname,
Packit Service 9f2c4a
                                      ini_config,
Packit Service 9f2c4a
                                      INI_GET_NEXT_VALUE,
Packit Service 9f2c4a
                                      &vo);
Packit Service 9f2c4a
        if (ret) {
Packit Service 9f2c4a
            goto done;
Packit Service 9f2c4a
        }
Packit Service 9f2c4a
        if (!vo) {
Packit Service 9f2c4a
            break;
Packit Service 9f2c4a
        }
Packit Service 9f2c4a
Packit Service 9f2c4a
        value = ini_get_const_string_config_value(vo, &ret;;
Packit Service 9f2c4a
        if (ret) {
Packit Service 9f2c4a
            goto done;
Packit Service 9f2c4a
        }
Packit Service 9f2c4a
Packit Service 9f2c4a
        t_array = realloc(array, (count+1) * sizeof(char *));
Packit Service 9f2c4a
        if (t_array == NULL) {
Packit Service 9f2c4a
            ret = ENOMEM;
Packit Service 9f2c4a
            goto done;
Packit Service 9f2c4a
        }
Packit Service 9f2c4a
        array = t_array;
Packit Service 9f2c4a
Packit Service 9f2c4a
        array[count] = strdup(value);
Packit Service 9f2c4a
        if (array[count] == NULL) {
Packit Service 9f2c4a
            ret = ENOMEM;
Packit Service 9f2c4a
            goto done;
Packit Service 9f2c4a
        }
Packit Service 9f2c4a
Packit Service 9f2c4a
        count++;
Packit Service 9f2c4a
Packit Service 9f2c4a
    } while (1);
Packit Service 9f2c4a
Packit Service 9f2c4a
    *num_values = count;
Packit Service 9f2c4a
    *values = array;
Packit Service 9f2c4a
Packit Service 9f2c4a
    ret = 0;
Packit Service 9f2c4a
Packit Service 9f2c4a
done:
Packit Service 9f2c4a
    if (ret && array) {
Packit Service 9f2c4a
        for (i = 0; i < count; i++) {
Packit Service 9f2c4a
            safefree(array[i]);
Packit Service 9f2c4a
        }
Packit Service 9f2c4a
        safefree(array);
Packit Service 9f2c4a
    }
Packit Service 9f2c4a
    return ret;
Packit Service 9f2c4a
}
Packit Service 9f2c4a
Packit Service 9f2c4a
int gp_config_get_int(struct gp_ini_context *ctx,
Packit Service 9f2c4a
                      const char *secname,
Packit Service 9f2c4a
                      const char *keyname,
Packit Service 9f2c4a
                      int *value)
Packit Service 9f2c4a
{
Packit Service 9f2c4a
    struct ini_cfgobj *ini_config = (struct ini_cfgobj *)ctx->private_data;
Packit Service 9f2c4a
    struct value_obj *vo = NULL;
Packit Service 9f2c4a
    int ret;
Packit Service 9f2c4a
    int val;
Packit Service 9f2c4a
Packit Service 9f2c4a
    if (!value) {
Packit Service 9f2c4a
        return EINVAL;
Packit Service 9f2c4a
    }
Packit Service 9f2c4a
Packit Service 9f2c4a
    *value = -1;
Packit Service 9f2c4a
Packit Service 9f2c4a
    ret = ini_get_config_valueobj(secname,
Packit Service 9f2c4a
                                  keyname,
Packit Service 9f2c4a
                                  ini_config,
Packit Service 9f2c4a
                                  INI_GET_FIRST_VALUE,
Packit Service 9f2c4a
                                  &vo);
Packit Service 9f2c4a
Packit Service 9f2c4a
    if (ret) {
Packit Service 9f2c4a
        return ret;
Packit Service 9f2c4a
    }
Packit Service 9f2c4a
    if (!vo) {
Packit Service 9f2c4a
        return ENOENT;
Packit Service 9f2c4a
    }
Packit Service 9f2c4a
Packit Service 9f2c4a
    val = ini_get_int_config_value(vo,
Packit Service 9f2c4a
                                   0, /* strict */
Packit Service 9f2c4a
                                   0, /* default */
Packit Service 9f2c4a
                                   &ret;;
Packit Service 9f2c4a
    if (ret) {
Packit Service 9f2c4a
        return ret;
Packit Service 9f2c4a
    }
Packit Service 9f2c4a
Packit Service 9f2c4a
    *value = val;
Packit Service 9f2c4a
Packit Service 9f2c4a
    return 0;
Packit Service 9f2c4a
}
Packit Service 9f2c4a
Packit Service 9f2c4a
int gp_config_get_nsec(struct gp_ini_context *ctx)
Packit Service 9f2c4a
{
Packit Service 9f2c4a
    struct ini_cfgobj *ini_config = (struct ini_cfgobj *)ctx->private_data;
Packit Service 9f2c4a
    char **list = NULL;
Packit Service 9f2c4a
    int count;
Packit Service 9f2c4a
    int error;
Packit Service 9f2c4a
Packit Service 9f2c4a
    list = ini_get_section_list(ini_config, &count, &error);
Packit Service 9f2c4a
    if (error) {
Packit Service 9f2c4a
        return 0;
Packit Service 9f2c4a
    }
Packit Service 9f2c4a
Packit Service 9f2c4a
    ini_free_section_list(list);
Packit Service 9f2c4a
Packit Service 9f2c4a
    return count;
Packit Service 9f2c4a
}
Packit Service 9f2c4a
Packit Service 9f2c4a
char *gp_config_get_secname(struct gp_ini_context *ctx,
Packit Service 9f2c4a
                            int i)
Packit Service 9f2c4a
{
Packit Service 9f2c4a
    struct ini_cfgobj *ini_config = (struct ini_cfgobj *)ctx->private_data;
Packit Service 9f2c4a
    char **list = NULL;
Packit Service 9f2c4a
    int count;
Packit Service 9f2c4a
    int error;
Packit Service 9f2c4a
    char *secname;
Packit Service 9f2c4a
Packit Service 9f2c4a
    list = ini_get_section_list(ini_config, &count, &error);
Packit Service 9f2c4a
    if (error) {
Packit Service 9f2c4a
        return NULL;
Packit Service 9f2c4a
    }
Packit Service 9f2c4a
Packit Service 9f2c4a
    if (i >= count) {
Packit Service 9f2c4a
        return NULL;
Packit Service 9f2c4a
    }
Packit Service 9f2c4a
Packit Service 9f2c4a
    secname = strdup(list[i]);
Packit Service 9f2c4a
    ini_free_section_list(list);
Packit Service 9f2c4a
    if (!secname) {
Packit Service 9f2c4a
        return NULL;
Packit Service 9f2c4a
    }
Packit Service 9f2c4a
Packit Service 9f2c4a
    return secname;
Packit Service 9f2c4a
}
Packit Service 9f2c4a
Packit Service 9f2c4a
int gp_config_close(struct gp_ini_context *ctx)
Packit Service 9f2c4a
{
Packit Service 9f2c4a
    struct ini_cfgobj *ini_config = NULL;
Packit Service 9f2c4a
Packit Service 9f2c4a
    if (!ctx) {
Packit Service 9f2c4a
        return 0;
Packit Service 9f2c4a
    }
Packit Service 9f2c4a
Packit Service 9f2c4a
    ini_config = (struct ini_cfgobj *)ctx->private_data;
Packit Service 9f2c4a
Packit Service 9f2c4a
    ini_config_destroy(ini_config);
Packit Service 9f2c4a
Packit Service 9f2c4a
    return 0;
Packit Service 9f2c4a
}