/** Log to thread local error buffer * * @param fmt printf style format string. If NULL sets the 'new' byte to false, * effectively clearing the last message. */ void fr_strerror_printf(char const *fmt, ...) { va_list ap; char *buffer; buffer = fr_thread_local_init(fr_strerror_buffer, _fr_logging_free); if (!buffer) { int ret; /* * malloc is thread safe, talloc is not */ buffer = calloc((FR_STRERROR_BUFSIZE * 2) + 1, sizeof(char)); /* One byte extra for status */ if (!buffer) { fr_perror("Failed allocating memory for libradius error buffer"); return; } ret = fr_thread_local_set(fr_strerror_buffer, buffer); if (ret != 0) { fr_perror("Failed setting up thread-local storage for libradius error buffer: %s", fr_syserror(ret)); free(buffer); return; } } /* * NULL has a special meaning, setting the new bit to false. */ if (!fmt) { buffer[FR_STRERROR_BUFSIZE * 2] &= 0x06; return; } va_start(ap, fmt); /* * Alternate where we write the message, so we can do: * fr_strerror_printf("Additional error: %s", fr_strerror()); */ switch (buffer[FR_STRERROR_BUFSIZE * 2] & 0x06) { default: vsnprintf(buffer + FR_STRERROR_BUFSIZE, FR_STRERROR_BUFSIZE, fmt, ap); buffer[FR_STRERROR_BUFSIZE * 2] = 0x05; /* Flip the 'new' bit to true */ break; case 0x04: vsnprintf(buffer, FR_STRERROR_BUFSIZE, fmt, ap); buffer[FR_STRERROR_BUFSIZE * 2] = 0x03; /* Flip the 'new' bit to true */ break; } va_end(ap); }
/* * Log to a buffer, trying to be thread-safe. */ void fr_strerror_printf(const char *fmt, ...) { va_list ap; #ifdef USE_PTHREAD_FOR_TLS char *buffer; pthread_once(&fr_strerror_once, fr_strerror_make_key); buffer = pthread_getspecific(fr_strerror_key); if (!buffer) { int ret; buffer = malloc(FR_STRERROR_BUFSIZE); if (!buffer) return; /* panic and die! */ ret = pthread_setspecific(fr_strerror_key, buffer); if (ret != 0) { fr_perror("Failed recording thread error: %s", strerror(ret)); return; } } va_start(ap, fmt); vsnprintf(buffer, FR_STRERROR_BUFSIZE, fmt, ap); #else va_start(ap, fmt); vsnprintf(fr_strerror_buffer, sizeof(fr_strerror_buffer), fmt, ap); #endif va_end(ap); }
static int test_open(void *ctx, UNUSED void const *master_ctx) { fr_listen_test_t *io_ctx = talloc_get_type_abort(ctx, fr_listen_test_t); io_ctx->sockfd = fr_socket_server_udp(&io_ctx->ipaddr, &io_ctx->port, NULL, true); if (io_ctx->sockfd < 0) { fr_perror("radius_test: Failed creating socket"); exit(EXIT_FAILURE); } if (fr_socket_bind(io_ctx->sockfd, &io_ctx->ipaddr, &io_ctx->port, NULL) < 0) { fr_perror("radius_test: Failed binding to socket"); exit(EXIT_FAILURE); } return 0; }
bool fr_assert_cond(char const *file, int line, char const *expr, bool cond) { if (!cond) { fr_perror("SOFT ASSERT FAILED %s[%u]: %s: ", file, line, expr); return false; } return cond; }
/** Initialises the server logging functionality, and the underlying libfreeradius log * * @note Call log free when the server is done to fix any spurious memory leaks. * * @param[in] log Logging parameters. * @param[in] daemonize Changes what we do with stdout/stderr. * @return * - 0 on success. * - -1 on failure. */ int log_global_init(fr_log_t *log, bool daemonize) { int ret; ret = fr_log_init(log, daemonize); if (ret < 0) return ret; if (fr_dict_autoload(log_dict) < 0) { fr_perror("log_init"); return -1; } if (fr_dict_attr_autoload(log_dict_attr) < 0) { fr_perror("log_init"); return -1; } return ret; }
void NEVER_RETURNS _fr_exit_now(char const *file, int line, int status) { #ifndef NDEBUG fr_perror("_EXIT CALLED %s[%u]: %i: ", file, line, status); #endif fflush(stderr); fr_debug_break(); /* If running under GDB we'll break here */ _exit(status); }
/** Log to thread local error buffer * * @param fmt printf style format string. If NULL sets the 'new' byte to false, * effectively clearing the last message. */ void fr_strerror_printf(char const *fmt, ...) { va_list ap; char *buffer; buffer = fr_thread_local_init(fr_strerror_buffer, _fr_logging_free); if (!buffer) { int ret; /* * malloc is thread safe, talloc is not */ buffer = malloc(sizeof(char) * (FR_STRERROR_BUFSIZE + 1)); /* One byte extra for status */ if (!buffer) { fr_perror("Failed allocating memory for libradius error buffer"); return; } ret = fr_thread_local_set(fr_strerror_buffer, buffer); if (ret != 0) { fr_perror("Failed setting up TLS for libradius error buffer: %s", fr_syserror(ret)); free(buffer); return; } } /* * NULL has a special meaning, setting the new byte to false. */ if (!fmt) { buffer[FR_STRERROR_BUFSIZE] = '\0'; return; } va_start(ap, fmt); vsnprintf(buffer, FR_STRERROR_BUFSIZE, fmt, ap); buffer[FR_STRERROR_BUFSIZE] = '\1'; /* Flip the 'new' byte to true */ va_end(ap); }
/* * Read valuepairs from the fp up to End-Of-File. * * Hmm... this function is only used by radclient.. */ VALUE_PAIR *readvp2(FILE *fp, int *pfiledone, const char *errprefix) { char buf[8192]; FR_TOKEN last_token = T_EOL; VALUE_PAIR *vp; VALUE_PAIR *list; int error = 0; list = NULL; while (!error && fgets(buf, sizeof(buf), fp) != NULL) { /* * If we get a '\n' by itself, we assume that's * the end of that VP */ if ((buf[0] == '\n') && (list)) { return list; } if ((buf[0] == '\n') && (!list)) { continue; } /* * Comments get ignored */ if (buf[0] == '#') continue; /* * Read all of the attributes on the current line. */ vp = NULL; last_token = userparse(buf, &vp); if (!vp) { if (last_token != T_EOL) { fr_perror("%s", errprefix); error = 1; break; } break; } pairadd(&list, vp); buf[0] = '\0'; } if (error) pairfree(&list); *pfiledone = 1; return error ? NULL: list; }
/** Initialise thread local storage * * @return fr_ring_buffer_t for messages */ static inline fr_ring_buffer_t *fr_network_rb_init(void) { fr_ring_buffer_t *rb; rb = fr_network_rb; if (rb) return rb; rb = fr_ring_buffer_create(NULL, FR_CONTROL_MAX_MESSAGES * FR_CONTROL_MAX_SIZE); if (!rb) { fr_perror("Failed allocating memory for network ring buffer"); return NULL; } fr_thread_local_set_destructor(fr_network_rb, _fr_network_rb_free, rb); return rb; }
int main(int argc, char **argv) { char *p; int c; char const *radius_dir = RADDBDIR; char const *dict_dir = DICTDIR; char const *filename = NULL; DICT_ATTR const *da; fr_debug_lvl = 0; while ((c = getopt(argc, argv, "d:D:f:hr:t:vxi:" )) != EOF) switch(c) { case 'D': dict_dir = optarg; break; case 'd': radius_dir = optarg; break; case 'f': filename = optarg; break; case 'i': iface = optarg; break; case 'r': if (!isdigit((int) *optarg)) usage(); retries = atoi(optarg); if ((retries == 0) || (retries > 1000)) usage(); break; case 't': if (!isdigit((int) *optarg)) usage(); timeout = atof(optarg); break; case 'v': printf("%s\n", dhcpclient_version); exit(0); case 'x': fr_debug_lvl++; fr_log_fp = stdout; break; case 'h': default: usage(); } argc -= (optind - 1); argv += (optind - 1); if (argc < 2) usage(); /* convert timeout to a struct timeval */ #define USEC 1000000 tv_timeout.tv_sec = timeout; tv_timeout.tv_usec = ((timeout - (float) tv_timeout.tv_sec) * USEC); if (dict_init(dict_dir, RADIUS_DICTIONARY) < 0) { fr_perror("radclient"); return 1; } if (dict_read(radius_dir, RADIUS_DICTIONARY) == -1) { fr_perror("radclient"); return 1; } fr_strerror(); /* Clear the error buffer */ /* * Ensure that dictionary.dhcp is loaded. */ da = dict_attrbyname("DHCP-Message-Type"); if (!da) { if (dict_read(dict_dir, "dictionary.dhcp") < 0) { fprintf(stderr, "Failed reading dictionary.dhcp: %s\n", fr_strerror()); return -1; } } /* * Resolve hostname. */ server_ipaddr.af = AF_INET; if (strcmp(argv[1], "-") != 0) { char const *hostname = argv[1]; char const *portname = argv[1]; char buffer[256]; if (*argv[1] == '[') { /* IPv6 URL encoded */ p = strchr(argv[1], ']'); if ((size_t) (p - argv[1]) >= sizeof(buffer)) { usage(); } memcpy(buffer, argv[1] + 1, p - argv[1] - 1); buffer[p - argv[1] - 1] = '\0'; hostname = buffer; portname = p + 1; } p = strchr(portname, ':'); if (p && (strchr(p + 1, ':') == NULL)) { *p = '\0'; portname = p + 1; } else { portname = NULL; } if (ip_hton(&server_ipaddr, AF_INET, hostname, false) < 0) { fprintf(stderr, "dhcpclient: Failed to find IP address for host %s: %s\n", hostname, fr_syserror(errno)); fr_exit_now(1); } /* * Strip port from hostname if needed. */ if (portname) server_port = atoi(portname); } /* * See what kind of request we want to send. */ if (argc >= 3) { if (!isdigit((int) argv[2][0])) { packet_code = fr_str2int(request_types, argv[2], -2); if (packet_code == -2) { fprintf(stderr, "Unknown packet type: %s\n", argv[2]); usage(); } } else { packet_code = atoi(argv[2]); } } if (server_port == 0) server_port = 67; request_init(filename); /* * No data read. Die. */ if (!request || !request->vps) { fprintf(stderr, "dhcpclient: Nothing to send.\n"); fr_exit_now(1); } /* * Sanity check. */ if (!request->code) { fprintf(stderr, "dhcpclient: Command was %s, and request did not contain DHCP-Message-Type nor Packet-Type.\n", (argc >= 3) ? "'auto'" : "unspecified"); exit(1); } if ((request->code == PW_DHCP_RELEASE) || (request->code == PW_DHCP_DECLINE)) { /* These kind of packets do not get a reply, so don't wait for one. */ reply_expected = false; } /* * Bind to the first specified IP address and port. * This means we ignore later ones. */ if (request->src_ipaddr.af == AF_UNSPEC) { memset(&client_ipaddr, 0, sizeof(client_ipaddr)); client_ipaddr.af = server_ipaddr.af; client_port = 0; } else { client_ipaddr = request->src_ipaddr; client_port = request->src_port; } /* set "raw mode" if an interface is specified and if destination IP address is the broadcast address. */ if (iface) { iface_ind = if_nametoindex(iface); if (iface_ind <= 0) { fprintf(stderr, "dhcpclient: unknown interface: %s\n", iface); fr_exit_now(1); } if (server_ipaddr.ipaddr.ip4addr.s_addr == 0xFFFFFFFF) { fprintf(stderr, "dhcpclient: Using interface: %s (index: %d) in raw packet mode\n", iface, iface_ind); raw_mode = true; } } if (request->src_ipaddr.af == AF_UNSPEC) { request->src_ipaddr = client_ipaddr; request->src_port = client_port; } if (request->dst_ipaddr.af == AF_UNSPEC) { request->dst_ipaddr = server_ipaddr; request->dst_port = server_port; } /* * Encode the packet */ if (fr_dhcp_encode(request) < 0) { fprintf(stderr, "dhcpclient: failed encoding: %s\n", fr_strerror()); fr_exit_now(1); } if (fr_debug_lvl) print_hex(request); #ifdef HAVE_LIBPCAP if (raw_mode) { send_with_pcap(); } else #endif { send_with_socket(); } if (reply && fr_debug_lvl) print_hex(reply); if (reply && fr_dhcp_decode(reply) < 0) { fprintf(stderr, "dhcpclient: failed decoding\n"); return 1; } dict_free(); if (success) return 0; return 1; }
/* * 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; /* * 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 if ((progname = strrchr(argv[0], FR_DIR_SEP)) == NULL) progname = argv[0]; else progname++; debug_flag = 0; set_radius_dir(NULL, RADIUS_DIR); /* * Ensure that the configuration is initialized. */ memset(&main_config, 0, sizeof(main_config)); main_config.myip.af = AF_UNSPEC; main_config.port = 0; main_config.name = "radiusd"; /* * 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: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 'X': debug_flag += 2; main_config.log_auth = true; main_config.log_auth_badpass = true; main_config.log_auth_goodpass = true; break; case 'x': debug_flag++; break; default: usage(1); break; } } if (debug_flag) { version(); } fr_debug_flag = debug_flag; /* * Mismatch between the binary and the libraries it depends on */ if (fr_check_lib_magic(RADIUSD_MAGIC_NUMBER) < 0) { fr_perror("radiusd"); exit(EXIT_FAILURE); } /* Read the configuration files, BEFORE doing anything else. */ if (main_config_init() < 0) { rcode = EXIT_FAILURE; goto finish; } /* * Load the modules */ if (modules_init(main_config.config) < 0) { rcode = EXIT_FAILURE; goto finish; } fr_state_init(); /* Set the panic action (if required) */ if (main_config.panic_action && #ifndef NDEBUG !getenv("PANIC_ACTION") && #endif (fr_fault_setup(main_config.panic_action, argv[0]) < 0)) { rcode = EXIT_FAILURE; goto finish; } 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; } } /* * 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 (readvp2(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_paircreate(request->reply, &request->reply->vps, PW_RESPONSE_PACKET_TYPE, 0); vp->vp_integer = request->reply->code; { VALUE_PAIR const *failed[2]; if (filter_vps && !pairvalidate(failed, filter_vps, request->reply->vps)) { pairvalidate_debug(request, failed); fr_perror("Output file %s does not match attributes in filter %s", output_file ? output_file : input_file, filter_file); rcode = EXIT_FAILURE; goto finish; } } INFO("Exiting normally"); finish: talloc_free(request); /* * Detach any modules. */ modules_free(); xlat_free(); /* modules may have xlat's */ fr_state_delete(); /* * Free the configuration items. */ main_config_free(); if (memory_report) { INFO("Allocated memory at time of report:"); fr_log_talloc_report(NULL); } return rcode; }
int main(int n,char **argv) { const char *fname = NULL; const char *ofile = NULL; FILE *fp; int print_stat = 1; int ch; const char *sm_radius_dir = NULL; progname = argv[0]; fr_debug_flag = 0; while ((ch = getopt(n, argv, "d:i:xo:qvc")) != -1) switch (ch) { case 'd': sm_radius_dir = optarg; break; case 'i': fname = optarg; break; case 'x': fr_debug_flag++; case 'o': ofile = optarg; break; case 'q': print_stat = 0; break; case 'v': printf("%s: $Id: 3425c4d125ea93aeef03abbbca7dd4f156480d26 $ \n",progname); exit(0); case 'c': oflags = O_CREAT | O_TRUNC | O_RDWR; break; default: sm_usage();exit(1); } if ( sm_radius_dir == NULL ) sm_radius_dir = RADDBDIR; DOUT1("Use dictionary in: %s\n",sm_radius_dir); if (dict_init(sm_radius_dir, RADIUS_DICTIONARY) < 0 ) { fr_perror("parser: init dictionary:"); exit(1); } if ( fname == NULL || fname[0] == '-') { fp = stdin; fname = "STDIN"; } else if ( ( fp = fopen(fname, "r") ) == NULL ) { fprintf( stderr,"%s: Couldn't open source file\n", progname); exit(1); } if ( ofile == NULL ) ofile = "sandy_db" ; if ( open_storage(ofile) ) { exit (1); } sm_parse_file(fp,fname); close_storage(); if ( print_stat ) fprintf(stderr,"\nRecord loaded: %lu\nLines parsed: %lu\nRecord skiped: %lu\nWarnings: %lu\nErrors: %lu\n" ,st_loaded,st_lines,st_skiped,st_warns,st_errors); return 0; }
int main(int argc, char **argv) { int c; char const *radius_dir = RADDBDIR; char const *dict_dir = DICTDIR; char filesecret[256]; FILE *fp; int do_summary = false; int persec = 0; int parallel = 1; rc_request_t *this; int force_af = AF_UNSPEC; /* * It's easier having two sets of flags to set the * verbosity of library calls and the verbosity of * radclient. */ fr_debug_lvl = 0; fr_log_fp = stdout; #ifndef NDEBUG if (fr_fault_setup(getenv("PANIC_ACTION"), argv[0]) < 0) { fr_perror("radclient"); exit(EXIT_FAILURE); } #endif talloc_set_log_stderr(); filename_tree = rbtree_create(NULL, filename_cmp, NULL, 0); if (!filename_tree) { oom: ERROR("Out of memory"); exit(1); } while ((c = getopt(argc, argv, "46c:d:D:f:Fhi:n:p:qr:sS:t:vx" #ifdef WITH_TCP "P:" #endif )) != EOF) switch (c) { case '4': force_af = AF_INET; break; case '6': force_af = AF_INET6; break; case 'c': if (!isdigit((int) *optarg)) usage(); resend_count = atoi(optarg); break; case 'D': dict_dir = optarg; break; case 'd': radius_dir = optarg; break; case 'f': { char const *p; rc_file_pair_t *files; files = talloc(talloc_autofree_context(), rc_file_pair_t); if (!files) goto oom; p = strchr(optarg, ':'); if (p) { files->packets = talloc_strndup(files, optarg, p - optarg); if (!files->packets) goto oom; files->filters = p + 1; } else { files->packets = optarg; files->filters = NULL; } rbtree_insert(filename_tree, (void *) files); } break; case 'F': print_filename = true; break; case 'i': /* currently broken */ if (!isdigit((int) *optarg)) usage(); last_used_id = atoi(optarg); if ((last_used_id < 0) || (last_used_id > 255)) { usage(); } break; case 'n': persec = atoi(optarg); if (persec <= 0) usage(); break; /* * Note that sending MANY requests in * parallel can over-run the kernel * queues, and Linux will happily discard * packets. So even if the server responds, * the client may not see the reply. */ case 'p': parallel = atoi(optarg); if (parallel <= 0) usage(); break; #ifdef WITH_TCP case 'P': proto = optarg; if (strcmp(proto, "tcp") != 0) { if (strcmp(proto, "udp") == 0) { proto = NULL; } else { usage(); } } else { ipproto = IPPROTO_TCP; } break; #endif case 'q': do_output = false; fr_log_fp = NULL; /* no output from you, either! */ break; case 'r': if (!isdigit((int) *optarg)) usage(); retries = atoi(optarg); if ((retries == 0) || (retries > 1000)) usage(); break; case 's': do_summary = true; break; case 'S': { char *p; fp = fopen(optarg, "r"); if (!fp) { ERROR("Error opening %s: %s", optarg, fr_syserror(errno)); exit(1); } if (fgets(filesecret, sizeof(filesecret), fp) == NULL) { ERROR("Error reading %s: %s", optarg, fr_syserror(errno)); exit(1); } fclose(fp); /* truncate newline */ p = filesecret + strlen(filesecret) - 1; while ((p >= filesecret) && (*p < ' ')) { *p = '\0'; --p; } if (strlen(filesecret) < 2) { ERROR("Secret in %s is too short", optarg); exit(1); } secret = filesecret; } break; case 't': if (!isdigit((int) *optarg)) usage(); timeout = atof(optarg); break; case 'v': fr_debug_lvl = 1; DEBUG("%s", radclient_version); exit(0); case 'x': fr_debug_lvl++; break; case 'h': default: usage(); } argc -= (optind - 1); argv += (optind - 1); if ((argc < 3) || ((secret == NULL) && (argc < 4))) { ERROR("Insufficient arguments"); usage(); } /* * Mismatch between the binary and the libraries it depends on */ if (fr_check_lib_magic(RADIUSD_MAGIC_NUMBER) < 0) { fr_perror("radclient"); return 1; } if (dict_init(dict_dir, RADIUS_DICTIONARY) < 0) { fr_perror("radclient"); return 1; } if (dict_read(radius_dir, RADIUS_DICTIONARY) == -1) { fr_perror("radclient"); return 1; } fr_strerror(); /* Clear the error buffer */ /* * Get the request type */ if (!isdigit((int) argv[2][0])) { packet_code = fr_str2int(request_types, argv[2], -2); if (packet_code == -2) { ERROR("Unrecognised request type \"%s\"", argv[2]); usage(); } } else { packet_code = atoi(argv[2]); } /* * Resolve hostname. */ if (strcmp(argv[1], "-") != 0) { if (fr_pton_port(&server_ipaddr, &server_port, argv[1], -1, force_af, true) < 0) { ERROR("%s", fr_strerror()); exit(1); } /* * Work backwards from the port to determine the packet type */ if (packet_code == PW_CODE_UNDEFINED) packet_code = radclient_get_code(server_port); } radclient_get_port(packet_code, &server_port); /* * Add the secret. */ if (argv[3]) secret = argv[3]; /* * If no '-f' is specified, we're reading from stdin. */ if (rbtree_num_elements(filename_tree) == 0) { rc_file_pair_t *files; files = talloc_zero(talloc_autofree_context(), rc_file_pair_t); files->packets = "-"; if (!radclient_init(files, files)) { exit(1); } } /* * Walk over the list of filenames, creating the requests. */ if (rbtree_walk(filename_tree, RBTREE_IN_ORDER, filename_walk, NULL) != 0) { ERROR("Failed parsing input files"); exit(1); } /* * No packets read. Die. */ if (!request_head) { ERROR("Nothing to send"); exit(1); } /* * Bind to the first specified IP address and port. * This means we ignore later ones. */ if (request_head->packet->src_ipaddr.af == AF_UNSPEC) { memset(&client_ipaddr, 0, sizeof(client_ipaddr)); client_ipaddr.af = server_ipaddr.af; } else { client_ipaddr = request_head->packet->src_ipaddr; } client_port = request_head->packet->src_port; #ifdef WITH_TCP if (proto) { sockfd = fr_socket_client_tcp(NULL, &server_ipaddr, server_port, false); } else #endif sockfd = fr_socket(&client_ipaddr, client_port); if (sockfd < 0) { ERROR("Error opening socket"); exit(1); } pl = fr_packet_list_create(1); if (!pl) { ERROR("Out of memory"); exit(1); } if (!fr_packet_list_socket_add(pl, sockfd, ipproto, &server_ipaddr, server_port, NULL)) { ERROR("Out of memory"); exit(1); } /* * Walk over the list of packets, sanity checking * everything. */ for (this = request_head; this != NULL; this = this->next) { this->packet->src_ipaddr = client_ipaddr; this->packet->src_port = client_port; if (radclient_sane(this) != 0) { exit(1); } } /* * Walk over the packets to send, until * we're all done. * * FIXME: This currently busy-loops until it receives * all of the packets. It should really have some sort of * send packet, get time to wait, select for time, etc. * loop. */ do { int n = parallel; rc_request_t *next; char const *filename = NULL; done = true; sleep_time = -1; /* * Walk over the packets, sending them. */ for (this = request_head; this != NULL; this = next) { next = this->next; /* * If there's a packet to receive, * receive it, but don't wait for a * packet. */ recv_one_packet(0); /* * This packet is done. Delete it. */ if (this->done) { talloc_free(this); continue; } /* * Packets from multiple '-f' are sent * in parallel. * * Packets from one file are sent in * series, unless '-p' is specified, in * which case N packets from each file * are sent in parallel. */ if (this->files->packets != filename) { filename = this->files->packets; n = parallel; } if (n > 0) { n--; /* * Send the current packet. */ if (send_one_packet(this) < 0) { talloc_free(this); break; } /* * Wait a little before sending * the next packet, if told to. */ if (persec) { struct timeval tv; /* * Don't sleep elsewhere. */ sleep_time = 0; if (persec == 1) { tv.tv_sec = 1; tv.tv_usec = 0; } else { tv.tv_sec = 0; tv.tv_usec = 1000000/persec; } /* * Sleep for milliseconds, * portably. * * If we get an error or * a signal, treat it like * a normal timeout. */ select(0, NULL, NULL, NULL, &tv); } /* * If we haven't sent this packet * often enough, we're not done, * and we shouldn't sleep. */ if (this->resend < resend_count) { done = false; sleep_time = 0; } } else { /* haven't sent this packet, we're not done */ assert(this->done == false); assert(this->reply == NULL); done = false; } } /* * Still have outstanding requests. */ if (fr_packet_list_num_elements(pl) > 0) { done = false; } else { sleep_time = 0; } /* * Nothing to do until we receive a request, so * sleep until then. Once we receive one packet, * we go back, and walk through the whole list again, * sending more packets (if necessary), and updating * the sleep time. */ if (!done && (sleep_time > 0)) { recv_one_packet(sleep_time); } } while (!done); rbtree_free(filename_tree); fr_packet_list_free(pl); while (request_head) TALLOC_FREE(request_head); dict_free(); if (do_summary) { DEBUG("Packet summary:\n" "\tAccepted : %" PRIu64 "\n" "\tRejected : %" PRIu64 "\n" "\tLost : %" PRIu64 "\n" "\tPassed filter : %" PRIu64 "\n" "\tFailed filter : %" PRIu64, stats.accepted, stats.rejected, stats.lost, stats.passed, stats.failed ); } if ((stats.lost > 0) || (stats.failed > 0)) { exit(1); } exit(0); }
static void got_packet(UNUSED uint8_t *args, const struct pcap_pkthdr *header, const uint8_t *data) { static int count = 1; /* Packets seen */ /* * Define pointers for packet's attributes */ const struct ip_header *ip; /* The IP header */ const struct udp_header *udp; /* The UDP header */ const uint8_t *payload; /* Packet payload */ /* * And define the size of the structures we're using */ int size_ethernet = sizeof(struct ethernet_header); int size_ip = sizeof(struct ip_header); int size_udp = sizeof(struct udp_header); /* * For FreeRADIUS */ RADIUS_PACKET *packet, *original; struct timeval elapsed; /* * Define our packet's attributes */ if ((data[0] == 2) && (data[1] == 0) && (data[2] == 0) && (data[3] == 0)) { ip = (const struct ip_header*) (data + 4); } else { ip = (const struct ip_header*)(data + size_ethernet); } udp = (const struct udp_header*)(((const uint8_t *) ip) + size_ip); payload = (const uint8_t *)(((const uint8_t *) udp) + size_udp); packet = rad_alloc(NULL, 0); if (!packet) { fprintf(stderr, "Out of memory\n"); return; } packet->src_ipaddr.af = AF_INET; packet->src_ipaddr.ipaddr.ip4addr.s_addr = ip->ip_src.s_addr; packet->src_port = ntohs(udp->udp_sport); packet->dst_ipaddr.af = AF_INET; packet->dst_ipaddr.ipaddr.ip4addr.s_addr = ip->ip_dst.s_addr; packet->dst_port = ntohs(udp->udp_dport); memcpy(&packet->data, &payload, sizeof(packet->data)); packet->data_len = header->len - (payload - data); if (!rad_packet_ok(packet, 0)) { DEBUG(log_dst, "Packet: %s\n", fr_strerror()); DEBUG(log_dst, " From %s:%d\n", inet_ntoa(ip->ip_src), ntohs(udp->udp_sport)); DEBUG(log_dst, " To: %s:%d\n", inet_ntoa(ip->ip_dst), ntohs(udp->udp_dport)); DEBUG(log_dst, " Type: %s\n", fr_packet_codes[packet->code]); rad_free(&packet); return; } switch (packet->code) { case PW_COA_REQUEST: /* we need a 16 x 0 byte vector for decrypting encrypted VSAs */ original = nullpacket; break; case PW_AUTHENTICATION_ACK: /* look for a matching request and use it for decoding */ original = rbtree_finddata(request_tree, packet); break; case PW_AUTHENTICATION_REQUEST: /* save the request for later matching */ original = rad_alloc_reply(NULL, packet); if (original) { /* just ignore allocation failures */ rbtree_deletebydata(request_tree, original); rbtree_insert(request_tree, original); } /* fallthrough */ default: /* don't attempt to decode any encrypted attributes */ original = NULL; } /* * Decode the data without bothering to check the signatures. */ if (rad_decode(packet, original, radius_secret) != 0) { rad_free(&packet); fr_perror("decode"); return; } /* * We've seen a successfull reply to this, so delete it now */ if (original) rbtree_deletebydata(request_tree, original); if (filter_vps && filter_packet(packet)) { rad_free(&packet); DEBUG(log_dst, "Packet number %d doesn't match\n", count++); return; } if (out) { pcap_dump((void *) out, header, data); goto check_filter; } INFO(log_dst, "%s Id %d\t", fr_packet_codes[packet->code], packet->id); /* * Print the RADIUS packet */ INFO(log_dst, "%s:%d -> ", inet_ntoa(ip->ip_src), ntohs(udp->udp_sport)); INFO(log_dst, "%s:%d", inet_ntoa(ip->ip_dst), ntohs(udp->udp_dport)); DEBUG1(log_dst, "\t(%d packets)", count++); if (!start_pcap.tv_sec) { start_pcap = header->ts; } tv_sub(&header->ts, &start_pcap, &elapsed); INFO(log_dst, "\t+%u.%03u", (unsigned int) elapsed.tv_sec, (unsigned int) elapsed.tv_usec / 1000); if (fr_debug_flag > 1) { DEBUG(log_dst, "\n"); if (packet->vps) { if (do_sort) sort(packet); vp_printlist(log_dst, packet->vps); pairfree(&packet->vps); } } INFO(log_dst, "\n"); if (!to_stdout && (fr_debug_flag > 4)) { rad_print_hex(packet); } fflush(log_dst); check_filter: /* * If we're doing filtering, Access-Requests are cached in the * filter tree. */ if (!filter_vps || ((packet->code != PW_AUTHENTICATION_REQUEST) && (packet->code != PW_ACCOUNTING_REQUEST))) { rad_free(&packet); } }
void backtrace_print(UNUSED fr_cbuff_t *cbuff, UNUSED void *obj) { fr_perror("Server built without fr_backtrace_* support, requires execinfo.h and possibly -lexecinfo"); }
int main(int argc, char *argv[]) { int c; int num_networks = 1; int num_workers = 2; uint16_t port16 = 0; TALLOC_CTX *autofree = talloc_autofree_context(); fr_schedule_t *sched; fr_listen_t listen = { .app_io = &app_io, .app = &test_app }; fr_listen_test_t *app_io_inst; listen.app_io_instance = app_io_inst = talloc_zero(autofree, fr_listen_test_t); fr_time_start(); fr_log_init(&default_log, false); default_log.colourise = true; memset(&my_ipaddr, 0, sizeof(my_ipaddr)); my_ipaddr.af = AF_INET; my_ipaddr.prefix = 32; my_ipaddr.addr.v4.s_addr = htonl(INADDR_LOOPBACK); my_port = 1812; while ((c = getopt(argc, argv, "i:n:s:w:x")) != EOF) switch (c) { case 'i': if (fr_inet_pton_port(&my_ipaddr, &port16, optarg, -1, AF_INET, true, false) < 0) { fr_perror("Failed parsing ipaddr"); exit(EXIT_FAILURE); } my_port = port16; break; case 'n': num_networks = atoi(optarg); if ((num_networks <= 0) || (num_networks > 16)) usage(); break; case 's': secret = optarg; break; case 'w': num_workers = atoi(optarg); if ((num_workers <= 0) || (num_workers > 1024)) usage(); break; case 'x': debug_lvl++; fr_debug_lvl++; break; case 'h': default: usage(); } #if 0 argc -= (optind - 1); argv += (optind - 1); #endif app_io_inst->ipaddr = my_ipaddr; app_io_inst->port = my_port; sched = fr_schedule_create(autofree, NULL, &default_log, debug_lvl, num_networks, num_workers, NULL, NULL); if (!sched) { fprintf(stderr, "schedule_test: Failed to create scheduler\n"); exit(EXIT_FAILURE); } if (listen.app_io->open(listen.app_io_instance, listen.app_io_instance) < 0) exit(EXIT_FAILURE); #if 0 /* * Set up the KQ filter for reading. */ EV_SET(&events[0], sockfd, EVFILT_READ, EV_ADD | EV_ENABLE, 0, 0, NULL); if (kevent(kq_master, events, 1, NULL, 0, NULL) < 0) { fr_perror("Failed setting KQ for EVFILT_READ"); exit(EXIT_FAILURE); } #endif (void) fr_fault_setup(autofree, NULL, argv[0]); (void) fr_schedule_listen_add(sched, &listen); sleep(10); (void) fr_schedule_destroy(sched); exit(EXIT_SUCCESS); }
/* * 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; }
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; }
fr_bt_marker_t *fr_backtrace_attach(UNUSED fr_cbuff_t **cbuff, UNUSED TALLOC_CTX *obj) { fr_perror("Server built without fr_backtrace_* support, requires execinfo.h and possibly -lexecinfo"); abort(); }
/* * Initialize a radclient data structure and add it to * the global linked list. */ static int radclient_init(const char *filename) { FILE *fp; VALUE_PAIR *vp; radclient_t *radclient; int filedone = 0; int packet_number = 1; assert(filename != NULL); /* * Determine where to read the VP's from. */ if (strcmp(filename, "-") != 0) { fp = fopen(filename, "r"); if (!fp) { fprintf(stderr, "radclient: Error opening %s: %s\n", filename, strerror(errno)); return 0; } } else { fp = stdin; } /* * Loop until the file is done. */ do { /* * Allocate it. */ radclient = malloc(sizeof(*radclient)); if (!radclient) { perror("radclient: X"); if (fp != stdin) fclose(fp); return 0; } memset(radclient, 0, sizeof(*radclient)); radclient->request = rad_alloc(1); if (!radclient->request) { fr_perror("radclient: Y"); free(radclient); if (fp != stdin) fclose(fp); return 0; } #ifdef WITH_TCP radclient->request->src_ipaddr = client_ipaddr; radclient->request->src_port = client_port; radclient->request->dst_ipaddr = server_ipaddr; radclient->request->dst_port = server_port; #endif radclient->filename = filename; radclient->request->id = -1; /* allocate when sending */ radclient->packet_number = packet_number++; /* * Read the VP's. */ radclient->request->vps = readvp2(fp, &filedone, "radclient:"); if (!radclient->request->vps) { rad_free(&radclient->request); free(radclient); if (fp != stdin) fclose(fp); return 1; } /* * Keep a copy of the the User-Password attribute. */ if ((vp = pairfind(radclient->request->vps, PW_USER_PASSWORD, 0)) != NULL) { strlcpy(radclient->password, vp->vp_strvalue, sizeof(radclient->password)); /* * Otherwise keep a copy of the CHAP-Password attribute. */ } else if ((vp = pairfind(radclient->request->vps, PW_CHAP_PASSWORD, 0)) != NULL) { strlcpy(radclient->password, vp->vp_strvalue, sizeof(radclient->password)); } else if ((vp = pairfind(radclient->request->vps, PW_MSCHAP_PASSWORD, 0)) != NULL) { strlcpy(radclient->password, vp->vp_strvalue, sizeof(radclient->password)); } else { radclient->password[0] = '\0'; } /* * Fix up Digest-Attributes issues */ for (vp = radclient->request->vps; vp != NULL; vp = vp->next) { switch (vp->attribute) { default: break; /* * Allow it to set the packet type in * the attributes read from the file. */ case PW_PACKET_TYPE: radclient->request->code = vp->vp_integer; break; case PW_PACKET_DST_PORT: radclient->request->dst_port = (vp->vp_integer & 0xffff); break; case PW_PACKET_DST_IP_ADDRESS: radclient->request->dst_ipaddr.af = AF_INET; radclient->request->dst_ipaddr.ipaddr.ip4addr.s_addr = vp->vp_ipaddr; break; case PW_PACKET_DST_IPV6_ADDRESS: radclient->request->dst_ipaddr.af = AF_INET6; radclient->request->dst_ipaddr.ipaddr.ip6addr = vp->vp_ipv6addr; break; case PW_PACKET_SRC_PORT: radclient->request->src_port = (vp->vp_integer & 0xffff); break; case PW_PACKET_SRC_IP_ADDRESS: radclient->request->src_ipaddr.af = AF_INET; radclient->request->src_ipaddr.ipaddr.ip4addr.s_addr = vp->vp_ipaddr; break; case PW_PACKET_SRC_IPV6_ADDRESS: radclient->request->src_ipaddr.af = AF_INET6; radclient->request->src_ipaddr.ipaddr.ip6addr = vp->vp_ipv6addr; 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! */ memmove(&vp->vp_octets[2], &vp->vp_octets[0], vp->length); vp->vp_octets[0] = vp->attribute - PW_DIGEST_REALM + 1; vp->length += 2; vp->vp_octets[1] = vp->length; vp->attribute = PW_DIGEST_ATTRIBUTES; break; } } /* loop over the VP's we read in */ /* * Add it to the tail of the list. */ if (!radclient_head) { assert(radclient_tail == NULL); radclient_head = radclient; radclient->prev = NULL; } else { assert(radclient_tail->next == NULL); radclient_tail->next = radclient; radclient->prev = radclient_tail; } radclient_tail = radclient; radclient->next = NULL; } while (!filedone); /* loop until the file is done. */ if (fp != stdin) fclose(fp); /* * And we're done. */ return 1; }
int main(int argc, char *argv[]) { const char *from_dev = NULL; /* Capture from device */ const char *from_file = NULL; /* Read from pcap file */ int from_stdin = 0; /* Read from stdin */ pcap_t *in; /* PCAP input handle */ int limit = -1; /* How many packets to sniff */ char errbuf[PCAP_ERRBUF_SIZE]; /* Error buffer */ char *to_file = NULL; /* PCAP output file */ char *pcap_filter = NULL; /* PCAP filter string */ char *radius_filter = NULL; int port = 1812; struct bpf_program fp; /* Holds compiled filter */ bpf_u_int32 ip_mask = PCAP_NETMASK_UNKNOWN; /* Device Subnet mask */ bpf_u_int32 ip_addr = 0; /* Device IP */ char buffer[1024]; int opt; FR_TOKEN parsecode; const char *radius_dir = RADIUS_DIR; fr_debug_flag = 2; log_dst = stdout; /* * Get options */ while ((opt = getopt(argc, argv, "c:d:Ff:hi:I:p:qr:s:Svw:xX")) != EOF) { switch (opt) { case 'c': limit = atoi(optarg); if (limit <= 0) { fprintf(stderr, "radsniff: Invalid number of packets \"%s\"\n", optarg); exit(1); } break; case 'd': radius_dir = optarg; break; case 'F': from_stdin = 1; to_stdout = 1; break; case 'f': pcap_filter = optarg; break; case 'h': usage(0); break; case 'i': from_dev = optarg; break; case 'I': from_file = optarg; break; case 'p': port = atoi(optarg); break; case 'q': if (fr_debug_flag > 0) { fr_debug_flag--; } break; case 'r': radius_filter = optarg; break; case 's': radius_secret = optarg; break; case 'S': do_sort = 1; break; case 'v': INFO(log_dst, "%s %s\n", radsniff_version, pcap_lib_version()); exit(0); break; case 'w': to_file = optarg; break; case 'x': case 'X': fr_debug_flag++; break; default: usage(64); } } /* What's the point in specifying -F ?! */ if (from_stdin && from_file && to_file) { usage(64); } /* Can't read from both... */ if (from_file && from_dev) { usage(64); } /* Reading from file overrides stdin */ if (from_stdin && (from_file || from_dev)) { from_stdin = 0; } /* Writing to file overrides stdout */ if (to_file && to_stdout) { to_stdout = 0; } /* * If were writing pcap data stdout we *really* don't want to send * logging there as well. */ log_dst = to_stdout ? stderr : stdout; #if !defined(HAVE_PCAP_FOPEN_OFFLINE) || !defined(HAVE_PCAP_DUMP_FOPEN) if (from_stdin || to_stdout) { fprintf(stderr, "radsniff: PCAP streams not supported.\n"); exit(64); } #endif if (!pcap_filter) { pcap_filter = buffer; snprintf(buffer, sizeof(buffer), "udp port %d or %d or %d", port, port + 1, 3799); } /* * There are times when we don't need the dictionaries. */ if (!to_stdout) { if (dict_init(radius_dir, RADIUS_DICTIONARY) < 0) { fr_perror("radsniff"); exit(64); } } if (radius_filter) { parsecode = userparse(radius_filter, &filter_vps); if (parsecode == T_OP_INVALID) { fprintf(stderr, "radsniff: Invalid RADIUS filter \"%s\" (%s)\n", radius_filter, fr_strerror()); exit(64); } if (!filter_vps) { fprintf(stderr, "radsniff: Empty RADIUS filter \"%s\"\n", radius_filter); exit(64); } filter_tree = rbtree_create((rbcmp) fr_packet_cmp, free, 0); if (!filter_tree) { fprintf(stderr, "radsniff: Failed creating filter tree\n"); exit(1); } } /* * Setup the request tree */ request_tree = rbtree_create((rbcmp) fr_packet_cmp, free, 0); if (!request_tree) { fprintf(stderr, "radsniff: Failed creating request tree\n"); exit(1); } /* * Allocate a null packet for decrypting attributes in CoA requests */ nullpacket = rad_alloc(NULL, 0); if (!nullpacket) { fprintf(stderr, "radsniff: Out of memory\n"); exit(1); } /* * Get the default capture device */ if (!from_stdin && !from_file && !from_dev) { from_dev = pcap_lookupdev(errbuf); if (!from_dev) { fprintf(stderr, "radsniff: Failed discovering default interface (%s)\n", errbuf); exit(1); } INFO(log_dst, "Capturing from interface \"%s\"\n", from_dev); } /* * Print captures values which will be used */ if (fr_debug_flag > 2) { DEBUG1(log_dst, "Sniffing with options:\n"); if (from_dev) DEBUG1(log_dst, " Device : [%s]\n", from_dev); if (limit > 0) DEBUG1(log_dst, " Capture limit (packets) : [%d]\n", limit); DEBUG1(log_dst, " PCAP filter : [%s]\n", pcap_filter); DEBUG1(log_dst, " RADIUS secret : [%s]\n", radius_secret); if (filter_vps){DEBUG1(log_dst, " RADIUS filter :\n"); vp_printlist(log_dst, filter_vps); } } /* * Figure out whether were doing a reading from a file, doing a live * capture or reading from stdin. */ if (from_file) { in = pcap_open_offline(from_file, errbuf); #ifdef HAVE_PCAP_FOPEN_OFFLINE } else if (from_stdin) { in = pcap_fopen_offline(stdin, errbuf); #endif } else if (from_dev) { pcap_lookupnet(from_dev, &ip_addr, &ip_mask, errbuf); in = pcap_open_live(from_dev, 65536, 1, 1, errbuf); } else { fprintf(stderr, "radsniff: No capture devices available\n"); } if (!in) { fprintf(stderr, "radsniff: Failed opening input (%s)\n", errbuf); exit(1); } if (to_file) { out = pcap_dump_open(in, to_file); if (!out) { fprintf(stderr, "radsniff: Failed opening output file (%s)\n", pcap_geterr(in)); exit(1); } #ifdef HAVE_PCAP_DUMP_FOPEN } else if (to_stdout) { out = pcap_dump_fopen(in, stdout); if (!out) { fprintf(stderr, "radsniff: Failed opening stdout (%s)\n", pcap_geterr(in)); exit(1); } #endif } /* * Apply the rules */ if (pcap_compile(in, &fp, pcap_filter, 0, ip_mask) < 0) { fprintf(stderr, "radsniff: Failed compiling PCAP filter (%s)\n", pcap_geterr(in)); exit(1); } if (pcap_setfilter(in, &fp) < 0) { fprintf(stderr, "radsniff: Failed applying PCAP filter (%s)\n", pcap_geterr(in)); exit(1); } /* * Enter the main capture loop... */ pcap_loop(in, limit, got_packet, NULL); /* * ...were done capturing. */ pcap_close(in); if (out) { pcap_dump_close(out); } if (filter_tree) { rbtree_free(filter_tree); } INFO(log_dst, "Done sniffing\n"); return 0; }
/* * Receive one packet, maybe. */ static int recv_one_packet(int wait_time) { fd_set set; struct timeval tv; radclient_t *radclient; RADIUS_PACKET *reply, **request_p; volatile int max_fd; /* And wait for reply, timing out as necessary */ FD_ZERO(&set); max_fd = fr_packet_list_fd_set(pl, &set); if (max_fd < 0) exit(1); /* no sockets to listen on! */ if (wait_time <= 0) { tv.tv_sec = 0; } else { tv.tv_sec = wait_time; } tv.tv_usec = 0; /* * No packet was received. */ if (select(max_fd, &set, NULL, NULL, &tv) <= 0) { return 0; } /* * Look for the packet. */ reply = fr_packet_list_recv(pl, &set); if (!reply) { fprintf(stderr, "radclient: received bad packet: %s\n", fr_strerror()); #ifdef WITH_TCP /* * If the packet is bad, we close the socket. * I'm not sure how to do that now, so we just * die... */ if (proto) exit(1); #endif return -1; /* bad packet */ } /* * udpfromto issues. We may have bound to "*", * and we want to find the replies that are sent to * (say) 127.0.0.1. */ reply->dst_ipaddr = client_ipaddr; reply->dst_port = client_port; #ifdef WITH_TCP reply->src_ipaddr = server_ipaddr; reply->src_port = server_port; #endif if (fr_debug_flag > 2) print_hex(reply); request_p = fr_packet_list_find_byreply(pl, reply); if (!request_p) { fprintf(stderr, "radclient: received response to request we did not send. (id=%d socket %d)\n", reply->id, reply->sockfd); rad_free(&reply); return -1; /* got reply to packet we didn't send */ } radclient = fr_packet2myptr(radclient_t, request, request_p); /* * Fails the signature validation: not a real reply. * FIXME: Silently drop it and listen for another packet. */ if (rad_verify(reply, radclient->request, secret) < 0) { fr_perror("rad_verify"); totallost++; goto packet_done; /* shared secret is incorrect */ } fr_packet_list_yank(pl, radclient->request); if (print_filename) printf("%s:%d %d\n", radclient->filename, radclient->packet_number, reply->code); deallocate_id(radclient); radclient->reply = reply; reply = NULL; /* * If this fails, we're out of memory. */ if (rad_decode(radclient->reply, radclient->request, secret) != 0) { fr_perror("rad_decode"); totallost++; goto packet_done; } /* libradius debug already prints out the value pairs for us */ if (!fr_debug_flag && do_output) { printf("Received response ID %d, code %d, length = %zd\n", radclient->reply->id, radclient->reply->code, radclient->reply->data_len); vp_printlist(stdout, radclient->reply->vps); } if ((radclient->reply->code == PW_AUTHENTICATION_ACK) || (radclient->reply->code == PW_ACCOUNTING_RESPONSE) || (radclient->reply->code == PW_COA_ACK) || (radclient->reply->code == PW_DISCONNECT_ACK)) { success = 1; /* have a good response */ totalapp++; } else { totaldeny++; } if (radclient->resend == resend_count) { radclient->done = 1; } packet_done: rad_free(&radclient->reply); rad_free(&reply); /* may be NULL */ return 0; }
static int sm_parse_file(FILE*fp,const char* fname) { FR_TOKEN tok; VALUE_PAIR *vp = NULL; sm_parse_state_t parse_state = SMP_USER; unsigned long lino = 0; char *p; char buff[MAX_BUFF_SIZE]; char username[256]; while( parse_state != SMP_INVALID && fgets(buff, sizeof(buff), fp) != NULL ) { lino ++; st_lines++; if ( strchr(buff, '\n') == NULL) { fprintf(stderr,"%s: %s[%lu]:Warning: line too long or not closed by \\n character. Skiped\n",progname,fname,lino); st_warns++; st_skiped++; /* _LINE_ skiped */ continue; } DOUT2("Parseline: %s",buff); for ( p = buff; isspace((int) *p); p++); if ( *p == '#' || *p == 0 ) continue; /* userparse hack */ if ( *p == ';' ) *p = '\n'; p = buff; /* try to decide is this line new user or new pattern */ if ( parse_state == SMP_PATTERN_OR_USER ) { if ( isspace((int) buff[0]) ) parse_state = SMP_PATTERN; else { parse_state = SMP_USER; storecontent(username); st_users++; } } if ( parse_state == SMP_USER ) { tok = getuname(&p,username,sizeof(username)); /* check: is it include. not implemented */ if ( tok ) { fprintf(stderr ,"%s: %s[%lu]: error while expecting user name\n",progname,fname,lino); parse_state = SMP_INVALID; st_errors++; } else { parse_state = SMP_PATTERN; DOUT1("Found user: %s\n",username); } } if ( parse_state == SMP_PATTERN || parse_state == SMP_ACTION ) { /* check for empty line */ while( *p && isspace((int) *p) ) p++; if ( *p && ( *p != ';' ) ) tok = userparse(p,&vp); else tok = T_EOL; /* ';' - signs empty line */ switch(tok) { case T_EOL: /* add to content */ addlinetocontent(vp); pairfree(&vp); if ( parse_state == SMP_PATTERN ) parse_state = SMP_ACTION; else parse_state = SMP_PATTERN_OR_USER; case T_COMMA: break; /* parse next line */ default: /* error: we do not expect anything else */ fprintf(stderr ,"%s: %s[%lu]: syntax error\n",progname,fname,lino); fr_perror("Error"); parse_state = SMP_INVALID; st_errors++; } } } if ( feof(fp) ) switch (parse_state ) { case SMP_USER: /* file is empty, last line is comment */ break; case SMP_PATTERN: /* only username ?*/ fprintf(stderr ,"%s: %s[%lu]: EOF while pattern line are expecting\n",progname,fname,lino); st_errors++; parse_state = SMP_INVALID; break; case SMP_ACTION: /* looking for reply line */ fprintf(stderr ,"%s: %s[%lu]: EOF while reply line are expecting\n",progname,fname,lino); st_errors++; parse_state = SMP_INVALID; break; case SMP_PATTERN_OR_USER: storecontent(username); st_users++; break; default:break; } else if ( parse_state != SMP_INVALID ) { /* file read error */ fprintf(stderr ,"%s: error file reading from file\n",progname); } pairfree(&vp); return (parse_state == SMP_INVALID)?-1:0; }
int main(int argc, char **argv) { char *p; int c; const char *radius_dir = RADDBDIR; char filesecret[256]; FILE *fp; int do_summary = 0; int persec = 0; int parallel = 1; radclient_t *this; int force_af = AF_UNSPEC; fr_debug_flag = 0; filename_tree = rbtree_create(filename_cmp, NULL, 0); if (!filename_tree) { fprintf(stderr, "radclient: Out of memory\n"); exit(1); } while ((c = getopt(argc, argv, "46c:d:f:Fhi:n:p:qr:sS:t:vx" #ifdef WITH_TCP "P:" #endif )) != EOF) switch(c) { case '4': force_af = AF_INET; break; case '6': force_af = AF_INET6; break; case 'c': if (!isdigit((int) *optarg)) usage(); resend_count = atoi(optarg); break; case 'd': radius_dir = optarg; break; case 'f': rbtree_insert(filename_tree, optarg); break; case 'F': print_filename = 1; break; case 'i': /* currently broken */ if (!isdigit((int) *optarg)) usage(); last_used_id = atoi(optarg); if ((last_used_id < 0) || (last_used_id > 255)) { usage(); } break; case 'n': persec = atoi(optarg); if (persec <= 0) usage(); break; /* * Note that sending MANY requests in * parallel can over-run the kernel * queues, and Linux will happily discard * packets. So even if the server responds, * the client may not see the response. */ case 'p': parallel = atoi(optarg); if (parallel <= 0) usage(); break; #ifdef WITH_TCP case 'P': proto = optarg; if (strcmp(proto, "tcp") != 0) { if (strcmp(proto, "udp") == 0) { proto = NULL; } else { usage(); } } else { ipproto = IPPROTO_TCP; } break; #endif case 'q': do_output = 0; fr_log_fp = NULL; /* no output from you, either! */ break; case 'r': if (!isdigit((int) *optarg)) usage(); retries = atoi(optarg); if ((retries == 0) || (retries > 1000)) usage(); break; case 's': do_summary = 1; break; case 'S': fp = fopen(optarg, "r"); if (!fp) { fprintf(stderr, "radclient: Error opening %s: %s\n", optarg, strerror(errno)); exit(1); } if (fgets(filesecret, sizeof(filesecret), fp) == NULL) { fprintf(stderr, "radclient: Error reading %s: %s\n", optarg, strerror(errno)); exit(1); } fclose(fp); /* truncate newline */ p = filesecret + strlen(filesecret) - 1; while ((p >= filesecret) && (*p < ' ')) { *p = '\0'; --p; } if (strlen(filesecret) < 2) { fprintf(stderr, "radclient: Secret in %s is too short\n", optarg); exit(1); } secret = filesecret; break; case 't': if (!isdigit((int) *optarg)) usage(); timeout = atof(optarg); break; case 'v': printf("%s", radclient_version); exit(0); break; case 'x': fr_debug_flag++; fr_log_fp = stdout; break; case 'h': default: usage(); break; } argc -= (optind - 1); argv += (optind - 1); if ((argc < 3) || ((secret == NULL) && (argc < 4))) { usage(); } if (dict_init(radius_dir, RADIUS_DICTIONARY) < 0) { fr_perror("radclient"); return 1; } /* * Resolve hostname. */ if (force_af == AF_UNSPEC) force_af = AF_INET; server_ipaddr.af = force_af; if (strcmp(argv[1], "-") != 0) { const char *hostname = argv[1]; const char *portname = argv[1]; char buffer[256]; if (*argv[1] == '[') { /* IPv6 URL encoded */ p = strchr(argv[1], ']'); if ((size_t) (p - argv[1]) >= sizeof(buffer)) { usage(); } memcpy(buffer, argv[1] + 1, p - argv[1] - 1); buffer[p - argv[1] - 1] = '\0'; hostname = buffer; portname = p + 1; } p = strchr(portname, ':'); if (p && (strchr(p + 1, ':') == NULL)) { *p = '\0'; portname = p + 1; } else { portname = NULL; } if (ip_hton(hostname, force_af, &server_ipaddr) < 0) { fprintf(stderr, "radclient: Failed to find IP address for host %s: %s\n", hostname, strerror(errno)); exit(1); } /* * Strip port from hostname if needed. */ if (portname) server_port = atoi(portname); } /* * See what kind of request we want to send. */ if (strcmp(argv[2], "auth") == 0) { if (server_port == 0) server_port = getport("radius"); if (server_port == 0) server_port = PW_AUTH_UDP_PORT; packet_code = PW_AUTHENTICATION_REQUEST; } else if (strcmp(argv[2], "challenge") == 0) { if (server_port == 0) server_port = getport("radius"); if (server_port == 0) server_port = PW_AUTH_UDP_PORT; packet_code = PW_ACCESS_CHALLENGE; } else if (strcmp(argv[2], "acct") == 0) { if (server_port == 0) server_port = getport("radacct"); if (server_port == 0) server_port = PW_ACCT_UDP_PORT; packet_code = PW_ACCOUNTING_REQUEST; do_summary = 0; } else if (strcmp(argv[2], "status") == 0) { if (server_port == 0) server_port = getport("radius"); if (server_port == 0) server_port = PW_AUTH_UDP_PORT; packet_code = PW_STATUS_SERVER; } else if (strcmp(argv[2], "disconnect") == 0) { if (server_port == 0) server_port = PW_COA_UDP_PORT; packet_code = PW_DISCONNECT_REQUEST; } else if (strcmp(argv[2], "coa") == 0) { if (server_port == 0) server_port = PW_COA_UDP_PORT; packet_code = PW_COA_REQUEST; } else if (strcmp(argv[2], "auto") == 0) { packet_code = -1; } else if (isdigit((int) argv[2][0])) { if (server_port == 0) server_port = getport("radius"); if (server_port == 0) server_port = PW_AUTH_UDP_PORT; packet_code = atoi(argv[2]); } else { usage(); } /* * Add the secret. */ if (argv[3]) secret = argv[3]; /* * If no '-f' is specified, we're reading from stdin. */ if (rbtree_num_elements(filename_tree) == 0) { if (!radclient_init("-")) exit(1); } /* * Walk over the list of filenames, creating the requests. */ if (rbtree_walk(filename_tree, InOrder, filename_walk, NULL) != 0) { exit(1); } /* * No packets read. Die. */ if (!radclient_head) { fprintf(stderr, "radclient: Nothing to send.\n"); exit(1); } /* * Bind to the first specified IP address and port. * This means we ignore later ones. */ if (radclient_head->request->src_ipaddr.af == AF_UNSPEC) { memset(&client_ipaddr, 0, sizeof(client_ipaddr)); client_ipaddr.af = server_ipaddr.af; client_port = 0; } else { client_ipaddr = radclient_head->request->src_ipaddr; client_port = radclient_head->request->src_port; } #ifdef WITH_TCP if (proto) { sockfd = fr_tcp_client_socket(NULL, &server_ipaddr, server_port); } else #endif sockfd = fr_socket(&client_ipaddr, client_port); if (sockfd < 0) { fprintf(stderr, "radclient: socket: %s\n", fr_strerror()); exit(1); } pl = fr_packet_list_create(1); if (!pl) { fprintf(stderr, "radclient: Out of memory\n"); exit(1); } if (!fr_packet_list_socket_add(pl, sockfd, ipproto, &server_ipaddr, server_port, NULL)) { fprintf(stderr, "radclient: Out of memory\n"); exit(1); } /* * Walk over the list of packets, sanity checking * everything. */ for (this = radclient_head; this != NULL; this = this->next) { this->request->src_ipaddr = client_ipaddr; this->request->src_port = client_port; if (radclient_sane(this) != 0) { exit(1); } } /* * Walk over the packets to send, until * we're all done. * * FIXME: This currently busy-loops until it receives * all of the packets. It should really have some sort of * send packet, get time to wait, select for time, etc. * loop. */ do { int n = parallel; radclient_t *next; const char *filename = NULL; done = 1; sleep_time = -1; /* * Walk over the packets, sending them. */ for (this = radclient_head; this != NULL; this = next) { next = this->next; /* * If there's a packet to receive, * receive it, but don't wait for a * packet. */ recv_one_packet(0); /* * This packet is done. Delete it. */ if (this->done) { radclient_free(this); continue; } /* * Packets from multiple '-f' are sent * in parallel. * * Packets from one file are sent in * series, unless '-p' is specified, in * which case N packets from each file * are sent in parallel. */ if (this->filename != filename) { filename = this->filename; n = parallel; } if (n > 0) { n--; /* * Send the current packet. */ send_one_packet(this); /* * Wait a little before sending * the next packet, if told to. */ if (persec) { struct timeval tv; /* * Don't sleep elsewhere. */ sleep_time = 0; if (persec == 1) { tv.tv_sec = 1; tv.tv_usec = 0; } else { tv.tv_sec = 0; tv.tv_usec = 1000000/persec; } /* * Sleep for milliseconds, * portably. * * If we get an error or * a signal, treat it like * a normal timeout. */ select(0, NULL, NULL, NULL, &tv); } /* * If we haven't sent this packet * often enough, we're not done, * and we shouldn't sleep. */ if (this->resend < resend_count) { done = 0; sleep_time = 0; } } else { /* haven't sent this packet, we're not done */ assert(this->done == 0); assert(this->reply == NULL); done = 0; } } /* * Still have outstanding requests. */ if (fr_packet_list_num_elements(pl) > 0) { done = 0; } else { sleep_time = 0; } /* * Nothing to do until we receive a request, so * sleep until then. Once we receive one packet, * we go back, and walk through the whole list again, * sending more packets (if necessary), and updating * the sleep time. */ if (!done && (sleep_time > 0)) { recv_one_packet(sleep_time); } } while (!done); rbtree_free(filename_tree); fr_packet_list_free(pl); while (radclient_head) radclient_free(radclient_head); dict_free(); if (do_summary) { printf("\n\t Total approved auths: %d\n", totalapp); printf("\t Total denied auths: %d\n", totaldeny); printf("\t Total lost auths: %d\n", totallost); } if (success) return 0; return 1; }
static REQUEST *request_setup(FILE *fp) { VALUE_PAIR *vp; REQUEST *request; vp_cursor_t cursor; /* * Create and initialize the new request. */ request = request_alloc(NULL); request->packet = rad_alloc(request, false); if (!request->packet) { ERROR("No memory"); talloc_free(request); return NULL; } request->reply = rad_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 (readvp2(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->value.xlat; vp->value.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; break; case PW_PACKET_DST_IPV6_ADDRESS: request->packet->dst_ipaddr.af = AF_INET6; request->packet->dst_ipaddr.ipaddr.ip6addr = vp->vp_ipv6addr; 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; break; case PW_PACKET_SRC_IPV6_ADDRESS: request->packet->src_ipaddr.af = AF_INET6; request->packet->src_ipaddr.ipaddr.ip6addr = vp->vp_ipv6addr; 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->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->length; if (len2 < 17) len2 = 17; p = talloc_zero_array(vp, uint8_t, len2); memcpy(p, vp->vp_strvalue, len); rad_chap_encode(request->packet, p, fr_rand() & 0xff, vp); vp->vp_octets = p; 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! */ { DICT_ATTR const *da; uint8_t *p, *q; p = talloc_array(vp, uint8_t, vp->length + 2); memcpy(p + 2, vp->vp_octets, vp->length); p[0] = vp->da->attr - PW_DIGEST_REALM + 1; vp->length += 2; p[1] = vp->length; da = dict_attrbyvalue(PW_DIGEST_ATTRIBUTES, 0); rad_assert(da != NULL); vp->da = da; /* * Re-do pairmemsteal ourselves, * because we play games with * vp->da, and pairmemsteal 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 (debug_flag) { 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); } vp_print(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 = debug_flag; request->log.func = vradlog_request; request->username = pairfind(request->packet->vps, PW_USER_NAME, 0, TAG_ANY); request->password = pairfind(request->packet->vps, PW_USER_PASSWORD, 0, TAG_ANY); return request; }
static void rs_process_packet(rs_event_t *event, struct pcap_pkthdr const *header, uint8_t const *data) { static int count = 0; /* Packets seen */ rs_stats_t *stats = event->stats; decode_fail_t reason; /* * Pointers into the packet data we just received */ size_t len; uint8_t const *p = data; struct ip_header const *ip = NULL; /* The IP header */ struct ip_header6 const *ip6 = NULL; /* The IPv6 header */ struct udp_header const *udp; /* The UDP header */ uint8_t version; /* IP header version */ bool response = false; /* Was it a response code */ RADIUS_PACKET *current, *original; struct timeval elapsed; struct timeval latency; count++; if (header->caplen <= 5) { INFO("Packet too small, captured %i bytes", header->caplen); return; } /* * Loopback header */ if ((p[0] == 2) && (p[1] == 0) && (p[2] == 0) && (p[3] == 0)) { p += 4; /* * Ethernet header */ } else { p += sizeof(struct ethernet_header); } version = (p[0] & 0xf0) >> 4; switch (version) { case 4: ip = (struct ip_header const *)p; len = (0x0f & ip->ip_vhl) * 4; /* ip_hl specifies length in 32bit words */ p += len; break; case 6: ip6 = (struct ip_header6 const *)p; p += sizeof(struct ip_header6); break; default: DEBUG("IP version invalid %i", version); return; } /* * End of variable length bits, do basic check now to see if packet looks long enough */ len = (p - data) + sizeof(struct udp_header) + (sizeof(radius_packet_t) - 1); /* length value */ if (len > header->caplen) { DEBUG("Packet too small, we require at least %zu bytes, captured %i bytes", (size_t) len, header->caplen); return; } udp = (struct udp_header const *)p; p += sizeof(struct udp_header); /* * With artificial talloc memory limits there's a good chance we can * recover once some requests timeout, so make an effort to deal * with allocation failures gracefully. */ current = rad_alloc(NULL, 0); if (!current) { ERROR("Failed allocating memory to hold decoded packet"); return; } current->timestamp = header->ts; current->data_len = header->caplen - (data - p); memcpy(¤t->data, &p, sizeof(current->data)); /* * Populate IP/UDP fields from PCAP data */ if (ip) { current->src_ipaddr.af = AF_INET; current->src_ipaddr.ipaddr.ip4addr.s_addr = ip->ip_src.s_addr; current->dst_ipaddr.af = AF_INET; current->dst_ipaddr.ipaddr.ip4addr.s_addr = ip->ip_dst.s_addr; } else { current->src_ipaddr.af = AF_INET6; memcpy(¤t->src_ipaddr.ipaddr.ip6addr.s6_addr, &ip6->ip_src.s6_addr, sizeof(current->src_ipaddr.ipaddr.ip6addr.s6_addr)); current->dst_ipaddr.af = AF_INET6; memcpy(¤t->dst_ipaddr.ipaddr.ip6addr.s6_addr, &ip6->ip_dst.s6_addr, sizeof(current->dst_ipaddr.ipaddr.ip6addr.s6_addr)); } current->src_port = ntohs(udp->udp_sport); current->dst_port = ntohs(udp->udp_dport); if (!rad_packet_ok(current, 0, &reason)) { DEBUG("(%i) ** %s **", count, fr_strerror()); DEBUG("(%i) %s Id %i %s:%s:%d -> %s:%d\t+%u.%03u", count, fr_packet_codes[current->code], current->id, event->in->name, fr_inet_ntop(current->src_ipaddr.af, ¤t->src_ipaddr.ipaddr), current->src_port, fr_inet_ntop(current->dst_ipaddr.af, ¤t->dst_ipaddr.ipaddr), current->dst_port, (unsigned int) elapsed.tv_sec, ((unsigned int) elapsed.tv_usec / 1000)); rad_free(¤t); return; } switch (current->code) { case PW_CODE_COA_REQUEST: /* we need a 16 x 0 byte vector for decrypting encrypted VSAs */ original = nullpacket; break; case PW_CODE_ACCOUNTING_RESPONSE: case PW_CODE_AUTHENTICATION_REJECT: case PW_CODE_AUTHENTICATION_ACK: response = true; /* look for a matching request and use it for decoding */ original = rbtree_finddata(request_tree, current); break; case PW_CODE_ACCOUNTING_REQUEST: case PW_CODE_AUTHENTICATION_REQUEST: /* save the request for later matching */ original = rad_alloc_reply(event->conf, current); original->timestamp = header->ts; if (original) { /* just ignore allocation failures */ rbtree_deletebydata(request_tree, original); rbtree_insert(request_tree, original); } /* fallthrough */ default: /* don't attempt to decode any encrypted attributes */ original = NULL; } /* * Decode the data without bothering to check the signatures. */ if (rad_decode(current, original, event->conf->radius_secret) != 0) { rad_free(¤t); fr_perror("decode"); return; } if (filter_vps && rs_filter_packet(current)) { rad_free(¤t); DEBUG("Packet number %d doesn't match", count++); return; } if (event->out) { pcap_dump((void *) (event->out->dumper), header, data); goto check_filter; } rs_tv_sub(&header->ts, &start_pcap, &elapsed); rs_stats_update_count(&stats->gauge, current); if (original) { rs_tv_sub(¤t->timestamp, &original->timestamp, &latency); /* * Update stats for both the request and response types. * * This isn't useful for things like Access-Requests, but will be useful for * CoA and Disconnect Messages, as we get the average latency across both * response types. * * It also justifies allocating 255 instances rs_latency_t. */ rs_stats_update_latency(&stats->exchange[current->code], &latency); rs_stats_update_latency(&stats->exchange[original->code], &latency); /* * Print info about the response. */ DEBUG("(%i) %s Id %i %s:%s:%d %s %s:%d\t+%u.%03u\t+%u.%03u", count, fr_packet_codes[current->code], current->id, event->in->name, fr_inet_ntop(current->src_ipaddr.af, ¤t->src_ipaddr.ipaddr), current->src_port, response ? "<-" : "->", fr_inet_ntop(current->dst_ipaddr.af, ¤t->dst_ipaddr.ipaddr), current->dst_port, (unsigned int) elapsed.tv_sec, ((unsigned int) elapsed.tv_usec / 1000), (unsigned int) latency.tv_sec, ((unsigned int) latency.tv_usec / 1000)); /* * It's the original request */ } else { /* * Print info about the request */ DEBUG("(%i) %s Id %i %s:%s:%d %s %s:%d\t+%u.%03u", count, fr_packet_codes[current->code], current->id, event->in->name, fr_inet_ntop(current->src_ipaddr.af, ¤t->src_ipaddr.ipaddr), current->src_port, response ? "<-" : "->", fr_inet_ntop(current->dst_ipaddr.af, ¤t->dst_ipaddr.ipaddr), current->dst_port, (unsigned int) elapsed.tv_sec, ((unsigned int) elapsed.tv_usec / 1000)); } if (fr_debug_flag > 1) { if (current->vps) { if (event->conf->do_sort) { pairsort(¤t->vps, true); } vp_printlist(log_dst, current->vps); pairfree(¤t->vps); } } /* * We've seen a successful reply to this, so delete it now */ if (original) { rbtree_deletebydata(request_tree, original); } if (!event->conf->to_stdout && (fr_debug_flag > 4)) { rad_print_hex(current); } fflush(log_dst); check_filter: /* * If we're doing filtering, Access-Requests are cached in the * filter tree. */ if (!filter_vps || ((current->code != PW_CODE_AUTHENTICATION_REQUEST) && (current->code != PW_CODE_ACCOUNTING_REQUEST))) { rad_free(¤t); } }
/* * 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; }
int main(int argc, char *argv[]) { rs_t *conf; fr_pcap_t *in = NULL, *in_p; fr_pcap_t **in_head = ∈ fr_pcap_t *out = NULL; int ret = 1; /* Exit status */ int limit = -1; /* How many packets to sniff */ char errbuf[PCAP_ERRBUF_SIZE]; /* Error buffer */ int port = 1812; char buffer[1024]; int opt; FR_TOKEN parsecode; char const *radius_dir = RADIUS_DIR; rs_stats_t stats; fr_debug_flag = 2; log_dst = stdout; talloc_set_log_stderr(); conf = talloc_zero(NULL, rs_t); if (!fr_assert(conf)) { exit (1); } /* * We don't really want probes taking down machines */ #ifdef HAVE_TALLOC_SET_MEMLIMIT talloc_set_memlimit(conf, 52428800); /* 50 MB */ #endif /* * Get options */ while ((opt = getopt(argc, argv, "c:d:DFf:hi:I:p:qr:s:Svw:xXW:P:O:")) != EOF) { switch (opt) { case 'c': limit = atoi(optarg); if (limit <= 0) { fprintf(stderr, "radsniff: Invalid number of packets \"%s\"", optarg); exit(1); } break; case 'd': radius_dir = optarg; break; case 'D': { pcap_if_t *all_devices = NULL; pcap_if_t *dev_p; if (pcap_findalldevs(&all_devices, errbuf) < 0) { ERROR("Error getting available capture devices: %s", errbuf); goto finish; } int i = 1; for (dev_p = all_devices; dev_p; dev_p = dev_p->next) { INFO("%i.%s", i++, dev_p->name); } ret = 0; goto finish; } case 'F': conf->from_stdin = true; conf->to_stdout = true; break; case 'f': conf->pcap_filter = optarg; break; case 'h': usage(0); break; case 'i': *in_head = fr_pcap_init(conf, optarg, PCAP_INTERFACE_IN); if (!*in_head) { goto finish; } in_head = &(*in_head)->next; conf->from_dev = true; break; case 'I': *in_head = fr_pcap_init(conf, optarg, PCAP_FILE_IN); if (!*in_head) { goto finish; } in_head = &(*in_head)->next; conf->from_file = true; break; case 'p': port = atoi(optarg); break; case 'q': if (fr_debug_flag > 0) { fr_debug_flag--; } break; case 'r': conf->radius_filter = optarg; break; case 's': conf->radius_secret = optarg; break; case 'S': conf->do_sort = true; break; case 'v': #ifdef HAVE_COLLECTDC_H INFO("%s, %s, collectdclient version %s", radsniff_version, pcap_lib_version(), lcc_version_string()); #else INFO("%s %s", radsniff_version, pcap_lib_version()); #endif exit(0); break; case 'w': out = fr_pcap_init(conf, optarg, PCAP_FILE_OUT); conf->to_file = true; break; case 'x': case 'X': fr_debug_flag++; break; case 'W': conf->stats.interval = atoi(optarg); if (conf->stats.interval <= 0) { ERROR("Stats interval must be > 0"); usage(64); } break; case 'T': conf->stats.timeout = atoi(optarg); if (conf->stats.timeout <= 0) { ERROR("Timeout value must be > 0"); usage(64); } break; #ifdef HAVE_COLLECTDC_H case 'P': conf->stats.prefix = optarg; break; case 'O': conf->stats.collectd = optarg; conf->stats.out = RS_STATS_OUT_COLLECTD; break; #endif default: usage(64); } } /* What's the point in specifying -F ?! */ if (conf->from_stdin && conf->from_file && conf->to_file) { usage(64); } /* Can't read from both... */ if (conf->from_file && conf->from_dev) { usage(64); } /* Reading from file overrides stdin */ if (conf->from_stdin && (conf->from_file || conf->from_dev)) { conf->from_stdin = false; } /* Writing to file overrides stdout */ if (conf->to_file && conf->to_stdout) { conf->to_stdout = false; } if (conf->to_stdout) { out = fr_pcap_init(conf, "stdout", PCAP_STDIO_OUT); if (!out) { goto finish; } } if (conf->from_stdin) { *in_head = fr_pcap_init(conf, "stdin", PCAP_STDIO_IN); if (!*in_head) { goto finish; } in_head = &(*in_head)->next; } if (!conf->radius_secret) { conf->radius_secret = RS_DEFAULT_SECRET; } if (conf->stats.interval && !conf->stats.out) { conf->stats.out = RS_STATS_OUT_STDIO; } if (conf->stats.timeout == 0) { conf->stats.timeout = RS_DEFAULT_TIMEOUT; } /* * If were writing pcap data stdout we *really* don't want to send * logging there as well. */ log_dst = conf->to_stdout ? stderr : stdout; #if !defined(HAVE_PCAP_FOPEN_OFFLINE) || !defined(HAVE_PCAP_DUMP_FOPEN) if (conf->from_stdin || conf->to_stdout) { ERROR("PCAP streams not supported"); goto finish; } #endif if (!conf->pcap_filter) { snprintf(buffer, sizeof(buffer), "udp port %d or %d or %d", port, port + 1, 3799); conf->pcap_filter = buffer; } if (dict_init(radius_dir, RADIUS_DICTIONARY) < 0) { fr_perror("radsniff"); ret = 64; goto finish; } fr_strerror(); /* Clear out any non-fatal errors */ if (conf->radius_filter) { parsecode = userparse(NULL, conf->radius_filter, &filter_vps); if (parsecode == T_OP_INVALID) { ERROR("Invalid RADIUS filter \"%s\" (%s)", conf->radius_filter, fr_strerror()); ret = 64; goto finish; } if (!filter_vps) { ERROR("Empty RADIUS filter \"%s\"", conf->radius_filter); ret = 64; goto finish; } filter_tree = rbtree_create((rbcmp) fr_packet_cmp, _rb_rad_free, 0); if (!filter_tree) { ERROR("Failed creating filter tree"); ret = 64; goto finish; } } /* * Setup the request tree */ request_tree = rbtree_create((rbcmp) fr_packet_cmp, _rb_rad_free, 0); if (!request_tree) { ERROR("Failed creating request tree"); goto finish; } /* * Allocate a null packet for decrypting attributes in CoA requests */ nullpacket = rad_alloc(conf, 0); if (!nullpacket) { ERROR("Out of memory"); goto finish; } /* * Get the default capture device */ if (!conf->from_stdin && !conf->from_file && !conf->from_dev) { pcap_if_t *all_devices; /* List of all devices libpcap can listen on */ pcap_if_t *dev_p; if (pcap_findalldevs(&all_devices, errbuf) < 0) { ERROR("Error getting available capture devices: %s", errbuf); goto finish; } if (!all_devices) { ERROR("No capture files specified and no live interfaces available"); ret = 64; goto finish; } for (dev_p = all_devices; dev_p; dev_p = dev_p->next) { /* Don't use the any devices, it's horribly broken */ if (!strcmp(dev_p->name, "any")) continue; *in_head = fr_pcap_init(conf, dev_p->name, PCAP_INTERFACE_IN); in_head = &(*in_head)->next; } conf->from_auto = true; conf->from_dev = true; INFO("Defaulting to capture on all interfaces"); } /* * Print captures values which will be used */ if (fr_debug_flag > 2) { DEBUG1("Sniffing with options:"); if (conf->from_dev) { char *buff = fr_pcap_device_names(conf, in, ' '); DEBUG1(" Device(s) : [%s]", buff); talloc_free(buff); } if (conf->to_file || conf->to_stdout) { DEBUG1(" Writing to : [%s]", out->name); } if (limit > 0) { DEBUG1(" Capture limit (packets) : [%d]", limit); } DEBUG1(" PCAP filter : [%s]", conf->pcap_filter); DEBUG1(" RADIUS secret : [%s]", conf->radius_secret); if (filter_vps){ DEBUG1(" RADIUS filter :"); vp_printlist(log_dst, filter_vps); } } /* * Open our interface to collectd */ #ifdef HAVE_COLLECTDC_H if (conf->stats.out == RS_STATS_OUT_COLLECTD) { size_t i; rs_stats_tmpl_t *tmpl, **next; if (rs_stats_collectd_open(conf) < 0) { exit(1); } next = &conf->stats.tmpl; for (i = 0; i < (sizeof(rs_useful_codes) / sizeof(*rs_useful_codes)); i++) { tmpl = rs_stats_collectd_init_latency(conf, next, conf, "radius_pkt_ex", &stats.exchange[rs_useful_codes[i]], rs_useful_codes[i]); if (!tmpl) { goto tmpl_error; } next = &(tmpl->next); tmpl = rs_stats_collectd_init_counter(conf, next, conf, "radius_pkt", &stats.gauge.type[rs_useful_codes[i]], rs_useful_codes[i]); if (!tmpl) { tmpl_error: ERROR("Error allocating memory for stats template"); goto finish; } next = &(tmpl->next); } } #endif /* * This actually opens the capture interfaces/files (we just allocated the memory earlier) */ { fr_pcap_t *prev = NULL; for (in_p = in; in_p; in_p = in_p->next) { if (fr_pcap_open(in_p) < 0) { if (!conf->from_auto) { ERROR("Failed opening pcap handle for %s", in_p->name); goto finish; } DEBUG("Failed opening pcap handle: %s", fr_strerror()); /* Unlink it from the list */ if (prev) { prev->next = in_p->next; talloc_free(in_p); in_p = prev; } else { in = in_p->next; talloc_free(in_p); in_p = in; } goto next; } if (conf->pcap_filter) { if (fr_pcap_apply_filter(in_p, conf->pcap_filter) < 0) { ERROR("Failed applying filter"); goto finish; } } next: prev = in_p; } } /* * Open our output interface (if we have one); */ if (out) { if (fr_pcap_open(out) < 0) { ERROR("Failed opening pcap output"); goto finish; } } /* * Setup and enter the main event loop. Who needs libev when you can roll your own... */ { struct timeval now; fr_event_list_t *events; rs_update_t update; char *buff; memset(&stats, 0, sizeof(stats)); memset(&update, 0, sizeof(update)); events = fr_event_list_create(conf, _rs_event_status); if (!events) { ERROR(); goto finish; } for (in_p = in; in_p; in_p = in_p->next) { rs_event_t *event; event = talloc_zero(events, rs_event_t); event->conf = conf; event->in = in_p; event->out = out; event->stats = &stats; if (!fr_event_fd_insert(events, 0, in_p->fd, rs_got_packet, event)) { ERROR("Failed inserting file descriptor"); goto finish; } } buff = fr_pcap_device_names(conf, in, ' '); INFO("Sniffing on (%s)", buff); talloc_free(buff); gettimeofday(&now, NULL); start_pcap = now; /* * Insert our stats processor */ if (conf->stats.interval) { update.list = events; update.conf = conf; update.stats = &stats; update.in = in; now.tv_sec += conf->stats.interval; now.tv_usec = 0; fr_event_insert(events, rs_stats_process, (void *) &update, &now, NULL); } ret = fr_event_loop(events); /* Enter the main event loop */ } INFO("Done sniffing"); finish: if (filter_tree) { rbtree_free(filter_tree); } INFO("Exiting..."); /* * Free all the things! This also closes all the sockets and file descriptors */ talloc_free(conf); return ret; }
int main(int argc, char **argv) { char *p; int c; char const *radius_dir = RADDBDIR; char const *filename = NULL; fr_debug_flag = 0; while ((c = getopt(argc, argv, "d:f:hr:t:vx")) != EOF) switch(c) { case 'd': radius_dir = optarg; break; case 'f': filename = optarg; break; case 'r': if (!isdigit((int) *optarg)) usage(); retries = atoi(optarg); if ((retries == 0) || (retries > 1000)) usage(); break; case 't': if (!isdigit((int) *optarg)) usage(); timeout = atof(optarg); break; case 'v': printf("%s\n", dhcpclient_version); exit(0); break; case 'x': fr_debug_flag++; fr_log_fp = stdout; break; case 'h': default: usage(); break; } argc -= (optind - 1); argv += (optind - 1); if (argc < 2) usage(); if (dict_init(radius_dir, RADIUS_DICTIONARY) < 0) { fr_perror("dhcpclient"); return 1; } /* * Resolve hostname. */ server_ipaddr.af = AF_INET; if (strcmp(argv[1], "-") != 0) { char const *hostname = argv[1]; char const *portname = argv[1]; char buffer[256]; if (*argv[1] == '[') { /* IPv6 URL encoded */ p = strchr(argv[1], ']'); if ((size_t) (p - argv[1]) >= sizeof(buffer)) { usage(); } memcpy(buffer, argv[1] + 1, p - argv[1] - 1); buffer[p - argv[1] - 1] = '\0'; hostname = buffer; portname = p + 1; } p = strchr(portname, ':'); if (p && (strchr(p + 1, ':') == NULL)) { *p = '\0'; portname = p + 1; } else { portname = NULL; } if (ip_hton(hostname, AF_INET, &server_ipaddr) < 0) { fprintf(stderr, "dhcpclient: Failed to find IP address for host %s: %s\n", hostname, fr_syserror(errno)); exit(1); } /* * Strip port from hostname if needed. */ if (portname) server_port = atoi(portname); } /* * See what kind of request we want to send. */ if (strcmp(argv[2], "discover") == 0) { if (server_port == 0) server_port = 67; packet_code = PW_DHCP_DISCOVER; } else if (strcmp(argv[2], "request") == 0) { if (server_port == 0) server_port = 67; packet_code = PW_DHCP_REQUEST; } else if (strcmp(argv[2], "offer") == 0) { if (server_port == 0) server_port = 67; packet_code = PW_DHCP_OFFER; } else if (isdigit((int) argv[2][0])) { if (server_port == 0) server_port = 67; packet_code = atoi(argv[2]); } else { fprintf(stderr, "Unknown packet type %s\n", argv[2]); usage(); } request_init(filename); /* * No data read. Die. */ if (!request || !request->vps) { fprintf(stderr, "dhcpclient: Nothing to send.\n"); exit(1); } request->code = packet_code; /* * Bind to the first specified IP address and port. * This means we ignore later ones. */ if (request->src_ipaddr.af == AF_UNSPEC) { memset(&client_ipaddr, 0, sizeof(client_ipaddr)); client_ipaddr.af = server_ipaddr.af; client_port = 0; } else { client_ipaddr = request->src_ipaddr; client_port = request->src_port; } sockfd = fr_socket(&client_ipaddr, client_port); if (sockfd < 0) { fprintf(stderr, "dhcpclient: socket: %s\n", fr_strerror()); exit(1); } request->sockfd = sockfd; if (request->src_ipaddr.af == AF_UNSPEC) { request->src_ipaddr = client_ipaddr; request->src_port = client_port; } if (request->dst_ipaddr.af == AF_UNSPEC) { request->dst_ipaddr = server_ipaddr; request->dst_port = server_port; } /* * Encode the packet */ if (fr_dhcp_encode(request) < 0) { fprintf(stderr, "dhcpclient: failed encoding: %s\n", fr_strerror()); exit(1); } if (fr_debug_flag) print_hex(request); if (fr_dhcp_send(request) < 0) { fprintf(stderr, "dhcpclient: failed sending: %s\n", fr_syserror(errno)); exit(1); } reply = fr_dhcp_recv(sockfd); if (!reply) { fprintf(stderr, "dhcpclient: no reply\n"); exit(1); } if (fr_debug_flag) print_hex(reply); if (fr_dhcp_decode(reply) < 0) { fprintf(stderr, "dhcpclient: failed decoding\n"); return 1; } dict_free(); if (success) return 0; return 1; }
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; }