Blame src/gssproxy.c

Packit Service 9f2c4a
/* Copyright (C) 2011,2015 the GSS-PROXY contributors, see COPYING for license */
Packit Service 9f2c4a
Packit Service 9f2c4a
#include "config.h"
Packit Service 9f2c4a
#include <stdlib.h>
Packit Service 9f2c4a
#include "popt.h"
Packit Service 9f2c4a
#include "gp_proxy.h"
Packit Service 9f2c4a
#include <signal.h>
Packit Service 9f2c4a
#include <string.h>
Packit Service 9f2c4a
Packit Service 9f2c4a
const int vflags =
Packit Service 9f2c4a
    VERTO_EV_FLAG_PERSIST |
Packit Service 9f2c4a
    VERTO_EV_FLAG_IO_READ |
Packit Service 9f2c4a
    VERTO_EV_FLAG_IO_CLOSE_FD;
Packit Service 9f2c4a
Packit Service 9f2c4a
char *opt_config_file = NULL;
Packit Service 9f2c4a
char *opt_config_dir = NULL;
Packit Service 9f2c4a
char *opt_config_socket = NULL;
Packit Service 9f2c4a
int opt_daemon = 0;
Packit Service 9f2c4a
Packit Service 9f2c4a
struct gssproxy_ctx *gpctx;
Packit Service 9f2c4a
Packit Service 9f2c4a
static struct gp_service *
Packit Service 9f2c4a
find_service_by_name(struct gp_config *cfg, const char *name)
Packit Service 9f2c4a
{
Packit Service 9f2c4a
    int i;
Packit Service 9f2c4a
    struct gp_service *ret = NULL;
Packit Service 9f2c4a
Packit Service 9f2c4a
    for (i = 0; i < cfg->num_svcs; i++) {
Packit Service 9f2c4a
        if (strcmp(cfg->svcs[i]->name, name) == 0) {
Packit Service 9f2c4a
            ret = cfg->svcs[i];
Packit Service 9f2c4a
            break;
Packit Service 9f2c4a
        }
Packit Service 9f2c4a
    }
Packit Service 9f2c4a
    return ret;
Packit Service 9f2c4a
}
Packit Service 9f2c4a
Packit Service 9f2c4a
static verto_ev *setup_socket(char *sock_name, verto_ctx *vctx)
Packit Service 9f2c4a
{
Packit Service 9f2c4a
    struct gp_sock_ctx *sock_ctx;
Packit Service 9f2c4a
    verto_ev *ev;
Packit Service 9f2c4a
Packit Service 9f2c4a
    sock_ctx = init_unix_socket(gpctx, sock_name);
Packit Service 9f2c4a
    if (!sock_ctx) {
Packit Service 9f2c4a
        return NULL;
Packit Service 9f2c4a
    }
Packit Service 9f2c4a
Packit Service 9f2c4a
    ev = verto_add_io(vctx, vflags, accept_sock_conn, sock_ctx->fd);
Packit Service 9f2c4a
    if (!ev) {
Packit Service 9f2c4a
        return NULL;
Packit Service 9f2c4a
    }
Packit Service 9f2c4a
Packit Service 9f2c4a
    verto_set_private(ev, sock_ctx, free_unix_socket);
Packit Service 9f2c4a
    return ev;
Packit Service 9f2c4a
}
Packit Service 9f2c4a
Packit Service 9f2c4a
static int init_sockets(verto_ctx *vctx, struct gp_config *old_config)
Packit Service 9f2c4a
{
Packit Service 9f2c4a
    int i;
Packit Service 9f2c4a
    struct gp_sock_ctx *sock_ctx;
Packit Service 9f2c4a
    verto_ev *ev;
Packit Service 9f2c4a
    struct gp_service *svc;
Packit Service 9f2c4a
Packit Service 9f2c4a
    /* init main socket */
Packit Service 9f2c4a
    if (!old_config) {
Packit Service 9f2c4a
        ev = setup_socket(gpctx->config->socket_name, vctx);
Packit Service 9f2c4a
        if (!ev) {
Packit Service 9f2c4a
            return 1;
Packit Service 9f2c4a
        }
Packit Service 9f2c4a
Packit Service 9f2c4a
        gpctx->sock_ev = ev;
Packit Service 9f2c4a
    } else if (strcmp(old_config->socket_name,
Packit Service 9f2c4a
                      gpctx->config->socket_name) != 0) {
Packit Service 9f2c4a
        ev = setup_socket(gpctx->config->socket_name, vctx);
Packit Service 9f2c4a
        if (!ev) {
Packit Service 9f2c4a
            return 1;
Packit Service 9f2c4a
        }
Packit Service 9f2c4a
Packit Service 9f2c4a
        gpctx->sock_ev = ev;
Packit Service 9f2c4a
        verto_del(gpctx->sock_ev);
Packit Service 9f2c4a
    } else {
Packit Service 9f2c4a
        /* free_config will erase the socket name; update it accordingly */
Packit Service 9f2c4a
        sock_ctx = verto_get_private(gpctx->sock_ev);
Packit Service 9f2c4a
        sock_ctx->socket = gpctx->config->socket_name;
Packit Service 9f2c4a
    }
Packit Service 9f2c4a
Packit Service 9f2c4a
    /* propagate any sockets that shouldn't change */
Packit Service 9f2c4a
    if (old_config) {
Packit Service 9f2c4a
        for (i = 0; i < old_config->num_svcs; i++) {
Packit Service 9f2c4a
            if (old_config->svcs[i]->ev) {
Packit Service 9f2c4a
                svc = find_service_by_name(gpctx->config,
Packit Service 9f2c4a
                                           old_config->svcs[i]->name);
Packit Service 9f2c4a
                if (svc &&
Packit Service 9f2c4a
                    ((svc->socket == old_config->svcs[i]->socket) ||
Packit Service 9f2c4a
                     ((svc->socket != NULL) &&
Packit Service 9f2c4a
                      (old_config->svcs[i]->socket != NULL) &&
Packit Service 9f2c4a
                      strcmp(svc->socket,
Packit Service 9f2c4a
                             old_config->svcs[i]->socket) == 0))) {
Packit Service 9f2c4a
                    svc->ev = old_config->svcs[i]->ev;
Packit Service 9f2c4a
                    sock_ctx = verto_get_private(svc->ev);
Packit Service 9f2c4a
                    sock_ctx->socket = svc->socket;
Packit Service 9f2c4a
                } else {
Packit Service 9f2c4a
                    verto_del(old_config->svcs[i]->ev);
Packit Service 9f2c4a
                }
Packit Service 9f2c4a
            }
Packit Service 9f2c4a
        }
Packit Service 9f2c4a
    }
Packit Service 9f2c4a
Packit Service 9f2c4a
    /* init all other sockets */
Packit Service 9f2c4a
    for (i = 0; i < gpctx->config->num_svcs; i++) {
Packit Service 9f2c4a
        svc = gpctx->config->svcs[i];
Packit Service 9f2c4a
        if (svc->socket != NULL && svc->ev == NULL) {
Packit Service 9f2c4a
            ev = setup_socket(svc->socket, vctx);
Packit Service 9f2c4a
            if (!ev) {
Packit Service 9f2c4a
                return 1;
Packit Service 9f2c4a
            }
Packit Service 9f2c4a
            svc->ev = ev;
Packit Service 9f2c4a
        }
Packit Service 9f2c4a
    }
Packit Service 9f2c4a
    return 0;
Packit Service 9f2c4a
}
Packit Service 9f2c4a
Packit Service 9f2c4a
static void hup_handler(verto_ctx *vctx, verto_ev *ev UNUSED)
Packit Service 9f2c4a
{
Packit Service 9f2c4a
    int ret;
Packit Service 9f2c4a
    struct gp_config *new_config, *old_config;
Packit Service 9f2c4a
Packit Service 9f2c4a
    GPDEBUG("Received SIGHUP; re-reading config.\n");
Packit Service 9f2c4a
    new_config = read_config(opt_config_file, opt_config_dir,
Packit Service 9f2c4a
                             opt_config_socket, opt_daemon);
Packit Service 9f2c4a
    if (!new_config) {
Packit Service 9f2c4a
        GPERROR("Error reading new configuration on SIGHUP; keeping old "
Packit Service 9f2c4a
                "configuration instead!\n");
Packit Service 9f2c4a
        return;
Packit Service 9f2c4a
    }
Packit Service 9f2c4a
    old_config = gpctx->config;
Packit Service 9f2c4a
    gpctx->config = new_config;
Packit Service 9f2c4a
Packit Service 9f2c4a
    ret = init_sockets(vctx, old_config);
Packit Service 9f2c4a
    if (ret != 0) {
Packit Service 9f2c4a
        exit(ret);
Packit Service 9f2c4a
    }
Packit Service 9f2c4a
Packit Service 9f2c4a
    /* conditionally reload kernel interface */
Packit Service 9f2c4a
    init_proc_nfsd(gpctx->config);
Packit Service 9f2c4a
Packit Service 9f2c4a
    free_config(&old_config);
Packit Service 9f2c4a
Packit Service 9f2c4a
    GPDEBUG("New config loaded successfully.\n");
Packit Service 9f2c4a
    return;
Packit Service 9f2c4a
}
Packit Service 9f2c4a
Packit Service 9f2c4a
int main(int argc, const char *argv[])
Packit Service 9f2c4a
{
Packit Service 9f2c4a
    int opt;
Packit Service 9f2c4a
    poptContext pc;
Packit Service 9f2c4a
    int opt_interactive = 0;
Packit Service 9f2c4a
    int opt_version = 0;
Packit Service 9f2c4a
    int opt_debug = 0;
Packit Service 9f2c4a
    int opt_debug_level = 0;
Packit Service 9f2c4a
    verto_ctx *vctx;
Packit Service 9f2c4a
    verto_ev *ev;
Packit Service 9f2c4a
    int wait_fd;
Packit Service 9f2c4a
    int ret = -1;
Packit Service 9f2c4a
Packit Service 9f2c4a
    /* initialize debug client id to 0 in the main thread */
Packit Service 9f2c4a
    /* we do this early, before any code starts using debug statements */
Packit Service 9f2c4a
    gp_debug_set_conn_id(0);
Packit Service 9f2c4a
Packit Service 9f2c4a
    struct poptOption long_options[] = {
Packit Service 9f2c4a
        POPT_AUTOHELP
Packit Service 9f2c4a
        {"daemon", 'D', POPT_ARG_NONE, &opt_daemon, 0, \
Packit Service 9f2c4a
         _("Become a daemon (default)"), NULL }, \
Packit Service 9f2c4a
        {"interactive", 'i', POPT_ARG_NONE, &opt_interactive, 0, \
Packit Service 9f2c4a
         _("Run interactive (not a daemon)"), NULL}, \
Packit Service 9f2c4a
        {"config", 'c', POPT_ARG_STRING, &opt_config_file, 0, \
Packit Service 9f2c4a
         _("Specify a non-default config file"), NULL}, \
Packit Service 9f2c4a
        {"configdir", 'C', POPT_ARG_STRING, &opt_config_dir, 0, \
Packit Service 9f2c4a
         _("Specify a non-default config directory"), NULL}, \
Packit Service 9f2c4a
        {"socket", 's', POPT_ARG_STRING, &opt_config_socket, 0, \
Packit Service 9f2c4a
         _("Specify a custom default socket"), NULL}, \
Packit Service 9f2c4a
        {"debug", 'd', POPT_ARG_NONE, &opt_debug, 0, \
Packit Service 9f2c4a
         _("Enable debugging"), NULL}, \
Packit Service 9f2c4a
        {"debug-level", '\0', POPT_ARG_INT, &opt_debug_level, 0, \
Packit Service 9f2c4a
         _("Set debugging level"), NULL}, \
Packit Service 9f2c4a
        {"version", '\0', POPT_ARG_NONE, &opt_version, 0, \
Packit Service 9f2c4a
         _("Print version number and exit"), NULL }, \
Packit Service 9f2c4a
        POPT_TABLEEND
Packit Service 9f2c4a
    };
Packit Service 9f2c4a
Packit Service 9f2c4a
    pc = poptGetContext(argv[0], argc, argv, long_options, 0);
Packit Service 9f2c4a
    while((opt = poptGetNextOpt(pc)) != -1) {
Packit Service 9f2c4a
        switch(opt) {
Packit Service 9f2c4a
        default:
Packit Service 9f2c4a
            fprintf(stderr, "\nInvalid option %s: %s\n\n",
Packit Service 9f2c4a
                    poptBadOption(pc, 0), poptStrerror(opt));
Packit Service 9f2c4a
            poptPrintUsage(pc, stderr, 0);
Packit Service 9f2c4a
Packit Service 9f2c4a
            ret = 1;
Packit Service 9f2c4a
            goto cleanup;
Packit Service 9f2c4a
        }
Packit Service 9f2c4a
    }
Packit Service 9f2c4a
Packit Service 9f2c4a
    if (opt_version) {
Packit Service 9f2c4a
        puts(VERSION""DISTRO_VERSION""PRERELEASE_VERSION);
Packit Service 9f2c4a
        ret = 0;
Packit Service 9f2c4a
        goto cleanup;
Packit Service 9f2c4a
    }
Packit Service 9f2c4a
Packit Service 9f2c4a
    if (opt_debug || opt_debug_level > 0) {
Packit Service 9f2c4a
        if (opt_debug_level == 0) opt_debug_level = 1;
rpm-build cc42d0
        gp_debug_toggle(opt_debug_level);
Packit Service 9f2c4a
    }
Packit Service 9f2c4a
Packit Service 9f2c4a
    if (opt_daemon && opt_interactive) {
Packit Service 9f2c4a
        fprintf(stderr, "Option -i|--interactive is not allowed together with -D|--daemon\n");
Packit Service 9f2c4a
        poptPrintUsage(pc, stderr, 0);
Packit Service 9f2c4a
        ret = 0;
Packit Service 9f2c4a
        goto cleanup;
Packit Service 9f2c4a
    }
Packit Service 9f2c4a
Packit Service 9f2c4a
    if (opt_interactive) {
Packit Service 9f2c4a
        opt_daemon = 2;
Packit Service 9f2c4a
    }
Packit Service 9f2c4a
Packit Service 9f2c4a
    gpctx = calloc(1, sizeof(struct gssproxy_ctx));
Packit Service 9f2c4a
Packit Service 9f2c4a
    gpctx->config = read_config(opt_config_file,
Packit Service 9f2c4a
                                opt_config_dir,
Packit Service 9f2c4a
                                opt_config_socket,
Packit Service 9f2c4a
                                opt_daemon);
Packit Service 9f2c4a
    if (!gpctx->config) {
Packit Service 9f2c4a
        ret = EXIT_FAILURE;
Packit Service 9f2c4a
        goto cleanup;
Packit Service 9f2c4a
    }
Packit Service 9f2c4a
Packit Service 9f2c4a
    init_server(gpctx->config->daemonize, &wait_fd);
Packit Service 9f2c4a
Packit Service 9f2c4a
    write_pid();
Packit Service 9f2c4a
Packit Service 9f2c4a
    vctx = init_event_loop();
Packit Service 9f2c4a
    if (!vctx) {
Packit Service 9f2c4a
        fprintf(stderr, "Failed to initialize event loop. "
Packit Service 9f2c4a
                        "Is there at least one libverto backend installed?\n");
Packit Service 9f2c4a
        ret = 1;
Packit Service 9f2c4a
        goto cleanup;
Packit Service 9f2c4a
    }
Packit Service 9f2c4a
    gpctx->vctx = vctx;
Packit Service 9f2c4a
Packit Service 9f2c4a
    /* Add SIGHUP here so that gpctx is in scope for the handler */
Packit Service 9f2c4a
    ev = verto_add_signal(vctx, VERTO_EV_FLAG_PERSIST, hup_handler, SIGHUP);
Packit Service 9f2c4a
    if (!ev) {
Packit Service 9f2c4a
        fprintf(stderr, "Failed to register SIGHUP handler with verto!\n");
Packit Service 9f2c4a
        ret = 1;
Packit Service 9f2c4a
        goto cleanup;
Packit Service 9f2c4a
    }
Packit Service 9f2c4a
Packit Service 9f2c4a
    ret = init_sockets(vctx, NULL);
Packit Service 9f2c4a
    if (ret != 0) {
Packit Service 9f2c4a
        goto cleanup;
Packit Service 9f2c4a
    }
Packit Service 9f2c4a
Packit Service 9f2c4a
    /* We need to tell nfsd that GSS-Proxy is available before it starts,
Packit Service 9f2c4a
     * as nfsd needs to know GSS-Proxy is in use before the first time it
Packit Service 9f2c4a
     * needs to call accept_sec_context. */
Packit Service 9f2c4a
    init_proc_nfsd(gpctx->config);
Packit Service 9f2c4a
Packit Service 9f2c4a
    /* Now it is safe to tell the init system that we're done starting up,
Packit Service 9f2c4a
     * so it can continue with dependencies and start nfsd */
Packit Service 9f2c4a
    init_done(wait_fd);
Packit Service 9f2c4a
Packit Service 9f2c4a
    ret = drop_privs(gpctx->config);
Packit Service 9f2c4a
    if (ret) {
Packit Service 9f2c4a
        ret = EXIT_FAILURE;
Packit Service 9f2c4a
        goto cleanup;
Packit Service 9f2c4a
    }
Packit Service 9f2c4a
Packit Service 9f2c4a
    ret = gp_workers_init(gpctx);
Packit Service 9f2c4a
    if (ret) {
Packit Service 9f2c4a
        ret = EXIT_FAILURE;
Packit Service 9f2c4a
        goto cleanup;
Packit Service 9f2c4a
    }
Packit Service 9f2c4a
Packit Service 9f2c4a
    verto_run(vctx);
Packit Service 9f2c4a
    verto_free(vctx);
Packit Service 9f2c4a
Packit Service 9f2c4a
    gp_workers_free(gpctx->workers);
Packit Service 9f2c4a
Packit Service 9f2c4a
    fini_server();
Packit Service 9f2c4a
Packit Service 9f2c4a
Packit Service 9f2c4a
    free_config(&gpctx->config);
Packit Service 9f2c4a
    free(gpctx);
Packit Service 9f2c4a
Packit Service 9f2c4a
    ret = 0;
Packit Service 9f2c4a
Packit Service 9f2c4a
cleanup:
Packit Service 9f2c4a
    poptFreeContext(pc);
Packit Service 9f2c4a
    free(opt_config_file);
Packit Service 9f2c4a
    free(opt_config_dir);
Packit Service 9f2c4a
    free(opt_config_socket);
Packit Service 9f2c4a
Packit Service 9f2c4a
#ifdef HAVE_VERTO_CLEANUP
Packit Service 9f2c4a
    verto_cleanup();
Packit Service 9f2c4a
#endif
Packit Service 9f2c4a
Packit Service 9f2c4a
    return ret;
Packit Service 9f2c4a
}