/* * Initialize the request. */ static int request_init(char const *filename) { FILE *fp; vp_cursor_t cursor; VALUE_PAIR *vp; bool filedone = false; /* * Determine where to read the VP's from. */ if (filename) { fp = fopen(filename, "r"); if (!fp) { fprintf(stderr, "dhcpclient: Error opening %s: %s\n", filename, fr_syserror(errno)); return 0; } } else { fp = stdin; } request = rad_alloc(NULL, false); /* * Read the VP's. */ if (fr_pair_list_afrom_file(NULL, &request->vps, fp, &filedone) < 0) { fr_perror("dhcpclient"); rad_free(&request); if (fp != stdin) fclose(fp); return 1; } /* * Fix / set various options */ for (vp = fr_cursor_init(&cursor, &request->vps); vp; vp = fr_cursor_next(&cursor)) { if (vp->da->vendor == DHCP_MAGIC_VENDOR && vp->da->attr == PW_DHCP_MESSAGE_TYPE) { /* Allow to set packet type using DHCP-Message-Type. */ request->code = vp->vp_integer + PW_DHCP_OFFSET; } else if (!vp->da->vendor) switch (vp->da->attr) { default: break; /* * Allow it to set the packet type in * the attributes read from the file. * (this takes precedence over the command argument.) */ case PW_PACKET_TYPE: request->code = vp->vp_integer; break; case PW_PACKET_DST_PORT: request->dst_port = (vp->vp_integer & 0xffff); break; case PW_PACKET_DST_IP_ADDRESS: request->dst_ipaddr.af = AF_INET; request->dst_ipaddr.ipaddr.ip4addr.s_addr = vp->vp_ipaddr; request->dst_ipaddr.prefix = 32; break; case PW_PACKET_DST_IPV6_ADDRESS: request->dst_ipaddr.af = AF_INET6; request->dst_ipaddr.ipaddr.ip6addr = vp->vp_ipv6addr; request->dst_ipaddr.prefix = 128; break; case PW_PACKET_SRC_PORT: request->src_port = (vp->vp_integer & 0xffff); break; case PW_PACKET_SRC_IP_ADDRESS: request->src_ipaddr.af = AF_INET; request->src_ipaddr.ipaddr.ip4addr.s_addr = vp->vp_ipaddr; request->src_ipaddr.prefix = 32; break; case PW_PACKET_SRC_IPV6_ADDRESS: request->src_ipaddr.af = AF_INET6; request->src_ipaddr.ipaddr.ip6addr = vp->vp_ipv6addr; request->src_ipaddr.prefix = 128; break; } /* switch over the attribute */ } /* loop over the VP's we read in */ /* * Use the default set on the command line */ if (!request->code) request->code = packet_code; if (fp != stdin) fclose(fp); /* * And we're done. */ return 1; }
/* * Initialize a radclient data structure and add it to * the global linked list. */ static int radclient_init(TALLOC_CTX *ctx, rc_file_pair_t *files) { FILE *packets, *filters = NULL; vp_cursor_t cursor; VALUE_PAIR *vp; rc_request_t *request; bool packets_done = false; uint64_t num = 0; assert(files->packets != NULL); /* * Determine where to read the VP's from. */ if (strcmp(files->packets, "-") != 0) { packets = fopen(files->packets, "r"); if (!packets) { ERROR("Error opening %s: %s", files->packets, strerror(errno)); return 0; } /* * Read in the pairs representing the expected response. */ if (files->filters) { filters = fopen(files->filters, "r"); if (!filters) { ERROR("Error opening %s: %s", files->filters, strerror(errno)); fclose(packets); return 0; } } } else { packets = stdin; } /* * Loop until the file is done. */ do { /* * Allocate it. */ request = talloc_zero(ctx, rc_request_t); if (!request) { ERROR("Out of memory"); goto error; } request->packet = rad_alloc(request, true); if (!request->packet) { ERROR("Out of memory"); goto error; } #ifdef WITH_TCP request->packet->src_ipaddr = client_ipaddr; request->packet->src_port = client_port; request->packet->dst_ipaddr = server_ipaddr; request->packet->dst_port = server_port; request->packet->proto = ipproto; #endif request->files = files; request->packet->id = -1; /* allocate when sending */ request->num = num++; /* * Read the request VP's. */ if (fr_pair_list_afrom_file(request->packet, &request->packet->vps, packets, &packets_done) < 0) { char const *input; if ((files->packets[0] == '-') && (files->packets[1] == '\0')) { input = "stdin"; } else { input = files->packets; } REDEBUG("Error parsing \"%s\"", input); goto error; } /* * Skip empty entries */ if (!request->packet->vps) { talloc_free(request); continue; } /* * Read in filter VP's. */ if (filters) { bool filters_done; if (fr_pair_list_afrom_file(request, &request->filter, filters, &filters_done) < 0) { REDEBUG("Error parsing \"%s\"", files->filters); goto error; } if (filters_done && !packets_done) { REDEBUG("Differing number of packets/filters in %s:%s " "(too many requests))", files->packets, files->filters); goto error; } if (!filters_done && packets_done) { REDEBUG("Differing number of packets/filters in %s:%s " "(too many filters))", files->packets, files->filters); goto error; } /* * xlat expansions aren't supported here */ for (vp = fr_cursor_init(&cursor, &request->filter); vp; vp = fr_cursor_next(&cursor)) { if (vp->type == VT_XLAT) { vp->type = VT_DATA; vp->vp_strvalue = vp->xlat; vp->vp_length = talloc_array_length(vp->vp_strvalue) - 1; } if (vp->da->vendor == 0 ) switch (vp->da->attr) { case PW_RESPONSE_PACKET_TYPE: case PW_PACKET_TYPE: fr_cursor_remove(&cursor); /* so we don't break the filter */ request->filter_code = vp->vp_integer; talloc_free(vp); default: break; } } /* * This allows efficient list comparisons later */ fr_pair_list_sort(&request->filter, fr_pair_cmp_by_da_tag); } /* * Process special attributes */ for (vp = fr_cursor_init(&cursor, &request->packet->vps); vp; vp = fr_cursor_next(&cursor)) { /* * Double quoted strings get marked up as xlat expansions, * but we don't support that in request. */ if (vp->type == VT_XLAT) { vp->type = VT_DATA; vp->vp_strvalue = vp->xlat; vp->vp_length = talloc_array_length(vp->vp_strvalue) - 1; } if (!vp->da->vendor) switch (vp->da->attr) { default: break; /* * Allow it to set the packet type in * the attributes read from the file. */ case PW_PACKET_TYPE: request->packet->code = vp->vp_integer; break; case PW_RESPONSE_PACKET_TYPE: request->filter_code = vp->vp_integer; break; case PW_PACKET_DST_PORT: request->packet->dst_port = (vp->vp_integer & 0xffff); break; case PW_PACKET_DST_IP_ADDRESS: request->packet->dst_ipaddr.af = AF_INET; request->packet->dst_ipaddr.ipaddr.ip4addr.s_addr = vp->vp_ipaddr; request->packet->dst_ipaddr.prefix = 32; break; case PW_PACKET_DST_IPV6_ADDRESS: request->packet->dst_ipaddr.af = AF_INET6; request->packet->dst_ipaddr.ipaddr.ip6addr = vp->vp_ipv6addr; request->packet->dst_ipaddr.prefix = 128; break; case PW_PACKET_SRC_PORT: if ((vp->vp_integer < 1024) || (vp->vp_integer > 65535)) { ERROR("Invalid value '%u' for Packet-Src-Port", vp->vp_integer); goto error; } request->packet->src_port = (vp->vp_integer & 0xffff); break; case PW_PACKET_SRC_IP_ADDRESS: request->packet->src_ipaddr.af = AF_INET; request->packet->src_ipaddr.ipaddr.ip4addr.s_addr = vp->vp_ipaddr; request->packet->src_ipaddr.prefix = 32; break; case PW_PACKET_SRC_IPV6_ADDRESS: request->packet->src_ipaddr.af = AF_INET6; request->packet->src_ipaddr.ipaddr.ip6addr = vp->vp_ipv6addr; request->packet->src_ipaddr.prefix = 128; break; case PW_DIGEST_REALM: case PW_DIGEST_NONCE: case PW_DIGEST_METHOD: case PW_DIGEST_URI: case PW_DIGEST_QOP: case PW_DIGEST_ALGORITHM: case PW_DIGEST_BODY_DIGEST: case PW_DIGEST_CNONCE: case PW_DIGEST_NONCE_COUNT: case PW_DIGEST_USER_NAME: /* overlapping! */ { DICT_ATTR const *da; uint8_t *p, *q; p = talloc_array(vp, uint8_t, vp->vp_length + 2); memcpy(p + 2, vp->vp_octets, vp->vp_length); p[0] = vp->da->attr - PW_DIGEST_REALM + 1; vp->vp_length += 2; p[1] = vp->vp_length; da = dict_attrbyvalue(PW_DIGEST_ATTRIBUTES, 0); if (!da) { ERROR("Out of memory"); goto error; } vp->da = da; /* * Re-do fr_pair_value_memsteal ourselves, * because we play games with * vp->da, and fr_pair_value_memsteal goes * to GREAT lengths to sanitize * and fix and change and * double-check the various * fields. */ memcpy(&q, &vp->vp_octets, sizeof(q)); talloc_free(q); vp->vp_octets = talloc_steal(vp, p); vp->type = VT_DATA; VERIFY_VP(vp); } break; /* * Cache this for later. */ case PW_CLEARTEXT_PASSWORD: request->password = vp; break; /* * Keep a copy of the the password attribute. */ case PW_CHAP_PASSWORD: /* * If it's already hex, do nothing. */ if ((vp->vp_length == 17) && (already_hex(vp))) break; /* * CHAP-Password is octets, so it may not be zero terminated. */ request->password = fr_pair_make(request->packet, &request->packet->vps, "Cleartext-Password", "", T_OP_EQ); fr_pair_value_bstrncpy(request->password, vp->vp_strvalue, vp->vp_length); break; case PW_USER_PASSWORD: case PW_MS_CHAP_PASSWORD: request->password = fr_pair_make(request->packet, &request->packet->vps, "Cleartext-Password", vp->vp_strvalue, T_OP_EQ); break; case PW_RADCLIENT_TEST_NAME: request->name = vp->vp_strvalue; break; } } /* loop over the VP's we read in */ /* * Use the default set on the command line */ if (request->packet->code == PW_CODE_UNDEFINED) request->packet->code = packet_code; /* * Default to the filename */ if (!request->name) request->name = request->files->packets; /* * Automatically set the response code from the request code * (if one wasn't already set). */ if (request->filter_code == PW_CODE_UNDEFINED) { switch (request->packet->code) { case PW_CODE_ACCESS_REQUEST: request->filter_code = PW_CODE_ACCESS_ACCEPT; break; case PW_CODE_ACCOUNTING_REQUEST: request->filter_code = PW_CODE_ACCOUNTING_RESPONSE; break; case PW_CODE_COA_REQUEST: request->filter_code = PW_CODE_COA_ACK; break; case PW_CODE_DISCONNECT_REQUEST: request->filter_code = PW_CODE_DISCONNECT_ACK; break; case PW_CODE_STATUS_SERVER: switch (radclient_get_code(request->packet->dst_port)) { case PW_CODE_ACCESS_REQUEST: request->filter_code = PW_CODE_ACCESS_ACCEPT; break; case PW_CODE_ACCOUNTING_REQUEST: request->filter_code = PW_CODE_ACCOUNTING_RESPONSE; break; default: REDEBUG("Can't determine expected response to Status-Server request, specify " "a well known RADIUS port, or add a Response-Packet-Type attribute " "to the request of filter"); goto error; } break; case PW_CODE_UNDEFINED: REDEBUG("Both Packet-Type and Response-Packet-Type undefined, specify at least one, " "or a well known RADIUS port"); goto error; default: REDEBUG("Can't determine expected Response-Packet-Type for Packet-Type %i", request->packet->code); goto error; } /* * Automatically set the request code from the response code * (if one wasn't already set). */ } else if (request->packet->code == PW_CODE_UNDEFINED) { switch (request->filter_code) { case PW_CODE_ACCESS_ACCEPT: case PW_CODE_ACCESS_REJECT: request->packet->code = PW_CODE_ACCESS_REQUEST; break; case PW_CODE_ACCOUNTING_RESPONSE: request->packet->code = PW_CODE_ACCOUNTING_REQUEST; break; case PW_CODE_DISCONNECT_ACK: case PW_CODE_DISCONNECT_NAK: request->packet->code = PW_CODE_DISCONNECT_REQUEST; break; case PW_CODE_COA_ACK: case PW_CODE_COA_NAK: request->packet->code = PW_CODE_COA_REQUEST; break; default: REDEBUG("Can't determine expected Packet-Type for Response-Packet-Type %i", request->filter_code); goto error; } } /* * Automatically set the dst port (if one wasn't already set). */ if (request->packet->dst_port == 0) { radclient_get_port(request->packet->code, &request->packet->dst_port); if (request->packet->dst_port == 0) { REDEBUG("Can't determine destination port"); goto error; } } /* * Add it to the tail of the list. */ if (!request_head) { assert(rc_request_tail == NULL); request_head = request; request->prev = NULL; } else { assert(rc_request_tail->next == NULL); rc_request_tail->next = request; request->prev = rc_request_tail; } rc_request_tail = request; request->next = NULL; /* * Set the destructor so it removes itself from the * request list when freed. We don't set this until * the packet is actually in the list, else we trigger * the asserts in the free callback. */ talloc_set_destructor(request, _rc_request_free); } while (!packets_done); /* loop until the file is done. */ if (packets != stdin) fclose(packets); if (filters) fclose(filters); /* * And we're done. */ return 1; error: talloc_free(request); if (packets != stdin) fclose(packets); if (filters) fclose(filters); return 0; }
static REQUEST *request_setup(FILE *fp) { VALUE_PAIR *vp; REQUEST *request; vp_cursor_t cursor; struct timeval now; /* * Create and initialize the new request. */ request = request_alloc(NULL); gettimeofday(&now, NULL); request->timestamp = now; request->packet = fr_radius_alloc(request, false); if (!request->packet) { ERROR("No memory"); talloc_free(request); return NULL; } request->packet->timestamp = now; request->reply = fr_radius_alloc(request, false); if (!request->reply) { ERROR("No memory"); talloc_free(request); return NULL; } request->listener = listen_alloc(request); request->client = client_alloc(request); request->number = 0; request->master_state = REQUEST_ACTIVE; request->child_state = REQUEST_RUNNING; request->handle = NULL; request->server = talloc_typed_strdup(request, "default"); request->root = &main_config; /* * Read packet from fp */ if (fr_pair_list_afrom_file(request->packet, &request->packet->vps, fp, &filedone) < 0) { fr_perror("unittest"); talloc_free(request); return NULL; } /* * Set the defaults for IPs, etc. */ request->packet->code = PW_CODE_ACCESS_REQUEST; request->packet->src_ipaddr.af = AF_INET; request->packet->src_ipaddr.ipaddr.ip4addr.s_addr = htonl(INADDR_LOOPBACK); request->packet->src_port = 18120; request->packet->dst_ipaddr.af = AF_INET; request->packet->dst_ipaddr.ipaddr.ip4addr.s_addr = htonl(INADDR_LOOPBACK); request->packet->dst_port = 1812; /* * Copied from radclient */ #if 1 /* * Fix up Digest-Attributes issues */ for (vp = fr_cursor_init(&cursor, &request->packet->vps); vp; vp = fr_cursor_next(&cursor)) { /* * Double quoted strings get marked up as xlat expansions, * but we don't support that here. */ if (vp->type == VT_XLAT) { vp->vp_strvalue = vp->xlat; vp->xlat = NULL; vp->type = VT_DATA; } if (!vp->da->vendor) switch (vp->da->attr) { default: break; /* * Allow it to set the packet type in * the attributes read from the file. */ case PW_PACKET_TYPE: request->packet->code = vp->vp_integer; break; case PW_PACKET_DST_PORT: request->packet->dst_port = (vp->vp_integer & 0xffff); break; case PW_PACKET_DST_IP_ADDRESS: request->packet->dst_ipaddr.af = AF_INET; request->packet->dst_ipaddr.ipaddr.ip4addr.s_addr = vp->vp_ipaddr; request->packet->dst_ipaddr.prefix = 32; break; case PW_PACKET_DST_IPV6_ADDRESS: request->packet->dst_ipaddr.af = AF_INET6; request->packet->dst_ipaddr.ipaddr.ip6addr = vp->vp_ipv6addr; request->packet->dst_ipaddr.prefix = 128; break; case PW_PACKET_SRC_PORT: request->packet->src_port = (vp->vp_integer & 0xffff); break; case PW_PACKET_SRC_IP_ADDRESS: request->packet->src_ipaddr.af = AF_INET; request->packet->src_ipaddr.ipaddr.ip4addr.s_addr = vp->vp_ipaddr; request->packet->src_ipaddr.prefix = 32; break; case PW_PACKET_SRC_IPV6_ADDRESS: request->packet->src_ipaddr.af = AF_INET6; request->packet->src_ipaddr.ipaddr.ip6addr = vp->vp_ipv6addr; request->packet->src_ipaddr.prefix = 128; break; case PW_CHAP_PASSWORD: { int i, already_hex = 0; /* * If it's 17 octets, it *might* be already encoded. * Or, it might just be a 17-character password (maybe UTF-8) * Check it for non-printable characters. The odds of ALL * of the characters being 32..255 is (1-7/8)^17, or (1/8)^17, * or 1/(2^51), which is pretty much zero. */ if (vp->vp_length == 17) { for (i = 0; i < 17; i++) { if (vp->vp_octets[i] < 32) { already_hex = 1; break; } } } /* * Allow the user to specify ASCII or hex CHAP-Password */ if (!already_hex) { uint8_t *p; size_t len, len2; len = len2 = vp->vp_length; if (len2 < 17) len2 = 17; p = talloc_zero_array(vp, uint8_t, len2); memcpy(p, vp->vp_strvalue, len); fr_radius_encode_chap_password(p, request->packet, fr_rand() & 0xff, vp); vp->vp_octets = p; vp->vp_length = 17; } } break; case PW_DIGEST_REALM: case PW_DIGEST_NONCE: case PW_DIGEST_METHOD: case PW_DIGEST_URI: case PW_DIGEST_QOP: case PW_DIGEST_ALGORITHM: case PW_DIGEST_BODY_DIGEST: case PW_DIGEST_CNONCE: case PW_DIGEST_NONCE_COUNT: case PW_DIGEST_USER_NAME: /* overlapping! */ { fr_dict_attr_t const *da; uint8_t *p, *q; p = talloc_array(vp, uint8_t, vp->vp_length + 2); memcpy(p + 2, vp->vp_octets, vp->vp_length); p[0] = vp->da->attr - PW_DIGEST_REALM + 1; vp->vp_length += 2; p[1] = vp->vp_length; da = fr_dict_attr_by_num(NULL, 0, PW_DIGEST_ATTRIBUTES); rad_assert(da != NULL); vp->da = da; /* * Re-do fr_pair_value_memsteal ourselves, * because we play games with * vp->da, and fr_pair_value_memsteal goes * to GREAT lengths to sanitize * and fix and change and * double-check the various * fields. */ memcpy(&q, &vp->vp_octets, sizeof(q)); talloc_free(q); vp->vp_octets = talloc_steal(vp, p); vp->type = VT_DATA; VERIFY_VP(vp); } break; } } /* loop over the VP's we read in */ #endif if (rad_debug_lvl) { for (vp = fr_cursor_init(&cursor, &request->packet->vps); vp; vp = fr_cursor_next(&cursor)) { /* * Take this opportunity to verify all the VALUE_PAIRs are still valid. */ if (!talloc_get_type(vp, VALUE_PAIR)) { ERROR("Expected VALUE_PAIR pointer got \"%s\"", talloc_get_name(vp)); fr_log_talloc_report(vp); rad_assert(0); } fr_pair_fprint(fr_log_fp, vp); } fflush(fr_log_fp); } /* * FIXME: set IPs, etc. */ request->packet->code = PW_CODE_ACCESS_REQUEST; request->packet->src_ipaddr.af = AF_INET; request->packet->src_ipaddr.ipaddr.ip4addr.s_addr = htonl(INADDR_LOOPBACK); request->packet->src_port = 18120; request->packet->dst_ipaddr.af = AF_INET; request->packet->dst_ipaddr.ipaddr.ip4addr.s_addr = htonl(INADDR_LOOPBACK); request->packet->dst_port = 1812; /* * Build the reply template from the request. */ request->reply->sockfd = request->packet->sockfd; request->reply->dst_ipaddr = request->packet->src_ipaddr; request->reply->src_ipaddr = request->packet->dst_ipaddr; request->reply->dst_port = request->packet->src_port; request->reply->src_port = request->packet->dst_port; request->reply->id = request->packet->id; request->reply->code = 0; /* UNKNOWN code */ memcpy(request->reply->vector, request->packet->vector, sizeof(request->reply->vector)); request->reply->vps = NULL; request->reply->data = NULL; request->reply->data_len = 0; /* * Debugging */ request->log.lvl = rad_debug_lvl; request->log.func = vradlog_request; request->username = fr_pair_find_by_num(request->packet->vps, 0, PW_USER_NAME, TAG_ANY); request->password = fr_pair_find_by_num(request->packet->vps, 0, PW_USER_PASSWORD, TAG_ANY); return request; }
/* * 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; }
/* * Initialize the request. */ static RADIUS_PACKET *request_init(char const *filename) { FILE *fp; fr_cursor_t cursor; VALUE_PAIR *vp; bool filedone = false; RADIUS_PACKET *request; /* * Determine where to read the VP's from. */ if (filename) { fp = fopen(filename, "r"); if (!fp) { ERROR("Error opening %s: %s", filename, fr_syserror(errno)); return NULL; } } else { fp = stdin; } request = fr_radius_alloc(NULL, false); /* * Read the VP's. */ if (fr_pair_list_afrom_file(NULL, dict_dhcpv4, &request->vps, fp, &filedone) < 0) { fr_perror("dhcpclient"); fr_radius_packet_free(&request); if (fp != stdin) fclose(fp); return NULL; } /* * Fix / set various options */ for (vp = fr_cursor_init(&cursor, &request->vps); vp; vp = fr_cursor_next(&cursor)) { /* * Xlat expansions are not supported. Convert xlat to value box (if possible). */ if (vp->type == VT_XLAT) { fr_type_t type = vp->da->type; if (fr_value_box_from_str(vp, &vp->data, &type, NULL, vp->xlat, -1, '\0', false) < 0) { fr_perror("dhcpclient"); fr_radius_packet_free(&request); if (fp != stdin) fclose(fp); return NULL; } vp->type = VT_DATA; } /* * Allow to set packet type using DHCP-Message-Type */ if (vp->da == attr_dhcp_message_type) { request->code = vp->vp_uint8; /* * Allow it to set the packet type in * the attributes read from the file. * (this takes precedence over the command argument.) */ } else if (vp->da == attr_packet_type) { request->code = vp->vp_uint32; } else if (vp->da == attr_packet_dst_port) { request->dst_port = vp->vp_uint16; } else if ((vp->da == attr_packet_dst_ip_address) || (vp->da == attr_packet_dst_ipv6_address)) { memcpy(&request->dst_ipaddr, &vp->vp_ip, sizeof(request->src_ipaddr)); } else if (vp->da == attr_packet_src_port) { request->src_port = vp->vp_uint16; } else if ((vp->da == attr_packet_src_ip_address) || (vp->da == attr_packet_src_ipv6_address)) { memcpy(&request->src_ipaddr, &vp->vp_ip, sizeof(request->src_ipaddr)); } /* switch over the attribute */ } /* loop over the VP's we read in */ if (fp != stdin) fclose(fp); /* * And we're done. */ return request; }