static int __ini_handler(void *u, const char *section, const char *name, const char *val) { struct duo_config *cfg = (struct duo_config *)u; if (!duo_common_ini_handler(cfg, section, name, val)) { /* Extra login_duo options */ if (strcmp(name, "motd") == 0) { cfg->motd = duo_set_boolean_option(val); } else { fprintf(stderr, "Invalid login_duo option: '%s'\n", name); return (0); } } return (1); }
int duo_common_ini_handler(struct duo_config *cfg, const char *section, const char *name, const char*val) { char *buf, *p; int int_val; if (strcmp(name, "ikey") == 0) { cfg->ikey = strdup(val); } else if (strcmp(name, "skey") == 0) { cfg->skey = strdup(val); } else if (strcmp(name, "host") == 0) { cfg->apihost = strdup(val); } else if (strcmp(name, "cafile") == 0) { cfg->cafile = strdup(val); } else if (strcmp(name, "http_proxy") == 0) { cfg->http_proxy = strdup(val); } else if (strcmp(name, "groups") == 0 || strcmp(name, "group") == 0) { if ((buf = strdup(val)) == NULL) { fprintf(stderr, "Out of memory parsing groups\n"); return (0); } for (p = strtok(buf, " "); p != NULL; p = strtok(NULL, " ")) { if (cfg->groups_cnt >= MAX_GROUPS) { fprintf(stderr, "Exceeded max %d groups\n", MAX_GROUPS); cfg->groups_cnt = 0; free(buf); return (0); } cfg->groups[cfg->groups_cnt++] = p; } } else if (strcmp(name, "failmode") == 0) { if (strcmp(val, "secure") == 0) { cfg->failmode = DUO_FAIL_SECURE; } else if (strcmp(val, "safe") == 0) { cfg->failmode = DUO_FAIL_SAFE; } else { fprintf(stderr, "Invalid failmode: '%s'\n", val); return (0); } } else if (strcmp(name, "pushinfo") == 0) { cfg->pushinfo = duo_set_boolean_option(val); } else if (strcmp(name, "noverify") == 0) { cfg->noverify = duo_set_boolean_option(val); } else if (strcmp(name, "prompts") == 0) { int_val = atoi(val); /* Clamp the value into acceptable range */ if (int_val <= 0) { int_val = 1; } else if (int_val < cfg->prompts) { cfg->prompts = int_val; } } else if (strcmp(name, "autopush") == 0) { cfg->autopush = duo_set_boolean_option(val); } else if (strcmp(name, "accept_env_factor") == 0) { cfg->accept_env = duo_set_boolean_option(val); } else if (strcmp(name, "fallback_local_ip") == 0) { cfg->local_ip_fallback = duo_set_boolean_option(val); } else if (strcmp(name, "https_timeout") == 0) { cfg->https_timeout = atoi(val); if (cfg->https_timeout <= 0) { cfg->https_timeout = -1; /* no timeout */ } else { /* Make timeout milliseconds */ cfg->https_timeout *= 1000; } } else if (strcmp(name, "send_gecos") == 0) { cfg->send_gecos = duo_set_boolean_option(val); } else if (strcmp(name, "gecos_parsed") == 0) { duo_log(LOG_ERR, "The gecos_parsed configuration item for Duo Unix is deprecated and no longer has any effect. Use gecos_delim and gecos_username_pos instead", NULL, NULL, NULL); } else if (strcmp(name, "gecos_delim") == 0) { if (strlen(val) != 1) { fprintf(stderr, "Invalid character option length. Character fields must be 1 character long: '%s'\n", val); return (0); } char delim = val[0]; if (!ispunct(delim) || delim == ':') { fprintf(stderr, "Invalid gecos_delim '%c' (delimiter must be punctuation other than ':')\n", delim); return (0); } cfg->gecos_delim = delim; } else if (strcmp(name, "gecos_username_pos") == 0) { int gecos_username_pos = atoi(val); if (gecos_username_pos < 1) { fprintf(stderr, "Gecos position starts at 1\n"); return (0); } else { // Offset the position so user facing first position is 1 cfg->gecos_username_pos = gecos_username_pos - 1; } } else if (strcmp(name, "dev_fips_mode") == 0) { /* This flag is for development */ cfg->fips_mode = duo_set_boolean_option(val); } else { /* Couldn't handle the option, maybe it's target specific? */ return (0); } return (1); }