Esempio n. 1
0
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;
}
Esempio n. 2
0
/*
 *	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;
}
Esempio n. 3
0
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;
}
Esempio n. 4
0
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;
}
Esempio n. 5
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;
	}
Esempio n. 6
0
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;
		}
	}
}
Esempio n. 7
0
/*
 *	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;
}
Esempio n. 8
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);
}
Esempio n. 9
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;
}
Esempio n. 10
0
/*
 *	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;
}
Esempio n. 11
0
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;
}
Esempio n. 12
0
int fr_packet_list_num_elements(fr_packet_list_t *pl)
{
	if (!pl) return 0;

	return rbtree_num_elements(pl->tree);
}
Esempio n. 13
0
/*
 *	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;
}