16#include <radcli/radcli.h>
23#if defined(HAVE_GNUTLS)
24# include <gnutls/gnutls.h>
25# include <gnutls/crypto.h>
33#define SCLOSE(fd) if (sfuncs->close_fd) sfuncs->close_fd(fd)
35static void rc_random_vector(
unsigned char *);
36static int rc_check_reply(AUTH_HDR *,
int,
char const *,
unsigned char const *,
53static int rc_pack_list(VALUE_PAIR * vp,
char *secret, AUTH_HDR * auth)
55 int length, i, pc, padded_length;
58 uint32_t lvalue, vendor;
59 unsigned char passbuf[RC_MAX(AUTH_PASS_LEN, CHAP_VALUE_LENGTH)];
60 unsigned char md5buf[256];
61 unsigned char *buf, *vector, *vsa_length_ptr;
66 vsa_length_ptr = NULL;
72 memcpy(buf, &vendor,
sizeof(uint32_t));
85 if (length > AUTH_PASS_LEN)
86 length = AUTH_PASS_LEN;
91 (AUTH_VECTOR_LEN - 1)) & ~(AUTH_VECTOR_LEN - 1);
94 *buf++ = padded_length + 2;
95 if (vsa_length_ptr != NULL)
96 *vsa_length_ptr += padded_length + 2;
99 memset((
char *)passbuf,
'\0', AUTH_PASS_LEN);
100 memcpy((
char *)passbuf, vp->
strvalue, (
size_t) length);
102 secretlen = strlen(secret);
103 vector = (
unsigned char *)auth->vector;
104 for (i = 0; i < padded_length; i += AUTH_VECTOR_LEN) {
106 strcpy((
char *)md5buf, secret);
107 memcpy((
char *)md5buf + secretlen, vector,
109 rc_md5_calc(buf, md5buf,
110 secretlen + AUTH_VECTOR_LEN);
116 for (pc = i; pc < (i + AUTH_VECTOR_LEN); pc++) {
117 *buf++ ^= passbuf[pc];
121 total_length += padded_length + 2;
129 if (vsa_length_ptr != NULL)
130 *vsa_length_ptr += length + 2;
131 memcpy(buf, vp->
strvalue, (
size_t) length);
133 total_length += length + 2;
139 if (vsa_length_ptr != NULL)
140 *vsa_length_ptr += length + 2;
141 memcpy(buf, vp->
strvalue, (
size_t) length);
143 total_length += length + 2;
149 if (vsa_length_ptr != NULL)
150 *vsa_length_ptr += length + 2;
151 memcpy(buf, vp->
strvalue, (
size_t) length);
153 total_length += length + 2;
159 *buf++ =
sizeof(uint32_t) + 2;
160 if (vsa_length_ptr != NULL)
161 *vsa_length_ptr +=
sizeof(uint32_t) + 2;
162 lvalue = htonl(vp->
lvalue);
163 memcpy(buf, (
char *)&lvalue,
sizeof(uint32_t));
164 buf +=
sizeof(uint32_t);
165 total_length +=
sizeof(uint32_t) + 2;
185static void strappend(
char *dest,
unsigned max_size,
int *pos,
const char *src)
187 unsigned len = strlen(src) + 1;
192 if (len + *pos > max_size) {
197 memcpy(&dest[*pos], src, len);
203static int populate_ctx(RC_AAA_CTX ** ctx,
char secret[MAX_SECRET_LENGTH + 1],
204 uint8_t vector[AUTH_VECTOR_LEN])
210 *ctx = malloc(
sizeof(RC_AAA_CTX));
212 memcpy((*ctx)->secret, secret,
sizeof((*ctx)->secret));
213 memcpy((*ctx)->request_vector, vector,
214 sizeof((*ctx)->request_vector));
234 return rc_send_server_ctx(rh, NULL, data, msg, type);
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];
257 totallen = ntohs(auth->length);
258 secretlen = (int)strlen(secret);
261 if ((totallen < 20) || (totallen > 4096)) {
263 "rc_check_reply: received RADIUS server response with invalid length");
268 if ((totallen + secretlen) > bufferlen) {
270 "rc_check_reply: not enough buffer space to verify RADIUS server response");
275 if (auth->id != seq_nbr) {
277 "rc_check_reply: received non-matching id in RADIUS server response");
281 memcpy((
char *)reply_digest, (
char *)auth->vector, AUTH_VECTOR_LEN);
282 memcpy((
char *)auth->vector, (
char *)vector, AUTH_VECTOR_LEN);
283 memcpy((
char *)auth + totallen, secret, secretlen);
285 rc_log(LOG_ERR,
"Calculating digest on:");
286 for (ptr = (u_char *) auth;
287 ptr < ((u_char *) auth) + totallen + secretlen; ptr += 32) {
292 for (i = 0; i < 32; i++) {
293 if (ptr + i >= ((u_char *) auth) + totallen + secretlen)
295 sprintf(buf + i * 2,
"%.2X", ptr[i]);
297 rc_log(LOG_ERR,
" %s", buf);
300 rc_md5_calc(calc_digest, (
unsigned char *)auth, totallen + secretlen);
302 rc_log(LOG_ERR,
"Calculated digest is:");
303 for (ptr = (u_char *) calc_digest; ptr < ((u_char *) calc_digest) + 16;
309 for (i = 0; i < 32; i++) {
310 if (ptr + i >= ((u_char *) calc_digest) + 16)
312 sprintf(buf + i * 2,
"%.2X", ptr[i]);
314 rc_log(LOG_ERR,
" %s", buf);
316 rc_log(LOG_ERR,
"Reply digest is:");
317 for (ptr = (u_char *) reply_digest;
318 ptr < ((u_char *) reply_digest) + 16; ptr += 32) {
323 for (i = 0; i < 32; i++) {
324 if (ptr + i >= ((u_char *) reply_digest) + 16)
326 sprintf(buf + i * 2,
"%.2X", ptr[i]);
328 rc_log(LOG_ERR,
" %s", buf);
332 if (rc_memcmp((
char *)reply_digest, (
char *)calc_digest,
333 AUTH_VECTOR_LEN) != 0) {
335 "rc_check_reply: received invalid reply digest from RADIUS server");
347static void rc_random_vector(
unsigned char *vector)
351#if defined(HAVE_GNUTLS)
352 if (gnutls_rnd(GNUTLS_RND_NONCE, vector, AUTH_VECTOR_LEN) >= 0) {
355#elif defined(HAVE_GETENTROPY)
356 if (getentropy(vector, AUTH_VECTOR_LEN) >= 0) {
359#elif defined(HAVE_DEV_URANDOM)
366 if ((fd = open(_PATH_DEV_URANDOM, O_RDONLY)) >= 0) {
373 readcount = read(fd, (
char *)pos, i);
374 if (readcount >= 0) {
378 if (errno != EINTR && errno != EAGAIN)
388 for (i = 0; i < AUTH_VECTOR_LEN;) {
390 memcpy((
char *)vector, (
char *)&randno,
sizeof(
int));
391 vector +=
sizeof(int);
413static int add_msg_auth_attr(rc_handle * rh,
char * secret,
414 AUTH_HDR *auth,
int total_length)
416 size_t secretlen = strlen(secret);
417 uint8_t *msg_auth = (uint8_t *)auth + total_length;
420 memset(&msg_auth[2], 0, MD5_DIGEST_SIZE);
422 auth->length = htons((
unsigned short)total_length);
425 uint8_t digest[MD5_DIGEST_SIZE];
426 rc_hmac_md5((uint8_t *)auth, (
size_t)total_length, (uint8_t *)secret, secretlen, digest);
427 memcpy(&msg_auth[2], digest, MD5_DIGEST_SIZE);
443static int validate_message_authenticator(VALUE_PAIR *vp,
const uint8_t *recv_buffer,
444 const size_t length,
const char *secret,
445 const unsigned char *req_auth)
447 uint8_t verify_buffer[RC_BUFFER_LEN];
448 uint8_t *idx = verify_buffer + AUTH_HDR_LEN;
449 const uint8_t *verify_end = verify_buffer +
sizeof(verify_buffer);
450 const char *received_message_authenticator = NULL;
451 uint8_t digest[MD5_DIGEST_SIZE];
454 if (AUTH_HDR_LEN + length >
sizeof(verify_buffer)) {
455 rc_log(LOG_ERR,
"%s: packet too large for verification buffer", __func__);
461 memcpy(verify_buffer, recv_buffer, AUTH_HDR_LEN + length);
462 memcpy(verify_buffer + 4, req_auth, AUTH_VECTOR_LEN);
463 for (; vp != NULL; vp = vp->next) {
472 if (idx + 2 + attr_len > verify_end) {
473 rc_log(LOG_ERR,
"%s: attribute overflows verification buffer", __func__);
479 if (vp->
lvalue != MD5_DIGEST_SIZE) {
480 rc_log(LOG_ERR,
"%s: Message-Authenticator has wrong length %u",
484 memset(idx,
'\0', MD5_DIGEST_SIZE);
485 received_message_authenticator = vp->
strvalue;
492 if (received_message_authenticator == NULL) {
497 rc_hmac_md5(verify_buffer, AUTH_HDR_LEN + length, (uint8_t *)secret, strlen(secret), digest);
498 return rc_memcmp(received_message_authenticator, digest, MD5_DIGEST_SIZE);
513int rc_send_server_ctx(rc_handle * rh, RC_AAA_CTX ** ctx, SEND_DATA * data,
517 AUTH_HDR *auth, *recv_auth;
518 char *server_name, *p;
519 struct sockaddr_storage our_sockaddr;
520 struct addrinfo *auth_addr = NULL;
526 const rc_sockets_override *sfuncs;
527 unsigned discover_local_ip;
529 char secret[MAX_SECRET_LENGTH + 1];
530 unsigned char vector[AUTH_VECTOR_LEN];
531 uint8_t recv_buffer[RC_BUFFER_LEN];
532 uint8_t send_buffer[RC_BUFFER_LEN];
538 double start_time, timeout;
539 struct sockaddr_storage *ss_set = NULL;
540 char *server_type =
"auth";
544 server_name = data->
server;
545 if (server_name == NULL || server_name[0] ==
'\0')
550 if(-1 == rc_set_netns(ns, &ns_def_hdl)) {
551 rc_log(LOG_ERR,
"rc_send_server: namespace %s set failed", ns);
556 (vp->
lvalue == PW_ADMINISTRATIVE)) {
559 rc_getaddrinfo(server_name,
560 type ==
AUTH ? PW_AI_AUTH : PW_AI_ACCT);
561 if (auth_addr == NULL) {
566 if (data->
secret != NULL) {
567 strlcpy(secret, data->
secret, MAX_SECRET_LENGTH);
574 (rh, server_name, &auth_addr, secret, type) != 0) {
576 "rc_send_server: unable to find server: %s",
586 if (sfuncs->static_secret) {
588 strlcpy(secret, sfuncs->static_secret,
593 if (sfuncs->lock(sfuncs->ptr) != 0) {
594 rc_log(LOG_ERR,
"%s: lock error", __func__);
601 discover_local_ip = 0;
602 if (our_sockaddr.ss_family == AF_INET) {
603 if (((
struct sockaddr_in *)(&our_sockaddr))->sin_addr.s_addr ==
605 discover_local_ip = 1;
609 DEBUG(LOG_ERR,
"DEBUG: rc_send_server: creating socket to: %s",
611 if (discover_local_ip) {
613 if (result != OK_RC) {
614 memset(secret,
'\0',
sizeof(secret));
616 "rc_send_server: cannot figure our own address");
621 if (sfuncs->get_fd) {
622 sockfd = sfuncs->get_fd(sfuncs->ptr, SA(&our_sockaddr));
624 memset(secret,
'\0',
sizeof(secret));
625 rc_log(LOG_ERR,
"rc_send_server: socket: %s",
632 if(our_sockaddr.ss_family == AF_INET6) {
634 char *non_temp_addr =
rc_conf_str(rh,
"use-public-addr");
635 if (non_temp_addr && (strcasecmp(non_temp_addr,
"true") == 0)) {
636#if defined(__linux__)
637 int sock_opt = IPV6_PREFER_SRC_PUBLIC;
638 if (setsockopt(sockfd, IPPROTO_IPV6, IPV6_ADDR_PREFERENCES,
639 &sock_opt,
sizeof(sock_opt)) != 0) {
640 rc_log(LOG_ERR,
"rc_send_server: setsockopt: %s",
645#elif defined(BSD) || defined(__APPLE__)
647 if (setsockopt(sockfd, IPPROTO_IPV6, IPV6_PREFER_TEMPADDR,
648 &sock_opt,
sizeof(sock_opt)) != 0) {
649 rc_log(LOG_ERR,
"rc_send_server: setsockopt: %s",
655 rc_log(LOG_INFO,
"rc_send_server: Usage of non-temporary IPv6"
656 " address is not supported in this system");
661 retry_max = data->retries;
665 if (our_sockaddr.ss_family == AF_INET)
666 ((
struct sockaddr_in *)auth_addr->ai_addr)->sin_port =
667 htons((
unsigned short)data->
svc_port);
669 ((
struct sockaddr_in6 *)auth_addr->ai_addr)->sin6_port =
670 htons((
unsigned short)data->
svc_port);
676 if (rh->nas_addr_set) {
680 ss_set = &rh->nas_addr;
684 ss_set = &our_sockaddr;
688 if (ss_set->ss_family == AF_INET) {
691 *) (&((
struct sockaddr_in *)ss_set)->
699 p = &((
struct sockaddr_in6 *)ss_set)->sin6_addr;
717 auth = (AUTH_HDR *) send_buffer;
718 auth->code = data->
code;
721 if (data->
code == PW_ACCOUNTING_REQUEST) {
722 server_type =
"acct";
724 rc_pack_list(data->
send_pairs, secret, auth) + AUTH_HDR_LEN;
726 tlen = htons((
unsigned short)total_length);
727 memcpy(&auth->length, &tlen,
sizeof(uint16_t));
729 memset((
char *)auth->vector, 0, AUTH_VECTOR_LEN);
730 secretlen = strlen(secret);
731 memcpy((
char *)auth + total_length, secret, secretlen);
732 rc_md5_calc(vector, (
unsigned char *)auth,
733 total_length + secretlen);
734 memcpy((
char *)auth->vector, (
char *)vector, AUTH_VECTOR_LEN);
736 rc_random_vector(vector);
737 memcpy((
char *)auth->vector, (
char *)vector, AUTH_VECTOR_LEN);
740 rc_pack_list(data->
send_pairs, secret, auth) + AUTH_HDR_LEN;
742 total_length = add_msg_auth_attr(rh, secret, auth, total_length);
744 auth->length = htons((
unsigned short)total_length);
748 char our_addr_txt[50] =
"";
749 char auth_addr_txt[50] =
"";
751 getnameinfo(SA(&our_sockaddr), SS_LEN(&our_sockaddr), NULL, 0,
752 our_addr_txt,
sizeof(our_addr_txt), NI_NUMERICHOST);
753 getnameinfo(auth_addr->ai_addr, auth_addr->ai_addrlen, NULL, 0,
754 auth_addr_txt,
sizeof(auth_addr_txt),
758 "DEBUG: timeout=%d retries=%d local %s : 0, remote %s : %u\n",
759 data->
timeout, retry_max, our_addr_txt, auth_addr_txt,
766 sfuncs->sendto(sfuncs->ptr, sockfd, (
char *)auth,
767 (
unsigned int)total_length, (
int)0,
768 SA(auth_addr->ai_addr),
769 auth_addr->ai_addrlen);
770 }
while (result == -1 && errno == EINTR);
772 result = errno == ENETUNREACH ? NETUNREACH_RC : ERROR_RC;
773 rc_log(LOG_ERR,
"%s: socket: %s", __FUNCTION__,
780 if (sfuncs->get_active_fd) {
781 int new_fd = sfuncs->get_active_fd(sfuncs->ptr);
788 start_time = rc_getmtime();
789 for (timeout = data->
timeout; timeout > 0;
790 timeout -= rc_getmtime() - start_time) {
791 result = poll(&pfd, 1, timeout * 1000);
792 if (result != -1 || errno != EINTR)
797 rc_log(LOG_ERR,
"rc_send_server: poll: %s",
799 memset(secret,
'\0',
sizeof(secret));
805 if (result == 1 && (pfd.revents & POLLIN) != 0) {
806 salen = auth_addr->ai_addrlen;
808 length = sfuncs->recvfrom(sfuncs->ptr, sockfd,
815 }
while (length == -1 && errno == EINTR);
820 "rc_send_server: recvfrom: %s:%d: %s",
823 if (length == -1 && (e == EAGAIN || e == EINTR))
826 memset(secret,
'\0',
sizeof(secret));
831 recv_auth = (AUTH_HDR *) recv_buffer;
833 if (length < AUTH_HDR_LEN
834 || length < ntohs(recv_auth->length)) {
836 "rc_send_server: recvfrom: %s:%d: reply is too short",
839 memset(secret,
'\0',
sizeof(secret));
845 rc_check_reply(recv_auth, RC_BUFFER_LEN, secret,
847 if (result != BADRESPID_RC) {
860 if (retries++ >= retry_max) {
861 char radius_server_ip[128];
862 struct sockaddr_in *si =
863 (
struct sockaddr_in *)auth_addr->ai_addr;
864 inet_ntop(auth_addr->ai_family, &si->sin_addr,
865 radius_server_ip,
sizeof(radius_server_ip));
867 "rc_send_server: no reply from RADIUS %s server %s:%u",
868 server_type, radius_server_ip, data->
svc_port);
870 memset(secret,
'\0',
sizeof(secret));
879 if (length > ntohs(recv_auth->length))
880 length = ntohs(recv_auth->length);
885 attr = recv_buffer + AUTH_HDR_LEN;
886 while (attr < (recv_buffer + length)) {
889 "rc_send_server: recvfrom: %s:%d: attribute zero is invalid",
892 memset(secret,
'\0',
sizeof(secret));
899 "rc_send_server: recvfrom: %s:%d: attribute length is too small",
902 memset(secret,
'\0',
sizeof(secret));
907 if ((attr + attr[1]) > (recv_buffer + length)) {
909 "rc_send_server: recvfrom: %s:%d: attribute overflows the packet",
912 memset(secret,
'\0',
sizeof(secret));
920 length = ntohs(recv_auth->length) - AUTH_HDR_LEN;
929 result = populate_ctx(ctx, secret, vector);
930 if (result != OK_RC) {
931 memset(secret,
'\0',
sizeof(secret));
942 if (validate_message_authenticator(data->
receive_pairs, recv_buffer, length, secret, vector)) {
944 "rc_send_server: recvfrom: %s:%d: received attribute Message-Authenticator is incorrect",
946 memset(secret,
'\0',
sizeof(secret));
951 p =
rc_conf_str(rh,
"require-message-authenticator");
952 if (p == NULL || (strcasecmp(p,
"false") != 0 && strcasecmp(p,
"no") != 0)) {
954 "rc_send_server: recvfrom: %s:%d: required attribute Message-Authenticator is missing or not first",
956 memset(secret,
'\0',
sizeof(secret));
963 memset(secret,
'\0',
sizeof(secret));
971 strappend(msg, PW_MAX_MSG_SIZE, &pos,
973 strappend(msg, PW_MAX_MSG_SIZE, &pos,
"\n");
979 switch (recv_auth->code) {
980 case PW_ACCESS_ACCEPT:
981 case PW_PASSWORD_ACK:
982 case PW_ACCOUNTING_RESPONSE:
986 case PW_ACCESS_REJECT:
987 case PW_PASSWORD_REJECT:
991 case PW_ACCESS_CHALLENGE:
992 result = CHALLENGE_RC;
996 rc_log(LOG_ERR,
"rc_send_server: received RADIUS server response neither ACCEPT nor REJECT, code=%d is invalid",
1003 freeaddrinfo(auth_addr);
1005 if (sfuncs->unlock) {
1006 if (sfuncs->unlock(sfuncs->ptr) != 0) {
1007 rc_log(LOG_ERR,
"%s: unlock error", __func__);
1012 if(-1 == rc_reset_netns(&ns_def_hdl)) {
1013 rc_log(LOG_ERR,
"rc_send_server: namespace %s reset failed", ns);
int rc_get_srcaddr(struct sockaddr *lia, const struct sockaddr *ria)
void rc_own_bind_addr(rc_handle *rh, struct sockaddr_storage *lia)
void rc_avpair_remove(VALUE_PAIR **list, uint32_t attrid, uint32_t vendorspec)
VALUE_PAIR * rc_avpair_gen(rc_handle const *rh, VALUE_PAIR *pair, unsigned char const *ptr, int length, uint32_t vendorspec)
#define MGMT_POLL_SECRET
Default for Merit radiusd.
int rc_send_server(rc_handle *rh, SEND_DATA *data, char *msg, rc_type type)
char * rc_conf_str(rc_handle const *rh, char const *optname)
int rc_find_server_addr(rc_handle const *rh, char const *server_name, struct addrinfo **info, char *secret, rc_type type)
VALUE_PAIR * rc_avpair_add(rc_handle const *rh, VALUE_PAIR **list, uint32_t attrid, void const *pval, int len, uint32_t vendorspec)
VALUE_PAIR * rc_avpair_get(VALUE_PAIR *vp, uint32_t attrid, uint32_t vendorspec)
@ 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_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.