struct chunk *chunk_manager_get_av_chunk_from_pool (struct chunk_manager *cm){ LOG(INFO, "chunk_manager_get_av_chunk_from_pool called\n"); assert(cm); unsigned end_index = (cm -> cur_chunk_index - 1) & (POOL_SIZE - 1); LOG(INFO, "end is %d, cur is %d\n", end_index, cm -> cur_chunk_index); //FIFO algorithm for (; cm -> cur_chunk_index != end_index; cm -> cur_chunk_index++){ struct chunk *cur_ch = cm -> chunk_pool + cm -> cur_chunk_index; //By default ref_cnt == -1 is unused chunk LOG(DEBUG, "Trying %d chunk\n", cm -> cur_chunk_index); if (cur_ch -> ref_cnt == -1){ LOG(DEBUG, "Unused chunk %d returned\n", cm -> cur_chunk_index); cm -> cur_chunk_index++; return cur_ch; }else if (cur_ch -> ref_cnt == 0){ LOG(DEBUG, "Refirbished chunk %d returned, cleaning\n", cm -> cur_chunk_index); if (cur_ch -> rbnode){ LOG(DEBUG, "Removing from rbtree\n"); rbtree_delete(cm -> rbtree, cur_ch -> rbnode); } LOG(DEBUG, "Current size of rbtree is %d\n", rbtree_num_elements(cm -> rbtree)); chunk_finalize(cur_ch); cm -> cur_chunk_index++; return cur_ch; }//else we can't use this chunk: ref_cnt != 0 } return NULL; }
/* * Reset the cached entries. */ static int cache_reset(rlm_radutmp_t *inst, radutmp_cache_t *cache) { NAS_PORT *this, *next; /* * Cache is already reset, do nothing. */ if ((rbtree_num_elements(cache->nas_ports) == 0) && (cache->free_offsets == NULL)) { DEBUG2(" rlm_radutmp: Not resetting the cache"); return 1; } DEBUG2(" rlm_radutmp: Resetting the cache"); pthread_mutex_lock(&cache->mutex); rbtree_free(inst->user_tree); rbtree_free(cache->nas_ports); for (this = cache->free_offsets; this != NULL; this = next) { next = this->next; free(this); } cache->free_offsets = NULL; /* * Re-create the caches. */ cache->nas_ports = rbtree_create(nas_port_cmp, free, 0); if (!cache->nas_ports) { pthread_mutex_unlock(&cache->mutex); radlog(L_ERR, "rlm_radutmp: No memory"); return 0; } cache->max_offset = 0; cache->cached_file = 1; if (inst->case_sensitive) { inst->user_tree = rbtree_create(user_cmp, free, 0); } else { inst->user_tree = rbtree_create(user_case_cmp, free, 0); } if (!inst->user_tree) { pthread_mutex_unlock(&cache->mutex); radlog(L_ERR, "rlm_radutmp: No memory"); return 0; } pthread_mutex_unlock(&cache->mutex); return 1; }
int fr_packet_list_num_incoming(fr_packet_list_t *pl) { int num_elements; if (!pl) return 0; num_elements = rbtree_num_elements(pl->tree); if (num_elements < pl->num_outgoing) return 0; /* panic! */ return num_elements - pl->num_outgoing; }
static int cmd_stats_self(FILE *fp, UNUSED FILE *fp_err, void *ctx, UNUSED fr_cmd_info_t const *info) { fr_network_t const *nr = ctx; fprintf(fp, "count.in\t%" PRIu64 "\n", nr->stats.in); fprintf(fp, "count.out\t%" PRIu64 "\n", nr->stats.out); fprintf(fp, "count.dup\t%" PRIu64 "\n", nr->stats.dup); fprintf(fp, "count.dropped\t%" PRIu64 "\n", nr->stats.dropped); fprintf(fp, "count.sockets\t%d\n", rbtree_num_elements(nr->sockets)); return 0; }
/* * Find a cached entry. */ static rlm_cache_entry_t *cache_find(rlm_cache_t *inst, REQUEST *request, char const *key) { int ttl; rlm_cache_entry_t *c, my_c; VALUE_PAIR *vp; /* * Look at the expiry heap. */ c = fr_heap_peek(inst->heap); if (!c) { rad_assert(rbtree_num_elements(inst->cache) == 0); return NULL; } /* * If it's time to expire an old entry, do so now. */ if (c->expires < request->timestamp) { fr_heap_extract(inst->heap, c); rbtree_deletebydata(inst->cache, c); } /* * Is there an entry for this key? */ my_c.key = key; c = rbtree_finddata(inst->cache, &my_c); if (!c) return NULL; /* * Yes, but it expired, OR the "forget all" epoch has * passed. Delete it, and pretend it doesn't exist. */ if ((c->expires < request->timestamp) || (c->created < inst->epoch)) { delete: RDEBUG("Entry has expired, removing"); fr_heap_extract(inst->heap, c); rbtree_deletebydata(inst->cache, c); return NULL; }
static void securid_sessionlist_clean_expired(rlm_securid_t *inst, REQUEST *request, time_t timestamp) { int num_sessions; SECURID_SESSION *session; num_sessions = rbtree_num_elements(inst->session_tree); RDEBUG2("There are %d sessions in the tree\n",num_sessions); /* * Delete old sessions from the list * */ while((session = inst->session_head)) { if ((timestamp - session->timestamp) > inst->timer_limit) { rbnode_t *node; node = rbtree_find(inst->session_tree, session); rad_assert(node != NULL); rbtree_delete(inst->session_tree, node); /* * session == inst->session_head */ inst->session_head = session->next; if (session->next) { session->next->prev = NULL; } else { inst->session_head = NULL; inst->session_tail = NULL; } RDEBUG2("Cleaning expired session: identity='%s' state='%s'\n", SAFE_STR(session->identity),session->state); securid_session_free(inst,request,session); } else { /* no need to check all sessions since they are sorted by age */ break; } } }
/* * Add a session to the set of active sessions. * * Since we're adding it to the list, we guess that this means * the packet needs a State attribute. So add one. */ int securid_sessionlist_add(rlm_securid_t *inst,REQUEST *request, SECURID_SESSION *session) { int status = 0; VALUE_PAIR *state; rad_assert(session != NULL); rad_assert(request != NULL); /* * The time at which this request was made was the time * at which it was received by the RADIUS server. */ session->timestamp = request->timestamp; session->src_ipaddr = request->packet->src_ipaddr; /* * Playing with a data structure shared among threads * means that we need a lock, to avoid conflict. */ pthread_mutex_lock(&(inst->session_mutex)); /* * If we have a DoS attack, discard new sessions. */ if (rbtree_num_elements(inst->session_tree) >= inst->max_sessions) { securid_sessionlist_clean_expired(inst, request, session->timestamp); goto done; } if (session->session_id == 0) { /* this is a NEW session (we are not inserting an updated session) */ inst->last_session_id++; session->session_id = inst->last_session_id; RDEBUG2("Creating a new session with id=%d\n",session->session_id); } snprintf(session->state,sizeof(session->state)-1,"FRR-CH %d|%d",session->session_id,session->trips+1); RDEBUG2("Inserting session id=%d identity='%s' state='%s' to the session list", session->session_id,SAFE_STR(session->identity),session->state); /* * Generate State, since we've been asked to add it to * the list. */ state = pairmake("State", session->state, T_OP_EQ); if (!state) return -1; state->length = SECURID_STATE_LEN; status = rbtree_insert(inst->session_tree, session); if (status) { /* tree insert SUCCESS */ /* insert the session to the linked list of sessions */ SECURID_SESSION *prev; prev = inst->session_tail; if (prev) { /* insert to the tail of the list */ prev->next = session; session->prev = prev; session->next = NULL; inst->session_tail = session; } else { /* 1st time */ inst->session_head = inst->session_tail = session; session->next = session->prev = NULL; } } /* * Now that we've finished mucking with the list, * unlock it. */ done: pthread_mutex_unlock(&(inst->session_mutex)); if (!status) { pairfree(&state); radlog(L_ERR, "rlm_securid: Failed to store session"); return -1; } pairadd(&(request->reply->vps), state); 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); }
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; }
/* * Add a handler to the set of active sessions. * * Since we're adding it to the list, we guess that this means * the packet needs a State attribute. So add one. */ int eaplist_add(rlm_eap_t *inst, eap_handler_t *handler) { int status = 0; VALUE_PAIR *state; REQUEST *request = handler->request; rad_assert(handler != NULL); rad_assert(request != NULL); /* * Generate State, since we've been asked to add it to * the list. */ state = pairmake_reply("State", "0x00", T_OP_EQ); if (!state) return 0; /* * The time at which this request was made was the time * at which it was received by the RADIUS server. */ handler->timestamp = request->timestamp; handler->status = 1; handler->src_ipaddr = request->packet->src_ipaddr; handler->eap_id = handler->eap_ds->request->id; /* * Playing with a data structure shared among threads * means that we need a lock, to avoid conflict. */ PTHREAD_MUTEX_LOCK(&(inst->session_mutex)); /* * If we have a DoS attack, discard new sessions. */ if (rbtree_num_elements(inst->session_tree) >= inst->max_sessions) { status = -1; eaplist_expire(inst, request, handler->timestamp); goto done; } /* * Create a unique content for the State variable. * It will be modified slightly per round trip, but less so * than in 1.x. */ if (handler->trips == 0) { int i; for (i = 0; i < 4; i++) { uint32_t lvalue; lvalue = eap_rand(&inst->rand_pool); memcpy(handler->state + i * 4, &lvalue, sizeof(lvalue)); } } memcpy(state->vp_octets, handler->state, sizeof(handler->state)); state->length = EAP_STATE_LEN; /* * Add some more data to distinguish the sessions. */ state->vp_octets[4] = handler->trips ^ handler->state[0]; state->vp_octets[5] = handler->eap_id ^ handler->state[1]; state->vp_octets[6] = handler->type ^ handler->state[2]; /* * and copy the state back again. */ memcpy(handler->state, state->vp_octets, sizeof(handler->state)); /* * Big-time failure. */ status = rbtree_insert(inst->session_tree, handler); /* * Catch Access-Challenge without response. */ if (inst->handler_tree) { check_handler_t *check = rad_malloc(sizeof(*check)); check->inst = inst; check->handler = handler; check->trips = handler->trips; request_data_add(request, inst, 0, check, check_handler); } if (status) { eap_handler_t *prev; prev = inst->session_tail; if (prev) { prev->next = handler; handler->prev = prev; handler->next = NULL; inst->session_tail = handler; } else { inst->session_head = inst->session_tail = handler; handler->next = handler->prev = NULL; } } /* * Now that we've finished mucking with the list, * unlock it. */ done: /* * We don't need this any more. */ if (status > 0) handler->request = NULL; PTHREAD_MUTEX_UNLOCK(&(inst->session_mutex)); if (status <= 0) { pairfree(&state); if (status < 0) { static time_t last_logged = 0; if (last_logged < handler->timestamp) { last_logged = handler->timestamp; radlog(L_ERR, "rlm_eap (%s): Too many open " "sessions. Try increasing " "\"max_sessions\" in the EAP module " "configuration", inst->xlat_name); } } else { radlog(L_ERR, "rlm_eap (%s): Internal error: " "failed to store handler", inst->xlat_name); } return 0; } RDEBUG("New EAP session, adding 'State' attribute to reply " "0x%02x%02x%02x%02x%02x%02x%02x%02x", state->vp_octets[0], state->vp_octets[1], state->vp_octets[2], state->vp_octets[3], state->vp_octets[4], state->vp_octets[5], state->vp_octets[6], state->vp_octets[7]); return 1; }
int radius_auth(char *username, char *password, char *radius_server_ip_address, unsigned short int radius_server_port, char * radius_server_secret) { /* printf("radius server = %s, port = %d\n", radius_server_ip_address, radius_server_port); printf("radius secret = %s\n", radius_server_secret); */ const char *radius_dir = RADDBDIR; int persec = 0; int parallel = 1; radclient_t *this; librad_debug = 0; if (dict_init(radius_dir, RADIUS_DICTIONARY) < 0) { librad_perror("radclient"); return 1; } /* * Strip port from hostname if needed. */ server_port = radius_server_port; packet_code = PW_AUTHENTICATION_REQUEST; /* * Grab the socket. */ if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { perror("radclient: socket: "); exit(1); } memset(radius_id, 0, sizeof(radius_id)); /* * Resolve hostname. */ server_ipaddr = ip_getaddr(radius_server_ip_address); /* * Add the secret. */ secret = radius_server_secret; /* * If no '-f' is specified, we're reading from stdin. */ if (last_used_id < 0) last_used_id = getpid() & 0xff; /* * 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. */ int n = parallel; const char *filename = NULL; done = 1; sleep_time = -1; /* * Walk over the packets, sending them. */ /* Send username and password to radius server */ char auth_context[128]; memset( auth_context, 0x00, sizeof(auth_context) ); sprintf(auth_context,"User-Name = %s, User-Password = %s", username, password); /* Send username and password to radius server */ this = radclient_init(auth_context); if (radclient_sane(this) != 0) { exit(1); } /* * 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. */ /* * 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 (rbtree_num_elements(request_tree) > 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. */ int ret = recv_one_packet(3); rbtree_free(filename_tree); rbtree_free(request_tree); return ret; }
int fr_packet_list_num_elements(fr_packet_list_t *pl) { if (!pl) return 0; return rbtree_num_elements(pl->tree); }
/* * Zap all users on a NAS from the radutmp file. */ static int radutmp_zap(rlm_radutmp_t *inst, radutmp_cache_t *cache, uint32_t nas_address, time_t now) { int rcode; rbtree_t *offset_tree; offset_walk_t walk; rad_assert(now != 0); /* * If there's nothing in the file, do nothing, * but truncate the file, just to be safe. */ if (rbtree_num_elements(cache->nas_ports) == 0) { truncate(cache->filename, (off_t) 0); DEBUG2(" rlm_radutmp: No entries in file. Quenching zap."); return 1; } /* * Create the offset tree, as we want to delete utmp * entries starting from the start of the file, and we * can't delete nodes from an rbtree while we're walking * it. */ offset_tree = rbtree_create(offset_cmp, NULL, 0); if (!offset_tree) { radlog(L_ERR, "rlm_radutmp: Out of memory"); return 0; } pthread_mutex_lock(&cache->mutex); /* * Walk through the cache, finding entries for this NAS, * and add those entries to the offset tree. */ memset(&walk, 0, sizeof(walk)); walk.inst = inst; walk.offset_tree = offset_tree; walk.nas_address = nas_address; rcode = rbtree_walk(cache->nas_ports, PreOrder, nas_port_walk, &walk); if (rcode != 0) { pthread_mutex_unlock(&cache->mutex); rbtree_free(offset_tree); radlog(L_ERR, "rlm_radutmp: Failed walking the cache."); return 0; } /* * If both trees have the same number of elements, then * don't do anything special, as UDP packets may be * received out of order, by several seconds. The * "offset_walk" routine MAY NOT delete the entries, if * it sees that the entries in the file are newer than * the reboot packet. */ /* * If there's nothing to do, don't do anything. */ if (rbtree_num_elements(offset_tree) == 0) { DEBUG2(" rlm_radutmp: NAS IP %08x has no users recorded in file %s.", htonl(nas_address), cache->filename); pthread_mutex_unlock(&cache->mutex); rbtree_free(offset_tree); return 1; } /* * Open the file, to re-write only a few of the entries. */ walk.fd = open(cache->filename, O_RDWR); if (walk.fd < 0) { pthread_mutex_unlock(&cache->mutex); rbtree_free(offset_tree); radlog(L_ERR, "rlm_radutmp: Error accessing file %s: %s", cache->filename, strerror(errno)); return 0; } /* * Lock the utmp file, prefer lockf() over flock(). * * FIXME: maybe we want to lock per-record? */ rad_lockfd(walk.fd, LOCK_LEN); /* * Walk through the offset tree, from start to finish, * deleting entries from the NAS tree, adding them to * the "free offset" cache, and lseek'ing to that offset * in the file, and clearing out the data. */ walk.cache = cache; walk.now = now; rcode = rbtree_walk(offset_tree, InOrder, offset_walk, &walk); rbtree_free(offset_tree); if (rcode != 0) { radlog(L_ERR, "rlm_radutmp: Failed walking the offsets."); return 0; } close(walk.fd); /* and implicitly release the locks */ /* * Just to clean up the file. If it's empty, * nuke everything. */ if (rbtree_num_elements(cache->nas_ports) == 0) { NAS_PORT *this, *next; /* too many copies of code */ for (this = inst->cache.free_offsets; this != NULL; this = next) { next = this->next; free(this); } truncate(cache->filename, 0); rad_assert(rbtree_num_elements(inst->user_tree) == 0); } pthread_mutex_unlock(&cache->mutex); return 1; }