示例#1
0
static int
do_auth(struct login_ctx *ctx, const char *cmd)
{
    struct duo_config cfg;
    struct passwd *pw;
    struct in_addr addr;
    duo_t *duo;
    duo_code_t code;
    const char *config, *p, *duouser;
    const char *ip, *host = NULL;
    char buf[64];
    int i, flags, ret, prompts, matched;
    int headless = 0;

        if ((pw = getpwuid(ctx->uid)) == NULL)
                die("Who are you?");
        
    duouser = ctx->duouser ? ctx->duouser : pw->pw_name;
    config = ctx->config ? ctx->config : DUO_CONF;
    flags = 0;
    
    duo_config_default(&cfg);
        
    /* Load our private config. */
    if ((i = duo_parse_config(config, __ini_handler, &cfg)) != 0 ||
            (!cfg.apihost || !cfg.apihost[0] || !cfg.skey || !cfg.skey[0] ||
                !cfg.ikey || !cfg.ikey[0])) {
                switch (i) {
                case -2:
                        fprintf(stderr, "%s must be readable only by "
                            "user '%s'\n", config, pw->pw_name);
                        break;
                case -1:
                        fprintf(stderr, "Couldn't open %s: %s\n",
                            config, strerror(errno));
                        break;
                case 0:
                        fprintf(stderr, "Missing host, ikey, or skey in %s\n",
                            config);
                        break;
                default:
                        fprintf(stderr, "Parse error in %s, line %d\n",
                            config, i);
                        break;
                }
                /* Implicit "safe" failmode for local configuration errors */
                if (cfg.failmode == DUO_FAIL_SAFE) {
                        return (EXIT_SUCCESS);
                }
                return (EXIT_FAILURE);
    }
    prompts = cfg.prompts;
    /* Check group membership. */
    matched = duo_check_groups(pw, cfg.groups, cfg.groups_cnt);
    if (matched == -1) {
        return (EXIT_FAILURE);
    } else if (matched == 0) {
        return (EXIT_SUCCESS);
    }


    /* Check for remote login host */
    if ((host = ip = getenv("SSH_CONNECTION")) != NULL ||
        (host = ip = (char *)ctx->host) != NULL) {
        if (inet_aton(ip, &addr)) {
            strlcpy(buf, ip, sizeof(buf));
            ip = strtok(buf, " ");
            host = ip;
        } else {
            ip = (cfg.local_ip_fallback ? duo_local_ip() : NULL);
        }
    }

    /* Honor configured http_proxy */
    if (cfg.http_proxy != NULL) {
        setenv("http_proxy", cfg.http_proxy, 1);
    }

    /* Try Duo auth. */
    if ((duo = duo_open(cfg.apihost, cfg.ikey, cfg.skey,
                    "login_duo/" PACKAGE_VERSION,
                    cfg.noverify ? "" : cfg.cafile,
                    cfg.https_timeout)) == NULL) {
        duo_log(LOG_ERR, "Couldn't open Duo API handle",
            pw->pw_name, host, NULL);
        return (EXIT_FAILURE);
    }

    /* Special handling for non-interactive sessions */
    if ((p = getenv("SSH_ORIGINAL_COMMAND")) != NULL ||
        !isatty(STDIN_FILENO)) {
        /* Try to support automatic one-shot login */
        duo_set_conv_funcs(duo, NULL, NULL, NULL);
        flags = (DUO_FLAG_SYNC|DUO_FLAG_AUTO);
        prompts = 1;
        headless = 1;
    } else if (cfg.autopush) { /* Special handling for autopush */
        duo_set_conv_funcs(duo, NULL, __autopush_status_fn, 
                NULL);
        flags = (DUO_FLAG_SYNC|DUO_FLAG_AUTO);
    }

    if (cfg.accept_env) {
        flags |= DUO_FLAG_ENV;
    }

    ret = EXIT_FAILURE;
    
    for (i = 0; i < prompts; i++) {
        code = duo_login(duo, duouser, host, flags,
                    cfg.pushinfo ? cmd : NULL);
        if (code == DUO_FAIL) {
            duo_log(LOG_WARNING, "Failed Duo login",
                duouser, host, duo_geterr(duo));
            if ((flags & DUO_FLAG_SYNC) == 0) {
                printf("\n");
            }
            /* The autopush failed, fall back to regular process */
            if (cfg.autopush && i == 0) {
                flags = 0;
                duo_reset_conv_funcs(duo);
            }
            /* Keep going */
            continue;
        }
        /* Terminal conditions */
        if (code == DUO_OK) {
            if ((p = duo_geterr(duo)) != NULL) {
                duo_log(LOG_WARNING, "Skipped Duo login",
                    duouser, host, p);
            } else {
                duo_log(LOG_INFO, "Successful Duo login",
                    duouser, host, NULL);
            }
            if (cfg.motd && !headless) {
                _print_motd();
            }
            ret = EXIT_SUCCESS;
        } else if (code == DUO_ABORT) {
            duo_log(LOG_WARNING, "Aborted Duo login",
                duouser, host, duo_geterr(duo));
        } else if (cfg.failmode == DUO_FAIL_SAFE &&
                    (code == DUO_CONN_ERROR ||
                     code == DUO_CLIENT_ERROR || code == DUO_SERVER_ERROR)) {
            duo_log(LOG_WARNING, "Failsafe Duo login",
                duouser, host, duo_geterr(duo));
                        ret = EXIT_SUCCESS;
        } else {
            duo_log(LOG_ERR, "Error in Duo login",
                duouser, host, duo_geterr(duo));
        }
        break;
    }
    duo_close(duo);

    return (ret);
}
示例#2
0
static int
do_auth(struct login_ctx *ctx, const char *cmd)
{
    struct duo_config cfg;
    struct passwd *pw;
    struct in_addr addr;
    duo_t *duo;
    duo_code_t code;
    const char *config, *p, *duouser;
    const char *ip, *host = NULL;
    char buf[64];
    int i, flags, ret, prompts, matched;
    int headless = 0;

    if ((pw = getpwuid(ctx->uid)) == NULL) {
        die("Who are you?");
    }

    duouser = ctx->duouser ? ctx->duouser : pw->pw_name;
    config = ctx->config ? ctx->config : DUO_CONF;
    flags = 0;

    duo_config_default(&cfg);

    /* Load our private config. */
    if ((i = duo_parse_config(config, __ini_handler, &cfg)) != 0 ||
            (!cfg.apihost || !cfg.apihost[0] || !cfg.skey || !cfg.skey[0] ||
                !cfg.ikey || !cfg.ikey[0])) {
        switch (i) {
        case -2:
            fprintf(stderr, "%s must be readable only by "
                "user '%s'\n", config, pw->pw_name);
            break;
        case -1:
            fprintf(stderr, "Couldn't open %s: %s\n",
                config, strerror(errno));
            break;
        case 0:
            fprintf(stderr, "Missing host, ikey, or skey in %s\n",
                config);
            break;
        default:
            fprintf(stderr, "Parse error in %s, line %d\n",
                config, i);
            break;
        }
        /* Implicit "safe" failmode for local configuration errors */
        if (cfg.failmode == DUO_FAIL_SAFE) {
            return (EXIT_SUCCESS);
        }
        return (EXIT_FAILURE);
    }
    

#ifdef OPENSSL_FIPS
    /*
     * When fips_mode is configured, invoke OpenSSL's FIPS_mode_set() API. Note
     * that in some environments, FIPS may be enabled system-wide, causing FIPS
     * operation to be enabled automatically when OpenSSL is initialized.  The
     * fips_mode option is an experimental feature allowing explicit entry to FIPS
     * operation in cases where it isn't enabled globally at the OS level (for
     * example, when integrating directly with the OpenSSL FIPS Object Module).
     */
    if(!FIPS_mode_set(cfg.fips_mode)) {
        /* The smallest size buff can be according to the openssl docs */ 
        char buff[256];
        int error = ERR_get_error();
        ERR_error_string_n(error, buff, sizeof(buff));
        duo_syslog(LOG_ERR, "Unable to start fips_mode: %s", buff);
	 
       return (EXIT_FAILURE);
    }
#else
    if(cfg.fips_mode) {
        duo_syslog(LOG_ERR, "FIPS mode flag specified, but OpenSSL not built with FIPS support. Failing the auth.");
        return (EXIT_FAILURE);
    }
#endif

    prompts = cfg.prompts;
    /* Check group membership. */
    matched = duo_check_groups(pw, cfg.groups, cfg.groups_cnt);
    if (matched == -1) {
        close_config(&cfg);
        return (EXIT_FAILURE);
    } else if (matched == 0) {
        close_config(&cfg);
        return (EXIT_SUCCESS);
    }

    /* Use GECOS field if called for */
    if ((cfg.send_gecos || cfg.gecos_username_pos >= 0) && !ctx->duouser) {
        if (strlen(pw->pw_gecos) > 0) {
            if (cfg.gecos_username_pos >= 0) {
                duouser = duo_split_at(pw->pw_gecos, cfg.gecos_delim, cfg.gecos_username_pos);
                if (duouser == NULL || (strcmp(duouser, "") == 0)) {
                    duo_log(LOG_DEBUG, "Could not parse GECOS field", pw->pw_name, NULL, NULL);
                    duouser = pw->pw_name;
                }
            } else {
                duouser = pw->pw_gecos;
            }
        } else {
            duo_log(LOG_WARNING, "Empty GECOS field", pw->pw_name, NULL, NULL);
        }
    }

    /* Check for remote login host */
    if ((host = ip = getenv("SSH_CONNECTION")) != NULL ||
        (host = ip = (char *)ctx->host) != NULL) {
        if (inet_aton(ip, &addr)) {
            strlcpy(buf, ip, sizeof(buf));
            ip = strtok(buf, " ");
            host = ip;
        } else {
            if (cfg.local_ip_fallback) {
                host = duo_local_ip();
            }
        }
    }

    /* Try Duo auth. */
    if ((duo = duo_open(cfg.apihost, cfg.ikey, cfg.skey,
                    "login_duo/" PACKAGE_VERSION,
                    cfg.noverify ? "" : cfg.cafile,
                    cfg.https_timeout, cfg.http_proxy)) == NULL) {
        duo_log(LOG_ERR, "Couldn't open Duo API handle",
            pw->pw_name, host, NULL);
        close_config(&cfg);
        return (EXIT_FAILURE);
    }

    /* Special handling for non-interactive sessions */
    if ((p = getenv("SSH_ORIGINAL_COMMAND")) != NULL ||
        !isatty(STDIN_FILENO)) {
        /* Try to support automatic one-shot login */
        duo_set_conv_funcs(duo, NULL, NULL, NULL);
        flags = (DUO_FLAG_SYNC|DUO_FLAG_AUTO);
        prompts = 1;
        headless = 1;
    } else if (cfg.autopush) { /* Special handling for autopush */
        duo_set_conv_funcs(duo, NULL, __autopush_status_fn, NULL);
        flags = (DUO_FLAG_SYNC|DUO_FLAG_AUTO);
    }

    if (cfg.accept_env) {
        flags |= DUO_FLAG_ENV;
    }

    ret = EXIT_FAILURE;

    for (i = 0; i < prompts; i++) {
        code = duo_login(duo, duouser, host, flags,
                    cfg.pushinfo ? cmd : NULL, cfg.failmode);
        if (code == DUO_FAIL) {
            duo_log(LOG_WARNING, "Failed Duo login",
                duouser, host, duo_geterr(duo));
            if ((flags & DUO_FLAG_SYNC) == 0) {
                printf("\n");
            }
            /* The autopush failed, fall back to regular process */
            if (cfg.autopush && i == 0) {
                flags = 0;
                duo_reset_conv_funcs(duo);
            }
            /* Keep going */
            continue;
        }
        /* Terminal conditions */
        if (code == DUO_OK) {
            if ((p = duo_geterr(duo)) != NULL) {
                duo_log(LOG_WARNING, "Skipped Duo login",
                    duouser, host, p);
            } else {
                duo_log(LOG_INFO, "Successful Duo login",
                    duouser, host, NULL);
            }
            if (cfg.motd && !headless) {
                _print_motd();
            }
            ret = EXIT_SUCCESS;
        } else if (code == DUO_ABORT) {
            duo_log(LOG_WARNING, "Aborted Duo login",
                duouser, host, duo_geterr(duo));
        } else if (code == DUO_FAIL_SAFE_ALLOW) {
            duo_log(LOG_WARNING, "Failsafe Duo login",
                duouser, host, duo_geterr(duo));
                        ret = EXIT_SUCCESS;
        } else if (code == DUO_FAIL_SECURE_DENY) {
            duo_log(LOG_WARNING, "Failsecure Duo login",
                duouser, host, duo_geterr(duo));
        } else {
            duo_log(LOG_ERR, "Error in Duo login",
                duouser, host, duo_geterr(duo));
        }
        break;
    }
    duo_close(duo);
    close_config(&cfg);

    return (ret);
}