static virtual_server_t *virtual_server_find(char const *name) { CONF_SECTION *cs; cs = cf_section_sub_find_name2(main_config.config, "server", name); if (!cs) return NULL; return (virtual_server_t *) cf_data_find(cs, name); }
/* * 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; }
/* * 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; }
/* * Find a module instance. */ module_instance_t *find_module_instance(CONF_SECTION *modules, char const *askedname, int do_link) { int check_config_safe = false; CONF_SECTION *cs; char const *name1, *instname; module_instance_t *node, myNode; char module_name[256]; if (!modules) return NULL; /* * Look for the real name. Ignore the first character, * which tells the server "it's OK for this module to not * exist." */ instname = askedname; if (instname[0] == '-') { instname++; } /* * Module instances are declared in the modules{} block * and referenced later by their name, which is the * name2 from the config section, or name1 if there was * no name2. */ cs = cf_section_sub_find_name2(modules, NULL, instname); if (!cs) { ERROR("Cannot find a configuration entry for module \"%s\"", instname); return NULL; } /* * If there's already a module instance, return it. */ strlcpy(myNode.name, instname, sizeof(myNode.name)); node = rbtree_finddata(instance_tree, &myNode); if (node) { return node; } if (!do_link) { return NULL; } name1 = cf_section_name1(cs); /* * Found the configuration entry, hang the node struct off of the * configuration section. If the CS is free'd the instance will * be too. */ node = talloc_zero(cs, module_instance_t); node->cs = cs; /* * Names in the "modules" section aren't prefixed * with "rlm_", so we add it here. */ snprintf(module_name, sizeof(module_name), "rlm_%s", name1); /* * Pull in the module object */ node->entry = linkto_module(module_name, cs); if (!node->entry) { talloc_free(node); /* linkto_module logs any errors */ return NULL; } if (check_config && (node->entry->module->instantiate) && (node->entry->module->type & RLM_TYPE_CHECK_CONFIG_SAFE) == 0) { char const *value = NULL; CONF_PAIR *cp; cp = cf_pair_find(cs, "force_check_config"); if (cp) { value = cf_pair_value(cp); } if (value && (strcmp(value, "yes") == 0)) goto print_inst; cf_log_module(cs, "Skipping instantiation of %s", instname); } else { print_inst: check_config_safe = true; cf_log_module(cs, "Instantiating module \"%s\" from file %s", instname, cf_section_filename(cs)); } strlcpy(node->name, instname, sizeof(node->name)); /* * Parse the module configuration, and setup destructors so the * module's detach method is called when it's instance data is * about to be freed. */ if (module_conf_parse(node, &node->insthandle) < 0) { talloc_free(node); return NULL; } /* * Call the module's instantiation routine. */ if ((node->entry->module->instantiate) && (!check_config || check_config_safe) && ((node->entry->module->instantiate)(cs, node->insthandle) < 0)) { cf_log_err_cs(cs, "Instantiation failed for module \"%s\"", node->name); talloc_free(node); return NULL; } #ifdef HAVE_PTHREAD_H /* * If we're threaded, check if the module is thread-safe. * * If it isn't, we create a mutex. */ if ((node->entry->module->type & RLM_TYPE_THREAD_UNSAFE) != 0) { node->mutex = talloc_zero(node, pthread_mutex_t); /* * Initialize the mutex. */ pthread_mutex_init(node->mutex, NULL); } else { /* * The module is thread-safe. Don't give it a mutex. */ node->mutex = NULL; } #endif rbtree_insert(instance_tree, node); return node; }
/** Create a client CONF_SECTION using a mapping section to map values from a result set to client attributes * * If we hit a CONF_SECTION we recurse and process its CONF_PAIRS too. * * @note Caller should free CONF_SECTION passed in as out, on error. * Contents of that section will be in an undefined state. * * @param[in,out] out Section to perform mapping on. Either the root of the client config, or a parent section * (when this function is called recursively). * Should be alloced with cf_section_alloc, or if there's a separate template section, the * result of calling cf_section_dup on that section. * @param[in] map section. * @param[in] func to call to retrieve CONF_PAIR values. Must return a talloced buffer containing the value. * @param[in] data to pass to func, usually a result pointer. * @return 0 on success else -1 on error. */ int client_map_section(CONF_SECTION *out, CONF_SECTION const *map, client_value_cb_t func, void *data) { CONF_ITEM const *ci; for (ci = cf_item_find_next(map, NULL); ci != NULL; ci = cf_item_find_next(map, ci)) { CONF_PAIR const *cp; CONF_PAIR *old; char *value; char const *attr; /* * Recursively process map subsection */ if (cf_item_is_section(ci)) { CONF_SECTION *cs, *cc; cs = cf_item_to_section(ci); /* * Use pre-existing section or alloc a new one */ cc = cf_section_sub_find_name2(out, cf_section_name1(cs), cf_section_name2(cs)); if (!cc) { cc = cf_section_alloc(out, cf_section_name1(cs), cf_section_name2(cs)); cf_section_add(out, cc); if (!cc) return -1; } if (client_map_section(cc, cs, func, data) < 0) return -1; continue; } cp = cf_item_to_pair(ci); attr = cf_pair_attr(cp); /* * The callback can return 0 (success) and not provide a value * in which case we skip the mapping pair. * * Or return -1 in which case we error out. */ if (func(&value, cp, data) < 0) { cf_log_err_cs(out, "Failed performing mapping \"%s\" = \"%s\"", attr, cf_pair_value(cp)); return -1; } if (!value) continue; /* * Replace an existing CONF_PAIR */ old = cf_pair_find(out, attr); if (old) { cf_pair_replace(out, old, value); talloc_free(value); continue; } /* * ...or add a new CONF_PAIR */ cp = cf_pair_alloc(out, attr, value, T_OP_SET, T_BARE_WORD, T_SINGLE_QUOTED_STRING); if (!cp) { cf_log_err_cs(out, "Failed allocing pair \"%s\" = \"%s\"", attr, value); talloc_free(value); return -1; } talloc_free(value); cf_item_add(out, cf_pair_to_item(cp)); } return 0; }
/** Add a client to a RADCLIENT_LIST * * @param clients list to add client to, may be NULL if global client list is being used. * @param client to add. * @return true on success, false on failure. */ bool client_add(RADCLIENT_LIST *clients, RADCLIENT *client) { RADCLIENT *old; char buffer[INET6_ADDRSTRLEN + 3]; if (!client) return false; /* * Hack to fixup wildcard clients * * If the IP is all zeros, with a 32 or 128 bit netmask * assume the user meant to configure 0.0.0.0/0 instead * of 0.0.0.0/32 - which would require the src IP of * the client to be all zeros. */ if (fr_inaddr_any(&client->ipaddr) == 1) switch (client->ipaddr.af) { case AF_INET: if (client->ipaddr.prefix == 32) client->ipaddr.prefix = 0; break; case AF_INET6: if (client->ipaddr.prefix == 128) client->ipaddr.prefix = 0; break; default: rad_assert(0); } fr_ntop(buffer, sizeof(buffer), &client->ipaddr); DEBUG3("Adding client %s (%s) to prefix tree %i", buffer, client->longname, client->ipaddr.prefix); /* * If the client also defines a server, do that now. */ if (client->defines_coa_server) if (!realm_home_server_add(client->coa_server)) return false; /* * If "clients" is NULL, it means add to the global list, * unless we're trying to add it to a virtual server... */ if (!clients) { if (client->server != NULL) { CONF_SECTION *cs; cs = cf_section_sub_find_name2(main_config.config, "server", client->server); if (!cs) { ERROR("Failed to find virtual server %s", client->server); return false; } /* * If the client list already exists, use that. * Otherwise, create a new client list. */ clients = cf_data_find(cs, "clients"); if (!clients) { clients = client_list_init(cs); if (!clients) { ERROR("Out of memory"); return false; } if (cf_data_add(cs, "clients", clients, (void (*)(void *)) client_list_free) < 0) { ERROR("Failed to associate clients with virtual server %s", client->server); client_list_free(clients); return false; } } } else { /* * Initialize the global list, if not done already. */ if (!root_clients) { root_clients = client_list_init(NULL); if (!root_clients) return false; } clients = root_clients; } } /* * Create a tree for it. */ if (!clients->trees[client->ipaddr.prefix]) { clients->trees[client->ipaddr.prefix] = rbtree_create(clients, client_ipaddr_cmp, NULL, 0); if (!clients->trees[client->ipaddr.prefix]) { return false; } } #define namecmp(a) ((!old->a && !client->a) || (old->a && client->a && (strcmp(old->a, client->a) == 0))) /* * Cannot insert the same client twice. */ old = rbtree_finddata(clients->trees[client->ipaddr.prefix], client); if (old) { /* * If it's a complete duplicate, then free the new * one, and return "OK". */ if ((fr_ipaddr_cmp(&old->ipaddr, &client->ipaddr) == 0) && (old->ipaddr.prefix == client->ipaddr.prefix) && namecmp(longname) && namecmp(secret) && namecmp(shortname) && namecmp(nas_type) && namecmp(login) && namecmp(password) && namecmp(server) && #ifdef WITH_DYNAMIC_CLIENTS (old->lifetime == client->lifetime) && namecmp(client_server) && #endif #ifdef WITH_COA namecmp(coa_name) && (old->coa_server == client->coa_server) && (old->coa_pool == client->coa_pool) && #endif (old->message_authenticator == client->message_authenticator)) { WARN("Ignoring duplicate client %s", client->longname); client_free(client); return true; } ERROR("Failed to add duplicate client %s", client->shortname); return false; } #undef namecmp /* * Other error adding client: likely is fatal. */ if (!rbtree_insert(clients->trees[client->ipaddr.prefix], client)) { return false; } #ifdef WITH_STATS if (!tree_num) { tree_num = rbtree_create(clients, client_num_cmp, NULL, 0); } #ifdef WITH_DYNAMIC_CLIENTS /* * More catching of clients added by rlm_sql. * * The sql modules sets the dynamic flag BEFORE calling * us. The client_afrom_request() function sets it AFTER * calling us. */ if (client->dynamic && (client->lifetime == 0)) { RADCLIENT *network; /* * If there IS an enclosing network, * inherit the lifetime from it. */ network = client_find(clients, &client->ipaddr, client->proto); if (network) { client->lifetime = network->lifetime; } } #endif client->number = tree_num_max; tree_num_max++; if (tree_num) rbtree_insert(tree_num, client); #endif if (client->ipaddr.prefix < clients->min_prefix) { clients->min_prefix = client->ipaddr.prefix; } (void) talloc_steal(clients, client); /* reparent it */ return true; }
/* * Find a module instance. */ module_instance_t *find_module_instance(CONF_SECTION *modules, const char *askedname, int do_link) { int check_config_safe = FALSE; CONF_SECTION *cs; const char *name1, *instname; module_instance_t *node, myNode; char module_name[256]; if (!modules) return NULL; /* * Look for the real name. Ignore the first character, * which tells the server "it's OK for this module to not * exist." */ instname = askedname; if (instname[0] == '-') instname++; /* * Module instances are declared in the modules{} block * and referenced later by their name, which is the * name2 from the config section, or name1 if there was * no name2. */ cs = cf_section_sub_find_name2(modules, NULL, instname); if (cs == NULL) { radlog(L_ERR, "ERROR: Cannot find a configuration entry for module \"%s\".\n", instname); return NULL; } /* * If there's already a module instance, return it. */ strlcpy(myNode.name, instname, sizeof(myNode.name)); node = rbtree_finddata(instance_tree, &myNode); if (node) return node; if (!do_link) return NULL; name1 = cf_section_name1(cs); /* * Found the configuration entry. */ node = rad_malloc(sizeof(*node)); memset(node, 0, sizeof(*node)); node->insthandle = NULL; node->cs = cs; /* * Names in the "modules" section aren't prefixed * with "rlm_", so we add it here. */ snprintf(module_name, sizeof(module_name), "rlm_%s", name1); node->entry = linkto_module(module_name, cs); if (!node->entry) { free(node); /* linkto_module logs any errors */ return NULL; } if (check_config && (node->entry->module->instantiate) && (node->entry->module->type & RLM_TYPE_CHECK_CONFIG_SAFE) == 0) { const char *value = NULL; CONF_PAIR *cp; cp = cf_pair_find(cs, "force_check_config"); if (cp) value = cf_pair_value(cp); if (value && (strcmp(value, "yes") == 0)) goto print_inst; cf_log_module(cs, "Skipping instantiation of %s", instname); } else { print_inst: check_config_safe = TRUE; cf_log_module(cs, "Instantiating module \"%s\" from file %s", instname, cf_section_filename(cs)); } /* * Call the module's instantiation routine. */ if ((node->entry->module->instantiate) && (!check_config || check_config_safe) && ((node->entry->module->instantiate)(cs, &node->insthandle) < 0)) { cf_log_err(cf_sectiontoitem(cs), "Instantiation failed for module \"%s\"", instname); free(node); return NULL; } /* * We're done. Fill in the rest of the data structure, * and link it to the module instance list. */ strlcpy(node->name, instname, sizeof(node->name)); #ifdef HAVE_PTHREAD_H /* * If we're threaded, check if the module is thread-safe. * * If it isn't, we create a mutex. */ if ((node->entry->module->type & RLM_TYPE_THREAD_UNSAFE) != 0) { node->mutex = (pthread_mutex_t *) rad_malloc(sizeof(pthread_mutex_t)); /* * Initialize the mutex. */ pthread_mutex_init(node->mutex, NULL); } else { /* * The module is thread-safe. Don't give it a mutex. */ node->mutex = NULL; } #endif rbtree_insert(instance_tree, node); return node; }
/* * Find a module instance. */ module_instance_t *find_module_instance(CONF_SECTION *modules, char const *askedname, int do_link) { int check_config_safe = false; CONF_SECTION *cs; char const *name1, *instname; module_instance_t *node, myNode; char module_name[256]; if (!modules) return NULL; /* * Look for the real name. Ignore the first character, * which tells the server "it's OK for this module to not * exist." */ instname = askedname; if (instname[0] == '-') instname++; /* * Module instances are declared in the modules{} block * and referenced later by their name, which is the * name2 from the config section, or name1 if there was * no name2. */ cs = cf_section_sub_find_name2(modules, NULL, instname); if (cs == NULL) { ERROR("Cannot find a configuration entry for module \"%s\".\n", instname); return NULL; } /* * If there's already a module instance, return it. */ strlcpy(myNode.name, instname, sizeof(myNode.name)); node = rbtree_finddata(instance_tree, &myNode); if (node) return node; if (!do_link) return NULL; name1 = cf_section_name1(cs); /* * Found the configuration entry. */ node = talloc_zero(cs, module_instance_t); node->insthandle = NULL; node->cs = cs; /* * Names in the "modules" section aren't prefixed * with "rlm_", so we add it here. */ snprintf(module_name, sizeof(module_name), "rlm_%s", name1); node->entry = linkto_module(module_name, cs); if (!node->entry) { talloc_free(node); /* linkto_module logs any errors */ return NULL; } if (check_config && (node->entry->module->instantiate) && (node->entry->module->type & RLM_TYPE_CHECK_CONFIG_SAFE) == 0) { char const *value = NULL; CONF_PAIR *cp; cp = cf_pair_find(cs, "force_check_config"); if (cp) value = cf_pair_value(cp); if (value && (strcmp(value, "yes") == 0)) goto print_inst; cf_log_module(cs, "Skipping instantiation of %s", instname); } else { print_inst: check_config_safe = true; cf_log_module(cs, "Instantiating module \"%s\" from file %s", instname, cf_section_filename(cs)); } /* * If there is supposed to be instance data, allocate it now. * Also parse the configuration data, if required. */ if (node->entry->module->inst_size) { /* FIXME: make this rlm_config_t ?? */ node->insthandle = talloc_zero_array(node, uint8_t, node->entry->module->inst_size); rad_assert(node->insthandle != NULL); /* * So we can see where this configuration is from * FIXME: set it to rlm_NAME_t, or some such thing */ talloc_set_name(node->insthandle, "rlm_config_t"); if (node->entry->module->config && (cf_section_parse(cs, node->insthandle, node->entry->module->config) < 0)) { cf_log_err_cs(cs, "Invalid configuration for module \"%s\"", instname); talloc_free(node); return NULL; } /* * Set the destructor. */ if (node->entry->module->detach) { talloc_set_destructor((void *) node->insthandle, node->entry->module->detach); } } /* * Call the module's instantiation routine. */ if ((node->entry->module->instantiate) && (!check_config || check_config_safe) && ((node->entry->module->instantiate)(cs, node->insthandle) < 0)) { cf_log_err_cs(cs, "Instantiation failed for module \"%s\"", instname); talloc_free(node); return NULL; } /* * We're done. Fill in the rest of the data structure, * and link it to the module instance list. */ strlcpy(node->name, instname, sizeof(node->name)); #ifdef HAVE_PTHREAD_H /* * If we're threaded, check if the module is thread-safe. * * If it isn't, we create a mutex. */ if ((node->entry->module->type & RLM_TYPE_THREAD_UNSAFE) != 0) { node->mutex = talloc_zero(node, pthread_mutex_t); /* * Initialize the mutex. */ pthread_mutex_init(node->mutex, NULL); } else { /* * The module is thread-safe. Don't give it a mutex. */ node->mutex = NULL; } #endif rbtree_insert(instance_tree, node); return node; }
/* * Attach the module. */ static int mod_instantiate(CONF_SECTION *cs, void **instance) { rlm_eap_fast_t *inst; *instance = inst = talloc_zero(cs, rlm_eap_fast_t); if (!inst) return -1; /* * Parse the configuration attributes. */ if (cf_section_parse(cs, inst, module_config) < 0) { return -1; } if (!cf_section_sub_find_name2(main_config.config, "server", inst->virtual_server)) { ERROR("rlm_eap_fast.virtual_server: Unknown virtual server '%s'", inst->virtual_server); return -1; } inst->default_method = eap_name2type(inst->default_method_name); if (!inst->default_method) { ERROR("rlm_eap_fast.default_provisioning_eap_type: " "Unknown EAP type %s", inst->default_method_name); return -1; } /* * Read tls configuration, either from group given by 'tls' * option, or from the eap-tls configuration. */ inst->tls_conf = eaptls_conf_parse(cs, "tls"); if (!inst->tls_conf) { ERROR("rlm_eap_fast.tls: Failed initializing SSL context"); return -1; } if (talloc_array_length(inst->pac_opaque_key) - 1 != 32) { ERROR("rlm_eap_fast.pac_opaque_key: Must be 32 bytes long"); return -1; } // FIXME TLSv1.2 uses a different PRF and SSL_export_keying_material("key expansion") is forbidden if (!inst->tls_conf->disable_tlsv1_2) { ERROR("rlm_eap_fast.disable_tlsv1_2: require disable_tlsv1_2=yes"); return -1; } if (!inst->pac_lifetime) { ERROR("rlm_eap_fast.pac_lifetime: must be non-zero"); return -1; } rad_assert(PAC_A_ID_LENGTH == MD5_DIGEST_LENGTH); FR_MD5_CTX ctx; fr_md5_init(&ctx); fr_md5_update(&ctx, inst->authority_identity, talloc_array_length(inst->authority_identity) - 1); fr_md5_final(inst->a_id, &ctx); return 0; }