Ejemplo n.º 1
0
static void
radius_test(struct parse_result *res)
{
	struct addrinfo		 hints, *ai;
	int			 sock, retval;
	struct sockaddr_storage	 sockaddr;
	socklen_t		 sockaddrlen;
	RADIUS_PACKET		*reqpkt, *respkt;
	struct sockaddr_in	*sin4;
	struct sockaddr_in6	*sin6;
	uint32_t		 u32val;
	uint8_t			 id;

	reqpkt = radius_new_request_packet(RADIUS_CODE_ACCESS_REQUEST);
	if (reqpkt == NULL)
		err(1, "radius_new_request_packet");
	id = arc4random();
	radius_set_id(reqpkt, id);

	memset(&hints, 0, sizeof(hints));
	hints.ai_family = PF_UNSPEC;
	hints.ai_socktype = SOCK_DGRAM;

	retval = getaddrinfo(res->hostname, "radius", &hints, &ai);
	if (retval)
		errx(1, "%s %s", res->hostname, gai_strerror(retval));

	if (res->port != 0)
		((struct sockaddr_in *)ai->ai_addr)->sin_port =
		    htons(res->port);

	sock = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
	if (sock == -1)
		err(1, "socket");

	/* Prepare NAS-IP{,V6}-ADDRESS attribute */
	if (connect(sock, ai->ai_addr, ai->ai_addrlen) == -1)
		err(1, "connect");
	sockaddrlen = sizeof(sockaddr);
	if (getsockname(sock, (struct sockaddr *)&sockaddr, &sockaddrlen) == -1)
		err(1, "getsockname");
	sin4 = (struct sockaddr_in *)&sockaddr;
	sin6 = (struct sockaddr_in6 *)&sockaddr;
	switch (sockaddr.ss_family) {
	case AF_INET:
		radius_put_ipv4_attr(reqpkt, RADIUS_TYPE_NAS_IP_ADDRESS,
		    sin4->sin_addr);
		break;
	case AF_INET6:
		radius_put_raw_attr(reqpkt, RADIUS_TYPE_NAS_IPV6_ADDRESS,
		    sin6->sin6_addr.s6_addr, sizeof(sin6->sin6_addr.s6_addr));
		break;
	}

	/* User-Name and User-Password */
	radius_put_string_attr(reqpkt, RADIUS_TYPE_USER_NAME,
	    res->username);

	switch (res->auth_method) {
	case PAP:
		if (res->password != NULL)
			radius_put_user_password_attr(reqpkt, res->password,
			    res->secret);
		break;
	case CHAP:
	    {
		u_char	 chal[16];
		u_char	 resp[1 + MD5_DIGEST_LENGTH]; /* "1 + " for CHAP Id */
		MD5_CTX	 md5ctx;

		arc4random_buf(resp, 1);	/* CHAP Id is random */
		MD5Init(&md5ctx);
		MD5Update(&md5ctx, resp, 1);
		if (res->password != NULL)
			MD5Update(&md5ctx, res->password,
			    strlen(res->password));
		MD5Update(&md5ctx, chal, sizeof(chal));
		MD5Final(resp + 1, &md5ctx);
		radius_put_raw_attr(reqpkt, RADIUS_TYPE_CHAP_CHALLENGE,
		    chal, sizeof(chal));
		radius_put_raw_attr(reqpkt, RADIUS_TYPE_CHAP_PASSWORD,
		    resp, sizeof(resp));
	    }
		break;
	case MSCHAPV2:
	    {
		u_char	pass[256], chal[16];
		u_int	i, lpass;
		struct _resp {
			u_int8_t ident;
			u_int8_t flags;
			char peer_challenge[16];
			char reserved[8];
			char response[24];
		} __packed resp;

		if (res->password == NULL) {
			lpass = 0;
		} else {
			lpass = strlen(res->password);
			if (lpass * 2 >= sizeof(pass))
				err(1, "password too long");
			for (i = 0; i < lpass; i++) {
				pass[i * 2] = res->password[i];
				pass[i * 2 + 1] = 0;
			}
		}

		memset(&resp, 0, sizeof(resp));
		resp.ident = arc4random();
		arc4random_buf(chal, sizeof(chal));
		arc4random_buf(resp.peer_challenge,
		    sizeof(resp.peer_challenge));

		mschap_nt_response(chal, resp.peer_challenge,
		    (char *)res->username, strlen(res->username), pass,
		    lpass * 2, resp.response);

		radius_put_vs_raw_attr(reqpkt, RADIUS_VENDOR_MICROSOFT,
		    RADIUS_VTYPE_MS_CHAP_CHALLENGE, chal, sizeof(chal));
		radius_put_vs_raw_attr(reqpkt, RADIUS_VENDOR_MICROSOFT,
		    RADIUS_VTYPE_MS_CHAP2_RESPONSE, &resp, sizeof(resp));
		explicit_bzero(pass, sizeof(pass));
	    }
		break;

	}
	u32val = htonl(res->nas_port);
	radius_put_raw_attr(reqpkt, RADIUS_TYPE_NAS_PORT, &u32val, 4);

	radius_put_message_authenticator(reqpkt, res->secret);

	/* Send! */
	fprintf(stderr, "Sending:\n");
	radius_dump(stdout, reqpkt, false, res->secret);
	if (send(sock, radius_get_data(reqpkt), radius_get_length(reqpkt), 0)
	    == -1)
		warn("send");
	if ((respkt = radius_recv(sock, 0)) == NULL)
		warn("recv");
	else {
		radius_set_request_packet(respkt, reqpkt);
		fprintf(stderr, "\nReceived:\n");
		radius_dump(stdout, respkt, true, res->secret);
	}

	/* Release the resources */
	radius_delete_packet(reqpkt);
	if (respkt)
		radius_delete_packet(respkt);
	close(sock);
	freeaddrinfo(ai);

	explicit_bzero((char *)res->secret, strlen(res->secret));
	if (res->password)
		explicit_bzero((char *)res->password, strlen(res->password));

	return;
}
Ejemplo n.º 2
0
/* Return: success: length, error: -1 */
static int
radius_send(
		u_long host, int port, char *secret,
		u_char *sendbuf, int sendlen, u_char *recvbuf, int maxrecvlen)
{
	int s;
	struct sockaddr_in salocal, saremote;
	fd_set set;
	struct timeval timeout;
	int ret, recvlen, sendcount;

	s = socket(PF_INET, SOCK_DGRAM, 0);
	if (s < 0) {
		syslog(LOG_ERR, "RADIUS: open socket failed: %m");
		return -1;
	}

	memset(&salocal, 0, sizeof(salocal));
	salocal.sin_family = AF_INET;
	salocal.sin_addr.s_addr = htonl(INADDR_ANY);
	salocal.sin_port = 0;

	if (bind(s, (struct sockaddr*)&salocal, sizeof(salocal)) < 0) {
		syslog(LOG_ERR, "RADIUS: bind socket failed: %m");
		close(s);
		return -1;
	}

	memset(&saremote, 0, sizeof(saremote));
	saremote.sin_family = AF_INET;
	saremote.sin_addr.s_addr = htonl(host);
	saremote.sin_port = htons(port);

	if (sendto(s, sendbuf, sendlen, 0,
			(struct sockaddr*)&saremote, sizeof(saremote)) < 0) {
		syslog(LOG_ERR, "RADIUS: sendto failed: %m");
		close(s);
		return -1;
	}
	sendcount = 1;
	while (sendcount < 10) {
		FD_ZERO(&set);
		FD_SET(s, &set);
		timeout.tv_sec = RESEND_TIMEOUT;
		timeout.tv_usec = 0;
		ret = select(s+1, &set, NULL, NULL, &timeout);
		if (ret < 0) {
			syslog(LOG_ERR, "RADIUS: select failed: %m");
			close(s);
			return -1;
		}
		if (ret == 0) {
			/* Timed out so resend */
			if (sendcount > 3) {
				syslog(LOG_WARNING, "RADIUS: server %s not responding",
						inet_ntoa(saremote.sin_addr));
			}
			if (sendto(s, sendbuf, sendlen, 0,
					(struct sockaddr*)&saremote, sizeof(saremote)) < 0) {
				syslog(LOG_ERR, "RADIUS: sendto failed: %m");
				close(s);
				return -1;
			}
			sendcount++;
		}
		else if (FD_ISSET(s, &set)) {
			recvlen = radius_recv(s, secret, sendbuf,
					recvbuf, maxrecvlen, &saremote);
			if (recvlen != 0) { /* either -1 , or positive */
				close(s);
				return recvlen;
			}
		}
	}

	close(s);
	syslog(LOG_ERR, "RADIUS: maximum retries reached for server %s",
			inet_ntoa(saremote.sin_addr));
	return -1;
}