/* * Free the configuration. Called only when the server is exiting. */ int free_mainconfig(void) { cached_config_t *cc, *next; virtual_servers_free(0); /* * Clean up the configuration data * structures. */ clients_free(NULL); realms_free(); listen_free(&mainconfig.listen); /* * Free all of the cached configurations. */ for (cc = cs_cache; cc != NULL; cc = next) { next = cc->next; cf_file_free(cc->cs); free(cc); } dict_free(); return 0; }
/* * Free the configuration. Called only when the server is exiting. */ int main_config_free(void) { virtual_servers_free(0); /* * Clean up the configuration data * structures. */ clients_free(NULL); realms_free(); listen_free(&main_config.listen); /* * Frees current config and any previous configs. */ TALLOC_FREE(cs_cache); dict_free(); return 0; }
RADCLIENT_LIST *clients_parse_section(CONF_SECTION *section, UNUSED bool tls_required) #endif { bool global = false, in_server = false; CONF_SECTION *cs; RADCLIENT *c; RADCLIENT_LIST *clients; /* * Be forgiving. If there's already a clients, return * it. Otherwise create a new one. */ clients = cf_data_find(section, "clients"); if (clients) return clients; clients = clients_init(section); if (!clients) return NULL; if (cf_top_section(section) == section) global = true; if (strcmp("server", cf_section_name1(section)) == 0) in_server = true; /* * Associate the clients structure with the section. */ if (cf_data_add(section, "clients", clients, NULL) < 0) { cf_log_err_cs(section, "Failed to associate clients with section %s", cf_section_name1(section)); clients_free(clients); return NULL; } for (cs = cf_subsection_find_next(section, NULL, "client"); cs != NULL; cs = cf_subsection_find_next(section, cs, "client")) { c = client_afrom_cs(cs, cs, in_server); if (!c) { return NULL; } #ifdef WITH_TLS /* * TLS clients CANNOT use non-TLS listeners. * non-TLS clients CANNOT use TLS listeners. */ if (tls_required != c->tls_required) { cf_log_err_cs(cs, "Client does not have the same TLS configuration as the listener"); client_free(c); clients_free(clients); return NULL; } #endif /* * FIXME: Add the client as data via cf_data_add, * for migration issues. */ #ifdef WITH_DYNAMIC_CLIENTS #ifdef HAVE_DIRENT_H if (c->client_server) { char const *value; CONF_PAIR *cp; DIR *dir; struct dirent *dp; struct stat stat_buf; char buf2[2048]; /* * Find the directory where individual * client definitions are stored. */ cp = cf_pair_find(cs, "directory"); if (!cp) goto add_client; value = cf_pair_value(cp); if (!value) { cf_log_err_cs(cs, "The \"directory\" entry must not be empty"); client_free(c); return NULL; } DEBUG("including dynamic clients in %s", value); dir = opendir(value); if (!dir) { cf_log_err_cs(cs, "Error reading directory %s: %s", value, fr_syserror(errno)); client_free(c); return NULL; } /* * Read the directory, ignoring "." files. */ while ((dp = readdir(dir)) != NULL) { char const *p; RADCLIENT *dc; if (dp->d_name[0] == '.') continue; /* * Check for valid characters */ for (p = dp->d_name; *p != '\0'; p++) { if (isalpha((int)*p) || isdigit((int)*p) || (*p == ':') || (*p == '.')) continue; break; } if (*p != '\0') continue; snprintf(buf2, sizeof(buf2), "%s/%s", value, dp->d_name); if ((stat(buf2, &stat_buf) != 0) || S_ISDIR(stat_buf.st_mode)) continue; dc = client_read(buf2, in_server, true); if (!dc) { cf_log_err_cs(cs, "Failed reading client file \"%s\"", buf2); client_free(c); closedir(dir); return NULL; } /* * Validate, and add to the list. */ if (!client_add_dynamic(clients, c, dc)) { client_free(c); closedir(dir); return NULL; } } /* loop over the directory */ closedir(dir); } #endif /* HAVE_DIRENT_H */ add_client: #endif /* WITH_DYNAMIC_CLIENTS */ if (!client_add(clients, c)) { cf_log_err_cs(cs, "Failed to add client %s", cf_section_name2(cs)); client_free(c); return NULL; } } /* * Replace the global list of clients with the new one. * The old one is still referenced from the original * configuration, and will be freed when that is freed. */ if (global) { root_clients = clients; } return clients; }
/* * Add a client to the tree. */ int client_add(RADCLIENT_LIST *clients, RADCLIENT *client) { RADCLIENT *old; char buffer[INET6_ADDRSTRLEN + 3]; if (!client) return 0; /* * 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 "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) { radlog(L_ERR, "Failed to find virtual server %s", client->server); return 0; } /* * If the client list already exists, use that. * Otherwise, create a new client list. */ clients = cf_data_find(cs, "clients"); if (!clients) { clients = clients_init(cs); if (!clients) { radlog(L_ERR, "Out of memory"); return 0; } if (cf_data_add(cs, "clients", clients, (void (*)(void *)) clients_free) < 0) { radlog(L_ERR, "Failed to associate clients with virtual server %s", client->server); clients_free(clients); return 0; } } } else { /* * Initialize the global list, if not done already. */ if (!root_clients) { root_clients = clients_init(NULL); if (!root_clients) return 0; } 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 0; } } #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 1; } ERROR("Failed to add duplicate client %s", client->shortname); return 0; } #undef namecmp /* * Other error adding client: likely is fatal. */ if (!rbtree_insert(clients->trees[client->ipaddr.prefix], client)) { return 0; } #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 1; }