22#if defined(HAVE_GNUTLS)
23# include <gnutls/gnutls.h>
24# include <gnutls/crypto.h>
32#define SCLOSE(fd) if (sfuncs->close_fd) sfuncs->close_fd(fd)
35static void rc_random_vector(
unsigned char[AUTH_VECTOR_LEN]);
38static int rc_check_reply(AUTH_HDR *,
int,
char const *,
unsigned char const *,
61int rc_pack_list(VALUE_PAIR * vp,
char *secret, AUTH_HDR * auth,
int max_len)
63 int length, i, pc, padded_length;
65 uint32_t lvalue, vendor;
66 unsigned char passbuf[RC_MAX(AUTH_PASS_LEN, CHAP_VALUE_LENGTH)];
67 unsigned char md5buf[MAX_SECRET_LENGTH + AUTH_VECTOR_LEN];
68 unsigned char *vector;
70 uint8_t *attr_start, *attr_len_ptr, *vsa_len_ptr;
74 pb.head = (uint8_t *)auth;
75 pb.data = (uint8_t *)auth;
77 pb.end = (uint8_t *)auth + max_len;
81 unsigned max_vlen = AUTH_STRING_LEN;
84 max_vlen = AUTH_STRING_LEN - VSA_HDR_LEN;
86 vsa_len_ptr = pb.tail;
87 if (pb_put_byte(&pb, 6) < 0)
goto too_large;
89 if (pb_put_bytes(&pb, &vendor,
sizeof(uint32_t)) < 0)
goto too_large;
93 if (pb_put_byte(&pb, vp->
attribute & 0xff) < 0)
goto too_large;
94 attr_len_ptr = pb.tail;
95 if (pb_put_byte(&pb, 2) < 0)
goto too_large;
100 if (length > AUTH_PASS_LEN)
101 length = AUTH_PASS_LEN;
103 (length + (AUTH_VECTOR_LEN - 1)) & ~(AUTH_VECTOR_LEN - 1);
105 if (pb.tail + padded_length > pb.end)
goto too_large;
108 memset((
char *)passbuf,
'\0', AUTH_PASS_LEN);
109 memcpy((
char *)passbuf, vp->
strvalue, (
size_t) length);
111 secretlen = strlen(secret);
112 if (secretlen > MAX_SECRET_LENGTH)
113 secretlen = MAX_SECRET_LENGTH;
114 vector = (
unsigned char *)auth->vector;
115 for (i = 0; i < padded_length; i += AUTH_VECTOR_LEN) {
117 memcpy(md5buf, secret, secretlen);
118 memcpy(md5buf + secretlen, vector, AUTH_VECTOR_LEN);
119 rc_md5_calc(pb.tail, md5buf, secretlen + AUTH_VECTOR_LEN);
125 for (pc = i; pc < (i + AUTH_VECTOR_LEN); pc++)
126 *pb.tail++ ^= passbuf[pc];
134 if (vp->
lvalue > max_vlen)
goto too_large;
140 if (pb_put_bytes(&pb, vp->
strvalue, 16) < 0)
147 lvalue = htonl(vp->
lvalue);
148 if (pb_put_bytes(&pb, &lvalue,
sizeof(uint32_t)) < 0)
159 *attr_len_ptr = (uint8_t)(pb.tail - attr_start);
160 if (vsa_len_ptr != NULL)
161 *vsa_len_ptr += *attr_len_ptr;
165 return (
int)pb_written(&pb);
168 rc_log(LOG_ERR,
"rc_pack_list: attribute value too large or packet would exceed %d bytes", max_len);
181static void strappend(
char *dest,
unsigned max_size,
int *pos,
const char *src)
183 unsigned len = strlen(src) + 1;
188 if (len + *pos > max_size) {
193 memcpy(&dest[*pos], src, len);
201static int populate_ctx(
RC_AAA_CTX ** ctx,
char secret[MAX_SECRET_LENGTH + 1],
202 uint8_t vector[AUTH_VECTOR_LEN])
210 memcpy((*ctx)->secret, secret,
sizeof((*ctx)->secret));
211 memcpy((*ctx)->request_vector, vector,
212 sizeof((*ctx)->request_vector));
233 return rc_send_server_ctx(rh, NULL, data, msg, type, 0);
246static int rc_check_reply(AUTH_HDR * auth,
int bufferlen,
char const *secret,
247 unsigned char const *vector, uint8_t seq_nbr)
251 unsigned char calc_digest[AUTH_VECTOR_LEN];
252 unsigned char reply_digest[AUTH_VECTOR_LEN];
254 totallen = ntohs(auth->length);
255 secretlen = (int)strlen(secret);
258 if ((totallen < 20) || (totallen > 4096)) {
260 "rc_check_reply: received RADIUS server response with invalid length");
265 if ((totallen + secretlen) > bufferlen) {
267 "rc_check_reply: not enough buffer space to verify RADIUS server response");
272 if (auth->id != seq_nbr) {
274 "rc_check_reply: received non-matching id in RADIUS server response");
278 memcpy((
char *)reply_digest, (
char *)auth->vector, AUTH_VECTOR_LEN);
279 memcpy((
char *)auth->vector, (
char *)vector, AUTH_VECTOR_LEN);
280 memcpy((
char *)auth + totallen, secret, secretlen);
281 rc_md5_calc(calc_digest, (
unsigned char *)auth, totallen + secretlen);
283 if (rc_memcmp((
char *)reply_digest, (
char *)calc_digest,
284 AUTH_VECTOR_LEN) != 0) {
286 "rc_check_reply: received invalid reply digest from RADIUS server");
300static void rc_random_vector(
unsigned char vector[AUTH_VECTOR_LEN])
302#if defined(HAVE_GNUTLS)
303 int ret = gnutls_rnd(GNUTLS_RND_NONCE, vector, AUTH_VECTOR_LEN);
306 int ret = getentropy(vector, AUTH_VECTOR_LEN);
327static int add_msg_auth_attr(rc_handle * rh,
char * secret,
328 AUTH_HDR *auth,
int total_length)
330 size_t secretlen = strlen(secret);
331 uint8_t *msg_auth = (uint8_t *)auth + total_length;
334 memset(&msg_auth[2], 0, MD5_DIGEST_SIZE);
336 auth->length = htons((
unsigned short)total_length);
339 uint8_t digest[MD5_DIGEST_SIZE];
340 rc_hmac_md5((uint8_t *)auth, (
size_t)total_length, (uint8_t *)secret, secretlen, digest);
341 memcpy(&msg_auth[2], digest, MD5_DIGEST_SIZE);
356static int validate_message_authenticator(
const uint8_t *recv_buffer,
357 size_t length,
const char *secret,
358 const unsigned char *req_auth)
360 uint8_t verify_buffer[RC_BUFFER_LEN];
362 uint8_t ma_copy[MD5_DIGEST_SIZE];
363 uint8_t digest[MD5_DIGEST_SIZE];
364 uint8_t attr_type, attr_len;
367 if (AUTH_HDR_LEN + length >
sizeof(verify_buffer)) {
368 rc_log(LOG_ERR,
"%s: packet too large for verification buffer", __func__);
374 memcpy(verify_buffer, recv_buffer, AUTH_HDR_LEN + length);
375 memcpy(verify_buffer + 4, req_auth, AUTH_VECTOR_LEN);
376 pb_init_read(&vb, verify_buffer + AUTH_HDR_LEN, length, length);
378 while (pb_len(&vb) >= 2) {
379 attr_type = vb.data[0];
380 attr_len = vb.data[1];
381 if (attr_len < 2 || (
size_t)attr_len > pb_len(&vb))
385 if (attr_len != 2 + MD5_DIGEST_SIZE) {
386 rc_log(LOG_ERR,
"%s: Message-Authenticator has wrong length %u",
387 __func__, (
unsigned)(attr_len - 2));
391 memcpy(ma_copy, vb.data + 2, MD5_DIGEST_SIZE);
392 memset(vb.data + 2,
'\0', MD5_DIGEST_SIZE);
396 assert(pb_pull(&vb, attr_len) == 0);
402 rc_hmac_md5(verify_buffer, AUTH_HDR_LEN + length, (uint8_t *)secret, strlen(secret), digest);
403 return rc_memcmp(ma_copy, digest, MD5_DIGEST_SIZE);
423int rc_send_server_ctx(rc_handle * rh,
RC_AAA_CTX ** ctx, SEND_DATA * data,
424 char *msg,
rc_type type,
int no_wait)
427 AUTH_HDR *auth, *recv_auth;
428 char *server_name, *p;
429 struct sockaddr_storage our_sockaddr;
430 struct addrinfo *auth_addr = NULL;
436 const rc_sockets_override *sfuncs;
437 unsigned discover_local_ip;
439 char secret[MAX_SECRET_LENGTH + 1];
440 unsigned char vector[AUTH_VECTOR_LEN];
441 uint8_t recv_buffer[RC_BUFFER_LEN];
442 uint8_t send_buffer[RC_BUFFER_LEN];
445 uint8_t attr_type, attr_len;
449 double start_time, timeout;
450 struct sockaddr_storage *ss_set = NULL;
451 char *server_type =
"auth";
455 server_name = data->
server;
456 if (server_name == NULL || server_name[0] ==
'\0')
461 if(-1 == rc_set_netns(ns, &ns_def_hdl)) {
462 rc_log(LOG_ERR,
"rc_send_server: namespace %s set failed", ns);
467 (vp->
lvalue == PW_ADMINISTRATIVE)) {
470 rc_getaddrinfo(server_name,
471 type ==
AUTH ? PW_AI_AUTH : PW_AI_ACCT);
472 if (auth_addr == NULL) {
477 if (data->
secret != NULL) {
478 strlcpy(secret, data->
secret,
sizeof(secret));
485 (rh, server_name, &auth_addr, secret, type) != 0) {
487 "rc_send_server: unable to find server: %s",
497 if (sfuncs->static_secret) {
499 strlcpy(secret, sfuncs->static_secret,
sizeof(secret));
503 if (sfuncs->lock(sfuncs->ptr) != 0) {
504 rc_log(LOG_ERR,
"%s: lock error", __func__);
510 rc_own_bind_addr(rh, &our_sockaddr);
511 discover_local_ip = 0;
512 if (our_sockaddr.ss_family == AF_INET) {
513 if (((
struct sockaddr_in *)(&our_sockaddr))->sin_addr.s_addr ==
515 discover_local_ip = 1;
519 DEBUG(LOG_ERR,
"DEBUG: rc_send_server: creating socket to: %s",
521 if (discover_local_ip) {
523 if (result != OK_RC) {
524 memset(secret,
'\0',
sizeof(secret));
526 "rc_send_server: cannot figure our own address");
531 if (sfuncs->get_fd) {
532 sockfd = sfuncs->get_fd(sfuncs->ptr, SA(&our_sockaddr));
534 memset(secret,
'\0',
sizeof(secret));
535 rc_log(LOG_ERR,
"rc_send_server: socket: %s",
542 if(our_sockaddr.ss_family == AF_INET6) {
544 char *non_temp_addr =
rc_conf_str(rh,
"use-public-addr");
545 if (non_temp_addr && (strcasecmp(non_temp_addr,
"true") == 0)) {
546#if defined(__linux__)
547 int sock_opt = IPV6_PREFER_SRC_PUBLIC;
548 if (setsockopt(sockfd, IPPROTO_IPV6, IPV6_ADDR_PREFERENCES,
549 &sock_opt,
sizeof(sock_opt)) != 0) {
550 rc_log(LOG_ERR,
"rc_send_server: setsockopt: %s",
555#elif defined(BSD) || defined(__APPLE__)
557 if (setsockopt(sockfd, IPPROTO_IPV6, IPV6_PREFER_TEMPADDR,
558 &sock_opt,
sizeof(sock_opt)) != 0) {
559 rc_log(LOG_ERR,
"rc_send_server: setsockopt: %s",
565 rc_log(LOG_INFO,
"rc_send_server: Usage of non-temporary IPv6"
566 " address is not supported in this system");
571 retry_max = data->retries;
575 if (our_sockaddr.ss_family == AF_INET)
576 ((
struct sockaddr_in *)auth_addr->ai_addr)->sin_port =
577 htons((
unsigned short)data->
svc_port);
579 ((
struct sockaddr_in6 *)auth_addr->ai_addr)->sin6_port =
580 htons((
unsigned short)data->
svc_port);
586 if (rh->nas_addr_set) {
590 ss_set = &rh->nas_addr;
594 ss_set = &our_sockaddr;
598 if (ss_set->ss_family == AF_INET) {
601 *) (&((
struct sockaddr_in *)ss_set)->
609 p = &((
struct sockaddr_in6 *)ss_set)->sin6_addr;
627 auth = (AUTH_HDR *) send_buffer;
628 auth->code = data->
code;
631 if (data->
code == PW_ACCOUNTING_REQUEST) {
632 server_type =
"acct";
633 total_length = rc_pack_list(data->
send_pairs, secret, auth, RC_MAX_PACKET_LEN);
634 if (total_length < 0) {
639 tlen = htons((
unsigned short)total_length);
640 memcpy(&auth->length, &tlen,
sizeof(uint16_t));
642 memset((
char *)auth->vector, 0, AUTH_VECTOR_LEN);
643 secretlen = strlen(secret);
644 memcpy((
char *)auth + total_length, secret, secretlen);
645 rc_md5_calc(vector, (
unsigned char *)auth,
646 total_length + secretlen);
647 memcpy((
char *)auth->vector, (
char *)vector, AUTH_VECTOR_LEN);
649 rc_random_vector(vector);
650 memcpy((
char *)auth->vector, (
char *)vector, AUTH_VECTOR_LEN);
653 total_length = rc_pack_list(data->
send_pairs, secret, auth,
654 RC_MAX_PACKET_LEN - (2 + MD5_DIGEST_SIZE));
655 if (total_length < 0) {
660 total_length = add_msg_auth_attr(rh, secret, auth, total_length);
662 auth->length = htons((
unsigned short)total_length);
666 char our_addr_txt[50] =
"";
667 char auth_addr_txt[50] =
"";
669 getnameinfo(SA(&our_sockaddr), SS_LEN(&our_sockaddr), NULL, 0,
670 our_addr_txt,
sizeof(our_addr_txt), NI_NUMERICHOST);
671 getnameinfo(auth_addr->ai_addr, auth_addr->ai_addrlen, NULL, 0,
672 auth_addr_txt,
sizeof(auth_addr_txt),
676 "DEBUG: timeout=%d retries=%d local %s : 0, remote %s : %u\n",
677 data->
timeout, retry_max, our_addr_txt, auth_addr_txt,
684 sfuncs->sendto(sfuncs->ptr, sockfd, (
char *)auth,
685 (
unsigned int)total_length, (
int)0,
686 SA(auth_addr->ai_addr),
687 auth_addr->ai_addrlen);
688 }
while (result == -1 && errno == EINTR);
690 result = errno == ENETUNREACH ? NETUNREACH_RC : ERROR_RC;
691 rc_log(LOG_ERR,
"%s: socket: %s", __FUNCTION__,
703 result = populate_ctx(ctx, secret, vector);
704 memset(secret,
'\0',
sizeof(secret));
713 if (sfuncs->get_active_fd) {
714 int new_fd = sfuncs->get_active_fd(sfuncs->ptr);
721 start_time = rc_getmtime();
722 for (timeout = data->
timeout; timeout > 0;
723 timeout -= rc_getmtime() - start_time) {
724 result = poll(&pfd, 1, timeout * 1000);
725 if (result != -1 || errno != EINTR)
730 rc_log(LOG_ERR,
"rc_send_server: poll: %s",
732 memset(secret,
'\0',
sizeof(secret));
738 if (result == 1 && (pfd.revents & POLLIN) != 0) {
739 salen = auth_addr->ai_addrlen;
741 length = sfuncs->recvfrom(sfuncs->ptr, sockfd,
748 }
while (length == -1 && errno == EINTR);
753 "rc_send_server: recvfrom: %s:%d: %s",
756 if (length == -1 && (e == EAGAIN || e == EINTR))
759 memset(secret,
'\0',
sizeof(secret));
764 recv_auth = (AUTH_HDR *) recv_buffer;
766 if (length < AUTH_HDR_LEN
767 || length < ntohs(recv_auth->length)) {
769 "rc_send_server: recvfrom: %s:%d: reply is too short",
772 memset(secret,
'\0',
sizeof(secret));
778 rc_check_reply(recv_auth, RC_BUFFER_LEN, secret,
780 if (result != BADRESPID_RC) {
793 if (retries++ >= retry_max) {
794 char radius_server_ip[128];
795 struct sockaddr_in *si =
796 (
struct sockaddr_in *)auth_addr->ai_addr;
797 inet_ntop(auth_addr->ai_family, &si->sin_addr,
798 radius_server_ip,
sizeof(radius_server_ip));
800 "rc_send_server: no reply from RADIUS %s server %s:%u",
801 server_type, radius_server_ip, data->
svc_port);
803 memset(secret,
'\0',
sizeof(secret));
812 if (length > ntohs(recv_auth->length))
813 length = ntohs(recv_auth->length);
818 pb_init_read(&rb, recv_buffer, length, RC_BUFFER_LEN);
819 assert(pb_pull(&rb, AUTH_HDR_LEN) == 0);
820 while (pb_len(&rb) > 0) {
821 if (pb_peek_byte(&rb, 0, &attr_type) < 0 ||
822 pb_peek_byte(&rb, 1, &attr_len) < 0) {
824 "rc_send_server: recvfrom: %s:%d: truncated attribute",
827 memset(secret,
'\0',
sizeof(secret));
831 if (attr_type == 0) {
833 "rc_send_server: recvfrom: %s:%d: attribute zero is invalid",
836 memset(secret,
'\0',
sizeof(secret));
842 "rc_send_server: recvfrom: %s:%d: attribute length is too small",
845 memset(secret,
'\0',
sizeof(secret));
849 if (attr_len > pb_len(&rb)) {
851 "rc_send_server: recvfrom: %s:%d: attribute overflows the packet",
854 memset(secret,
'\0',
sizeof(secret));
858 assert(pb_pull(&rb, attr_len) == 0);
861 length = ntohs(recv_auth->length) - AUTH_HDR_LEN;
870 result = populate_ctx(ctx, secret, vector);
871 if (result != OK_RC) {
872 memset(secret,
'\0',
sizeof(secret));
883 if (validate_message_authenticator(recv_buffer, length, secret, vector)) {
885 "rc_send_server: recvfrom: %s:%d: received attribute Message-Authenticator is incorrect",
887 memset(secret,
'\0',
sizeof(secret));
902 p =
rc_conf_str(rh,
"require-message-authenticator");
903 if (p == NULL || (strcasecmp(p,
"false") != 0 && strcasecmp(p,
"no") != 0)) {
905 "rc_send_server: recvfrom: %s:%d: required attribute Message-Authenticator is missing or not first",
907 memset(secret,
'\0',
sizeof(secret));
915 memset(secret,
'\0',
sizeof(secret));
923 strappend(msg, PW_MAX_MSG_SIZE, &pos,
925 strappend(msg, PW_MAX_MSG_SIZE, &pos,
"\n");
931 switch (recv_auth->code) {
932 case PW_ACCESS_ACCEPT:
933 case PW_PASSWORD_ACK:
934 case PW_ACCOUNTING_RESPONSE:
938 case PW_ACCESS_REJECT:
939 case PW_PASSWORD_REJECT:
943 case PW_ACCESS_CHALLENGE:
944 result = CHALLENGE_RC;
948 rc_log(LOG_ERR,
"rc_send_server: received RADIUS server response neither ACCEPT nor REJECT, code=%d is invalid",
955 freeaddrinfo(auth_addr);
957 if (sfuncs->unlock) {
958 if (sfuncs->unlock(sfuncs->ptr) != 0) {
959 rc_log(LOG_ERR,
"%s: unlock error", __func__);
964 if(-1 == rc_reset_netns(&ns_def_hdl)) {
965 rc_log(LOG_ERR,
"rc_send_server: namespace %s reset failed", ns);
int rc_get_srcaddr(struct sockaddr *lia, const struct sockaddr *ria)
Find outbound interface address for a given destination.
void rc_avpair_remove(VALUE_PAIR **list, uint32_t attrid, uint32_t vendorspec)
Removes an attribute-value pair from the given list.
struct rc_aaa_ctx_st RC_AAA_CTX
VALUE_PAIR * rc_avpair_gen(rc_handle const *rh, VALUE_PAIR *pair, unsigned char const *ptr, int length, uint32_t vendorspec)
Decode a raw RADIUS attribute buffer into a VALUE_PAIR list.
#define MGMT_POLL_SECRET
Default for Merit radiusd.
int rc_send_server(rc_handle *rh, SEND_DATA *data, char *msg, rc_type type)
Sends a request to a RADIUS server and waits for the reply.
char * rc_conf_str(rc_handle const *rh, char const *optname)
Get the value of a config option.
int rc_find_server_addr(rc_handle const *rh, char const *server_name, struct addrinfo **info, char *secret, rc_type type)
Locate a server in the rh config or if not found, check for a servers file.
VALUE_PAIR * rc_avpair_add(rc_handle const *rh, VALUE_PAIR **list, uint32_t attrid, void const *pval, int len, uint32_t vendorspec)
Adds an attribute-value pair to the given list.
VALUE_PAIR * rc_avpair_get(VALUE_PAIR *vp, uint32_t attrid, uint32_t vendorspec)
Find the first attribute value-pair (which matches the given attribute) from the specified value-pair...
@ AUTH
Request for authentication server.
@ PW_NAS_IDENTIFIER
Its type is string.
@ PW_NAS_IP_ADDRESS
Its type is ipaddr.
@ PW_SERVICE_TYPE
Its type is integer.
@ PW_NAS_IPV6_ADDRESS
Its type is string.
@ PW_MESSAGE_AUTHENTICATOR
Its type is string.
@ PW_REPLY_MESSAGE
Its type is string.
@ PW_VENDOR_SPECIFIC
Its type is string.
@ PW_USER_PASSWORD
Its type is string.
@ PW_TYPE_IPADDR
The attribute is an IPv4 address in host-byte order.
@ PW_TYPE_IPV6ADDR
The attribute is an 128-bit IPv6 address.
@ PW_TYPE_IPV6PREFIX
The attribute is an IPv6 prefix; the lvalue will indicate its size.
@ PW_TYPE_INTEGER
The attribute is a 32-bit integer.
@ PW_TYPE_DATE
The attribute contains a 32-bit number indicating the seconds since epoch.
@ PW_TYPE_STRING
The attribute is a printable string.
@ RC_SOCKET_DTLS
DTLS socket.
@ RC_SOCKET_TLS
TLS socket.
Public API of the radcli library.
rc_attr_type type
attribute type.
uint64_t attribute
attribute numeric value of type rc_attr_id including vendor; use VENDOR() and ATTRID() to separate.
uint32_t lvalue
attribute value if type is PW_TYPE_INTEGER, PW_TYPE_DATE or PW_TYPE_IPADDR.
char strvalue[AUTH_STRING_LEN+1]
contains attribute value in other cases.
int timeout
Session timeout in seconds.
char * secret
Shared secret of RADIUS server.
uint8_t seq_nbr
Packet sequence number.
int svc_port
RADIUS protocol destination port.
char * server
Name/address of RADIUS server.
VALUE_PAIR * send_pairs
More a/v pairs to send.
VALUE_PAIR * receive_pairs
Where to place received a/v pairs.
uint8_t code
RADIUS packet code.