コード例 #1
0
ファイル: packet.c プロジェクト: RoJackal/freeradius-server
/*
 *	Should be called AFTER yanking it from the list, so that
 *	any newly inserted entries don't collide with this one.
 */
bool fr_packet_list_id_free(fr_packet_list_t *pl,
			    RADIUS_PACKET *request, bool yank)
{
	fr_packet_socket_t *ps;

	if (!pl || !request) return false;

	if (yank && !fr_packet_list_yank(pl, request)) return false;

	ps = fr_socket_find(pl, request->sockfd);
	if (!ps) return false;

	/*
	 *	Don't mark the ID as free.  We just won't use it until
	 *	we've cycled through all 256 IDs.
	 */
	ps->num_outgoing--;
	pl->num_outgoing--;

	request->id = -1;

	return true;
}
コード例 #2
0
ファイル: radclient.c プロジェクト: peruchi/freeradius-server
/*
 *	Send one packet.
 */
static int send_one_packet(rc_request_t *request)
{
	assert(request->done == false);

	/*
	 *	Remember when we have to wake up, to re-send the
	 *	request, of we didn't receive a reply.
	 */
	if ((sleep_time == -1) || (sleep_time > (int) timeout)) sleep_time = (int) timeout;

	/*
	 *	Haven't sent the packet yet.  Initialize it.
	 */
	if (request->packet->id == -1) {
		int i;
		bool rcode;

		assert(request->reply == NULL);

		/*
		 *	Didn't find a free packet ID, we're not done,
		 *	we don't sleep, and we stop trying to process
		 *	this packet.
		 */
	retry:
		request->packet->src_ipaddr.af = server_ipaddr.af;
		rcode = fr_packet_list_id_alloc(pl, ipproto, &request->packet, NULL);
		if (!rcode) {
			int mysockfd;

#ifdef WITH_TCP
			if (proto) {
				mysockfd = fr_socket_client_tcp(NULL,
								&request->packet->dst_ipaddr,
								request->packet->dst_port, false);
			} else
#endif
			mysockfd = fr_socket(&client_ipaddr, 0);
			if (mysockfd < 0) {
				ERROR("Failed opening socket");
				exit(1);
			}
			if (!fr_packet_list_socket_add(pl, mysockfd, ipproto,
						       &request->packet->dst_ipaddr,
						       request->packet->dst_port, NULL)) {
				ERROR("Can't add new socket");
				exit(1);
			}
			goto retry;
		}

		assert(request->packet->id != -1);
		assert(request->packet->data == NULL);

		for (i = 0; i < 4; i++) {
			((uint32_t *) request->packet->vector)[i] = fr_rand();
		}

		/*
		 *	Update the password, so it can be encrypted with the
		 *	new authentication vector.
		 */
		if (request->password) {
			VALUE_PAIR *vp;

			if ((vp = fr_pair_find_by_num(request->packet->vps, PW_USER_PASSWORD, 0, TAG_ANY)) != NULL) {
				fr_pair_value_strcpy(vp, request->password->vp_strvalue);

			} else if ((vp = fr_pair_find_by_num(request->packet->vps, PW_CHAP_PASSWORD, 0, TAG_ANY)) != NULL) {
				uint8_t buffer[17];

				rad_chap_encode(request->packet, buffer, fr_rand() & 0xff, request->password);
				fr_pair_value_memcpy(vp, buffer, 17);

			} else if (fr_pair_find_by_num(request->packet->vps, PW_MS_CHAP_PASSWORD, 0, TAG_ANY) != NULL) {
				mschapv1_encode(request->packet, &request->packet->vps, request->password->vp_strvalue);

			} else {
				DEBUG("WARNING: No password in the request");
			}
		}

		request->timestamp = time(NULL);
		request->tries = 1;
		request->resend++;

	} else {		/* request->packet->id >= 0 */
		time_t now = time(NULL);

		/*
		 *	FIXME: Accounting packets are never retried!
		 *	The Acct-Delay-Time attribute is updated to
		 *	reflect the delay, and the packet is re-sent
		 *	from scratch!
		 */

		/*
		 *	Not time for a retry, do so.
		 */
		if ((now - request->timestamp) < timeout) {
			/*
			 *	When we walk over the tree sending
			 *	packets, we update the minimum time
			 *	required to sleep.
			 */
			if ((sleep_time == -1) ||
			    (sleep_time > (now - request->timestamp))) {
				sleep_time = now - request->timestamp;
			}
			return 0;
		}

		/*
		 *	We're not trying later, maybe the packet is done.
		 */
		if (request->tries == retries) {
			assert(request->packet->id >= 0);

			/*
			 *	Delete the request from the tree of
			 *	outstanding requests.
			 */
			fr_packet_list_yank(pl, request->packet);

			REDEBUG("No reply from server for ID %d socket %d",
				request->packet->id, request->packet->sockfd);
			deallocate_id(request);

			/*
			 *	Normally we mark it "done" when we've received
			 *	the reply, but this is a special case.
			 */
			if (request->resend == resend_count) {
				request->done = true;
			}
			stats.lost++;
			return -1;
		}

		/*
		 *	We are trying later.
		 */
		request->timestamp = now;
		request->tries++;
	}

	/*
	 *	Send the packet.
	 */
	if (rad_send(request->packet, NULL, secret) < 0) {
		REDEBUG("Failed to send packet for ID %d", request->packet->id);
		deallocate_id(request);
		request->done = true;
		return -1;
	}

	fr_packet_header_print(fr_log_fp, request->packet, false);
	if (fr_debug_lvl > 0) vp_printlist(fr_log_fp, request->packet->vps);

	return 0;
}
コード例 #3
0
ファイル: radclient.c プロジェクト: rssh/freeradius-server
/*
 *	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;
}
コード例 #4
0
ファイル: radclient.c プロジェクト: rssh/freeradius-server
/*
 *	Send one packet.
 */
static int send_one_packet(radclient_t *radclient)
{
	assert(radclient->done == 0);

	/*
	 *	Remember when we have to wake up, to re-send the
	 *	request, of we didn't receive a response.
	 */
	if ((sleep_time == -1) ||
	    (sleep_time > (int) timeout)) {
		sleep_time = (int) timeout;
	}

	/*
	 *	Haven't sent the packet yet.  Initialize it.
	 */
	if (radclient->request->id == -1) {
		int i, rcode;

		assert(radclient->reply == NULL);

		/*
		 *	Didn't find a free packet ID, we're not done,
		 *	we don't sleep, and we stop trying to process
		 *	this packet.
		 */
	retry:
		radclient->request->src_ipaddr.af = server_ipaddr.af;
		rcode = fr_packet_list_id_alloc(pl, ipproto,
						radclient->request, NULL);
		if (rcode < 0) {
			int mysockfd;

#ifdef WITH_TCP
			if (proto) {
				mysockfd = fr_tcp_client_socket(NULL,
								&server_ipaddr,
								server_port);
			} else
#endif
			mysockfd = fr_socket(&client_ipaddr, 0);
			if (!mysockfd) {
				fprintf(stderr, "radclient: Can't open new socket\n");
				exit(1);
			}
			if (!fr_packet_list_socket_add(pl, mysockfd, ipproto,
						       &server_ipaddr,
						       server_port, NULL)) {
				fprintf(stderr, "radclient: Can't add new socket\n");
				exit(1);
			}
			goto retry;
		}

		if (rcode == 0) {
			done = 0;
			sleep_time = 0;
			return 0;
		}

		assert(radclient->request->id != -1);
		assert(radclient->request->data == NULL);

		for (i = 0; i < 4; i++) {
			((uint32_t *) radclient->request->vector)[i] = fr_rand();
		}

		/*
		 *	Update the password, so it can be encrypted with the
		 *	new authentication vector.
		 */
		if (radclient->password[0] != '\0') {
			VALUE_PAIR *vp;

			if ((vp = pairfind(radclient->request->vps, PW_USER_PASSWORD, 0)) != NULL) {
				strlcpy(vp->vp_strvalue, radclient->password,
					sizeof(vp->vp_strvalue));
				vp->length = strlen(vp->vp_strvalue);

			} else if ((vp = pairfind(radclient->request->vps, PW_CHAP_PASSWORD, 0)) != NULL) {
				int 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) {
					strlcpy(vp->vp_strvalue, radclient->password,
						sizeof(vp->vp_strvalue));
					vp->length = strlen(vp->vp_strvalue);
					
					rad_chap_encode(radclient->request,
							vp->vp_octets,
							fr_rand() & 0xff, vp);
					vp->length = 17;
				}
			} else if (pairfind(radclient->request->vps, PW_MSCHAP_PASSWORD, 0) != NULL) {
				mschapv1_encode(&radclient->request->vps,
						radclient->password);
			} else if (fr_debug_flag) {
				printf("WARNING: No password in the request\n");
			}
		}

		radclient->timestamp = time(NULL);
		radclient->tries = 1;
		radclient->resend++;

		/*
		 *	Duplicate found.  Serious error!
		 */
		if (!fr_packet_list_insert(pl, &radclient->request)) {
			assert(0 == 1);
		}

#ifdef WITH_TCP
		/*
		 *	WTF?
		 */
		if (client_port == 0) {
			client_ipaddr = radclient->request->src_ipaddr;
			client_port = radclient->request->src_port;
		}
#endif

	} else {		/* radclient->request->id >= 0 */
		time_t now = time(NULL);

		/*
		 *	FIXME: Accounting packets are never retried!
		 *	The Acct-Delay-Time attribute is updated to
		 *	reflect the delay, and the packet is re-sent
		 *	from scratch!
		 */

		/*
		 *	Not time for a retry, do so.
		 */
		if ((now - radclient->timestamp) < timeout) {
			/*
			 *	When we walk over the tree sending
			 *	packets, we update the minimum time
			 *	required to sleep.
			 */
			if ((sleep_time == -1) ||
			    (sleep_time > (now - radclient->timestamp))) {
				sleep_time = now - radclient->timestamp;
			}
			return 0;
		}

		/*
		 *	We're not trying later, maybe the packet is done.
		 */
		if (radclient->tries == retries) {
			assert(radclient->request->id >= 0);

			/*
			 *	Delete the request from the tree of
			 *	outstanding requests.
			 */
			fr_packet_list_yank(pl, radclient->request);

			fprintf(stderr, "radclient: no response from server for ID %d socket %d\n", radclient->request->id, radclient->request->sockfd);
			deallocate_id(radclient);

			/*
			 *	Normally we mark it "done" when we've received
			 *	the response, but this is a special case.
			 */
			if (radclient->resend == resend_count) {
				radclient->done = 1;
			}
			totallost++;
			return -1;
		}

		/*
		 *	We are trying later.
		 */
		radclient->timestamp = now;
		radclient->tries++;
	}


	/*
	 *	Send the packet.
	 */
	if (rad_send(radclient->request, NULL, secret) < 0) {
		fprintf(stderr, "radclient: Failed to send packet for ID %d: %s\n",
			radclient->request->id, fr_strerror());
	}

	if (fr_debug_flag > 2) print_hex(radclient->request);

	return 0;
}
コード例 #5
0
/*
 *	Send one packet.
 */
static int send_one_packet(rc_request_t *request)
{
	assert(request->done == false);

	/*
	 *	Remember when we have to wake up, to re-send the
	 *	request, of we didn't receive a reply.
	 */
	if ((sleep_time == -1) || (sleep_time > (int) timeout)) {
		sleep_time = (int) timeout;
	}

	/*
	 *	Haven't sent the packet yet.  Initialize it.
	 */
	if (request->packet->id == -1) {
		int i;
		bool rcode;

		assert(request->reply == NULL);

		/*
		 *	Didn't find a free packet ID, we're not done,
		 *	we don't sleep, and we stop trying to process
		 *	this packet.
		 */
	retry:
		request->packet->src_ipaddr.af = server_ipaddr.af;
		rcode = fr_packet_list_id_alloc(pl, ipproto,
						&request->packet, NULL);
		if (!rcode) {
			int mysockfd;

#ifdef WITH_TCP
			if (proto) {
				mysockfd = fr_tcp_client_socket(NULL,
								&server_ipaddr,
								server_port);
			} else
#endif
			mysockfd = fr_socket(&client_ipaddr, 0);
			if (mysockfd < 0) {
				ERROR("Can't open new socket: %s", strerror(errno));
				exit(1);
			}
			if (!fr_packet_list_socket_add(pl, mysockfd, ipproto,
						       &server_ipaddr,
						       server_port, NULL)) {
				ERROR("Can't add new socket");
				exit(1);
			}
			goto retry;
		}

		assert(request->packet->id != -1);
		assert(request->packet->data == NULL);

		for (i = 0; i < 4; i++) {
			((uint32_t *) request->packet->vector)[i] = fr_rand();
		}

		/*
		 *	Update the password, so it can be encrypted with the
		 *	new authentication vector.
		 */
		if (request->password[0] != '\0') {
			VALUE_PAIR *vp;

			if ((vp = pairfind(request->packet->vps, PW_USER_PASSWORD, 0, TAG_ANY)) != NULL) {
				pairstrcpy(vp, request->password);

			} else if ((vp = pairfind(request->packet->vps, PW_CHAP_PASSWORD, 0, TAG_ANY)) != NULL) {
				bool already_hex = false;

				/*
				 *	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 = true;
							break;
						}
					}
				}

				/*
				 *	Allow the user to specify ASCII or hex CHAP-Password
				 */
				if (!already_hex) {
					uint8_t *p;
					size_t len, len2;

					len = len2 = strlen(request->password);
					if (len2 < 17) len2 = 17;

					p = talloc_zero_array(vp, uint8_t, len2);

					memcpy(p, request->password, len);

					rad_chap_encode(request->packet,
							p,
							fr_rand() & 0xff, vp);
					vp->vp_octets = p;
					vp->length = 17;
				}
			} else if (pairfind(request->packet->vps, PW_MSCHAP_PASSWORD, 0, TAG_ANY) != NULL) {
				mschapv1_encode(request->packet,
						&request->packet->vps,
						request->password);
			} else {
				DEBUG("WARNING: No password in the request");
			}
		}

		request->timestamp = time(NULL);
		request->tries = 1;
		request->resend++;

#ifdef WITH_TCP
		/*
		 *	WTF?
		 */
		if (client_port == 0) {
			client_ipaddr = request->packet->src_ipaddr;
			client_port = request->packet->src_port;
		}
#endif

	} else {		/* request->packet->id >= 0 */
		time_t now = time(NULL);

		/*
		 *	FIXME: Accounting packets are never retried!
		 *	The Acct-Delay-Time attribute is updated to
		 *	reflect the delay, and the packet is re-sent
		 *	from scratch!
		 */

		/*
		 *	Not time for a retry, do so.
		 */
		if ((now - request->timestamp) < timeout) {
			/*
			 *	When we walk over the tree sending
			 *	packets, we update the minimum time
			 *	required to sleep.
			 */
			if ((sleep_time == -1) ||
			    (sleep_time > (now - request->timestamp))) {
				sleep_time = now - request->timestamp;
			}
			return 0;
		}

		/*
		 *	We're not trying later, maybe the packet is done.
		 */
		if (request->tries == retries) {
			assert(request->packet->id >= 0);

			/*
			 *	Delete the request from the tree of
			 *	outstanding requests.
			 */
			fr_packet_list_yank(pl, request->packet);

			REDEBUG("No reply from server for ID %d socket %d",
				request->packet->id, request->packet->sockfd);
			deallocate_id(request);

			/*
			 *	Normally we mark it "done" when we've received
			 *	the reply, but this is a special case.
			 */
			if (request->resend == resend_count) {
				request->done = true;
			}
			stats.lost++;
			return -1;
		}

		/*
		 *	We are trying later.
		 */
		request->timestamp = now;
		request->tries++;
	}

	/*
	 *	Send the packet.
	 */
	if (rad_send(request->packet, NULL, secret) < 0) {
		REDEBUG("Failed to send packet for ID %d", request->packet->id);
	}

	return 0;
}