Пример #1
0
/*
 *	Initialize the request.
 */
static int request_init(char const *filename)
{
	FILE *fp;
	vp_cursor_t cursor;
	VALUE_PAIR *vp;
	bool filedone = false;

	/*
	 *	Determine where to read the VP's from.
	 */
	if (filename) {
		fp = fopen(filename, "r");
		if (!fp) {
			fprintf(stderr, "dhcpclient: Error opening %s: %s\n",
				filename, fr_syserror(errno));
			return 0;
		}
	} else {
		fp = stdin;
	}

	request = rad_alloc(NULL, false);

	/*
	 *	Read the VP's.
	 */
	if (fr_pair_list_afrom_file(NULL, &request->vps, fp, &filedone) < 0) {
		fr_perror("dhcpclient");
		rad_free(&request);
		if (fp != stdin) fclose(fp);
		return 1;
	}

	/*
	 *	Fix / set various options
	 */
	for (vp = fr_cursor_init(&cursor, &request->vps); vp; vp = fr_cursor_next(&cursor)) {

		if (vp->da->vendor == DHCP_MAGIC_VENDOR && vp->da->attr == PW_DHCP_MESSAGE_TYPE) {
			/*	Allow to set packet type using DHCP-Message-Type. */
			request->code = vp->vp_integer + PW_DHCP_OFFSET;

		} else if (!vp->da->vendor) switch (vp->da->attr) {

		default:
			break;

		/*
		 *	Allow it to set the packet type in
		 *	the attributes read from the file.
		 *	(this takes precedence over the command argument.)
		 */
		case PW_PACKET_TYPE:
			request->code = vp->vp_integer;
			break;

		case PW_PACKET_DST_PORT:
			request->dst_port = (vp->vp_integer & 0xffff);
			break;

		case PW_PACKET_DST_IP_ADDRESS:
			request->dst_ipaddr.af = AF_INET;
			request->dst_ipaddr.ipaddr.ip4addr.s_addr = vp->vp_ipaddr;
			request->dst_ipaddr.prefix = 32;
			break;

		case PW_PACKET_DST_IPV6_ADDRESS:
			request->dst_ipaddr.af = AF_INET6;
			request->dst_ipaddr.ipaddr.ip6addr = vp->vp_ipv6addr;
			request->dst_ipaddr.prefix = 128;
			break;

		case PW_PACKET_SRC_PORT:
			request->src_port = (vp->vp_integer & 0xffff);
			break;

		case PW_PACKET_SRC_IP_ADDRESS:
			request->src_ipaddr.af = AF_INET;
			request->src_ipaddr.ipaddr.ip4addr.s_addr = vp->vp_ipaddr;
			request->src_ipaddr.prefix = 32;
			break;

		case PW_PACKET_SRC_IPV6_ADDRESS:
			request->src_ipaddr.af = AF_INET6;
			request->src_ipaddr.ipaddr.ip6addr = vp->vp_ipv6addr;
			request->src_ipaddr.prefix = 128;
			break;
		} /* switch over the attribute */

	} /* loop over the VP's we read in */

	/*
	 *	Use the default set on the command line
	 */
	if (!request->code) request->code = packet_code;

	if (fp != stdin) fclose(fp);

	/*
	 *	And we're done.
	 */
	return 1;
}
Пример #2
0
/*
 *	Initialize a radclient data structure and add it to
 *	the global linked list.
 */
static int radclient_init(TALLOC_CTX *ctx, rc_file_pair_t *files)
{
	FILE *packets, *filters = NULL;

	vp_cursor_t cursor;
	VALUE_PAIR *vp;
	rc_request_t *request;
	bool packets_done = false;
	uint64_t num = 0;

	assert(files->packets != NULL);

	/*
	 *	Determine where to read the VP's from.
	 */
	if (strcmp(files->packets, "-") != 0) {
		packets = fopen(files->packets, "r");
		if (!packets) {
			ERROR("Error opening %s: %s", files->packets, strerror(errno));
			return 0;
		}

		/*
		 *	Read in the pairs representing the expected response.
		 */
		if (files->filters) {
			filters = fopen(files->filters, "r");
			if (!filters) {
				ERROR("Error opening %s: %s", files->filters, strerror(errno));
				fclose(packets);
				return 0;
			}
		}
	} else {
		packets = stdin;
	}


	/*
	 *	Loop until the file is done.
	 */
	do {
		/*
		 *	Allocate it.
		 */
		request = talloc_zero(ctx, rc_request_t);
		if (!request) {
			ERROR("Out of memory");
			goto error;
		}

		request->packet = rad_alloc(request, true);
		if (!request->packet) {
			ERROR("Out of memory");
			goto error;
		}

#ifdef WITH_TCP
		request->packet->src_ipaddr = client_ipaddr;
		request->packet->src_port = client_port;
		request->packet->dst_ipaddr = server_ipaddr;
		request->packet->dst_port = server_port;
		request->packet->proto = ipproto;
#endif

		request->files = files;
		request->packet->id = -1; /* allocate when sending */
		request->num = num++;

		/*
		 *	Read the request VP's.
		 */
		if (fr_pair_list_afrom_file(request->packet, &request->packet->vps, packets, &packets_done) < 0) {
			char const *input;

			if ((files->packets[0] == '-') && (files->packets[1] == '\0')) {
				input = "stdin";
			} else {
				input = files->packets;
			}

			REDEBUG("Error parsing \"%s\"", input);
			goto error;
		}

		/*
		 *	Skip empty entries
		 */
		if (!request->packet->vps) {
			talloc_free(request);
			continue;
		}

		/*
		 *	Read in filter VP's.
		 */
		if (filters) {
			bool filters_done;

			if (fr_pair_list_afrom_file(request, &request->filter, filters, &filters_done) < 0) {
				REDEBUG("Error parsing \"%s\"", files->filters);
				goto error;
			}

			if (filters_done && !packets_done) {
				REDEBUG("Differing number of packets/filters in %s:%s "
				        "(too many requests))", files->packets, files->filters);
				goto error;
			}

			if (!filters_done && packets_done) {
				REDEBUG("Differing number of packets/filters in %s:%s "
				        "(too many filters))", files->packets, files->filters);
				goto error;
			}

			/*
			 *	xlat expansions aren't supported here
			 */
			for (vp = fr_cursor_init(&cursor, &request->filter);
			     vp;
			     vp = fr_cursor_next(&cursor)) {
				if (vp->type == VT_XLAT) {
					vp->type = VT_DATA;
					vp->vp_strvalue = vp->xlat;
					vp->vp_length = talloc_array_length(vp->vp_strvalue) - 1;
				}

				if (vp->da->vendor == 0 ) switch (vp->da->attr) {
				case PW_RESPONSE_PACKET_TYPE:
				case PW_PACKET_TYPE:
					fr_cursor_remove(&cursor);	/* so we don't break the filter */
					request->filter_code = vp->vp_integer;
					talloc_free(vp);

				default:
					break;
				}
			}

			/*
			 *	This allows efficient list comparisons later
			 */
			fr_pair_list_sort(&request->filter, fr_pair_cmp_by_da_tag);
		}

		/*
		 *	Process special attributes
		 */
		for (vp = fr_cursor_init(&cursor, &request->packet->vps);
		     vp;
		     vp = fr_cursor_next(&cursor)) {
			/*
			 *	Double quoted strings get marked up as xlat expansions,
			 *	but we don't support that in request.
			 */
			if (vp->type == VT_XLAT) {
				vp->type = VT_DATA;
				vp->vp_strvalue = vp->xlat;
				vp->vp_length = talloc_array_length(vp->vp_strvalue) - 1;
			}

			if (!vp->da->vendor) switch (vp->da->attr) {
			default:
				break;

			/*
			 *	Allow it to set the packet type in
			 *	the attributes read from the file.
			 */
			case PW_PACKET_TYPE:
				request->packet->code = vp->vp_integer;
				break;

			case PW_RESPONSE_PACKET_TYPE:
				request->filter_code = vp->vp_integer;
				break;

			case PW_PACKET_DST_PORT:
				request->packet->dst_port = (vp->vp_integer & 0xffff);
				break;

			case PW_PACKET_DST_IP_ADDRESS:
				request->packet->dst_ipaddr.af = AF_INET;
				request->packet->dst_ipaddr.ipaddr.ip4addr.s_addr = vp->vp_ipaddr;
				request->packet->dst_ipaddr.prefix = 32;
				break;

			case PW_PACKET_DST_IPV6_ADDRESS:
				request->packet->dst_ipaddr.af = AF_INET6;
				request->packet->dst_ipaddr.ipaddr.ip6addr = vp->vp_ipv6addr;
				request->packet->dst_ipaddr.prefix = 128;
				break;

			case PW_PACKET_SRC_PORT:
				if ((vp->vp_integer < 1024) ||
				    (vp->vp_integer > 65535)) {
					ERROR("Invalid value '%u' for Packet-Src-Port", vp->vp_integer);
					goto error;
				}
				request->packet->src_port = (vp->vp_integer & 0xffff);
				break;

			case PW_PACKET_SRC_IP_ADDRESS:
				request->packet->src_ipaddr.af = AF_INET;
				request->packet->src_ipaddr.ipaddr.ip4addr.s_addr = vp->vp_ipaddr;
				request->packet->src_ipaddr.prefix = 32;
				break;

			case PW_PACKET_SRC_IPV6_ADDRESS:
				request->packet->src_ipaddr.af = AF_INET6;
				request->packet->src_ipaddr.ipaddr.ip6addr = vp->vp_ipv6addr;
				request->packet->src_ipaddr.prefix = 128;
				break;

			case PW_DIGEST_REALM:
			case PW_DIGEST_NONCE:
			case PW_DIGEST_METHOD:
			case PW_DIGEST_URI:
			case PW_DIGEST_QOP:
			case PW_DIGEST_ALGORITHM:
			case PW_DIGEST_BODY_DIGEST:
			case PW_DIGEST_CNONCE:
			case PW_DIGEST_NONCE_COUNT:
			case PW_DIGEST_USER_NAME:
			/* overlapping! */
			{
				DICT_ATTR const *da;
				uint8_t *p, *q;

				p = talloc_array(vp, uint8_t, vp->vp_length + 2);

				memcpy(p + 2, vp->vp_octets, vp->vp_length);
				p[0] = vp->da->attr - PW_DIGEST_REALM + 1;
				vp->vp_length += 2;
				p[1] = vp->vp_length;

				da = dict_attrbyvalue(PW_DIGEST_ATTRIBUTES, 0);
				if (!da) {
					ERROR("Out of memory");
					goto error;
				}
				vp->da = da;

				/*
				 *	Re-do fr_pair_value_memsteal ourselves,
				 *	because we play games with
				 *	vp->da, and fr_pair_value_memsteal goes
				 *	to GREAT lengths to sanitize
				 *	and fix and change and
				 *	double-check the various
				 *	fields.
				 */
				memcpy(&q, &vp->vp_octets, sizeof(q));
				talloc_free(q);

				vp->vp_octets = talloc_steal(vp, p);
				vp->type = VT_DATA;

				VERIFY_VP(vp);
			}
				break;

				/*
				 *	Cache this for later.
				 */
			case PW_CLEARTEXT_PASSWORD:
				request->password = vp;
				break;

			/*
			 *	Keep a copy of the the password attribute.
			 */
			case PW_CHAP_PASSWORD:
				/*
				 *	If it's already hex, do nothing.
				 */
				if ((vp->vp_length == 17) &&
				    (already_hex(vp))) break;

				/*
				 *	CHAP-Password is octets, so it may not be zero terminated.
				 */
				request->password = fr_pair_make(request->packet, &request->packet->vps, "Cleartext-Password",
							     "", T_OP_EQ);
				fr_pair_value_bstrncpy(request->password, vp->vp_strvalue, vp->vp_length);
				break;

			case PW_USER_PASSWORD:
			case PW_MS_CHAP_PASSWORD:
				request->password = fr_pair_make(request->packet, &request->packet->vps, "Cleartext-Password",
							     vp->vp_strvalue, T_OP_EQ);
				break;

			case PW_RADCLIENT_TEST_NAME:
				request->name = vp->vp_strvalue;
				break;
			}
		} /* loop over the VP's we read in */

		/*
		 *	Use the default set on the command line
		 */
		if (request->packet->code == PW_CODE_UNDEFINED) request->packet->code = packet_code;

		/*
		 *	Default to the filename
		 */
		if (!request->name) request->name = request->files->packets;

		/*
		 *	Automatically set the response code from the request code
		 *	(if one wasn't already set).
		 */
		if (request->filter_code == PW_CODE_UNDEFINED) {
			switch (request->packet->code) {
			case PW_CODE_ACCESS_REQUEST:
				request->filter_code = PW_CODE_ACCESS_ACCEPT;
				break;

			case PW_CODE_ACCOUNTING_REQUEST:
				request->filter_code = PW_CODE_ACCOUNTING_RESPONSE;
				break;

			case PW_CODE_COA_REQUEST:
				request->filter_code = PW_CODE_COA_ACK;
				break;

			case PW_CODE_DISCONNECT_REQUEST:
				request->filter_code = PW_CODE_DISCONNECT_ACK;
				break;

			case PW_CODE_STATUS_SERVER:
				switch (radclient_get_code(request->packet->dst_port)) {
				case PW_CODE_ACCESS_REQUEST:
					request->filter_code = PW_CODE_ACCESS_ACCEPT;
					break;

				case PW_CODE_ACCOUNTING_REQUEST:
					request->filter_code = PW_CODE_ACCOUNTING_RESPONSE;
					break;

				default:
					REDEBUG("Can't determine expected response to Status-Server request, specify "
					        "a well known RADIUS port, or add a Response-Packet-Type attribute "
					        "to the request of filter");
					goto error;
				}
				break;

			case PW_CODE_UNDEFINED:
				REDEBUG("Both Packet-Type and Response-Packet-Type undefined, specify at least one, "
					"or a well known RADIUS port");
				goto error;

			default:
				REDEBUG("Can't determine expected Response-Packet-Type for Packet-Type %i",
					request->packet->code);
				goto error;
			}
		/*
		 *	Automatically set the request code from the response code
		 *	(if one wasn't already set).
		 */
		} else if (request->packet->code == PW_CODE_UNDEFINED) {
			switch (request->filter_code) {
			case PW_CODE_ACCESS_ACCEPT:
			case PW_CODE_ACCESS_REJECT:
				request->packet->code = PW_CODE_ACCESS_REQUEST;
				break;

			case PW_CODE_ACCOUNTING_RESPONSE:
				request->packet->code = PW_CODE_ACCOUNTING_REQUEST;
				break;

			case PW_CODE_DISCONNECT_ACK:
			case PW_CODE_DISCONNECT_NAK:
				request->packet->code = PW_CODE_DISCONNECT_REQUEST;
				break;

			case PW_CODE_COA_ACK:
			case PW_CODE_COA_NAK:
				request->packet->code = PW_CODE_COA_REQUEST;
				break;

			default:
				REDEBUG("Can't determine expected Packet-Type for Response-Packet-Type %i",
					request->filter_code);
				goto error;
			}
		}

		/*
		 *	Automatically set the dst port (if one wasn't already set).
		 */
		if (request->packet->dst_port == 0) {
			radclient_get_port(request->packet->code, &request->packet->dst_port);
			if (request->packet->dst_port == 0) {
				REDEBUG("Can't determine destination port");
				goto error;
			}
		}

		/*
		 *	Add it to the tail of the list.
		 */
		if (!request_head) {
			assert(rc_request_tail == NULL);
			request_head = request;
			request->prev = NULL;
		} else {
			assert(rc_request_tail->next == NULL);
			rc_request_tail->next = request;
			request->prev = rc_request_tail;
		}
		rc_request_tail = request;
		request->next = NULL;

		/*
		 *	Set the destructor so it removes itself from the
		 *	request list when freed. We don't set this until
		 *	the packet is actually in the list, else we trigger
		 *	the asserts in the free callback.
		 */
		talloc_set_destructor(request, _rc_request_free);
	} while (!packets_done); /* loop until the file is done. */

	if (packets != stdin) fclose(packets);
	if (filters) fclose(filters);

	/*
	 *	And we're done.
	 */
	return 1;

error:
	talloc_free(request);

	if (packets != stdin) fclose(packets);
	if (filters) fclose(filters);

	return 0;
}
Пример #3
0
static REQUEST *request_setup(FILE *fp)
{
	VALUE_PAIR	*vp;
	REQUEST		*request;
	vp_cursor_t	cursor;
	struct timeval	now;

	/*
	 *	Create and initialize the new request.
	 */
	request = request_alloc(NULL);
	gettimeofday(&now, NULL);
	request->timestamp = now;

	request->packet = fr_radius_alloc(request, false);
	if (!request->packet) {
		ERROR("No memory");
		talloc_free(request);
		return NULL;
	}
	request->packet->timestamp = now;

	request->reply = fr_radius_alloc(request, false);
	if (!request->reply) {
		ERROR("No memory");
		talloc_free(request);
		return NULL;
	}

	request->listener = listen_alloc(request);
	request->client = client_alloc(request);

	request->number = 0;

	request->master_state = REQUEST_ACTIVE;
	request->child_state = REQUEST_RUNNING;
	request->handle = NULL;
	request->server = talloc_typed_strdup(request, "default");

	request->root = &main_config;

	/*
	 *	Read packet from fp
	 */
	if (fr_pair_list_afrom_file(request->packet, &request->packet->vps, fp, &filedone) < 0) {
		fr_perror("unittest");
		talloc_free(request);
		return NULL;
	}

	/*
	 *	Set the defaults for IPs, etc.
	 */
	request->packet->code = PW_CODE_ACCESS_REQUEST;

	request->packet->src_ipaddr.af = AF_INET;
	request->packet->src_ipaddr.ipaddr.ip4addr.s_addr = htonl(INADDR_LOOPBACK);
	request->packet->src_port = 18120;

	request->packet->dst_ipaddr.af = AF_INET;
	request->packet->dst_ipaddr.ipaddr.ip4addr.s_addr = htonl(INADDR_LOOPBACK);
	request->packet->dst_port = 1812;

	/*
	 *	Copied from radclient
	 */
#if 1
	/*
	 *	Fix up Digest-Attributes issues
	 */
	for (vp = fr_cursor_init(&cursor, &request->packet->vps);
	     vp;
	     vp = fr_cursor_next(&cursor)) {
		/*
		 *	Double quoted strings get marked up as xlat expansions,
		 *	but we don't support that here.
		 */
		if (vp->type == VT_XLAT) {
			vp->vp_strvalue = vp->xlat;
			vp->xlat = NULL;
			vp->type = VT_DATA;
		}

		if (!vp->da->vendor) switch (vp->da->attr) {
		default:
			break;

			/*
			 *	Allow it to set the packet type in
			 *	the attributes read from the file.
			 */
		case PW_PACKET_TYPE:
			request->packet->code = vp->vp_integer;
			break;

		case PW_PACKET_DST_PORT:
			request->packet->dst_port = (vp->vp_integer & 0xffff);
			break;

		case PW_PACKET_DST_IP_ADDRESS:
			request->packet->dst_ipaddr.af = AF_INET;
			request->packet->dst_ipaddr.ipaddr.ip4addr.s_addr = vp->vp_ipaddr;
			request->packet->dst_ipaddr.prefix = 32;
			break;

		case PW_PACKET_DST_IPV6_ADDRESS:
			request->packet->dst_ipaddr.af = AF_INET6;
			request->packet->dst_ipaddr.ipaddr.ip6addr = vp->vp_ipv6addr;
			request->packet->dst_ipaddr.prefix = 128;
			break;

		case PW_PACKET_SRC_PORT:
			request->packet->src_port = (vp->vp_integer & 0xffff);
			break;

		case PW_PACKET_SRC_IP_ADDRESS:
			request->packet->src_ipaddr.af = AF_INET;
			request->packet->src_ipaddr.ipaddr.ip4addr.s_addr = vp->vp_ipaddr;
			request->packet->src_ipaddr.prefix = 32;
			break;

		case PW_PACKET_SRC_IPV6_ADDRESS:
			request->packet->src_ipaddr.af = AF_INET6;
			request->packet->src_ipaddr.ipaddr.ip6addr = vp->vp_ipv6addr;
			request->packet->src_ipaddr.prefix = 128;
			break;

		case PW_CHAP_PASSWORD: {
			int i, already_hex = 0;

			/*
			 *	If it's 17 octets, it *might* be already encoded.
			 *	Or, it might just be a 17-character password (maybe UTF-8)
			 *	Check it for non-printable characters.  The odds of ALL
			 *	of the characters being 32..255 is (1-7/8)^17, or (1/8)^17,
			 *	or 1/(2^51), which is pretty much zero.
			 */
			if (vp->vp_length == 17) {
				for (i = 0; i < 17; i++) {
					if (vp->vp_octets[i] < 32) {
						already_hex = 1;
						break;
					}
				}
			}

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

				len = len2 = vp->vp_length;
				if (len2 < 17) len2 = 17;

				p = talloc_zero_array(vp, uint8_t, len2);

				memcpy(p, vp->vp_strvalue, len);

				fr_radius_encode_chap_password(p, request->packet, fr_rand() & 0xff, vp);
				vp->vp_octets = p;
				vp->vp_length = 17;
			}
		}
			break;

		case PW_DIGEST_REALM:
		case PW_DIGEST_NONCE:
		case PW_DIGEST_METHOD:
		case PW_DIGEST_URI:
		case PW_DIGEST_QOP:
		case PW_DIGEST_ALGORITHM:
		case PW_DIGEST_BODY_DIGEST:
		case PW_DIGEST_CNONCE:
		case PW_DIGEST_NONCE_COUNT:
		case PW_DIGEST_USER_NAME:
			/* overlapping! */
		{
			fr_dict_attr_t const *da;
			uint8_t *p, *q;

			p = talloc_array(vp, uint8_t, vp->vp_length + 2);

			memcpy(p + 2, vp->vp_octets, vp->vp_length);
			p[0] = vp->da->attr - PW_DIGEST_REALM + 1;
			vp->vp_length += 2;
			p[1] = vp->vp_length;

			da = fr_dict_attr_by_num(NULL, 0, PW_DIGEST_ATTRIBUTES);
			rad_assert(da != NULL);
			vp->da = da;

			/*
			 *	Re-do fr_pair_value_memsteal ourselves,
			 *	because we play games with
			 *	vp->da, and fr_pair_value_memsteal goes
			 *	to GREAT lengths to sanitize
			 *	and fix and change and
			 *	double-check the various
			 *	fields.
			 */
			memcpy(&q, &vp->vp_octets, sizeof(q));
			talloc_free(q);

			vp->vp_octets = talloc_steal(vp, p);
			vp->type = VT_DATA;

			VERIFY_VP(vp);
		}

		break;
		}
	} /* loop over the VP's we read in */
#endif

	if (rad_debug_lvl) {
		for (vp = fr_cursor_init(&cursor, &request->packet->vps);
		     vp;
		     vp = fr_cursor_next(&cursor)) {
			/*
			 *	Take this opportunity to verify all the VALUE_PAIRs are still valid.
			 */
			if (!talloc_get_type(vp, VALUE_PAIR)) {
				ERROR("Expected VALUE_PAIR pointer got \"%s\"", talloc_get_name(vp));

				fr_log_talloc_report(vp);
				rad_assert(0);
			}

			fr_pair_fprint(fr_log_fp, vp);
		}
		fflush(fr_log_fp);
	}

	/*
	 *	FIXME: set IPs, etc.
	 */
	request->packet->code = PW_CODE_ACCESS_REQUEST;

	request->packet->src_ipaddr.af = AF_INET;
	request->packet->src_ipaddr.ipaddr.ip4addr.s_addr = htonl(INADDR_LOOPBACK);
	request->packet->src_port = 18120;

	request->packet->dst_ipaddr.af = AF_INET;
	request->packet->dst_ipaddr.ipaddr.ip4addr.s_addr = htonl(INADDR_LOOPBACK);
	request->packet->dst_port = 1812;

	/*
	 *	Build the reply template from the request.
	 */
	request->reply->sockfd = request->packet->sockfd;
	request->reply->dst_ipaddr = request->packet->src_ipaddr;
	request->reply->src_ipaddr = request->packet->dst_ipaddr;
	request->reply->dst_port = request->packet->src_port;
	request->reply->src_port = request->packet->dst_port;
	request->reply->id = request->packet->id;
	request->reply->code = 0; /* UNKNOWN code */
	memcpy(request->reply->vector, request->packet->vector,
	       sizeof(request->reply->vector));
	request->reply->vps = NULL;
	request->reply->data = NULL;
	request->reply->data_len = 0;

	/*
	 *	Debugging
	 */
	request->log.lvl = rad_debug_lvl;
	request->log.func = vradlog_request;

	request->username = fr_pair_find_by_num(request->packet->vps, 0, PW_USER_NAME, TAG_ANY);
	request->password = fr_pair_find_by_num(request->packet->vps, 0, PW_USER_PASSWORD, TAG_ANY);

	return request;
}
Пример #4
0
/*
 *	The main guy.
 */
int main(int argc, char *argv[])
{
	int rcode = EXIT_SUCCESS;
	int argval;
	const char *input_file = NULL;
	const char *output_file = NULL;
	const char *filter_file = NULL;
	FILE *fp;
	REQUEST *request = NULL;
	VALUE_PAIR *vp;
	VALUE_PAIR *filter_vps = NULL;
	bool xlat_only = false;
	fr_state_tree_t *state = NULL;

	fr_talloc_fault_setup();

	/*
	 *	If the server was built with debugging enabled always install
	 *	the basic fatal signal handlers.
	 */
#ifndef NDEBUG
	if (fr_fault_setup(getenv("PANIC_ACTION"), argv[0]) < 0) {
		fr_perror("unittest");
		exit(EXIT_FAILURE);
	}
#endif

	rad_debug_lvl = 0;
	set_radius_dir(NULL, RADIUS_DIR);

	/*
	 *	Ensure that the configuration is initialized.
	 */
	memset(&main_config, 0, sizeof(main_config));
	main_config.name = "unittest";

	/*
	 *	The tests should have only IPs, not host names.
	 */
	fr_hostname_lookups = false;

	/*
	 *	We always log to stdout.
	 */
	fr_log_fp = stdout;
	default_log.dst = L_DST_STDOUT;
	default_log.fd = STDOUT_FILENO;

	/*  Process the options.  */
	while ((argval = getopt(argc, argv, "d:D:f:hi:mMn:o:O:xX")) != EOF) {

		switch (argval) {
			case 'd':
				set_radius_dir(NULL, optarg);
				break;

			case 'D':
				main_config.dictionary_dir = talloc_typed_strdup(NULL, optarg);
				break;

			case 'f':
				filter_file = optarg;
				break;

			case 'h':
				usage(0);
				break;

			case 'i':
				input_file = optarg;
				break;

			case 'm':
				main_config.debug_memory = true;
				break;

			case 'M':
				memory_report = true;
				main_config.debug_memory = true;
				break;

			case 'n':
				main_config.name = optarg;
				break;

			case 'o':
				output_file = optarg;
				break;

			case 'O':
				if (strcmp(optarg, "xlat_only") == 0) {
					xlat_only = true;
					break;
				}

				fprintf(stderr, "Unknown option '%s'\n", optarg);
				exit(EXIT_FAILURE);

			case 'X':
				rad_debug_lvl += 2;
				main_config.log_auth = true;
				main_config.log_auth_badpass = true;
				main_config.log_auth_goodpass = true;
				break;

			case 'x':
				rad_debug_lvl++;
				break;

			default:
				usage(1);
				break;
		}
	}

	if (rad_debug_lvl) version_print();
	fr_debug_lvl = rad_debug_lvl;

	/*
	 *	Mismatch between the binary and the libraries it depends on
	 */
	if (fr_check_lib_magic(RADIUSD_MAGIC_NUMBER) < 0) {
		fr_perror("%s", main_config.name);
		exit(EXIT_FAILURE);
	}

	/*
	 *  Initialising OpenSSL once, here, is safer than having individual modules do it.
	 */
#ifdef HAVE_OPENSSL_CRYPTO_H
	if (tls_global_init() < 0) {
		rcode = EXIT_FAILURE;
		goto finish;
	}
#endif

	if (xlat_register(NULL, "poke", xlat_poke, NULL, NULL, 0, XLAT_DEFAULT_BUF_LEN) < 0) {
		rcode = EXIT_FAILURE;
		goto finish;
	}

	if (map_proc_register(NULL, "test-fail", mod_map_proc, NULL,  NULL, 0) < 0) {
		rcode = EXIT_FAILURE;
		goto finish;
	}


	/*  Read the configuration files, BEFORE doing anything else.  */
	if (main_config_init() < 0) {
	exit_failure:
		rcode = EXIT_FAILURE;
		goto finish;
	}

	/*
	 *	Setup dummy virtual server
	 */
	cf_section_add(main_config.config, cf_section_alloc(main_config.config, "server", "unit_test"));

	/*
	 *	Initialize Auth-Type, etc. in the virtual servers
	 *	before loading the modules.  Some modules need those
	 *	to be defined.
	 */
	if (virtual_servers_bootstrap(main_config.config) < 0) goto exit_failure;

	/*
	 *	Bootstrap the modules.  This links to them, and runs
	 *	their "bootstrap" routines.
	 *
	 *	After this step, all dynamic attributes, xlats, etc. are defined.
	 */
	if (modules_bootstrap(main_config.config) < 0) exit(EXIT_FAILURE);

	/*
	 *	Load the modules
	 */
	if (modules_init(main_config.config) < 0) goto exit_failure;

	/*
	 *	And then load the virtual servers.
	 */
	if (virtual_servers_init(main_config.config) < 0) goto exit_failure;

	state = fr_state_tree_init(NULL, main_config.max_requests * 2, 10);

	/*
	 *  Set the panic action (if required)
	 */
	{
		char const *panic_action = NULL;

		panic_action = getenv("PANIC_ACTION");
		if (!panic_action) panic_action = main_config.panic_action;

		if (panic_action && (fr_fault_setup(panic_action, argv[0]) < 0)) {
			fr_perror("%s", main_config.name);
			exit(EXIT_FAILURE);
		}
	}

	setlinebuf(stdout); /* unbuffered output */

	if (!input_file || (strcmp(input_file, "-") == 0)) {
		fp = stdin;
	} else {
		fp = fopen(input_file, "r");
		if (!fp) {
			fprintf(stderr, "Failed reading %s: %s\n",
				input_file, strerror(errno));
			rcode = EXIT_FAILURE;
			goto finish;
		}
	}

	/*
	 *	For simplicity, read xlat's.
	 */
	if (xlat_only) {
		if (!do_xlats(input_file, fp)) rcode = EXIT_FAILURE;
		if (input_file) fclose(fp);
		goto finish;
	}

	/*
	 *	Grab the VPs from stdin, or from the file.
	 */
	request = request_setup(fp);
	if (!request) {
		fprintf(stderr, "Failed reading input: %s\n", fr_strerror());
		rcode = EXIT_FAILURE;
		goto finish;
	}

	/*
	 *	No filter file, OR there's no more input, OR we're
	 *	reading from a file, and it's different from the
	 *	filter file.
	 */
	if (!filter_file || filedone ||
	    ((input_file != NULL) && (strcmp(filter_file, input_file) != 0))) {
		if (output_file) {
			fclose(fp);
			fp = NULL;
		}
		filedone = false;
	}

	/*
	 *	There is a filter file.  If necessary, open it.  If we
	 *	already are reading it via "input_file", then we don't
	 *	need to re-open it.
	 */
	if (filter_file) {
		if (!fp) {
			fp = fopen(filter_file, "r");
			if (!fp) {
				fprintf(stderr, "Failed reading %s: %s\n", filter_file, strerror(errno));
				rcode = EXIT_FAILURE;
				goto finish;
			}
		}


		if (fr_pair_list_afrom_file(request, &filter_vps, fp, &filedone) < 0) {
			fprintf(stderr, "Failed reading attributes from %s: %s\n",
				filter_file, fr_strerror());
			rcode = EXIT_FAILURE;
			goto finish;
		}

		/*
		 *	FIXME: loop over input packets.
		 */
		fclose(fp);
	}

	rad_virtual_server(request);

	if (!output_file || (strcmp(output_file, "-") == 0)) {
		fp = stdout;
	} else {
		fp = fopen(output_file, "w");
		if (!fp) {
			fprintf(stderr, "Failed writing %s: %s\n",
				output_file, strerror(errno));
			exit(EXIT_FAILURE);
		}
	}

	print_packet(fp, request->reply);

	if (output_file) fclose(fp);

	/*
	 *	Update the list with the response type.
	 */
	vp = radius_pair_create(request->reply, &request->reply->vps,
			       PW_RESPONSE_PACKET_TYPE, 0);
	vp->vp_integer = request->reply->code;

	{
		VALUE_PAIR const *failed[2];

		if (filter_vps && !fr_pair_validate(failed, filter_vps, request->reply->vps)) {
			fr_pair_validate_debug(request, failed);
			fr_perror("Output file %s does not match attributes in filter %s (%s)",
				  output_file ? output_file : input_file, filter_file, fr_strerror());
			rcode = EXIT_FAILURE;
			goto finish;
		}
	}

	INFO("Exiting normally");

finish:
	talloc_free(request);
	talloc_free(state);

	/*
	 *	Free the configuration items.
	 */
	main_config_free();

	/*
	 *	Detach any modules.
	 */
	modules_free();

	xlat_unregister(NULL, "poke", xlat_poke);

	xlat_free();		/* modules may have xlat's */

	if (memory_report) {
		INFO("Allocated memory at time of report:");
		fr_log_talloc_report(NULL);
	}

	return rcode;
}
Пример #5
0
/*
 *	Initialize the request.
 */
static RADIUS_PACKET *request_init(char const *filename)
{
	FILE *fp;
	fr_cursor_t cursor;
	VALUE_PAIR *vp;
	bool filedone = false;
	RADIUS_PACKET *request;

	/*
	 *	Determine where to read the VP's from.
	 */
	if (filename) {
		fp = fopen(filename, "r");
		if (!fp) {
			ERROR("Error opening %s: %s", filename, fr_syserror(errno));
			return NULL;
		}
	} else {
		fp = stdin;
	}

	request = fr_radius_alloc(NULL, false);
	/*
	 *	Read the VP's.
	 */
	if (fr_pair_list_afrom_file(NULL, dict_dhcpv4, &request->vps, fp, &filedone) < 0) {
		fr_perror("dhcpclient");
		fr_radius_packet_free(&request);
		if (fp != stdin) fclose(fp);
		return NULL;
	}

	/*
	 *	Fix / set various options
	 */
	for (vp = fr_cursor_init(&cursor, &request->vps);
	     vp;
	     vp = fr_cursor_next(&cursor)) {

		/*
		 *	Xlat expansions are not supported. Convert xlat to value box (if possible).
		 */
		if (vp->type == VT_XLAT) {
			fr_type_t type = vp->da->type;
			if (fr_value_box_from_str(vp, &vp->data, &type, NULL, vp->xlat, -1, '\0', false) < 0) {
				fr_perror("dhcpclient");
				fr_radius_packet_free(&request);
				if (fp != stdin) fclose(fp);
				return NULL;
			}
			vp->type = VT_DATA;
		}

		/*
		 *	Allow to set packet type using DHCP-Message-Type
		 */
	     	if (vp->da == attr_dhcp_message_type) {
	     		request->code = vp->vp_uint8;

		/*
		 *	Allow it to set the packet type in
		 *	the attributes read from the file.
		 *	(this takes precedence over the command argument.)
		 */
	     	} else if (vp->da == attr_packet_type) {
	     		request->code = vp->vp_uint32;

		} else if (vp->da == attr_packet_dst_port) {
			request->dst_port = vp->vp_uint16;

		} else if ((vp->da == attr_packet_dst_ip_address) ||
			   (vp->da == attr_packet_dst_ipv6_address)) {
			memcpy(&request->dst_ipaddr, &vp->vp_ip, sizeof(request->src_ipaddr));

		} else if (vp->da == attr_packet_src_port) {
			request->src_port = vp->vp_uint16;

		} else if ((vp->da == attr_packet_src_ip_address) ||
			   (vp->da == attr_packet_src_ipv6_address)) {
			memcpy(&request->src_ipaddr, &vp->vp_ip, sizeof(request->src_ipaddr));
		} /* switch over the attribute */

	} /* loop over the VP's we read in */

	if (fp != stdin) fclose(fp);

	/*
	 *	And we're done.
	 */
	return request;
}