int DBUtil::Init(const char* conffile, const char* dbsection, const char* logsection) { SQL_INST* sqlinst = NULL; // free previous instance first Free(); // init sql module rlm_sql_init(); // read conf file CONF_SECTION *conf; conf = conf_read(__FILE__, __LINE__, conffile, NULL); if(!conf) { radlog(L_CONS|L_ERROR, "[DBUtil::DBUtil] can not read '%s'", conffile); rlm_sql_destroy(); return -1; } // get db section CONF_SECTION* sqlconf = cf_section_sub_find(conf, dbsection); if(!sqlconf) { radlog(L_CONS|L_ERROR, "[DBUtil::DBUtil] can not find sub section '%s'", dbsection); cf_section_free(&conf); rlm_sql_destroy(); return -1; } // get log section if present CONF_SECTION* logconf = NULL; if(logsection) { logconf = cf_section_sub_find(conf, logsection); if(!logconf) { radlog(L_CONS|L_WARN, "[DBUtil::DBUtil] can not find sub section '%s', " "no logging parameters would be applied to rlm_sql. This may be " "a problem when using rlm_sql with dynamic loading sql_drivers", logsection); } } // get sql instance if(rlm_sql_instantiate(sqlconf, &sqlinst, logconf) != 0) { radlog(L_CONS|L_ERROR, "[DBUtil::DBUtil] can not instantiate sql instance"); cf_section_free(&conf); rlm_sql_destroy(); return -1; } // free conf section cf_section_free(&conf); dbHandle_ = sqlinst; return 0; }
static int parse_sub_section(CONF_SECTION *parent, rlm_sql_t *inst, sql_acct_section_t **config, rlm_components_t comp) { CONF_SECTION *cs; char const *name = section_type_value[comp].section; cs = cf_section_sub_find(parent, name); if (!cs) { INFO("rlm_sql (%s): Couldn't find configuration for " "%s, will return NOOP for calls from this section", inst->config->xlat_name, name); return 0; } *config = talloc_zero(parent, sql_acct_section_t); if (cf_section_parse(cs, *config, acct_section_config) < 0) { ERROR("rlm_sql (%s): Couldn't find configuration for " "%s, will return NOOP for calls from this section", inst->config->xlat_name, name); return -1; } (*config)->cs = cs; return 0; }
/** Parse an accounting sub section. * * Allocate a new ldap_acct_section_t and write the config data into it. * * @param[in] inst rlm_ldap configuration. * @param[in] parent of the config section. * @param[out] config to write the sub section parameters to. * @param[in] comp The section name were parsing the config for. * @return 0 on success, else < 0 on failure. */ static int parse_sub_section(ldap_instance_t *inst, CONF_SECTION *parent, ldap_acct_section_t **config, rlm_components_t comp) { CONF_SECTION *cs; char const *name = section_type_value[comp].section; cs = cf_section_sub_find(parent, name); if (!cs) { INFO("rlm_ldap (%s): Couldn't find configuration for %s, will return NOOP for calls " "from this section", inst->xlat_name, name); return 0; } *config = talloc_zero(inst, ldap_acct_section_t); if (cf_section_parse(cs, *config, acct_section_config) < 0) { LDAP_ERR("Failed parsing configuration for section %s", name); return -1; } (*config)->cs = cs; return 0; }
static int parse_sub_section(CONF_SECTION *parent, UNUSED SQL_INST *instance, rlm_sql_config_section_t *config, rlm_components_t comp) { CONF_SECTION *cs; const char *name = section_type_value[comp].section; cs = cf_section_sub_find(parent, name); if (!cs) { radlog(L_INFO, "Couldn't find configuration for %s. Will return NOOP for calls from this section.", name); return 1; } if (cf_section_parse(cs, config, section_config) < 0) { radlog(L_ERR, "Failed parsing configuration for section %s", name); return -1; } config->cs = cs; return 1; }
static int parse_sub_section(CONF_SECTION *parent, rlm_rest_section_t *config, rlm_components_t comp) { CONF_SECTION *cs; char const *name = section_type_value[comp].section; cs = cf_section_sub_find(parent, name); if (!cs) { /* TODO: Should really setup section with default values */ return 0; } if (cf_section_parse(cs, config, section_config) < 0) { return -1; } /* * Add section name (Maybe add to headers later?). */ config->name = name; /* * Convert HTTP method auth and body type strings into their * integer equivalents. */ config->auth = fr_str2int(http_auth_table, config->auth_str, HTTP_AUTH_UNKNOWN); if (config->auth == HTTP_AUTH_UNKNOWN) { cf_log_err_cs(cs, "Unknown HTTP auth type '%s'", config->auth_str); return -1; } else if ((config->auth != HTTP_AUTH_NONE) && !http_curl_auth[config->auth]) { cf_log_err_cs(cs, "Unsupported HTTP auth type \"%s\"" ", check libcurl version, OpenSSL build configuration," " then recompile this module", config->auth_str); return -1; } config->method = fr_str2int(http_method_table, config->method_str, HTTP_METHOD_CUSTOM); config->body = fr_str2int(http_body_type_table, config->body_str, HTTP_BODY_UNKNOWN); if (config->body == HTTP_BODY_UNKNOWN) { cf_log_err_cs(cs, "Unknown HTTP body type '%s'", config->body_str); return -1; } if (http_body_type_supported[config->body] == HTTP_BODY_UNSUPPORTED) { cf_log_err_cs(cs, "Unsupported HTTP body type \"%s\"" ", please submit patches", config->body_str); return -1; } return 1; }
void main_config_hup(void) { cached_config_t *cc; CONF_SECTION *cs; char buffer[1024]; INFO("HUP - Re-reading configuration files"); /* Read the configuration file */ snprintf(buffer, sizeof(buffer), "%.200s/%.50s.conf", radius_dir, main_config.name); if ((cs = cf_file_read(buffer)) == NULL) { ERROR("Failed to re-read or parse %s", buffer); return; } cc = talloc_zero(cs_cache, cached_config_t); if (!cc) { ERROR("Out of memory"); return; } /* * Save the current configuration. Note that we do NOT * free older ones. We should probably do so at some * point. Doing so will require us to mark which modules * are still in use, and which aren't. Modules that * can't be HUPed always use the original configuration. * Modules that can be HUPed use one of the newer * configurations. */ cc->created = time(NULL); cc->cs = talloc_steal(cc, cs); cc->next = cs_cache; cs_cache = cc; /* * Re-open the log file. If we can't, then keep logging * to the old log file. * * The "open log file" code is here rather than in log.c, * because it makes that function MUCH simpler. */ hup_logfile(); INFO("HUP - loading modules"); /* * Prefer the new module configuration. */ modules_hup(cf_section_sub_find(cs, "modules")); /* * Load new servers BEFORE freeing old ones. */ virtual_servers_load(cs); virtual_servers_free(cc->created - main_config.max_request_time * 4); }
/** Build a JSON object map from the configuration "map" section * * Parse the "map" section from the module configuration file and store this * as a JSON object (key/value list) in the module instance. This map will be * used to lookup and map attributes for all incoming accounting requests. * * @param conf Configuration section. * @param instance The module instance. * @return Returns 0 on success, -1 on error. */ int mod_build_attribute_element_map(CONF_SECTION *conf, void *instance) { rlm_couchbase_t *inst = instance; /* our module instance */ CONF_SECTION *cs; /* module config section */ CONF_ITEM *ci; /* config item */ CONF_PAIR *cp; /* conig pair */ const char *attribute, *element; /* attribute and element names */ /* find map section */ cs = cf_section_sub_find(conf, "map"); /* check section */ if (!cs) { ERROR("rlm_couchbase: failed to find 'map' section in config"); /* fail */ return -1; } /* create attribute map object */ inst->map = json_object_new_object(); /* parse update section */ for (ci = cf_item_find_next(cs, NULL); ci != NULL; ci = cf_item_find_next(cs, ci)) { /* validate item */ if (!cf_item_is_pair(ci)) { ERROR("rlm_couchbase: failed to parse invalid item in 'map' section"); /* free map */ if (inst->map) { json_object_put(inst->map); } /* fail */ return -1; } /* get value pair from item */ cp = cf_itemtopair(ci); /* get pair name (element name) */ element = cf_pair_attr(cp); /* get pair value (attribute name) */ attribute = cf_pair_value(cp); /* add pair name and value */ json_object_object_add(inst->map, attribute, json_object_new_string(element)); /* debugging */ DEBUG("rlm_couchbase: added attribute '%s' to element '%s' map to object", attribute, element); } /* debugging */ DEBUG("rlm_couchbase: built attribute to element map %s", json_object_to_json_string(inst->map)); /* return */ return 0; }
static int rediswho_accounting(void * instance, REQUEST * request) { int rcode; VALUE_PAIR * vp; DICT_VALUE *dv; CONF_SECTION *cs; const char *insert, *trim, *expire; rlm_rediswho_t *inst = (rlm_rediswho_t *) instance; REDISSOCK *dissocket; vp = pairfind(request->packet->vps, PW_ACCT_STATUS_TYPE, 0, TAG_ANY); if (!vp) { RDEBUG("Could not find account status type in packet."); return RLM_MODULE_NOOP; } dv = dict_valbyattr(vp->attribute, vp->vendor, vp->vp_integer); if (!dv) { RDEBUG("Unknown Acct-Status-Type %u", vp->vp_integer); return RLM_MODULE_NOOP; } cs = cf_section_sub_find(inst->cs, dv->name); if (!cs) { RDEBUG("No subsection %s", dv->name); return RLM_MODULE_NOOP; } dissocket = fr_connection_get(inst->redis_inst->pool); if (!dissocket) { RDEBUG("cannot allocate redis connection"); return RLM_MODULE_FAIL; } insert = cf_pair_value(cf_pair_find(cs, "insert")); trim = cf_pair_value(cf_pair_find(cs, "trim")); expire = cf_pair_value(cf_pair_find(cs, "expire")); rcode = rediswho_accounting_all(&dissocket, inst, request, insert, trim, expire); if (dissocket) fr_connection_release(inst->redis_inst->pool, dissocket); return rcode; }
void hup_mainconfig(void) { cached_config_t *cc; CONF_SECTION *cs; char buffer[1024]; /* Read the configuration file */ snprintf(buffer, sizeof(buffer), "%.200s/%.50s.conf", radius_dir, mainconfig.name); if ((cs = cf_file_read(buffer)) == NULL) { radlog(L_ERR, "Failed to re-read %s", buffer); return; } cc = rad_malloc(sizeof(*cc)); memset(cc, 0, sizeof(*cc)); /* * Save the current configuration. Note that we do NOT * free older ones. We should probably do so at some * point. Doing so will require us to mark which modules * are still in use, and which aren't. Modules that * can't be HUPed always use the original configuration. * Modules that can be HUPed use one of the newer * configurations. */ cc->created = time(NULL); cc->cs = cs; cc->next = cs_cache; cs_cache = cc; /* * Prefer the new module configuration. */ module_hup(cf_section_sub_find(cs, "modules")); /* * Load new servers BEFORE freeing old ones. */ virtual_servers_load(cs); virtual_servers_free(cc->created - mainconfig.max_request_time * 4); }
/* * Read a client definition from the given filename. */ RADCLIENT *client_read(char const *filename, int in_server, int flag) { char const *p; RADCLIENT *c; CONF_SECTION *cs; char buffer[256]; if (!filename) return NULL; cs = cf_file_read(filename); if (!cs) return NULL; cs = cf_section_sub_find(cs, "client"); if (!cs) { ERROR("No \"client\" section found in client file"); return NULL; } c = client_parse(cs, in_server); if (!c) return NULL; p = strrchr(filename, FR_DIR_SEP); if (p) { p++; } else { p = filename; } if (!flag) return c; /* * Additional validations */ ip_ntoh(&c->ipaddr, buffer, sizeof(buffer)); if (strcmp(p, buffer) != 0) { DEBUG("Invalid client definition in %s: IP address %s does not match name %s", filename, buffer, p); client_free(c); return NULL; } return c; }
static rlm_rcode_t CC_HINT(nonnull) mod_accounting(void * instance, REQUEST * request) { rlm_rcode_t rcode; VALUE_PAIR * vp; DICT_VALUE *dv; CONF_SECTION *cs; rlm_rediswho_t *inst = (rlm_rediswho_t *) instance; REDISSOCK *dissocket; vp = pairfind(request->packet->vps, PW_ACCT_STATUS_TYPE, 0, TAG_ANY); if (!vp) { RDEBUG("Could not find account status type in packet"); return RLM_MODULE_NOOP; } dv = dict_valbyattr(vp->da->attr, vp->da->vendor, vp->vp_integer); if (!dv) { RDEBUG("Unknown Acct-Status-Type %u", vp->vp_integer); return RLM_MODULE_NOOP; } cs = cf_section_sub_find(inst->cs, dv->name); if (!cs) { RDEBUG("No subsection %s", dv->name); return RLM_MODULE_NOOP; } dissocket = fr_connection_get(inst->redis_inst->pool); if (!dissocket) return RLM_MODULE_FAIL; rcode = mod_accounting_all(&dissocket, inst, request); if (dissocket) fr_connection_release(inst->redis_inst->pool, dissocket); return rcode; }
/* * Parse TLS configuration * * If the option given by 'attr' is set, we find the config section * of that name and use that for the TLS configuration. If not, we * fall back to compatibility mode and read the TLS options from * the 'tls' section. */ fr_tls_server_conf_t *eaptls_conf_parse(CONF_SECTION *cs, char const *attr) { char const *tls_conf_name; CONF_PAIR *cp; CONF_SECTION *parent; CONF_SECTION *tls_cs; fr_tls_server_conf_t *tls_conf; if (!cs) return NULL; rad_assert(attr != NULL); parent = cf_item_parent(cf_section_to_item(cs)); cp = cf_pair_find(cs, attr); if (cp) { tls_conf_name = cf_pair_value(cp); tls_cs = cf_section_sub_find_name2(parent, TLS_CONFIG_SECTION, tls_conf_name); if (!tls_cs) { ERROR("Cannot find tls config \"%s\"", tls_conf_name); return NULL; } } else { /* * If we can't find the section given by the 'attr', we * fall-back to looking for the "tls" section, as in * previous versions. * * We don't fall back if the 'attr' is specified, but we can't * find the section - that is just a config error. */ INFO("TLS section \"%s\" missing, trying to use legacy configuration", attr); tls_cs = cf_section_sub_find(parent, "tls"); } if (!tls_cs) return NULL; tls_conf = tls_server_conf_parse(tls_cs); if (!tls_conf) return NULL; /* * The EAP RFC's say 1020, but we're less picky. */ if (tls_conf->fragment_size < 100) { ERROR("Configured fragment size is too small, must be >= 100"); return NULL; } /* * The maximum size for a RADIUS packet is 4096, * minus the header (20), Message-Authenticator (18), * and State (18), etc. results in about 4000 bytes of data * that can be devoted *solely* to EAP. */ if (tls_conf->fragment_size > 4000) { ERROR("Configured fragment size is too large, must be <= 4000"); return NULL; } /* * Account for the EAP header (4), and the EAP-TLS header * (6), as per Section 4.2 of RFC 2716. What's left is * the maximum amount of data we read from a TLS buffer. */ tls_conf->fragment_size -= 10; return tls_conf; }
int rlm_ldap_map_verify(ldap_instance_t *inst, value_pair_map_t **head) { value_pair_map_t *map; if (radius_attrmap(cf_section_sub_find(inst->cs, "update"), head, PAIR_LIST_REPLY, PAIR_LIST_REQUEST, LDAP_MAX_ATTRMAP) < 0) { return -1; } /* * Attrmap only performs some basic validation checks, we need * to do rlm_ldap specific checks here. */ for (map = *head; map != NULL; map = map->next) { switch (map->dst->type) { case VPT_TYPE_LIST: if (map->op != T_OP_ADD) { cf_log_err(map->ci, "Only '+=' operator is permitted for valuepair to list mapping"); return -1; } case VPT_TYPE_ATTR: break; default: cf_log_err(map->ci, "valuepair destination must be an attribute or list"); return -1; } switch (map->src->type) { case VPT_TYPE_LIST: cf_log_err(map->ci, "LDAP attribute name cannot be derived from a list"); return -1; default: break; } /* * Be smart about whether we warn the user about missing passwords. * If there are no password attributes in the mapping, then the user's either an idiot * and has no idea what they're doing, or they're authenticating the user using a different * method. */ if (!inst->expect_password && map->dst->vpt_da && (map->dst->type == VPT_TYPE_ATTR)) { switch (map->dst->vpt_da->attr) { case PW_CLEARTEXT_PASSWORD: case PW_NT_PASSWORD: case PW_USER_PASSWORD: case PW_PASSWORD_WITH_HEADER: case PW_CRYPT_PASSWORD: /* * Because you just know someone is going to map NT-Password to the * request list, and then complain it's not working... */ if (map->dst->vpt_list != PAIR_LIST_CONTROL) { LDAP_DBGW("Mapping LDAP (%s) attribute to \"known good\" password attribute " "(%s) in %s list. This is probably *NOT* the correct list, " "you should prepend \"control:\" to password attribute " "(control:%s)", map->src->name, map->dst->vpt_da->name, fr_int2str(pair_lists, map->dst->vpt_list, "<invalid>"), map->dst->vpt_da->name); } inst->expect_password = true; default: break; } } switch (map->src->type) { /* * Only =, :=, += and -= operators are supported for * cache entries. */ case VPT_TYPE_LITERAL: case VPT_TYPE_XLAT: case VPT_TYPE_ATTR: switch (map->op) { case T_OP_SET: case T_OP_EQ: case T_OP_SUB: case T_OP_ADD: break; default: cf_log_err(map->ci, "Operator \"%s\" not allowed for %s values", fr_int2str(fr_tokens, map->op, "<INVALID>"), fr_int2str(vpt_types, map->src->type, "<INVALID>")); return -1; } default: break; } } return 0; }
int rlm_yubikey_ykclient_init(CONF_SECTION *conf, rlm_yubikey_t *inst) { ykclient_rc status; CONF_SECTION *servers; char prefix[100]; int count = 0; if (!inst->client_id) { ERROR("rlm_yubikey (%s): validation.client_id must be set (to a valid id) when validation is enabled", inst->name); return -1; } if (!inst->api_key || !*inst->api_key || is_zero(inst->api_key)) { ERROR("rlm_yubikey (%s): validation.api_key must be set (to a valid key) when validation is enabled", inst->name); return -1; } DEBUG("rlm_yubikey (%s): Initialising ykclient", inst->name); status = ykclient_global_init(); if (status != YKCLIENT_OK) { yk_error: ERROR("rlm_yubikey (%s): %s", ykclient_strerror(status), inst->name); return -1; } status = ykclient_init(&inst->ykc); if (status != YKCLIENT_OK) { goto yk_error; } servers = cf_section_sub_find(conf, "servers"); if (servers) { CONF_PAIR *uri, *first; /* * If there were no uris configured we just use the default * ykclient uris which point to the yubico servers. */ first = uri = cf_pair_find(servers, "uri"); if (!uri) { goto init; } while (uri) { count++; uri = cf_pair_find_next(servers, uri, "uri"); } inst->uris = talloc_zero_array(inst, char const *, count); uri = first; count = 0; while (uri) { inst->uris[count++] = cf_pair_value(uri); uri = cf_pair_find_next(servers, uri, "uri"); } if (count) { status = ykclient_set_url_templates(inst->ykc, count, inst->uris); if (status != YKCLIENT_OK) { goto yk_error; } } } init: status = ykclient_set_client_b64(inst->ykc, inst->client_id, inst->api_key); if (status != YKCLIENT_OK) { ERROR("rlm_yubikey (%s): Failed setting API credentials: %s", ykclient_strerror(status), inst->name); return -1; } snprintf(prefix, sizeof(prefix), "rlm_yubikey (%s)", inst->name); inst->pool = module_connection_pool_init(conf, inst, mod_conn_create, NULL, prefix); if (!inst->pool) { ykclient_done(&inst->ykc); return -1; } return 0; }
static int mod_instantiate(CONF_SECTION *conf, void *instance) { rlm_sql_t *inst = instance; /* * Hack... */ inst->config = &inst->myconfig; inst->cs = conf; inst->config->xlat_name = cf_section_name2(conf); if (!inst->config->xlat_name) { inst->config->xlat_name = cf_section_name1(conf); } else { char *group_name; DICT_ATTR const *da; ATTR_FLAGS flags; /* * Allocate room for <instance>-SQL-Group */ group_name = talloc_typed_asprintf(inst, "%s-SQL-Group", inst->config->xlat_name); DEBUG("rlm_sql (%s): Creating new attribute %s", inst->config->xlat_name, group_name); memset(&flags, 0, sizeof(flags)); if (dict_addattr(group_name, -1, 0, PW_TYPE_STRING, flags) < 0) { ERROR("rlm_sql (%s): Failed to create " "attribute %s: %s", inst->config->xlat_name, group_name, fr_strerror()); return -1; } da = dict_attrbyname(group_name); if (!da) { ERROR("rlm_sql (%s): Failed to create " "attribute %s", inst->config->xlat_name, group_name); return -1; } if (inst->config->groupmemb_query && inst->config->groupmemb_query[0]) { DEBUG("rlm_sql (%s): Registering sql_groupcmp for %s", inst->config->xlat_name, group_name); paircompare_register(da, dict_attrbyvalue(PW_USER_NAME, 0), false, sql_groupcmp, inst); } } rad_assert(inst->config->xlat_name); /* * If the configuration parameters can't be parsed, then fail. */ if ((parse_sub_section(conf, inst, &inst->config->accounting, RLM_COMPONENT_ACCT) < 0) || (parse_sub_section(conf, inst, &inst->config->postauth, RLM_COMPONENT_POST_AUTH) < 0)) { cf_log_err_cs(conf, "Invalid configuration"); return -1; } /* * Cache the SQL-User-Name DICT_ATTR, so we can be slightly * more efficient about creating SQL-User-Name attributes. */ inst->sql_user = dict_attrbyname("SQL-User-Name"); if (!inst->sql_user) { return -1; } /* * Export these methods, too. This avoids RTDL_GLOBAL. */ inst->sql_set_user = sql_set_user; inst->sql_get_socket = sql_get_socket; inst->sql_release_socket = sql_release_socket; inst->sql_escape_func = sql_escape_func; inst->sql_query = rlm_sql_query; inst->sql_select_query = rlm_sql_select_query; inst->sql_fetch_row = rlm_sql_fetch_row; /* * Register the SQL xlat function */ xlat_register(inst->config->xlat_name, sql_xlat, sql_escape_func, inst); /* * Sanity check for crazy people. */ if (strncmp(inst->config->sql_driver_name, "rlm_sql_", 8) != 0) { ERROR("rlm_sql (%s): \"%s\" is NOT an SQL driver!", inst->config->xlat_name, inst->config->sql_driver_name); return -1; } /* * Load the appropriate driver for our database */ inst->handle = lt_dlopenext(inst->config->sql_driver_name); if (!inst->handle) { ERROR("Could not link driver %s: %s", inst->config->sql_driver_name, dlerror()); ERROR("Make sure it (and all its dependent libraries!)" "are in the search path of your system's ld"); return -1; } inst->module = (rlm_sql_module_t *) dlsym(inst->handle, inst->config->sql_driver_name); if (!inst->module) { ERROR("Could not link symbol %s: %s", inst->config->sql_driver_name, dlerror()); return -1; } if (inst->module->mod_instantiate) { CONF_SECTION *cs; char const *name; name = strrchr(inst->config->sql_driver_name, '_'); if (!name) { name = inst->config->sql_driver_name; } else { name++; } cs = cf_section_sub_find(conf, name); if (!cs) { cs = cf_section_alloc(conf, name, NULL); if (!cs) { return -1; } } /* * It's up to the driver to register a destructor */ if (inst->module->mod_instantiate(cs, inst->config) < 0) { return -1; } } inst->lf = fr_logfile_init(inst); if (!inst->lf) { cf_log_err_cs(conf, "Failed creating log file context"); return -1; } INFO("rlm_sql (%s): Driver %s (module %s) loaded and linked", inst->config->xlat_name, inst->config->sql_driver_name, inst->module->name); /* * Initialise the connection pool for this instance */ INFO("rlm_sql (%s): Attempting to connect to database \"%s\"", inst->config->xlat_name, inst->config->sql_db); if (sql_socket_pool_init(inst) < 0) return -1; if (inst->config->groupmemb_query && inst->config->groupmemb_query[0]) { paircompare_register(dict_attrbyvalue(PW_SQL_GROUP, 0), dict_attrbyvalue(PW_USER_NAME, 0), false, sql_groupcmp, inst); } if (inst->config->do_clients) { if (generate_sql_clients(inst) == -1){ ERROR("Failed to load clients from SQL"); return -1; } } return RLM_MODULE_OK; }
/** Set the global trigger section exec_trigger will search in * * @note Triggers are used by the connection pool, which is used in the server library * which may not have the mainconfig available. Additionally, utilities may want * to set their own root config sections. * * @param cs to use as global trigger section */ void exec_trigger_set_conf(CONF_SECTION *cs) { exec_trigger_main = cs; exec_trigger_subcs = cf_section_sub_find(cs, "trigger"); }
/* * Main program */ int main(int argc, char **argv) { CONF_SECTION *maincs, *cs; FILE *fp; struct radutmp rt; char othername[256]; char nasname[1024]; char session_id[sizeof(rt.session_id)+1]; int hideshell = 0; int showsid = 0; int rawoutput = 0; int radiusoutput = 0; /* Radius attributes */ char const *portind; int c; unsigned int portno; char buffer[2048]; char const *user = NULL; int user_cmp = 0; time_t now = 0; uint32_t nas_port = ~0; uint32_t nas_ip_address = INADDR_NONE; int zap = 0; raddb_dir = RADIUS_DIR; #ifndef NDEBUG if (fr_fault_setup(getenv("PANIC_ACTION"), argv[0]) < 0) { fr_perror("radwho"); exit(EXIT_FAILURE); } #endif talloc_set_log_stderr(); while((c = getopt(argc, argv, "d:fF:nN:sSipP:crRu:U:Z")) != EOF) switch(c) { case 'd': raddb_dir = optarg; break; case 'F': radutmp_file = optarg; break; case 'h': usage(0); break; case 'S': hideshell = 1; break; case 'n': showname = 0; break; case 'N': if (inet_pton(AF_INET, optarg, &nas_ip_address) < 0) { usage(1); } break; case 's': showname = 1; break; case 'i': showsid = 1; break; case 'p': showptype = 1; break; case 'P': nas_port = atoi(optarg); break; case 'c': showcid = 1; showname = 1; break; case 'r': rawoutput = 1; break; case 'R': radiusoutput = 1; now = time(NULL); break; case 'u': user = optarg; user_cmp = 0; break; case 'U': user = optarg; user_cmp = 1; break; case 'Z': zap = 1; break; default: usage(1); break; } /* * Mismatch between the binary and the libraries it depends on */ if (fr_check_lib_magic(RADIUSD_MAGIC_NUMBER) < 0) { fr_perror("radwho"); return 1; } /* * Be safe. */ if (zap && !radiusoutput) zap = 0; /* * zap EVERYONE, but only on this nas */ if (zap && !user && (~nas_port == 0)) { /* * We need to know which NAS to zap users in. */ if (nas_ip_address == INADDR_NONE) usage(1); printf("Acct-Status-Type = Accounting-Off\n"); printf("NAS-IP-Address = %s\n", hostname(buffer, sizeof(buffer), nas_ip_address)); printf("Acct-Delay-Time = 0\n"); exit(0); /* don't bother printing anything else */ } if (radutmp_file) goto have_radutmp; /* * Initialize main_config */ memset(&main_config, 0, sizeof(main_config)); /* Read radiusd.conf */ snprintf(buffer, sizeof(buffer), "%.200s/radiusd.conf", raddb_dir); maincs = cf_file_read(buffer); if (!maincs) { fprintf(stderr, "%s: Error reading or parsing radiusd.conf\n", argv[0]); exit(1); } cs = cf_section_sub_find(maincs, "modules"); if (!cs) { fprintf(stderr, "%s: No modules section found in radiusd.conf\n", argv[0]); exit(1); } /* Read the radutmp section of radiusd.conf */ cs = cf_section_sub_find_name2(cs, "radutmp", NULL); if (!cs) { fprintf(stderr, "%s: No configuration information in radutmp section of radiusd.conf\n", argv[0]); exit(1); } cf_section_parse(cs, NULL, module_config); /* Assign the correct path for the radutmp file */ radutmp_file = radutmpconfig.radutmp_fn; have_radutmp: if (showname < 0) showname = 1; /* * Show the users logged in on the terminal server(s). */ if ((fp = fopen(radutmp_file, "r")) == NULL) { fprintf(stderr, "%s: Error reading %s: %s\n", progname, radutmp_file, fr_syserror(errno)); return 0; } /* * Don't print the headers if raw or RADIUS */ if (!rawoutput && !radiusoutput) { fputs(showname ? hdr1 : hdr2, stdout); fputs(eol, stdout); } /* * Read the file, printing out active entries. */ while (fread(&rt, sizeof(rt), 1, fp) == 1) { char name[sizeof(rt.login) + 1]; if (rt.type != P_LOGIN) continue; /* hide logout sessions */ /* * We don't show shell users if we are * fingerd, as we have done that above. */ if (hideshell && !strchr("PCS", rt.proto)) continue; /* * Print out sessions only for the given user. */ if (user) { /* only for a particular user */ if (((user_cmp == 0) && (strncasecmp(rt.login, user, strlen(user)) != 0)) || ((user_cmp == 1) && (strncmp(rt.login, user, strlen(user)) != 0))) { continue; } } /* * Print out only for the given NAS port. */ if (~nas_port != 0) { if (rt.nas_port != nas_port) continue; } /* * Print out only for the given NAS IP address */ if (nas_ip_address != INADDR_NONE) { if (rt.nas_address != nas_ip_address) continue; } memcpy(session_id, rt.session_id, sizeof(rt.session_id)); session_id[sizeof(rt.session_id)] = 0; if (!rawoutput && rt.nas_port > (showname ? 999 : 99999)) { portind = ">"; portno = (showname ? 999 : 99999); } else { portind = "S"; portno = rt.nas_port; } /* * Print output as RADIUS attributes */ if (radiusoutput) { memcpy(nasname, rt.login, sizeof(rt.login)); nasname[sizeof(rt.login)] = '\0'; fr_print_string(nasname, 0, buffer, sizeof(buffer)); printf("User-Name = \"%s\"\n", buffer); fr_print_string(session_id, 0, buffer, sizeof(buffer)); printf("Acct-Session-Id = \"%s\"\n", buffer); if (zap) printf("Acct-Status-Type = Stop\n"); printf("NAS-IP-Address = %s\n", hostname(buffer, sizeof(buffer), rt.nas_address)); printf("NAS-Port = %u\n", rt.nas_port); switch (rt.proto) { case 'S': printf("Service-Type = Framed-User\n"); printf("Framed-Protocol = SLIP\n"); break; case 'P': printf("Service-Type = Framed-User\n"); printf("Framed-Protocol = PPP\n"); break; default: printf("Service-type = Login-User\n"); break; } if (rt.framed_address != INADDR_NONE) { printf("Framed-IP-Address = %s\n", hostname(buffer, sizeof(buffer), rt.framed_address)); } /* * Some sanity checks on the time */ if ((rt.time <= now) && (now - rt.time) <= (86400 * 365)) { printf("Acct-Session-Time = %" PRId64 "\n", (int64_t) (now - rt.time)); } if (rt.caller_id[0] != '\0') { memcpy(nasname, rt.caller_id, sizeof(rt.caller_id)); nasname[sizeof(rt.caller_id)] = '\0'; fr_print_string(nasname, 0, buffer, sizeof(buffer)); printf("Calling-Station-Id = \"%s\"\n", buffer); } printf("\n"); /* separate entries with a blank line */ continue; } /* * Show the fill name, or not. */ memcpy(name, rt.login, sizeof(rt.login)); name[sizeof(rt.login)] = '\0'; if (showname) { if (rawoutput == 0) { printf("%-10.10s %-17.17s %-5.5s %s%-3u %-9.9s %-15.15s %-.19s%s", name, showcid ? rt.caller_id : (showsid? session_id : fullname(rt.login)), proto(rt.proto, rt.porttype), portind, portno, dotime(rt.time), hostname(nasname, sizeof(nasname), rt.nas_address), hostname(othername, sizeof(othername), rt.framed_address), eol); } else { printf("%s,%s,%s,%s%u,%s,%s,%s%s", name, showcid ? rt.caller_id : (showsid? session_id : fullname(rt.login)), proto(rt.proto, rt.porttype), portind, portno, dotime(rt.time), hostname(nasname, sizeof(nasname), rt.nas_address), hostname(othername, sizeof(othername), rt.framed_address), eol); } } else { if (rawoutput == 0) { printf("%-10.10s %s%-5u %-6.6s %-13.13s %-15.15s %-.28s%s", name, portind, portno, proto(rt.proto, rt.porttype), dotime(rt.time), hostname(nasname, sizeof(nasname), rt.nas_address), hostname(othername, sizeof(othername), rt.framed_address), eol); } else { printf("%s,%s%u,%s,%s,%s,%s%s", name, portind, portno, proto(rt.proto, rt.porttype), dotime(rt.time), hostname(nasname, sizeof(nasname), rt.nas_address), hostname(othername, sizeof(othername), rt.framed_address), eol); } } } fclose(fp); return 0; }
static int parse_sub_section(CONF_SECTION *parent, rlm_rest_section_t *config, rlm_components_t comp) { CONF_SECTION *cs; char const *name = section_type_value[comp].section; cs = cf_section_sub_find(parent, name); if (!cs) { config->name = NULL; return 0; } if (cf_section_parse(cs, config, section_config) < 0) { config->name = NULL; return -1; } /* * Add section name (Maybe add to headers later?). */ config->name = name; /* * Sanity check */ if ((config->username && !config->password) || (!config->username && config->password)) { cf_log_err_cs(cs, "'username' and 'password' must both be set or both be absent"); return -1; } /* * Convert HTTP method auth and body type strings into their integer equivalents. */ config->auth = fr_str2int(http_auth_table, config->auth_str, HTTP_AUTH_UNKNOWN); if (config->auth == HTTP_AUTH_UNKNOWN) { cf_log_err_cs(cs, "Unknown HTTP auth type '%s'", config->auth_str); return -1; } else if ((config->auth != HTTP_AUTH_NONE) && !http_curl_auth[config->auth]) { cf_log_err_cs(cs, "Unsupported HTTP auth type \"%s\", check libcurl version, OpenSSL build " "configuration, then recompile this module", config->auth_str); return -1; } config->method = fr_str2int(http_method_table, config->method_str, HTTP_METHOD_CUSTOM); /* * We don't have any custom user data, so we need to select the right encoder based * on the body type. * * To make this slightly more/less confusing, we accept both canonical body_types, * and content_types. */ if (!config->data) { config->body = fr_str2int(http_body_type_table, config->body_str, HTTP_BODY_UNKNOWN); if (config->body == HTTP_BODY_UNKNOWN) { config->body = fr_str2int(http_content_type_table, config->body_str, HTTP_BODY_UNKNOWN); } if (config->body == HTTP_BODY_UNKNOWN) { cf_log_err_cs(cs, "Unknown HTTP body type '%s'", config->body_str); return -1; } switch (http_body_type_supported[config->body]) { case HTTP_BODY_UNSUPPORTED: cf_log_err_cs(cs, "Unsupported HTTP body type \"%s\", please submit patches", config->body_str); return -1; case HTTP_BODY_INVALID: cf_log_err_cs(cs, "Invalid HTTP body type. \"%s\" is not a valid web API data " "markup format", config->body_str); return -1; default: break; } /* * We have custom body data so we set HTTP_BODY_CUSTOM_XLAT, but also need to try and * figure out what content-type to use. So if they've used the canonical form we * need to convert it back into a proper HTTP content_type value. */ } else { http_body_type_t body; config->body = HTTP_BODY_CUSTOM_XLAT; body = fr_str2int(http_body_type_table, config->body_str, HTTP_BODY_UNKNOWN); if (body != HTTP_BODY_UNKNOWN) { config->body_str = fr_int2str(http_content_type_table, body, config->body_str); } } if (config->force_to_str) { config->force_to = fr_str2int(http_body_type_table, config->force_to_str, HTTP_BODY_UNKNOWN); if (config->force_to == HTTP_BODY_UNKNOWN) { config->force_to = fr_str2int(http_content_type_table, config->force_to_str, HTTP_BODY_UNKNOWN); } if (config->force_to == HTTP_BODY_UNKNOWN) { cf_log_err_cs(cs, "Unknown forced response body type '%s'", config->force_to_str); return -1; } switch (http_body_type_supported[config->force_to]) { case HTTP_BODY_UNSUPPORTED: cf_log_err_cs(cs, "Unsupported forced response body type \"%s\", please submit patches", config->force_to_str); return -1; case HTTP_BODY_INVALID: cf_log_err_cs(cs, "Invalid HTTP forced response body type. \"%s\" is not a valid web API data " "markup format", config->force_to_str); return -1; default: break; } } return 0; }
/** Instantiate the module * * Creates a new instance of the module reading parameters from a configuration section. * * @param conf to parse. * @param instance Where to write pointer to configuration data. * @return 0 on success < 0 on failure. */ static int mod_instantiate(CONF_SECTION *conf, void *instance) { static bool version_done; CONF_SECTION *options; ldap_instance_t *inst = instance; inst->cs = conf; options = cf_section_sub_find(conf, "options"); if (!options || !cf_pair_find(options, "chase_referrals")) { inst->chase_referrals_unset = true; /* use OpenLDAP defaults */ } inst->xlat_name = cf_section_name2(conf); if (!inst->xlat_name) { inst->xlat_name = cf_section_name1(conf); } /* * Only needs to be done once, prevents races in environment * initialisation within libldap. * * See: https://github.com/arr2036/ldapperf/issues/2 */ #ifdef HAVE_LDAP_INITIALIZE ldap_initialize(&inst->handle, ""); #else inst->handle = ldap_init("", 0); #endif /* * Get version info from the LDAP API. */ if (!version_done) { static LDAPAPIInfo info; /* static to quiet valgrind about this being uninitialised */ int ldap_errno; version_done = true; ldap_errno = ldap_get_option(NULL, LDAP_OPT_API_INFO, &info); if (ldap_errno == LDAP_OPT_SUCCESS) { if (strcmp(info.ldapai_vendor_name, LDAP_VENDOR_NAME) != 0) { WARN("rlm_ldap: libldap vendor changed since the server was built"); WARN("rlm_ldap: linked: %s, built: %s", info.ldapai_vendor_name, LDAP_VENDOR_NAME); } if (info.ldapai_vendor_version != LDAP_VENDOR_VERSION) { WARN("rlm_ldap: libldap version changed since the server was built"); WARN("rlm_ldap: linked: %i, built: %i", info.ldapai_vendor_version, LDAP_VENDOR_VERSION); } INFO("rlm_ldap: libldap vendor: %s, version: %i", info.ldapai_vendor_name, info.ldapai_vendor_version); ldap_memfree(info.ldapai_vendor_name); ldap_memfree(info.ldapai_extensions); } else { DEBUG("rlm_ldap: Falling back to build time libldap version info. Query for LDAP_OPT_API_INFO " "returned: %i", ldap_errno); INFO("rlm_ldap: libldap vendor: %s, version: %i.%i.%i", LDAP_VENDOR_NAME, LDAP_VENDOR_VERSION_MAJOR, LDAP_VENDOR_VERSION_MINOR, LDAP_VENDOR_VERSION_PATCH); } } /* * If the configuration parameters can't be parsed, then fail. */ if ((parse_sub_section(inst, conf, &inst->accounting, RLM_COMPONENT_ACCT) < 0) || (parse_sub_section(inst, conf, &inst->postauth, RLM_COMPONENT_POST_AUTH) < 0)) { cf_log_err_cs(conf, "Failed parsing configuration"); goto error; } /* * Sanity checks for cacheable groups code. */ if (inst->cacheable_group_name && inst->groupobj_membership_filter) { if (!inst->groupobj_name_attr) { cf_log_err_cs(conf, "Directive 'group.name_attribute' must be set if cacheable " "group names are enabled"); goto error; } } /* * Split original server value out into URI, server and port * so whatever initialization function we use later will have * the server information in the format it needs. */ if (ldap_is_ldap_url(inst->server)) { LDAPURLDesc *ldap_url; int port; if (ldap_url_parse(inst->server, &ldap_url)){ cf_log_err_cs(conf, "Parsing LDAP URL \"%s\" failed", inst->server); return -1; } /* * Figure out the port from the URL */ if (ldap_url->lud_port == 0) { if (strcmp(ldap_url->lud_scheme, "ldaps://") == 0) { if (inst->start_tls == true) { start_tls_error: cf_log_err_cs(conf, "ldaps:// scheme is not compatible with 'start_tls'"); return -1; } port = 636; } else { port = 384; } } else { port = ldap_url->lud_port; } inst->uri = inst->server; inst->server = talloc_strdup(inst, ldap_url->lud_host); if ((inst->port != 384) && (port != inst->port)) { WARN("Non-default 'port' directive %i set to %i by LDAP URI", inst->port, port); } inst->port = port; /* * @todo We could set a few other top level * directives using the URL, like base_dn * and scope. */ ldap_free_urldesc(ldap_url); /* * We need to construct an LDAP URI */ } else { switch (inst->port) { default: case 384: inst->uri = talloc_asprintf(inst, "ldap://%s:%i/", inst->server, inst->port); break; case 636: if (inst->start_tls == true) goto start_tls_error; inst->uri = talloc_asprintf(inst, "ldaps://%s:%i/", inst->server, inst->port); break; } } #ifdef LDAP_OPT_X_TLS_NEVER /* * Workaround for servers which support LDAPS but not START TLS */ if (inst->port == LDAPS_PORT || inst->tls_mode) { inst->tls_mode = LDAP_OPT_X_TLS_HARD; } else { inst->tls_mode = 0; } #endif /* * Convert dereference strings to enumerated constants */ if (inst->dereference_str) { inst->dereference = fr_str2int(ldap_dereference, inst->dereference_str, -1); if (inst->dereference < 0) { cf_log_err_cs(conf, "Invalid 'dereference' value \"%s\", expected 'never', 'searching', " "'finding' or 'always'", inst->dereference_str); goto error; } } #if LDAP_SET_REBIND_PROC_ARGS != 3 /* * The 2-argument rebind doesn't take an instance variable. Our rebind function needs the instance * variable for the username, password, etc. */ if (inst->rebind == true) { cf_log_err_cs(conf, "Cannot use 'rebind' directive as this version of libldap " "does not support the API that we need"); goto error; } #endif /* * Convert scope strings to enumerated constants */ inst->userobj_scope = fr_str2int(ldap_scope, inst->userobj_scope_str, -1); if (inst->userobj_scope < 0) { cf_log_err_cs(conf, "Invalid 'user.scope' value \"%s\", expected 'sub', 'one'" #ifdef LDAP_SCOPE_CHILDREN ", 'base' or 'children'" #else " or 'base'" #endif , inst->userobj_scope_str); goto error; } inst->groupobj_scope = fr_str2int(ldap_scope, inst->groupobj_scope_str, -1); if (inst->groupobj_scope < 0) { cf_log_err_cs(conf, "Invalid 'group.scope' value \"%s\", expected 'sub', 'one'" #ifdef LDAP_SCOPE_CHILDREN ", 'base' or 'children'" #else " or 'base'" #endif , inst->groupobj_scope_str); goto error; } inst->clientobj_scope = fr_str2int(ldap_scope, inst->clientobj_scope_str, -1); if (inst->clientobj_scope < 0) { cf_log_err_cs(conf, "Invalid 'client.scope' value \"%s\", expected 'sub', 'one'" #ifdef LDAP_SCOPE_CHILDREN ", 'base' or 'children'" #else " or 'base'" #endif , inst->clientobj_scope_str); goto error; } if (inst->tls_require_cert_str) { #ifdef LDAP_OPT_X_TLS_NEVER /* * Convert cert strictness to enumerated constants */ inst->tls_require_cert = fr_str2int(ldap_tls_require_cert, inst->tls_require_cert_str, -1); if (inst->tls_require_cert < 0) { cf_log_err_cs(conf, "Invalid 'tls.require_cert' value \"%s\", expected 'never', " "'demand', 'allow', 'try' or 'hard'", inst->tls_require_cert_str); goto error; } #else cf_log_err_cs(conf, "Modifying 'tls.require_cert' is not supported by current " "version of libldap. Please upgrade or substitute current libldap and " "rebuild this module"); goto error; #endif } /* * Build the attribute map */ if (map_afrom_cs(&inst->user_map, cf_section_sub_find(inst->cs, "update"), PAIR_LIST_REPLY, PAIR_LIST_REQUEST, rlm_ldap_map_verify, inst, LDAP_MAX_ATTRMAP) < 0) { return -1; } /* * Group comparison checks. */ if (cf_section_name2(conf)) { static ATTR_FLAGS flags; char buffer[256]; snprintf(buffer, sizeof(buffer), "%s-Ldap-Group", inst->xlat_name); if (dict_addattr(buffer, -1, 0, PW_TYPE_STRING, flags) < 0) { LDAP_ERR("Error creating group attribute: %s", fr_strerror()); return -1; } inst->group_da = dict_attrbyname(buffer); if (!inst->group_da) { LDAP_ERR("Failed creating attribute %s", buffer); goto error; } paircompare_register(inst->group_da, dict_attrbyvalue(PW_USER_NAME, 0), false, rlm_ldap_groupcmp, inst); /* * Were the default instance */ } else { inst->group_da = dict_attrbyvalue(PW_LDAP_GROUP, 0); paircompare_register(dict_attrbyvalue(PW_LDAP_GROUP, 0), dict_attrbyvalue(PW_USER_NAME, 0), false, rlm_ldap_groupcmp, inst); } xlat_register(inst->xlat_name, ldap_xlat, rlm_ldap_escape_func, inst); /* * Setup the cache attribute */ if (inst->cache_attribute) { static ATTR_FLAGS flags; if (dict_addattr(inst->cache_attribute, -1, 0, PW_TYPE_STRING, flags) < 0) { LDAP_ERR("Error creating cache attribute: %s", fr_strerror()); goto error; } inst->cache_da = dict_attrbyname(inst->cache_attribute); } else { inst->cache_da = inst->group_da; /* Default to the group_da */ } /* * Initialize the socket pool. */ inst->pool = fr_connection_pool_module_init(inst->cs, inst, mod_conn_create, NULL, NULL); if (!inst->pool) goto error; /* * Bulk load dynamic clients. */ if (inst->do_clients) { CONF_SECTION *cs; cs = cf_section_sub_find(inst->cs, "client"); if (!cs) { cf_log_err_cs(conf, "Told to load clients but no client section found"); goto error; } cs = cf_section_sub_find(cs, "attribute"); if (!cs) { cf_log_err_cs(conf, "Told to load clients but no attribute section found"); goto error; } if (rlm_ldap_client_load(inst, cs) < 0) { cf_log_err_cs(conf, "Error loading clients"); return -1; } } return 0; error: return -1; }
/** Instantiate the module * * Creates a new instance of the module reading parameters from a configuration section. * * @param conf to parse. * @param instance Where to write pointer to configuration data. * @return 0 on success < 0 on failure. */ static int mod_instantiate(CONF_SECTION *conf, void *instance) { CONF_SECTION *options; ldap_instance_t *inst = instance; inst->cs = conf; options = cf_section_sub_find(conf, "options"); if (!options || !cf_pair_find(options, "chase_referrals")) { inst->chase_referrals_unset = true; /* use OpenLDAP defaults */ } inst->xlat_name = cf_section_name2(conf); if (!inst->xlat_name) { inst->xlat_name = cf_section_name1(conf); } /* * If the configuration parameters can't be parsed, then fail. */ if ((parse_sub_section(inst, conf, &inst->accounting, RLM_COMPONENT_ACCT) < 0) || (parse_sub_section(inst, conf, &inst->postauth, RLM_COMPONENT_POST_AUTH) < 0)) { LDAP_ERR("Failed parsing configuration"); goto error; } /* * Sanity checks for cacheable groups code. */ if (inst->cacheable_group_name && inst->groupobj_membership_filter) { if (!inst->groupobj_name_attr) { LDAP_ERR("Directive 'group.name_attribute' must be set if cacheable group names are enabled"); goto error; } } /* * Check for URLs. If they're used and the library doesn't support them, then complain. */ inst->is_url = 0; if (ldap_is_ldap_url(inst->server)) { #ifdef HAVE_LDAP_INITIALIZE inst->is_url = 1; inst->port = 0; #else LDAP_ERR("Directive 'server' is in URL form but ldap_initialize() is not available"); goto error; #endif } /* * Workaround for servers which support LDAPS but not START TLS */ if (inst->port == LDAPS_PORT || inst->tls_mode) { inst->tls_mode = LDAP_OPT_X_TLS_HARD; } else { inst->tls_mode = 0; } #if LDAP_SET_REBIND_PROC_ARGS != 3 /* * The 2-argument rebind doesn't take an instance variable. Our rebind function needs the instance * variable for the username, password, etc. */ if (inst->rebind == true) { LDAP_ERR("Cannot use 'rebind' directive as this version of libldap does not support the API " "that we need"); goto error; } #endif /* * Convert scope strings to enumerated constants */ inst->userobj_scope = fr_str2int(ldap_scope, inst->userobj_scope_str, -1); if (inst->userobj_scope < 0) { LDAP_ERR("Invalid 'user.scope' value \"%s\", expected 'sub', 'one', 'base' or 'children'", inst->userobj_scope_str); goto error; } inst->groupobj_scope = fr_str2int(ldap_scope, inst->groupobj_scope_str, -1); if (inst->groupobj_scope < 0) { LDAP_ERR("Invalid 'group.scope' value \"%s\", expected 'sub', 'one', 'base' or 'children'", inst->groupobj_scope_str); goto error; } inst->clientobj_scope = fr_str2int(ldap_scope, inst->clientobj_scope_str, -1); if (inst->clientobj_scope < 0) { LDAP_ERR("Invalid 'client.scope' value \"%s\", expected 'sub', 'one', 'base' or 'children'", inst->clientobj_scope_str); goto error; } if (inst->tls_require_cert_str) { #ifdef LDAP_OPT_X_TLS_NEVER /* * Convert cert strictness to enumerated constants */ inst->tls_require_cert = fr_str2int(ldap_tls_require_cert, inst->tls_require_cert_str, -1); if (inst->tls_require_cert < 0) { LDAP_ERR("Invalid 'tls.require_cert' value \"%s\", expected 'never', 'demand', 'allow', " "'try' or 'hard'", inst->tls_require_cert_str); goto error; } #else LDAP_ERR("Modifying 'tls.require_cert' is not supported by current version of libldap. " "Please upgrade libldap and rebuild this module"); goto error; #endif } /* * Build the attribute map */ if (rlm_ldap_map_verify(inst, &(inst->user_map)) < 0) { goto error; } /* * Group comparison checks. */ if (cf_section_name2(conf)) { ATTR_FLAGS flags; char buffer[256]; snprintf(buffer, sizeof(buffer), "%s-Ldap-Group", inst->xlat_name); memset(&flags, 0, sizeof(flags)); if (dict_addattr(buffer, -1, 0, PW_TYPE_STRING, flags) < 0) { LDAP_ERR("Error creating group attribute: %s", fr_strerror()); return -1; } inst->group_da = dict_attrbyname(buffer); if (!inst->group_da) { LDAP_ERR("Failed creating attribute %s", buffer); goto error; } paircompare_register(inst->group_da, dict_attrbyvalue(PW_USER_NAME, 0), false, rlm_ldap_groupcmp, inst); /* * Were the default instance */ } else { inst->group_da = dict_attrbyvalue(PW_LDAP_GROUP, 0); paircompare_register(dict_attrbyvalue(PW_LDAP_GROUP, 0), dict_attrbyvalue(PW_USER_NAME, 0), false, rlm_ldap_groupcmp, inst); } xlat_register(inst->xlat_name, ldap_xlat, rlm_ldap_escape_func, inst); /* * Setup the cache attribute */ if (inst->cache_attribute) { ATTR_FLAGS flags; memset(&flags, 0, sizeof(flags)); if (dict_addattr(inst->cache_attribute, -1, 0, PW_TYPE_STRING, flags) < 0) { LDAP_ERR("Error creating cache attribute: %s", fr_strerror()); return -1; } inst->cache_da = dict_attrbyname(inst->cache_attribute); } else { inst->cache_da = inst->group_da; /* Default to the group_da */ } /* * Initialize the socket pool. */ inst->pool = fr_connection_pool_init(inst->cs, inst, mod_conn_create, NULL, mod_conn_delete, NULL); if (!inst->pool) { return -1; } /* * Bulk load dynamic clients. */ if (inst->do_clients) { if (rlm_ldap_load_clients(inst) < 0) { LDAP_ERR("Error loading clients"); return -1; } } return 0; error: return -1; }
void hup_mainconfig(void) { cached_config_t *cc; CONF_SECTION *cs; char buffer[1024]; radlog(L_INFO, "HUP - Re-reading configuration files"); /* Read the configuration file */ snprintf(buffer, sizeof(buffer), "%.200s/%.50s.conf", radius_dir, mainconfig.name); if ((cs = cf_file_read(buffer)) == NULL) { radlog(L_ERR, "Failed to re-read or parse %s", buffer); return; } cc = rad_malloc(sizeof(*cc)); memset(cc, 0, sizeof(*cc)); /* * Save the current configuration. Note that we do NOT * free older ones. We should probably do so at some * point. Doing so will require us to mark which modules * are still in use, and which aren't. Modules that * can't be HUPed always use the original configuration. * Modules that can be HUPed use one of the newer * configurations. */ cc->created = time(NULL); cc->cs = cs; cc->next = cs_cache; cs_cache = cc; /* * Re-open the log file. If we can't, then keep logging * to the old log file. * * The "open log file" code is here rather than in log.c, * because it makes that function MUCH simpler. */ if (mainconfig.radlog_dest == RADLOG_FILES) { int fd, old_fd; fd = open(mainconfig.log_file, O_WRONLY | O_APPEND | O_CREAT, 0640); if (fd >= 0) { /* * Atomic swap. We'd like to keep the old * FD around so that callers don't * suddenly find the FD closed, and the * writes go nowhere. But that's hard to * do. So... we have the case where a * log message *might* be lost on HUP. */ old_fd = mainconfig.radlog_fd; mainconfig.radlog_fd = fd; close(old_fd); } } radlog(L_INFO, "HUP - loading modules"); /* * Prefer the new module configuration. */ module_hup(cf_section_sub_find(cs, "modules")); /* * Load new servers BEFORE freeing old ones. */ virtual_servers_load(cs); virtual_servers_free(cc->created - mainconfig.max_request_time * 4); }
void exec_trigger(REQUEST *request, CONF_SECTION *cs, const char *name) { CONF_SECTION *subcs; CONF_ITEM *ci; CONF_PAIR *cp; const char *attr; const char *value; VALUE_PAIR *vp; /* * Use global "trigger" section if no local config is given. */ if (!cs) { cs = mainconfig.config; attr = name; } else { /* * Try to use pair name, rather than reference. */ attr = strrchr(name, '.'); if (attr) { attr++; } else { attr = name; } } /* * Find local "trigger" subsection. If it isn't found, * try using the global "trigger" section, and reset the * reference to the full path, rather than the sub-path. */ subcs = cf_section_sub_find(cs, "trigger"); if (!subcs && (cs != mainconfig.config)) { subcs = cf_section_sub_find(mainconfig.config, "trigger"); attr = name; } if (!subcs) { DEBUG3("No trigger subsection: ignoring trigger %s", name); return; } ci = cf_reference_item(subcs, mainconfig.config, attr); if (!ci) { DEBUG3("No such item in trigger section: %s", attr); return; } if (!cf_item_is_pair(ci)) { DEBUG2("Trigger is not a configuration variable: %s", attr); return; } cp = cf_itemtopair(ci); if (!cp) return; value = cf_pair_value(cp); if (!value) { DEBUG2("Trigger has no value: %s", name); return; } /* * May be called for Status-Server packets. */ vp = NULL; if (request && request->packet) vp = request->packet->vps; DEBUG("Trigger %s -> %s", name, value); radius_exec_program(value, request, 0, NULL, 0, vp, NULL, 1); }
/* * Do any per-module initialization that is separate to each * configured instance of the module. e.g. set up connections * to external databases, read configuration files, set up * dictionary entries, etc. * * If configuration information is given in the config section * that must be referenced in later calls, store a handle to it * in *instance otherwise put a null pointer there. * * Setup a hashes wich we will use later * parse a module and give him a chance to live * */ static int mod_instantiate(CONF_SECTION *conf, void *instance) { rlm_perl_t *inst = instance; AV *end_AV; char const **embed_c; /* Stupid Perl and lack of const consistency */ char **embed; char **envp = NULL; char const *xlat_name; int exitstatus = 0, argc=0; MEM(embed_c = talloc_zero_array(inst, char const *, 4)); memcpy(&embed, &embed_c, sizeof(embed)); /* * Create pthread key. This key will be stored in instance */ #ifdef USE_ITHREADS pthread_mutex_init(&inst->clone_mutex, NULL); inst->thread_key = rad_malloc(sizeof(*inst->thread_key)); memset(inst->thread_key,0,sizeof(*inst->thread_key)); rlm_perl_make_key(inst->thread_key); #endif char arg[] = "0"; embed_c[0] = NULL; if (inst->perl_flags) { embed_c[1] = inst->perl_flags; embed_c[2] = inst->module; embed_c[3] = arg; argc = 4; } else { embed_c[1] = inst->module; embed_c[2] = arg; argc = 3; } PERL_SYS_INIT3(&argc, &embed, &envp); if ((inst->perl = perl_alloc()) == NULL) { ERROR("rlm_perl: No memory for allocating new perl !"); return (-1); } perl_construct(inst->perl); #ifdef USE_ITHREADS PL_perl_destruct_level = 2; { dTHXa(inst->perl); } PERL_SET_CONTEXT(inst->perl); #endif #if PERL_REVISION >= 5 && PERL_VERSION >=8 PL_exit_flags |= PERL_EXIT_DESTRUCT_END; #endif exitstatus = perl_parse(inst->perl, xs_init, argc, embed, NULL); end_AV = PL_endav; PL_endav = Nullav; if(!exitstatus) { perl_run(inst->perl); } else { ERROR("rlm_perl: perl_parse failed: %s not found or has syntax errors. \n", inst->module); return (-1); } PL_endav = end_AV; xlat_name = cf_section_name2(conf); if (!xlat_name) xlat_name = cf_section_name1(conf); if (xlat_name) { xlat_register(xlat_name, perl_xlat, NULL, inst); } /* parse perl configuration sub-section */ CONF_SECTION *cs; cs = cf_section_sub_find(conf, "config"); if (cs) { DEBUG("rlm_perl (%s): parsing 'config' section...", xlat_name); inst->rad_perlconf_hv = get_hv("RAD_PERLCONF",1); perl_parse_config(cs, 0, inst->rad_perlconf_hv); DEBUG("rlm_perl (%s): done parsing 'config'.", xlat_name); } return 0; }
/** Execute a trigger - call an executable to process an event * * @param request The current request. * @param cs to search for triggers in. If not NULL, only the portion after the last '.' * in name is used for the trigger. If cs is NULL, the entire name is used to find * the trigger in the global trigger section. * @param name the path relative to the global trigger section ending in the trigger name * e.g. module.ldap.pool.start. * @param quench whether to rate limit triggers. */ void exec_trigger(REQUEST *request, CONF_SECTION *cs, char const *name, bool quench) { CONF_SECTION *subcs; CONF_ITEM *ci; CONF_PAIR *cp; char const *attr; char const *value; VALUE_PAIR *vp; bool alloc = false; /* * Use global "trigger" section if no local config is given. */ if (!cs) { cs = exec_trigger_main; attr = name; } else { /* * Try to use pair name, rather than reference. */ attr = strrchr(name, '.'); if (attr) { attr++; } else { attr = name; } } /* * Find local "trigger" subsection. If it isn't found, * try using the global "trigger" section, and reset the * reference to the full path, rather than the sub-path. */ subcs = cf_section_sub_find(cs, "trigger"); if (!subcs && exec_trigger_main && (cs != exec_trigger_main)) { subcs = exec_trigger_subcs; attr = name; } if (!subcs) return; ci = cf_reference_item(subcs, exec_trigger_main, attr); if (!ci) { ERROR("No such item in trigger section: %s", attr); return; } if (!cf_item_is_pair(ci)) { ERROR("Trigger is not a configuration variable: %s", attr); return; } cp = cf_item_to_pair(ci); if (!cp) return; value = cf_pair_value(cp); if (!value) { ERROR("Trigger has no value: %s", name); return; } /* * May be called for Status-Server packets. */ vp = NULL; if (request && request->packet) vp = request->packet->vps; /* * Perform periodic quenching. */ if (quench) { time_t *last_time; last_time = cf_data_find(cs, value); if (!last_time) { last_time = rad_malloc(sizeof(*last_time)); *last_time = 0; if (cf_data_add(cs, value, last_time, time_free) < 0) { free(last_time); last_time = NULL; } } /* * Send the quenched traps at most once per second. */ if (last_time) { time_t now = time(NULL); if (*last_time == now) return; *last_time = now; } } /* * radius_exec_program always needs a request. */ if (!request) { request = request_alloc(NULL); alloc = true; } DEBUG("Trigger %s -> %s", name, value); radius_exec_program(request, NULL, 0, NULL, request, value, vp, false, true, EXEC_TIMEOUT); if (alloc) talloc_free(request); }
/** Modify user's object in LDAP * * Process a modifcation map to update a user object in the LDAP directory. * * @param inst rlm_ldap instance. * @param request Current request. * @param section that holds the map to process. * @return one of the RLM_MODULE_* values. */ static rlm_rcode_t user_modify(ldap_instance_t *inst, REQUEST *request, ldap_acct_section_t *section) { rlm_rcode_t rcode = RLM_MODULE_OK; ldap_rcode_t status; ldap_handle_t *conn = NULL; LDAPMod *mod_p[LDAP_MAX_ATTRMAP + 1], mod_s[LDAP_MAX_ATTRMAP]; LDAPMod **modify = mod_p; char *passed[LDAP_MAX_ATTRMAP * 2]; int i, total = 0, last_pass = 0; char *expanded[LDAP_MAX_ATTRMAP]; int last_exp = 0; char const *attr; char const *value; char const *dn; /* * Build our set of modifications using the update sections in * the config. */ CONF_ITEM *ci; CONF_PAIR *cp; CONF_SECTION *cs; FR_TOKEN op; char path[MAX_STRING_LEN]; char *p = path; rad_assert(section); /* * Locate the update section were going to be using */ if (section->reference[0] != '.') { *p++ = '.'; } if (radius_xlat(p, (sizeof(path) - (p - path)) - 1, request, section->reference, NULL, NULL) < 0) { goto error; } ci = cf_reference_item(NULL, section->cs, path); if (!ci) { goto error; } if (!cf_item_is_section(ci)){ REDEBUG("Reference must resolve to a section"); goto error; } cs = cf_section_sub_find(cf_itemtosection(ci), "update"); if (!cs) { REDEBUG("Section must contain 'update' subsection"); goto error; } /* * Iterate over all the pairs, building our mods array */ for (ci = cf_item_find_next(cs, NULL); ci != NULL; ci = cf_item_find_next(cs, ci)) { bool do_xlat = false; if (total == LDAP_MAX_ATTRMAP) { REDEBUG("Modify map size exceeded"); goto error; } if (!cf_item_is_pair(ci)) { REDEBUG("Entry is not in \"ldap-attribute = value\" format"); goto error; } /* * Retrieve all the information we need about the pair */ cp = cf_itemtopair(ci); value = cf_pair_value(cp); attr = cf_pair_attr(cp); op = cf_pair_operator(cp); if (!value || (*value == '\0')) { RDEBUG("Empty value string, skipping attribute \"%s\"", attr); continue; } switch (cf_pair_value_type(cp)) { case T_BARE_WORD: case T_SINGLE_QUOTED_STRING: break; case T_BACK_QUOTED_STRING: case T_DOUBLE_QUOTED_STRING: do_xlat = true; break; default: rad_assert(0); goto error; } if (op == T_OP_CMP_FALSE) { passed[last_pass] = NULL; } else if (do_xlat) { char *exp = NULL; if (radius_axlat(&exp, request, value, NULL, NULL) <= 0) { RDEBUG("Skipping attribute \"%s\"", attr); talloc_free(exp); continue; } expanded[last_exp++] = exp; passed[last_pass] = exp; /* * Static strings */ } else { memcpy(&(passed[last_pass]), &value, sizeof(passed[last_pass])); } passed[last_pass + 1] = NULL; mod_s[total].mod_values = &(passed[last_pass]); last_pass += 2; switch (op) { /* * T_OP_EQ is *NOT* supported, it is impossible to * support because of the lack of transactions in LDAP */ case T_OP_ADD: mod_s[total].mod_op = LDAP_MOD_ADD; break; case T_OP_SET: mod_s[total].mod_op = LDAP_MOD_REPLACE; break; case T_OP_SUB: case T_OP_CMP_FALSE: mod_s[total].mod_op = LDAP_MOD_DELETE; break; #ifdef LDAP_MOD_INCREMENT case T_OP_INCRM: mod_s[total].mod_op = LDAP_MOD_INCREMENT; break; #endif default: REDEBUG("Operator '%s' is not supported for LDAP modify operations", fr_int2str(fr_tokens, op, "<INVALID>")); goto error; } /* * Now we know the value is ok, copy the pointers into * the ldapmod struct. */ memcpy(&(mod_s[total].mod_type), &attr, sizeof(mod_s[total].mod_type)); mod_p[total] = &(mod_s[total]); total++; } if (total == 0) { rcode = RLM_MODULE_NOOP; goto release; } mod_p[total] = NULL; conn = mod_conn_get(inst, request); if (!conn) return RLM_MODULE_FAIL; dn = rlm_ldap_find_user(inst, request, &conn, NULL, false, NULL, &rcode); if (!dn || (rcode != RLM_MODULE_OK)) { goto error; } status = rlm_ldap_modify(inst, request, &conn, dn, modify); switch (status) { case LDAP_PROC_SUCCESS: break; case LDAP_PROC_REJECT: case LDAP_PROC_BAD_DN: rcode = RLM_MODULE_INVALID; break; default: rcode = RLM_MODULE_FAIL; break; }; release: error: /* * Free up any buffers we allocated for xlat expansion */ for (i = 0; i < last_exp; i++) { talloc_free(expanded[i]); } mod_conn_release(inst, conn); return rcode; }
/* * Main program, either pmwho or fingerd. */ int main(int argc, char **argv) { CONF_SECTION *maincs, *cs; FILE *fp; struct radutmp rt; char inbuf[128]; char othername[256]; char nasname[1024]; char session_id[sizeof(rt.session_id)+1]; int fingerd = 0; int hideshell = 0; int showsid = 0; int rawoutput = 0; int radiusoutput = 0; /* Radius attributes */ char *p, *q; const char *portind; int c; unsigned int portno; char buffer[2048]; const char *user = NULL; int user_cmp = 0; time_t now = 0; uint32_t nas_port = ~0; uint32_t nas_ip_address = INADDR_NONE; int zap = 0; raddb_dir = RADIUS_DIR; while((c = getopt(argc, argv, "d:fF:nN:sSipP:crRu:U:Z")) != EOF) switch(c) { case 'd': raddb_dir = optarg; break; case 'f': fingerd++; showname = 0; break; case 'F': radutmp_file = optarg; break; case 'h': usage(0); break; case 'S': hideshell = 1; break; case 'n': showname = 0; break; case 'N': if (inet_pton(AF_INET, optarg, &nas_ip_address) < 0) { usage(1); } break; case 's': showname = 1; break; case 'i': showsid = 1; break; case 'p': showptype = 1; break; case 'P': nas_port = atoi(optarg); break; case 'c': showcid = 1; showname = 1; break; case 'r': rawoutput = 1; break; case 'R': radiusoutput = 1; now = time(NULL); break; case 'u': user = optarg; user_cmp = 0; break; case 'U': user = optarg; user_cmp = 1; break; case 'Z': zap = 1; break; default: usage(1); break; } /* * Be safe. */ if (zap && !radiusoutput) zap = 0; /* * zap EVERYONE, but only on this nas */ if (zap && !user && (~nas_port == 0)) { /* * We need to know which NAS to zap users in. */ if (nas_ip_address == INADDR_NONE) usage(1); printf("Acct-Status-Type = Accounting-Off\n"); printf("NAS-IP-Address = %s\n", hostname(buffer, sizeof(buffer), nas_ip_address)); printf("Acct-Delay-Time = 0\n"); exit(0); /* don't bother printing anything else */ } if (radutmp_file) goto have_radutmp; /* * Initialize mainconfig */ memset(&mainconfig, 0, sizeof(mainconfig)); mainconfig.radlog_dest = RADLOG_STDOUT; /* Read radiusd.conf */ snprintf(buffer, sizeof(buffer), "%.200s/radiusd.conf", raddb_dir); maincs = cf_file_read(buffer); if (!maincs) { fprintf(stderr, "%s: Error reading or parsing radiusd.conf.\n", argv[0]); exit(1); } /* Read the radutmp section of radiusd.conf */ cs = cf_section_find_name2(cf_section_sub_find(maincs, "modules"), "radutmp", NULL); if(!cs) { fprintf(stderr, "%s: No configuration information in radutmp section of radiusd.conf!\n", argv[0]); exit(1); } cf_section_parse(cs, NULL, module_config); /* Assign the correct path for the radutmp file */ radutmp_file = radutmpconfig.radutmp_fn; have_radutmp: /* * See if we are "fingerd". */ if (strstr(argv[0], "fingerd")) { fingerd++; eol = "\r\n"; if (showname < 0) showname = 0; } if (showname < 0) showname = 1; if (fingerd) { /* * Read first line of the input. */ fgets(inbuf, 128, stdin); p = inbuf; while(*p == ' ' || *p == '\t') p++; if (*p == '/' && *(p + 1)) p += 2; while(*p == ' ' || *p == '\t') p++; for(q = p; *q && *q != '\r' && *q != '\n'; q++) ; *q = 0; /* * See if we fingered a specific user. */ ffile("header"); if (*p) sys_finger(p); } /* * Show the users logged in on the terminal server(s). */ if ((fp = fopen(radutmp_file, "r")) == NULL) { fprintf(stderr, "%s: Error reading %s: %s\n", progname, radutmp_file, strerror(errno)); return 0; } /* * Don't print the headers if raw or RADIUS */ if (!rawoutput && !radiusoutput) { fputs(showname ? hdr1 : hdr2, stdout); fputs(eol, stdout); } /* * Read the file, printing out active entries. */ while (fread(&rt, sizeof(rt), 1, fp) == 1) { if (rt.type != P_LOGIN) continue; /* hide logout sessions */ /* * We don't show shell users if we are * fingerd, as we have done that above. */ if (hideshell && !strchr("PCS", rt.proto)) continue; /* * Print out sessions only for the given user. */ if (user) { /* only for a particular user */ if (((user_cmp == 0) && (strncasecmp(rt.login, user, strlen(user)) != 0)) || ((user_cmp == 1) && (strncmp(rt.login, user, strlen(user)) != 0))) { continue; } } /* * Print out only for the given NAS port. */ if (~nas_port != 0) { if (rt.nas_port != nas_port) continue; } /* * Print out only for the given NAS IP address */ if (nas_ip_address != INADDR_NONE) { if (rt.nas_address != nas_ip_address) continue; } memcpy(session_id, rt.session_id, sizeof(rt.session_id)); session_id[sizeof(rt.session_id)] = 0; if (!rawoutput && rt.nas_port > (showname ? 999 : 99999)) { portind = ">"; portno = (showname ? 999 : 99999); } else { portind = "S"; portno = rt.nas_port; } /* * Print output as RADIUS attributes */ if (radiusoutput) { memcpy(nasname, rt.login, sizeof(rt.login)); nasname[sizeof(rt.login)] = '\0'; fr_print_string(nasname, 0, buffer, sizeof(buffer)); printf("User-Name = \"%s\"\n", buffer); fr_print_string(session_id, 0, buffer, sizeof(buffer)); printf("Acct-Session-Id = \"%s\"\n", buffer); if (zap) printf("Acct-Status-Type = Stop\n"); printf("NAS-IP-Address = %s\n", hostname(buffer, sizeof(buffer), rt.nas_address)); printf("NAS-Port = %u\n", rt.nas_port); switch (rt.proto) { case 'S': printf("Service-Type = Framed-User\n"); printf("Framed-Protocol = SLIP\n"); break; case 'P': printf("Service-Type = Framed-User\n"); printf("Framed-Protocol = PPP\n"); break; default: printf("Service-type = Login-User\n"); break; } if (rt.framed_address != INADDR_NONE) { printf("Framed-IP-Address = %s\n", hostname(buffer, sizeof(buffer), rt.framed_address)); } /* * Some sanity checks on the time */ if ((rt.time <= now) && (now - rt.time) <= (86400 * 365)) { printf("Acct-Session-Time = %ld\n", now - rt.time); } if (rt.caller_id[0] != '\0') { memcpy(nasname, rt.caller_id, sizeof(rt.caller_id)); nasname[sizeof(rt.caller_id)] = '\0'; fr_print_string(nasname, 0, buffer, sizeof(buffer)); printf("Calling-Station-Id = \"%s\"\n", buffer); } printf("\n"); /* separate entries with a blank line */ continue; } /* * Show the fill name, or not. */ if (showname) { printf((rawoutput == 0? rfmt1: rfmt1r), rt.login, showcid ? rt.caller_id : (showsid? session_id : fullname(rt.login)), proto(rt.proto, rt.porttype), portind, portno, dotime(rt.time), hostname(nasname, sizeof(nasname), rt.nas_address), hostname(othername, sizeof(othername), rt.framed_address), eol); } else { printf((rawoutput == 0? rfmt2: rfmt2r), rt.login, portind, portno, proto(rt.proto, rt.porttype), dotime(rt.time), hostname(nasname, sizeof(nasname), rt.nas_address), hostname(othername, sizeof(othername), rt.framed_address), eol); } } fclose(fp); return 0; }
/** Initialize the rlm_couchbase module * * Intialize the module and create the initial Couchbase connection pool. * * @param conf The module configuration. * @param instance The module instance. * @return Returns 0 on success, -1 on error. */ static int mod_instantiate(CONF_SECTION *conf, void *instance) { static bool version_done; rlm_couchbase_t *inst = instance; /* our module instance */ if (!version_done) { version_done = true; INFO("rlm_couchbase: json-c version: %s", json_c_version()); INFO("rlm_couchbase: libcouchbase version: %s", lcb_get_version(NULL)); } { char *server, *p; size_t len, i; bool sep = false; len = talloc_array_length(inst->server_raw); server = p = talloc_array(inst, char, len); for (i = 0; i < len; i++) { switch (inst->server_raw[i]) { case '\t': case ' ': case ',': /* Consume multiple separators occurring in sequence */ if (sep == true) continue; sep = true; *p++ = ';'; break; default: sep = false; *p++ = inst->server_raw[i]; break; } } *p = '\0'; inst->server = server; } /* setup item map */ if (mod_build_attribute_element_map(conf, inst) != 0) { /* fail */ return -1; } /* initiate connection pool */ inst->pool = fr_connection_pool_module_init(conf, inst, mod_conn_create, mod_conn_alive, NULL); /* check connection pool */ if (!inst->pool) { ERROR("rlm_couchbase: failed to initiate connection pool"); /* fail */ return -1; } /* load clients if requested */ if (inst->read_clients) { CONF_SECTION *cs; /* conf section */ /* attempt to find client section */ cs = cf_section_sub_find(conf, "client"); if (!cs) { ERROR("rlm_couchbase: failed to find client section while loading clients"); /* fail */ return -1; } /* attempt to find attribute subsection */ cs = cf_section_sub_find(cs, "attribute"); if (!cs) { ERROR("rlm_couchbase: failed to find attribute subsection while loading clients"); /* fail */ return -1; } /* debugging */ DEBUG("rlm_couchbase: preparing to load client documents"); /* attempt to load clients */ if (mod_load_client_documents(inst, cs) != 0) { /* fail */ return -1; } } /* return okay */ return 0; }
/* * Do any per-module initialization that is separate to each * configured instance of the module. e.g. set up connections * to external databases, read configuration files, set up * dictionary entries, etc. * * If configuration information is given in the config section * that must be referenced in later calls, store a handle to it * in *instance otherwise put a null pointer there. * * Setup a hashes wich we will use later * parse a module and give him a chance to live * */ static int mod_instantiate(CONF_SECTION *conf, void *instance) { rlm_perl_t *inst = instance; AV *end_AV; char const **embed_c; /* Stupid Perl and lack of const consistency */ char **embed; char **envp = NULL; int exitstatus = 0, argc=0; char arg[] = "0"; CONF_SECTION *cs; #ifdef USE_ITHREADS /* * Create pthread key. This key will be stored in instance */ pthread_mutex_init(&inst->clone_mutex, NULL); inst->thread_key = rad_malloc(sizeof(*inst->thread_key)); memset(inst->thread_key,0,sizeof(*inst->thread_key)); rlm_perl_make_key(inst->thread_key); #endif /* * Setup the argument array we pass to the perl interpreter */ MEM(embed_c = talloc_zero_array(inst, char const *, 4)); memcpy(&embed, &embed_c, sizeof(embed)); embed_c[0] = NULL; if (inst->perl_flags) { embed_c[1] = inst->perl_flags; embed_c[2] = inst->module; embed_c[3] = arg; argc = 4; } else { embed_c[1] = inst->module; embed_c[2] = arg; argc = 3; } /* * Create tweak the server's environment to support * perl. Docs say only call this once... Oops. */ PERL_SYS_INIT3(&argc, &embed, &envp); /* * Allocate a new perl interpreter to do the parsing */ if ((inst->perl = perl_alloc()) == NULL) { ERROR("rlm_perl: No memory for allocating new perl !"); return -1; } perl_construct(inst->perl); /* ...and initialise it */ #ifdef USE_ITHREADS PL_perl_destruct_level = 2; { dTHXa(inst->perl); } PERL_SET_CONTEXT(inst->perl); #endif #if PERL_REVISION >= 5 && PERL_VERSION >=8 PL_exit_flags |= PERL_EXIT_DESTRUCT_END; #endif exitstatus = perl_parse(inst->perl, xs_init, argc, embed, NULL); end_AV = PL_endav; PL_endav = (AV *)NULL; if (exitstatus) { ERROR("rlm_perl: perl_parse failed: %s not found or has syntax errors", inst->module); return -1; } /* parse perl configuration sub-section */ cs = cf_section_sub_find(conf, "config"); if (cs) { inst->rad_perlconf_hv = get_hv("RAD_PERLCONF", 1); perl_parse_config(cs, 0, inst->rad_perlconf_hv); } inst->perl_parsed = true; perl_run(inst->perl); PL_endav = end_AV; return 0; }
/* * Instantiate the module. */ static int mod_instantiate(CONF_SECTION *conf, void *instance) { rlm_cache_t *inst = instance; inst->cs = conf; inst->xlat_name = cf_section_name2(conf); if (!inst->xlat_name) { inst->xlat_name = cf_section_name1(conf); } /* * Register the cache xlat function */ xlat_register(inst->xlat_name, cache_xlat, NULL, inst); /* * Sanity check for crazy people. */ if (strncmp(inst->driver_name, "rlm_cache_", 8) != 0) { ERROR("%s: \"%s\" is NOT an Cache driver!", inst->xlat_name, inst->driver_name); return -1; } /* * Load the appropriate driver for our database */ inst->handle = lt_dlopenext(inst->driver_name); if (!inst->handle) { ERROR("Could not link driver %s: %s", inst->driver_name, dlerror()); ERROR("Make sure it (and all its dependent libraries!) are in the search path of your system's ld"); return -1; } inst->module = (cache_module_t *) dlsym(inst->handle, inst->driver_name); if (!inst->module) { ERROR("Could not link symbol %s: %s", inst->driver_name, dlerror()); return -1; } DEBUG3("Driver %s loaded successfully", inst->module->name); /* * Non optional fields and callbacks */ rad_assert(inst->module->name); rad_assert(inst->module->find); rad_assert(inst->module->insert); rad_assert(inst->module->expire); if (inst->module->mod_instantiate) { CONF_SECTION *cs; char const *name; name = strrchr(inst->driver_name, '_'); if (!name) { name = inst->driver_name; } else { name++; } cs = cf_section_sub_find(conf, name); if (!cs) { cs = cf_section_alloc(conf, name, NULL); if (!cs) return -1; } /* * It's up to the driver to register a destructor (using talloc) * * Should write its instance data in inst->driver, * and parent it off of inst. */ if (inst->module->mod_instantiate(cs, inst) < 0) return -1; } rad_assert(inst->key && *inst->key); if (inst->ttl == 0) { cf_log_err_cs(conf, "Must set 'ttl' to non-zero"); return -1; } if (inst->epoch != 0) { cf_log_err_cs(conf, "Must not set 'epoch' in the configuration files"); return -1; } /* * Make sure the users don't screw up too badly. */ if (map_afrom_cs(&inst->maps, cf_section_sub_find(inst->cs, "update"), PAIR_LIST_REQUEST, PAIR_LIST_REQUEST, cache_verify, NULL, MAX_ATTRMAP) < 0) { return -1; } if (!inst->maps) { cf_log_err_cs(inst->cs, "Cache config must contain an update section, and " "that section must not be empty"); return -1; } return 0; }
/* * (Re-)read radiusd.conf into memory. */ static int mod_instantiate(CONF_SECTION *conf, void *instance) { detail_instance_t *inst = instance; CONF_SECTION *cs; inst->name = cf_section_name2(conf); if (!inst->name) { inst->name = cf_section_name1(conf); } inst->lf= fr_logfile_init(inst); if (!inst->lf) { cf_log_err_cs(conf, "Failed creating log file context"); return -1; } /* * Suppress certain attributes. */ cs = cf_section_sub_find(conf, "suppress"); if (cs) { CONF_ITEM *ci; inst->ht = fr_hash_table_create(detail_hash, detail_cmp, NULL); for (ci = cf_item_find_next(cs, NULL); ci != NULL; ci = cf_item_find_next(cs, ci)) { char const *attr; DICT_ATTR const *da; if (!cf_item_is_pair(ci)) continue; attr = cf_pair_attr(cf_itemtopair(ci)); if (!attr) continue; /* pair-anoia */ da = dict_attrbyname(attr); if (!da) { cf_log_err_cs(conf, "No such attribute '%s'", attr); return -1; } /* * Be kind to minor mistakes. */ if (fr_hash_table_finddata(inst->ht, da)) { WARN("rlm_detail (%s): Ignoring duplicate entry '%s'", inst->name, attr); continue; } if (!fr_hash_table_insert(inst->ht, da)) { ERROR("rlm_detail (%s): Failed inserting '%s' into suppression table", inst->name, attr); return -1; } DEBUG("rlm_detail (%s): '%s' suppressed, will not appear in detail output", inst->name, attr); } /* * If we didn't suppress anything, delete the hash table. */ if (fr_hash_table_num_elements(inst->ht) == 0) { fr_hash_table_free(inst->ht); inst->ht = NULL; } } return 0; }