/* * 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. */ static int mod_bootstrap(void *instance, UNUSED CONF_SECTION *conf) { xlat_register(instance, "client", xlat_client, NULL, NULL, 0, 0, true); map_proc_register(instance, "client", map_proc_client, NULL, 0); return 0; }
/* * The main guy. */ int main(int argc, char *argv[]) { int rcode = EXIT_SUCCESS; int argval; const char *input_file = NULL; const char *output_file = NULL; const char *filter_file = NULL; FILE *fp; REQUEST *request = NULL; VALUE_PAIR *vp; VALUE_PAIR *filter_vps = NULL; bool xlat_only = false; fr_state_tree_t *state = NULL; fr_talloc_fault_setup(); /* * If the server was built with debugging enabled always install * the basic fatal signal handlers. */ #ifndef NDEBUG if (fr_fault_setup(getenv("PANIC_ACTION"), argv[0]) < 0) { fr_perror("unittest"); exit(EXIT_FAILURE); } #endif rad_debug_lvl = 0; set_radius_dir(NULL, RADIUS_DIR); /* * Ensure that the configuration is initialized. */ memset(&main_config, 0, sizeof(main_config)); main_config.name = "unittest"; /* * The tests should have only IPs, not host names. */ fr_hostname_lookups = false; /* * We always log to stdout. */ fr_log_fp = stdout; default_log.dst = L_DST_STDOUT; default_log.fd = STDOUT_FILENO; /* Process the options. */ while ((argval = getopt(argc, argv, "d:D:f:hi:mMn:o:O:xX")) != EOF) { switch (argval) { case 'd': set_radius_dir(NULL, optarg); break; case 'D': main_config.dictionary_dir = talloc_typed_strdup(NULL, optarg); break; case 'f': filter_file = optarg; break; case 'h': usage(0); break; case 'i': input_file = optarg; break; case 'm': main_config.debug_memory = true; break; case 'M': memory_report = true; main_config.debug_memory = true; break; case 'n': main_config.name = optarg; break; case 'o': output_file = optarg; break; case 'O': if (strcmp(optarg, "xlat_only") == 0) { xlat_only = true; break; } fprintf(stderr, "Unknown option '%s'\n", optarg); exit(EXIT_FAILURE); case 'X': rad_debug_lvl += 2; main_config.log_auth = true; main_config.log_auth_badpass = true; main_config.log_auth_goodpass = true; break; case 'x': rad_debug_lvl++; break; default: usage(1); break; } } if (rad_debug_lvl) version_print(); fr_debug_lvl = rad_debug_lvl; /* * Mismatch between the binary and the libraries it depends on */ if (fr_check_lib_magic(RADIUSD_MAGIC_NUMBER) < 0) { fr_perror("%s", main_config.name); exit(EXIT_FAILURE); } /* * Initialising OpenSSL once, here, is safer than having individual modules do it. */ #ifdef HAVE_OPENSSL_CRYPTO_H if (tls_global_init() < 0) { rcode = EXIT_FAILURE; goto finish; } #endif if (xlat_register(NULL, "poke", xlat_poke, NULL, NULL, 0, XLAT_DEFAULT_BUF_LEN) < 0) { rcode = EXIT_FAILURE; goto finish; } if (map_proc_register(NULL, "test-fail", mod_map_proc, NULL, NULL, 0) < 0) { rcode = EXIT_FAILURE; goto finish; } /* Read the configuration files, BEFORE doing anything else. */ if (main_config_init() < 0) { exit_failure: rcode = EXIT_FAILURE; goto finish; } /* * Setup dummy virtual server */ cf_section_add(main_config.config, cf_section_alloc(main_config.config, "server", "unit_test")); /* * Initialize Auth-Type, etc. in the virtual servers * before loading the modules. Some modules need those * to be defined. */ if (virtual_servers_bootstrap(main_config.config) < 0) goto exit_failure; /* * Bootstrap the modules. This links to them, and runs * their "bootstrap" routines. * * After this step, all dynamic attributes, xlats, etc. are defined. */ if (modules_bootstrap(main_config.config) < 0) exit(EXIT_FAILURE); /* * Load the modules */ if (modules_init(main_config.config) < 0) goto exit_failure; /* * And then load the virtual servers. */ if (virtual_servers_init(main_config.config) < 0) goto exit_failure; state = fr_state_tree_init(NULL, main_config.max_requests * 2, 10); /* * Set the panic action (if required) */ { char const *panic_action = NULL; panic_action = getenv("PANIC_ACTION"); if (!panic_action) panic_action = main_config.panic_action; if (panic_action && (fr_fault_setup(panic_action, argv[0]) < 0)) { fr_perror("%s", main_config.name); exit(EXIT_FAILURE); } } setlinebuf(stdout); /* unbuffered output */ if (!input_file || (strcmp(input_file, "-") == 0)) { fp = stdin; } else { fp = fopen(input_file, "r"); if (!fp) { fprintf(stderr, "Failed reading %s: %s\n", input_file, strerror(errno)); rcode = EXIT_FAILURE; goto finish; } } /* * For simplicity, read xlat's. */ if (xlat_only) { if (!do_xlats(input_file, fp)) rcode = EXIT_FAILURE; if (input_file) fclose(fp); goto finish; } /* * Grab the VPs from stdin, or from the file. */ request = request_setup(fp); if (!request) { fprintf(stderr, "Failed reading input: %s\n", fr_strerror()); rcode = EXIT_FAILURE; goto finish; } /* * No filter file, OR there's no more input, OR we're * reading from a file, and it's different from the * filter file. */ if (!filter_file || filedone || ((input_file != NULL) && (strcmp(filter_file, input_file) != 0))) { if (output_file) { fclose(fp); fp = NULL; } filedone = false; } /* * There is a filter file. If necessary, open it. If we * already are reading it via "input_file", then we don't * need to re-open it. */ if (filter_file) { if (!fp) { fp = fopen(filter_file, "r"); if (!fp) { fprintf(stderr, "Failed reading %s: %s\n", filter_file, strerror(errno)); rcode = EXIT_FAILURE; goto finish; } } if (fr_pair_list_afrom_file(request, &filter_vps, fp, &filedone) < 0) { fprintf(stderr, "Failed reading attributes from %s: %s\n", filter_file, fr_strerror()); rcode = EXIT_FAILURE; goto finish; } /* * FIXME: loop over input packets. */ fclose(fp); } rad_virtual_server(request); if (!output_file || (strcmp(output_file, "-") == 0)) { fp = stdout; } else { fp = fopen(output_file, "w"); if (!fp) { fprintf(stderr, "Failed writing %s: %s\n", output_file, strerror(errno)); exit(EXIT_FAILURE); } } print_packet(fp, request->reply); if (output_file) fclose(fp); /* * Update the list with the response type. */ vp = radius_pair_create(request->reply, &request->reply->vps, PW_RESPONSE_PACKET_TYPE, 0); vp->vp_integer = request->reply->code; { VALUE_PAIR const *failed[2]; if (filter_vps && !fr_pair_validate(failed, filter_vps, request->reply->vps)) { fr_pair_validate_debug(request, failed); fr_perror("Output file %s does not match attributes in filter %s (%s)", output_file ? output_file : input_file, filter_file, fr_strerror()); rcode = EXIT_FAILURE; goto finish; } } INFO("Exiting normally"); finish: talloc_free(request); talloc_free(state); /* * Free the configuration items. */ main_config_free(); /* * Detach any modules. */ modules_free(); xlat_unregister(NULL, "poke", xlat_poke); xlat_free(); /* modules may have xlat's */ if (memory_report) { INFO("Allocated memory at time of report:"); fr_log_talloc_report(NULL); } return rcode; }
static int mod_bootstrap(CONF_SECTION *conf, void *instance) { rlm_sql_t *inst = instance; /* * Hack... */ inst->config = &inst->myconfig; inst->cs = conf; inst->name = cf_section_name2(conf); if (!inst->name) inst->name = cf_section_name1(conf); /* * Load the appropriate driver for our database. * * We need this to check if the sql_fields callback is provided. */ inst->handle = lt_dlopenext(inst->config->sql_driver_name); if (!inst->handle) { ERROR("Could not link driver %s: %s", inst->config->sql_driver_name, fr_strerror()); 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; } INFO("rlm_sql (%s): Driver %s (module %s) loaded and linked", inst->name, inst->config->sql_driver_name, inst->module->name); if (inst->config->groupmemb_query) { char buffer[256]; char const *group_attribute; if (inst->config->group_attribute) { group_attribute = inst->config->group_attribute; } else if (cf_section_name2(conf)) { snprintf(buffer, sizeof(buffer), "%s-SQL-Group", inst->name); group_attribute = buffer; } else { group_attribute = "SQL-Group"; } /* * Checks if attribute already exists. */ if (paircompare_register_byname(group_attribute, fr_dict_attr_by_num(NULL, 0, PW_USER_NAME), false, sql_groupcmp, inst) < 0) { ERROR("Failed registering group comparison: %s", fr_strerror()); return -1; } inst->group_da = fr_dict_attr_by_name(NULL, group_attribute); if (!inst->group_da) { ERROR("Failed resolving group attribute \"%s\"", group_attribute); return -1; } } /* * Register the SQL xlat function */ xlat_register(inst, inst->name, sql_xlat, sql_escape_for_xlat_func, NULL, 0, 0); /* * Register the SQL map processor function */ if (inst->module->sql_fields) map_proc_register(inst, inst->name, mod_map_proc, sql_escape_for_xlat_func, NULL, 0); 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. */ static int mod_bootstrap(CONF_SECTION *conf, void *instance) { rlm_csv_t *inst = instance; int i; char const *p; char *q; char *header; FILE *fp; int lineno; char buffer[8192]; inst->name = cf_section_name2(conf); if (!inst->name) { inst->name = cf_section_name1(conf); } if (inst->delimiter[1]) { cf_log_err_cs(conf, "'delimiter' must be one character long"); return -1; } for (p = inst->header; p != NULL; p = strchr(p + 1, *inst->delimiter)) { inst->num_fields++; } if (inst->num_fields < 2) { cf_log_err_cs(conf, "Must have at least a key field and data field"); return -1; } inst->field_names = talloc_array(inst, const char *, inst->num_fields); if (!inst->field_names) { oom: cf_log_err_cs(conf, "Out of memory"); return -1; } inst->field_offsets = talloc_array(inst, int, inst->num_fields); if (!inst->field_offsets) goto oom; for (i = 0; i < inst->num_fields; i++) { inst->field_offsets[i] = -1; /* unused */ } /* * Get a writeable copy of the header */ header = talloc_strdup(inst, inst->header); if (!header) goto oom; /* * Mark up the field names. Note that they can be empty, * in which case they don't map to anything. */ inst->key_field = -1; /* * FIXME: remove whitespace from field names, if we care. */ for (p = header, i = 0; p != NULL; p = q, i++) { q = strchr(p, *inst->delimiter); /* * Fields 0..N-1 */ if (q) { *q = '\0'; if (q > (p + 1)) { if (strcmp(p, inst->key) == 0) { inst->key_field = i; } else { inst->field_offsets[i] = inst->used_fields++; } } q++; } else { /* field N */ if (*p) { if (strcmp(p, inst->key) == 0) { inst->key_field = i; } else { inst->field_offsets[i] = inst->used_fields++; } } } /* * Save the field names, even when they're not used. */ inst->field_names[i] = p; } if (inst->key_field < 0) { cf_log_err_cs(conf, "Key field '%s' does not appear in header", inst->key); return -1; } inst->tree = rbtree_create(inst, csv_entry_cmp, NULL, 0); if (!inst->tree) goto oom; /* * Read the file line by line. */ fp = fopen(inst->filename, "r"); if (!fp) { cf_log_err_cs(conf, "Error opening filename %s: %s", inst->filename, strerror(errno)); return -1; } lineno = 1; while (fgets(buffer, sizeof(buffer), fp)) { rlm_csv_entry_t *e; e = file2csv(conf, inst, lineno, buffer); if (!e) { fclose(fp); return -1; } lineno++; } fclose(fp); /* * And register the map function. */ map_proc_register(inst, inst->name, mod_map_proc, NULL, csv_map_verify, 0); return 0; }