int open_config() { FILE *fp = NULL; char *line; key_cmd *cmd; confentry *lastnode = NULL, *newnode = NULL; int lineno = 1, ret = 0; size_t n = 0; /* Allow the configuration file to be overridden */ if (!config) config = CONFIG; fp = fopen(config, "r"); if (fp == NULL) { lprintf("Warning: could not open the configuration file %s: %s\n", config, strerror(errno)); return OK; } if (verbose > 1) lprintf("Using configuration file %s\n", config); while (!feof(fp) && (ret >=0)) { line = NULL; ret = getline(&line, &n, fp); if ((ret > 0) && (proc_config(lineno, line, &cmd) == OK)) { newnode = (confentry *)(malloc(sizeof(confentry))); if (newnode == NULL) { lprintf("Error: memory allocation failed\n"); close_config(); free(line); return MEMERR; } newnode->cmd = cmd; newnode->next = NULL; if (list == NULL) { list = newnode; } else { lastnode->next = newnode; } lastnode = newnode; if (verbose > 1) { lprintf("Config: "); lprint_mask(cmd->keys); lprintf(" -:- "); print_etype(cmd->type); lprintf(" -:- "); print_attrs(cmd); lprintf(" -:- %s\n", cmd->command); } } free(line); ++lineno; } fclose(fp); return OK; }
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); }