int rad_load_proposals(ikev2_ctx *i2,CONF_SECTION *cf) { rad_assert(i2!=NULL && cf!=NULL); CONF_SECTION *cf_prop=NULL; cf=cf_subsection_find_next(cf,NULL,"proposals"); if(!cf) { ERROR(IKEv2_LOG_PREFIX "Can't find proposals section"); return -1; } int nprop=0; for( cf_prop=cf_subsection_find_next(cf,NULL,"proposal"); cf_prop; cf_prop=cf_subsection_find_next(cf,cf_prop,"proposal") ) { nprop++; struct Proposal *prop; struct Protocol *prot; prop=AddProposal(&i2->suppProp); prot=AddProtocol(prop,IKEv2_PID_IKE_SA,0,0); if(rad_load_transforms(prot,cf_prop)) { ERROR(IKEv2_LOG_PREFIX "Failed to load proposal (%d)", nprop); return -1; } } if(!nprop) { ERROR(IKEv2_LOG_PREFIX "Can't find any proposal"); return -1; } return 0; }
/* * read the config section and load all the eap authentication types present. */ static int eap_instantiate(CONF_SECTION *cs, void **instance) { int i, num_types; int has_tls, do_tls; rlm_eap_t *inst; CONF_SECTION *scs; inst = (rlm_eap_t *) malloc(sizeof(*inst)); if (!inst) { return -1; } memset(inst, 0, sizeof(*inst)); if (cf_section_parse(cs, inst, module_config) < 0) { eap_detach(inst); return -1; } /* * Create our own random pool. */ for (i = 0; i < 256; i++) { inst->rand_pool.randrsl[i] = fr_rand(); } fr_randinit(&inst->rand_pool, 1); /* * List of sessions are set to NULL by the memset * of 'inst', above. */ /* * Lookup sessions in the tree. We don't free them in * the tree, as that's taken care of elsewhere... */ inst->session_tree = rbtree_create(eap_handler_cmp, NULL, 0); if (!inst->session_tree) { radlog(L_ERR|L_CONS, "rlm_eap2: Cannot initialize tree"); eap_detach(inst); return -1; } /* * This registers ALL available methods. * * FIXME: we probably want to selectively register * some methods. */ if (eap_server_register_methods() < 0) { eap_detach(inst); return -1; } /* Load all the configured EAP-Types */ num_types = 0; has_tls = do_tls = 0; for (scs=cf_subsection_find_next(cs, NULL, NULL); scs != NULL; scs=cf_subsection_find_next(cs, scs, NULL)) { const char *auth_type; char buffer[64], *p; auth_type = cf_section_name1(scs); if (!auth_type) continue; if (num_types >= EAP_MAX_METHODS) { radlog(L_INFO, "WARNING: Ignoring EAP type %s: too many types defined", auth_type); continue; } /* * Hostapd doesn't do case-insensitive comparisons. * So we mash everything to uppercase for it. */ strlcpy(buffer, auth_type, sizeof(buffer)); for (p = buffer; *p; p++) { if (!islower((int)*p)) continue; *p = toupper((int)*p); } inst->methods[num_types] = eap_server_get_type(buffer, &inst->vendors[num_types]); if (inst->methods[num_types] == EAP_TYPE_NONE) { radlog(L_ERR|L_CONS, "rlm_eap2: Unknown EAP type %s", auth_type); eap_detach(inst); return -1; } switch (inst->methods[num_types]) { case EAP_TYPE_TLS: has_tls = TRUE; /* FALL-THROUGH */ case EAP_TYPE_TTLS: case EAP_TYPE_PEAP: case EAP_TYPE_FAST: do_tls = TRUE; break; default: break; } num_types++; /* successfully loaded one more types */ } inst->num_types = num_types; if (do_tls && !has_tls) { radlog(L_ERR|L_CONS, "rlm_eap2: TLS has not been configured. Cannot do methods that need TLS."); eap_detach(inst); return -1; } if (do_tls) { /* * Initialize TLS. */ if (eap_example_server_init_tls(inst) < 0) { radlog(L_ERR|L_CONS, "rlm_eap2: Cannot initialize TLS"); eap_detach(inst); return -1; } } pthread_mutex_init(&(inst->session_mutex), NULL); *instance = inst; return 0; }
/* * Allocate the thread pool, and seed it with an initial number * of threads. * * FIXME: What to do on a SIGHUP??? */ int thread_pool_init(CONF_SECTION *cs, int *spawn_flag) { #ifndef WITH_GCD int i, rcode; CONF_SECTION *pool_cf; #endif time_t now; cs = cs; /* -Wunused */ now = time(NULL); rad_assert(spawn_flag != NULL); rad_assert(*spawn_flag == TRUE); rad_assert(pool_initialized == FALSE); /* not called on HUP */ #ifndef WITH_GCD pool_cf = cf_subsection_find_next(cs, NULL, "thread"); if (!pool_cf) *spawn_flag = FALSE; #endif /* * Initialize the thread pool to some reasonable values. */ memset(&thread_pool, 0, sizeof(THREAD_POOL)); #ifndef WITH_GCD thread_pool.head = NULL; thread_pool.tail = NULL; thread_pool.total_threads = 0; thread_pool.max_thread_num = 1; thread_pool.cleanup_delay = 5; thread_pool.stop_flag = 0; #endif thread_pool.spawn_flag = *spawn_flag; /* * Don't bother initializing the mutexes or * creating the hash tables. They won't be used. */ if (!*spawn_flag) return 0; #ifdef WNOHANG if ((pthread_mutex_init(&thread_pool.wait_mutex,NULL) != 0)) { radlog(L_ERR, "FATAL: Failed to initialize wait mutex: %s", strerror(errno)); return -1; } /* * Create the hash table of child PID's */ thread_pool.waiters = fr_hash_table_create(pid_hash, pid_cmp, free); if (!thread_pool.waiters) { radlog(L_ERR, "FATAL: Failed to set up wait hash"); return -1; } #endif #ifndef WITH_GCD if (cf_section_parse(pool_cf, NULL, thread_config) < 0) { return -1; } /* * Catch corner cases. */ if (thread_pool.min_spare_threads < 1) thread_pool.min_spare_threads = 1; if (thread_pool.max_spare_threads < 1) thread_pool.max_spare_threads = 1; if (thread_pool.max_spare_threads < thread_pool.min_spare_threads) thread_pool.max_spare_threads = thread_pool.min_spare_threads; if (thread_pool.max_threads == 0) thread_pool.max_threads = 256; if ((thread_pool.max_queue_size < 2) || (thread_pool.max_queue_size > 1048576)) { radlog(L_ERR, "FATAL: max_queue_size value must be in range 2-1048576"); return -1; } #endif /* WITH_GCD */ /* * The pool has already been initialized. Don't spawn * new threads, and don't forget about forked children, */ if (pool_initialized) { return 0; } #ifndef WITH_GCD /* * Initialize the queue of requests. */ memset(&thread_pool.semaphore, 0, sizeof(thread_pool.semaphore)); rcode = sem_init(&thread_pool.semaphore, 0, SEMAPHORE_LOCKED); if (rcode != 0) { radlog(L_ERR, "FATAL: Failed to initialize semaphore: %s", strerror(errno)); return -1; } rcode = pthread_mutex_init(&thread_pool.queue_mutex,NULL); if (rcode != 0) { radlog(L_ERR, "FATAL: Failed to initialize queue mutex: %s", strerror(errno)); return -1; } /* * Allocate multiple fifos. */ for (i = 0; i < RAD_LISTEN_MAX; i++) { thread_pool.fifo[i] = fr_fifo_create(thread_pool.max_queue_size, NULL); if (!thread_pool.fifo[i]) { radlog(L_ERR, "FATAL: Failed to set up request fifo"); return -1; } } #endif #ifdef HAVE_OPENSSL_CRYPTO_H /* * If we're linking with OpenSSL too, then we need * to set up the mutexes and enable the thread callbacks. */ if (!setup_ssl_mutexes()) { radlog(L_ERR, "FATAL: Failed to set up SSL mutexes"); return -1; } #endif #ifndef WITH_GCD /* * Create a number of waiting threads. * * If we fail while creating them, do something intelligent. */ for (i = 0; i < thread_pool.start_threads; i++) { if (spawn_thread(now, 0) == NULL) { return -1; } } #else thread_pool.queue = dispatch_queue_create("org.freeradius.threads", NULL); if (!thread_pool.queue) { radlog(L_ERR, "Failed creating dispatch queue: %s\n", strerror(errno)); exit(1); } #endif DEBUG2("Thread pool initialized"); pool_initialized = TRUE; return 0; }
int main(int argc, char **argv) { int argval; bool quiet = false; int sockfd = -1; char *line = NULL; ssize_t len; char const *file = NULL; char const *name = "radiusd"; char *p, buffer[65536]; char const *input_file = NULL; FILE *inputfp = stdin; char const *output_file = NULL; char const *server = NULL; char const *radius_dir = RADIUS_DIR; char const *dict_dir = DICTDIR; char *commands[MAX_COMMANDS]; int num_commands = -1; #ifndef NDEBUG if (fr_fault_setup(getenv("PANIC_ACTION"), argv[0]) < 0) { fr_perror("radmin"); exit(EXIT_FAILURE); } #endif talloc_set_log_stderr(); outputfp = stdout; /* stdout is not a constant value... */ if ((progname = strrchr(argv[0], FR_DIR_SEP)) == NULL) { progname = argv[0]; } else { progname++; } while ((argval = getopt(argc, argv, "d:D:hi:e:Ef:n:o:qs:S")) != EOF) { switch (argval) { case 'd': if (file) { fprintf(stderr, "%s: -d and -f cannot be used together.\n", progname); exit(1); } if (server) { fprintf(stderr, "%s: -d and -s cannot be used together.\n", progname); exit(1); } radius_dir = optarg; break; case 'D': dict_dir = optarg; break; case 'e': num_commands++; /* starts at -1 */ if (num_commands >= MAX_COMMANDS) { fprintf(stderr, "%s: Too many '-e'\n", progname); exit(1); } commands[num_commands] = optarg; break; case 'E': echo = true; break; case 'f': radius_dir = NULL; file = optarg; break; default: case 'h': usage(0); break; case 'i': if (strcmp(optarg, "-") != 0) { input_file = optarg; } quiet = true; break; case 'n': name = optarg; break; case 'o': if (strcmp(optarg, "-") != 0) { output_file = optarg; } quiet = true; break; case 'q': quiet = true; break; case 's': if (file) { fprintf(stderr, "%s: -s and -f cannot be used together.\n", progname); usage(1); } radius_dir = NULL; server = optarg; break; case 'S': secret = NULL; break; } } /* * Mismatch between the binary and the libraries it depends on */ if (fr_check_lib_magic(RADIUSD_MAGIC_NUMBER) < 0) { fr_perror("radmin"); exit(1); } if (radius_dir) { int rcode; CONF_SECTION *cs, *subcs; file = NULL; /* MUST read it from the conffile now */ snprintf(buffer, sizeof(buffer), "%s/%s.conf", radius_dir, name); /* * Need to read in the dictionaries, else we may get * validation errors when we try and parse the config. */ if (dict_init(dict_dir, RADIUS_DICTIONARY) < 0) { fr_perror("radmin"); exit(64); } if (dict_read(radius_dir, RADIUS_DICTIONARY) == -1) { fr_perror("radmin"); exit(64); } cs = cf_file_read(buffer); if (!cs) { fprintf(stderr, "%s: Errors reading or parsing %s\n", progname, buffer); usage(1); } subcs = NULL; while ((subcs = cf_subsection_find_next(cs, subcs, "listen")) != NULL) { char const *value; CONF_PAIR *cp = cf_pair_find(subcs, "type"); if (!cp) continue; value = cf_pair_value(cp); if (!value) continue; if (strcmp(value, "control") != 0) continue; /* * Now find the socket name (sigh) */ rcode = cf_item_parse(subcs, "socket", FR_ITEM_POINTER(PW_TYPE_STRING, &file), NULL); if (rcode < 0) { fprintf(stderr, "%s: Failed parsing listen section\n", progname); exit(1); } if (!file) { fprintf(stderr, "%s: No path given for socket\n", progname); usage(1); } break; } if (!file) { fprintf(stderr, "%s: Could not find control socket in %s\n", progname, buffer); exit(1); } } if (input_file) { inputfp = fopen(input_file, "r"); if (!inputfp) { fprintf(stderr, "%s: Failed opening %s: %s\n", progname, input_file, fr_syserror(errno)); exit(1); } } if (output_file) { outputfp = fopen(output_file, "w"); if (!outputfp) { fprintf(stderr, "%s: Failed creating %s: %s\n", progname, output_file, fr_syserror(errno)); exit(1); } } if (!file && !server) { fprintf(stderr, "%s: Must use one of '-d' or '-f' or '-s'\n", progname); exit(1); } /* * Check if stdin is a TTY only if input is from stdin */ if (input_file && !quiet && !isatty(STDIN_FILENO)) quiet = true; #ifdef USE_READLINE if (!quiet) { #ifdef USE_READLINE_HISTORY using_history(); #endif rl_bind_key('\t', rl_insert); } #endif /* * Prevent SIGPIPEs from terminating the process */ signal(SIGPIPE, SIG_IGN); if (do_connect(&sockfd, file, server) < 0) exit(1); /* * Run one command. */ if (num_commands >= 0) { int i; for (i = 0; i <= num_commands; i++) { len = run_command(sockfd, commands[i], buffer, sizeof(buffer)); if (len < 0) exit(1); if (buffer[0]) { fputs(buffer, outputfp); fprintf(outputfp, "\n"); fflush(outputfp); } } exit(0); } if (!quiet) { printf("%s - FreeRADIUS Server administration tool.\n", radmin_version); printf("Copyright (C) 2008-2014 The FreeRADIUS server project and contributors.\n"); printf("There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A\n"); printf("PARTICULAR PURPOSE.\n"); printf("You may redistribute copies of FreeRADIUS under the terms of the\n"); printf("GNU General Public License v2.\n"); } /* * FIXME: Do login? */ while (1) { #ifndef USE_READLINE if (!quiet) { printf("radmin> "); fflush(stdout); } #else if (!quiet) { line = readline("radmin> "); if (!line) break; if (!*line) { free(line); continue; } #ifdef USE_READLINE_HISTORY add_history(line); #endif } else /* quiet, or no readline */ #endif { line = fgets(buffer, sizeof(buffer), inputfp); if (!line) break; p = strchr(buffer, '\n'); if (!p) { fprintf(stderr, "%s: Input line too long\n", progname); exit(1); } *p = '\0'; /* * Strip off leading spaces. */ for (p = line; *p != '\0'; p++) { if ((p[0] == ' ') || (p[0] == '\t')) { line = p + 1; continue; } if (p[0] == '#') { line = NULL; break; } break; } /* * Comments: keep going. */ if (!line) continue; /* * Strip off CR / LF */ for (p = line; *p != '\0'; p++) { if ((p[0] == '\r') || (p[0] == '\n')) { p[0] = '\0'; break; } } } if (strcmp(line, "reconnect") == 0) { if (do_connect(&sockfd, file, server) < 0) exit(1); line = NULL; continue; } if (memcmp(line, "secret ", 7) == 0) { if (!secret) { secret = line + 7; do_challenge(sockfd); } line = NULL; continue; } /* * Exit, done, etc. */ if ((strcmp(line, "exit") == 0) || (strcmp(line, "quit") == 0)) { break; } if (server && !secret) { fprintf(stderr, "ERROR: You must enter 'secret <SECRET>' before running any commands\n"); line = NULL; continue; } len = run_command(sockfd, line, buffer, sizeof(buffer)); if ((len < 0) && (do_connect(&sockfd, file, server) < 0)) { fprintf(stderr, "Reconnecting..."); exit(1); } else if (len == 0) break; else if (len == 1) continue; /* no output. */ fputs(buffer, outputfp); fflush(outputfp); fprintf(outputfp, "\n"); } fprintf(outputfp, "\n"); return 0; }
int main(int argc, char **argv) { int argval, quiet = 0; int done_license = 0; int sockfd; uint32_t magic, needed; char *line = NULL; ssize_t len, size; char const *file = NULL; char const *name = "radiusd"; char *p, buffer[65536]; char const *input_file = NULL; FILE *inputfp = stdin; char const *output_file = NULL; char const *server = NULL; char *commands[MAX_COMMANDS]; int num_commands = -1; #ifndef NDEBUG fr_fault_setup(getenv("PANIC_ACTION"), argv[0]); #endif talloc_set_log_stderr(); outputfp = stdout; /* stdout is not a constant value... */ if ((progname = strrchr(argv[0], FR_DIR_SEP)) == NULL) progname = argv[0]; else progname++; while ((argval = getopt(argc, argv, "d:hi:e:Ef:n:o:qs:S")) != EOF) { switch(argval) { case 'd': if (file) { fprintf(stderr, "%s: -d and -f cannot be used together.\n", progname); exit(1); } if (server) { fprintf(stderr, "%s: -d and -s cannot be used together.\n", progname); exit(1); } radius_dir = optarg; break; case 'e': num_commands++; /* starts at -1 */ if (num_commands >= MAX_COMMANDS) { fprintf(stderr, "%s: Too many '-e'\n", progname); exit(1); } commands[num_commands] = optarg; break; case 'E': echo = true; break; case 'f': radius_dir = NULL; file = optarg; break; default: case 'h': usage(0); break; case 'i': if (strcmp(optarg, "-") != 0) { input_file = optarg; } quiet = 1; break; case 'n': name = optarg; break; case 'o': if (strcmp(optarg, "-") != 0) { output_file = optarg; } quiet = 1; break; case 'q': quiet = 1; break; case 's': if (file) { fprintf(stderr, "%s: -s and -f cannot be used together.\n", progname); usage(1); } radius_dir = NULL; server = optarg; break; case 'S': secret = NULL; break; } } /* * Mismatch between the binary and the libraries it depends on */ if (fr_check_lib_magic(RADIUSD_MAGIC_NUMBER) < 0) { fr_perror("radmin"); exit(1); } if (radius_dir) { int rcode; CONF_SECTION *cs, *subcs; file = NULL; /* MUST read it from the conffile now */ snprintf(buffer, sizeof(buffer), "%s/%s.conf", radius_dir, name); cs = cf_file_read(buffer); if (!cs) { fprintf(stderr, "%s: Errors reading or parsing %s\n", progname, buffer); usage(1); } subcs = NULL; while ((subcs = cf_subsection_find_next(cs, subcs, "listen")) != NULL) { char const *value; CONF_PAIR *cp = cf_pair_find(subcs, "type"); if (!cp) continue; value = cf_pair_value(cp); if (!value) continue; if (strcmp(value, "control") != 0) continue; /* * Now find the socket name (sigh) */ rcode = cf_item_parse(subcs, "socket", PW_TYPE_STRING_PTR, &file, NULL); if (rcode < 0) { fprintf(stderr, "%s: Failed parsing listen section\n", progname); exit(1); } if (!file) { fprintf(stderr, "%s: No path given for socket\n", progname); usage(1); } break; } if (!file) { fprintf(stderr, "%s: Could not find control socket in %s\n", progname, buffer); exit(1); } } if (input_file) { inputfp = fopen(input_file, "r"); if (!inputfp) { fprintf(stderr, "%s: Failed opening %s: %s\n", progname, input_file, strerror(errno)); exit(1); } } if (output_file) { outputfp = fopen(output_file, "w"); if (!outputfp) { fprintf(stderr, "%s: Failed creating %s: %s\n", progname, output_file, strerror(errno)); exit(1); } } /* * Check if stdin is a TTY only if input is from stdin */ if (input_file && !quiet && !isatty(STDIN_FILENO)) quiet = 1; #ifdef USE_READLINE if (!quiet) { #ifdef USE_READLINE_HISTORY using_history(); #endif rl_bind_key('\t', rl_insert); } #endif reconnect: if (file) { /* * FIXME: Get destination from command line, if possible? */ sockfd = fr_domain_socket(file); if (sockfd < 0) { exit(1); } } else { sockfd = client_socket(server); } /* * Read initial magic && version information. */ for (size = 0; size < 8; size += len) { len = read(sockfd, buffer + size, 8 - size); if (len < 0) { fprintf(stderr, "%s: Error reading initial data from socket: %s\n", progname, strerror(errno)); exit(1); } } memcpy(&magic, buffer, 4); magic = ntohl(magic); if (magic != 0xf7eead15) { fprintf(stderr, "%s: Socket %s is not FreeRADIUS administration socket\n", progname, file); exit(1); } memcpy(&magic, buffer + 4, 4); magic = ntohl(magic); if (!server) { needed = 1; } else { needed = 2; } if (magic != needed) { fprintf(stderr, "%s: Socket version mismatch: Need %d, got %d\n", progname, needed, magic); exit(1); } if (server && secret) do_challenge(sockfd); /* * Run one command. */ if (num_commands >= 0) { int i; for (i = 0; i <= num_commands; i++) { size = run_command(sockfd, commands[i], buffer, sizeof(buffer)); if (size < 0) exit(1); if (buffer[0]) { fputs(buffer, outputfp); fprintf(outputfp, "\n"); fflush(outputfp); } } exit(0); } if (!done_license && !quiet) { printf("%s - FreeRADIUS Server administration tool.\n", radmin_version); printf("Copyright (C) 2008-2014 The FreeRADIUS server project and contributors.\n"); printf("There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A\n"); printf("PARTICULAR PURPOSE.\n"); printf("You may redistribute copies of FreeRADIUS under the terms of the\n"); printf("GNU General Public License v2.\n"); done_license = 1; } /* * FIXME: Do login? */ while (1) { #ifndef USE_READLINE if (!quiet) { printf("radmin> "); fflush(stdout); } #else if (!quiet) { line = readline("radmin> "); if (!line) break; if (!*line) { free(line); continue; } #ifdef USE_READLINE_HISTORY add_history(line); #endif } else /* quiet, or no readline */ #endif { line = fgets(buffer, sizeof(buffer), inputfp); if (!line) break; p = strchr(buffer, '\n'); if (!p) { fprintf(stderr, "%s: Input line too long\n", progname); exit(1); } *p = '\0'; /* * Strip off leading spaces. */ for (p = line; *p != '\0'; p++) { if ((p[0] == ' ') || (p[0] == '\t')) { line = p + 1; continue; } if (p[0] == '#') { line = NULL; break; } break; } /* * Comments: keep going. */ if (!line) continue; /* * Strip off CR / LF */ for (p = line; *p != '\0'; p++) { if ((p[0] == '\r') || (p[0] == '\n')) { p[0] = '\0'; break; } } } if (strcmp(line, "reconnect") == 0) { close(sockfd); line = NULL; goto reconnect; } if (memcmp(line, "secret ", 7) == 0) { if (!secret) { secret = line + 7; do_challenge(sockfd); } line = NULL; continue; } /* * Exit, done, etc. */ if ((strcmp(line, "exit") == 0) || (strcmp(line, "quit") == 0)) { break; } if (server && !secret) { fprintf(stderr, "ERROR: You must enter 'secret <SECRET>' before running any commands\n"); line = NULL; continue; } size = run_command(sockfd, line, buffer, sizeof(buffer)); if (size <= 0) break; /* error, or clean exit */ if (size == 1) continue; /* no output. */ fputs(buffer, outputfp); fflush(outputfp); fprintf(outputfp, "\n"); } fprintf(outputfp, "\n"); return 0; }
/* * Find a module instance. */ module_instance_t *find_module_instance(const char *instname) { CONF_SECTION *cs, *inst_cs; const char *name1, *name2; module_instance_t *node, **last; char module_name[256]; /* * Look through the global module instance list for the * named module. */ last = &module_instance_list; for (node = module_instance_list; node != NULL; node = node->next) { /* * Found the named instance. Return it. */ if (strcmp(node->name, instname) == 0) return node; /* * Keep a pointer to the last entry to update... */ last = &node->next; } /* * Instance doesn't exist yet. Try to find the * corresponding configuration section and create it. */ /* * Look for the 'modules' configuration section. */ cs = cf_section_find("modules"); if (cs == NULL) { radlog(L_ERR|L_CONS, "ERROR: Cannot find a 'modules' section in the configuration file.\n"); return NULL; } /* * 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. */ name1 = name2 = NULL; for(inst_cs=cf_subsection_find_next(cs, NULL, NULL); inst_cs != NULL; inst_cs=cf_subsection_find_next(cs, inst_cs, NULL)) { name1 = cf_section_name1(inst_cs); name2 = cf_section_name2(inst_cs); if ( (name2 && !strcmp(name2, instname)) || (!name2 && !strcmp(name1, instname)) ) break; } if (inst_cs == NULL) { radlog(L_ERR|L_CONS, "ERROR: Cannot find a configuration entry for module \"%s\".\n", instname); return NULL; } /* * Found the configuration entry. */ node = rad_malloc(sizeof(*node)); node->next = NULL; node->insthandle = NULL; /* * Link to the module by name: rlm_FOO-major.minor */ if (strncmp(name1, "rlm_", 4)) { #if 0 snprintf(module_name, sizeof(module_name), "rlm_%s-%d.%d", name1, RADIUSD_MAJOR_VERSION, RADIUSD_MINOR_VERSION); #else snprintf(module_name, sizeof(module_name), "rlm_%s", name1); #endif } else { strNcpy(module_name, name1, sizeof(module_name)); } /* * FIXME: "radiusd.conf" is wrong here; must find cf filename */ node->entry = linkto_module(module_name, "radiusd.conf", cf_section_lineno(inst_cs)); if (!node->entry) { free(node); /* linkto_module logs any errors */ return NULL; } /* * Call the module's instantiation routine. */ if ((node->entry->module->instantiate) && ((node->entry->module->instantiate)(inst_cs, &node->insthandle) < 0)) { radlog(L_ERR|L_CONS, "radiusd.conf[%d]: %s: Module instantiation failed.\n", cf_section_lineno(inst_cs), instname); free(node); return NULL; } /* * We're done. Fill in the rest of the data structure, * and link it to the module instance list. */ strNcpy(node->name, instname, sizeof(node->name)); #if 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 *last = node; DEBUG("Module: Instantiated %s (%s) ", name1, node->name); return node; }
RADCLIENT_LIST *client_list_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 = client_list_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)); client_list_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, false); 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); client_list_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; }
/* * read the config section and load all the eap authentication types present. */ static int mod_instantiate(CONF_SECTION *cs, void *instance) { int i, ret; eap_type_t method; int num_methods; CONF_SECTION *scs; rlm_eap_t *inst = instance; /* * Create our own random pool. */ for (i = 0; i < 256; i++) { inst->rand_pool.randrsl[i] = fr_rand(); } fr_randinit(&inst->rand_pool, 1); inst->rand_pool.randcnt = 0; inst->xlat_name = cf_section_name2(cs); if (!inst->xlat_name) inst->xlat_name = "EAP"; /* Load all the configured EAP-Types */ num_methods = 0; for(scs = cf_subsection_find_next(cs, NULL, NULL); scs != NULL; scs = cf_subsection_find_next(cs, scs, NULL)) { const char *name; name = cf_section_name1(scs); if (!name) continue; if (!strcmp(name, TLS_CONFIG_SECTION)) continue; method = eap_name2type(name); if (method == PW_EAP_INVALID) { cf_log_err_cs(cs, "Unknown EAP method %s", name); return -1; } if ((method < PW_EAP_MD5) || (method >= PW_EAP_MAX_TYPES)) { cf_log_err_cs(cs, "Invalid EAP method %s (unsupported)", name); return -1; } #if !defined(HAVE_OPENSSL_SSL_H) || !defined(HAVE_LIBSSL) /* * This allows the default configuration to be * shipped with EAP-TLS, etc. enabled. If the * system doesn't have OpenSSL, they will be * ignored. * * If the system does have OpenSSL, then this * code will not be used. The administrator will * then have to delete the tls, * etc. configurations from eap.conf in order to * have EAP without the TLS types. */ if ((method == PW_EAP_TLS) || (method == PW_EAP_TTLS) || (method == PW_EAP_PEAP)) { DEBUG2("rlm_eap (%s): Ignoring EAP method %s because we do not have OpenSSL support", inst->xlat_name, name); continue; } #endif /* * Load the type. */ ret = eap_module_load(inst, &inst->methods[method], method, scs); (void) talloc_get_type_abort(inst->methods[method], eap_module_t); if (ret < 0) { (void) talloc_steal(inst, inst->methods[method]); return -1; } (void) talloc_steal(inst, inst->methods[method]); num_methods++; /* successfully loaded one more methods */ } if (num_methods == 0) { cf_log_err_cs(cs, "No EAP method configured, module cannot do anything"); return -1; } /* * Ensure that the default EAP type is loaded. */ method = eap_name2type(inst->default_method_name); if (method == PW_EAP_INVALID) { cf_log_err_cs(cs, "Unknown default EAP method '%s'", inst->default_method_name); return -1; } if (!inst->methods[method]) { cf_log_err_cs(cs, "No such sub-type for default EAP method %s", inst->default_method_name); return -1; } inst->default_method = method; /* save the numerical method */ /* * List of sessions are set to NULL by the memset * of 'inst', above. */ /* * Lookup sessions in the tree. We don't free them in * the tree, as that's taken care of elsewhere... */ inst->session_tree = rbtree_create(eap_handler_cmp, NULL, 0); if (!inst->session_tree) { radlog(L_ERR, "rlm_eap (%s): Cannot initialize tree", inst->xlat_name); return -1; } if (fr_debug_flag) { inst->handler_tree = rbtree_create(eap_handler_ptr_cmp, NULL, 0); if (!inst->handler_tree) { radlog(L_ERR, "rlm_eap (%s): Cannot initialize tree", inst->xlat_name); return -1; } #ifdef HAVE_PTHREAD_H if (pthread_mutex_init(&(inst->handler_mutex), NULL) < 0) { radlog(L_ERR, "rlm_eap (%s): Failed initializing mutex: %s", inst->xlat_name, strerror(errno)); return -1; } #endif } #ifdef HAVE_PTHREAD_H if (pthread_mutex_init(&(inst->session_mutex), NULL) < 0) { radlog(L_ERR, "rlm_eap (%s): Failed initializing mutex: %s", inst->xlat_name, strerror(errno)); return -1; } #endif return 0; }
/* * Parse a module statement. */ static int parse_module(policy_lex_file_t *lexer, policy_item_t **tail) { int component; policy_lex_t token; policy_module_t *this; char *p; const char *section_name; char filename[1024]; char buffer[2048]; CONF_SECTION *cs, *subcs; modcallable *mc; /* * And the filename */ token = policy_lex_file(lexer, 0, filename, sizeof(filename)); if (token != POLICY_LEX_DOUBLE_QUOTED_STRING) { fprintf(stderr, "%s[%d]: Expected filename, got \"%s\"\n", lexer->filename, lexer->lineno, fr_int2str(rlm_policy_tokens, token, "?")); return 0; } /* * See if we're including all of the files in a subdirectory. */ strlcpy(buffer, lexer->filename, sizeof(buffer)); p = strrchr(buffer, '/'); if (p) { strlcpy(p + 1, filename, sizeof(buffer) - 1 - (p - buffer)); } else { snprintf(buffer, sizeof(buffer), "%s/%s", radius_dir, filename); } /* * Include section calling a module. */ debug_tokens("including module section from file %s\n", buffer); cs = cf_file_read(buffer); if (!cs) { return 0; /* it prints out error messages */ } /* * The outer section is called "main", and can be ignored. * It should be a section, so there should be a subsection. */ subcs = cf_subsection_find_next(cs, NULL, NULL); if (!subcs) { fprintf(stderr, "%s[%d]: Expected section containing modules\n", lexer->filename, lexer->lineno); cf_section_free(&cs); return 0; } section_name = cf_section_name1(subcs); rad_assert(section_name != NULL); component = fr_str2int(policy_component_names, section_name, RLM_COMPONENT_COUNT); if (component == RLM_COMPONENT_COUNT) { fprintf(stderr, "%s[%d]: Invalid section name \"%s\"\n", lexer->filename, lexer->lineno, section_name); cf_section_free(&cs); return 0; } /* * Compile the module entry. */ mc = compile_modgroup(NULL, component, subcs); if (!mc) { cf_section_free(&cs); return 0; /* more often results in calling exit... */ } this = rad_malloc(sizeof(*this)); memset(this, 0, sizeof(*this)); this->item.type = POLICY_TYPE_MODULE; this->item.lineno = lexer->lineno; this->component = component; this->cs = cs; this->mc = mc; *tail = (policy_item_t *) this; return 1; }
/* * read the config section and load all the eap authentication types present. */ static int eap_instantiate(CONF_SECTION *cs, void **instance) { int i, eap_type; int num_types; CONF_SECTION *scs; rlm_eap_t *inst; inst = (rlm_eap_t *) malloc(sizeof(*inst)); if (!inst) { return -1; } memset(inst, 0, sizeof(*inst)); if (cf_section_parse(cs, inst, module_config) < 0) { eap_detach(inst); return -1; } /* * Create our own random pool. */ for (i = 0; i < 256; i++) { inst->rand_pool.randrsl[i] = fr_rand(); } fr_randinit(&inst->rand_pool, 1); inst->rand_pool.randcnt = 0; inst->xlat_name = cf_section_name2(cs); if (!inst->xlat_name) inst->xlat_name = "EAP"; /* Load all the configured EAP-Types */ num_types = 0; for(scs=cf_subsection_find_next(cs, NULL, NULL); scs != NULL; scs=cf_subsection_find_next(cs, scs, NULL)) { const char *auth_type; auth_type = cf_section_name1(scs); if (!auth_type) continue; if (!strcmp(auth_type, TLS_CONFIG_SECTION)) continue; eap_type = eaptype_name2type(auth_type); if (eap_type < 0) { radlog(L_ERR, "rlm_eap: Unknown EAP type %s", auth_type); eap_detach(inst); return -1; } #ifndef HAVE_OPENSSL_SSL_H /* * This allows the default configuration to be * shipped with EAP-TLS, etc. enabled. If the * system doesn't have OpenSSL, they will be * ignored. * * If the system does have OpenSSL, then this * code will not be used. The administrator will * then have to delete the tls, * etc. configurations from eap.conf in order to * have EAP without the TLS types. */ if ((eap_type == PW_EAP_TLS) || (eap_type == PW_EAP_TTLS) || (eap_type == PW_EAP_PEAP)) { DEBUG2("Ignoring EAP-Type/%s because we do not have OpenSSL support.", auth_type); continue; } #endif /* * Load the type. */ if (eaptype_load(&inst->types[eap_type], eap_type, scs) < 0) { eap_detach(inst); return -1; } num_types++; /* successfully loaded one more types */ } if (num_types == 0) { radlog(L_ERR|L_CONS, "rlm_eap: No EAP type configured, module cannot do anything."); eap_detach(inst); return -1; } /* * Ensure that the default EAP type is loaded. */ eap_type = eaptype_name2type(inst->default_eap_type_name); if (eap_type < 0) { radlog(L_ERR|L_CONS, "rlm_eap: Unknown default EAP type %s", inst->default_eap_type_name); eap_detach(inst); return -1; } if (inst->types[eap_type] == NULL) { radlog(L_ERR|L_CONS, "rlm_eap: No such sub-type for default EAP type %s", inst->default_eap_type_name); eap_detach(inst); return -1; } inst->default_eap_type = eap_type; /* save the numerical type */ /* * List of sessions are set to NULL by the memset * of 'inst', above. */ /* * Lookup sessions in the tree. We don't free them in * the tree, as that's taken care of elsewhere... */ inst->session_tree = rbtree_create(eap_handler_cmp, NULL, 0); if (!inst->session_tree) { radlog(L_ERR|L_CONS, "rlm_eap: Cannot initialize tree"); eap_detach(inst); return -1; } if (fr_debug_flag) { inst->handler_tree = rbtree_create(eap_handler_ptr_cmp, NULL, 0); if (!inst->handler_tree) { radlog(L_ERR|L_CONS, "rlm_eap: Cannot initialize tree"); eap_detach(inst); return -1; } #ifdef HAVE_PTHREAD_H if (pthread_mutex_init(&(inst->handler_mutex), NULL) < 0) { radlog(L_ERR|L_CONS, "rlm_eap: Failed initializing mutex: %s", strerror(errno)); eap_detach(inst); return -1; } #endif } #ifdef HAVE_PTHREAD_H if (pthread_mutex_init(&(inst->session_mutex), NULL) < 0) { radlog(L_ERR|L_CONS, "rlm_eap: Failed initializing mutex: %s", strerror(errno)); eap_detach(inst); return -1; } #endif *instance = inst; return 0; }
/* * Allocate the thread pool, and seed it with an initial number * of threads. * * FIXME: What to do on a SIGHUP??? */ int thread_pool_init(CONF_SECTION *cs, int spawn_flag) { int i, rcode; CONF_SECTION *pool_cf; time_t now; now = time(NULL); /* * We're not spawning new threads, don't do * anything. */ if (!spawn_flag) return 0; /* * After a SIGHUP, we don't over-write the previous values. */ if (!pool_initialized) { /* * Initialize the thread pool to some reasonable values. */ memset(&thread_pool, 0, sizeof(THREAD_POOL)); thread_pool.head = NULL; thread_pool.tail = NULL; thread_pool.total_threads = 0; thread_pool.max_thread_num = 1; thread_pool.cleanup_delay = 5; thread_pool.spawn_flag = spawn_flag; #ifdef WNOHANG if ((pthread_mutex_init(&thread_pool.wait_mutex,NULL) != 0)) { radlog(L_ERR, "FATAL: Failed to initialize wait mutex: %s", strerror(errno)); return -1; } /* * Create the hash table of child PID's */ thread_pool.waiters = fr_hash_table_create(pid_hash, pid_cmp, free); if (!thread_pool.waiters) { radlog(L_ERR, "FATAL: Failed to set up wait hash"); return -1; } #endif } pool_cf = cf_subsection_find_next(cs, NULL, "thread"); if (!pool_cf) { radlog(L_ERR, "FATAL: Attempting to start in multi-threaded mode with no thread configuration in radiusd.conf"); return -1; } if (cf_section_parse(pool_cf, NULL, thread_config) < 0) { return -1; } /* * Catch corner cases. */ if (thread_pool.min_spare_threads < 1) thread_pool.min_spare_threads = 1; if (thread_pool.max_spare_threads < 1) thread_pool.max_spare_threads = 1; if (thread_pool.max_spare_threads < thread_pool.min_spare_threads) thread_pool.max_spare_threads = thread_pool.min_spare_threads; /* * The pool has already been initialized. Don't spawn * new threads, and don't forget about forked children, */ if (pool_initialized) { return 0; } /* * Initialize the queue of requests. */ memset(&thread_pool.semaphore, 0, sizeof(thread_pool.semaphore)); rcode = sem_init(&thread_pool.semaphore, 0, SEMAPHORE_LOCKED); if (rcode != 0) { radlog(L_ERR, "FATAL: Failed to initialize semaphore: %s", strerror(errno)); return -1; } rcode = pthread_mutex_init(&thread_pool.queue_mutex,NULL); if (rcode != 0) { radlog(L_ERR, "FATAL: Failed to initialize queue mutex: %s", strerror(errno)); return -1; } /* * Allocate multiple fifos. */ for (i = 0; i < RAD_LISTEN_MAX; i++) { thread_pool.fifo[i] = fr_fifo_create(65536, NULL); if (!thread_pool.fifo[i]) { radlog(L_ERR, "FATAL: Failed to set up request fifo"); return -1; } } #ifdef HAVE_OPENSSL_CRYPTO_H /* * If we're linking with OpenSSL too, then we need * to set up the mutexes and enable the thread callbacks. */ if (!setup_ssl_mutexes()) { radlog(L_ERR, "FATAL: Failed to set up SSL mutexes"); return -1; } #endif /* * Create a number of waiting threads. * * If we fail while creating them, do something intelligent. */ for (i = 0; i < thread_pool.start_threads; i++) { if (spawn_thread(now) == NULL) { return -1; } } DEBUG2("Thread pool initialized"); pool_initialized = TRUE; return 0; }