15#include <radcli/radcli.h>
24#if defined(HAVE_GNUTLS)
25# include <gnutls/gnutls.h>
26# include <gnutls/crypto.h>
37#define SCLOSE(fd) do { if (sfuncs->close_fd) sfuncs->close_fd(fd); (fd) = -1; } while (0)
57int populate_ctx(
RC_AAA_CTX ** ctx,
char secret[MAX_SECRET_LENGTH + 1],
58 uint8_t vector[AUTH_VECTOR_LEN])
66 memcpy((*ctx)->secret, secret,
sizeof((*ctx)->secret));
67 memcpy((*ctx)->request_vector, vector,
68 sizeof((*ctx)->request_vector));
85int rc_check_reply(AUTH_HDR * auth,
int bufferlen,
char const *secret,
86 unsigned char const *vector, uint8_t seq_nbr)
90 unsigned char calc_digest[AUTH_VECTOR_LEN];
91 unsigned char reply_digest[AUTH_VECTOR_LEN];
93 totallen = ntohs(auth->length);
94 secretlen = (int)strlen(secret);
97 if ((totallen < 20) || (totallen > 4096)) {
99 "rc_check_reply: received RADIUS server response with invalid length");
104 if ((totallen + secretlen) > bufferlen) {
106 "rc_check_reply: not enough buffer space to verify RADIUS server response");
111 if (auth->id != seq_nbr) {
113 "rc_check_reply: received non-matching id in RADIUS server response");
117 memcpy((
char *)reply_digest, (
char *)auth->vector, AUTH_VECTOR_LEN);
118 memcpy((
char *)auth->vector, (
char *)vector, AUTH_VECTOR_LEN);
119 memcpy((
char *)auth + totallen, secret, secretlen);
120 rc_md5_calc(calc_digest, (
unsigned char *)auth, totallen + secretlen);
122 if (rc_memcmp((
char *)reply_digest, (
char *)calc_digest,
123 AUTH_VECTOR_LEN) != 0) {
125 "rc_check_reply: received invalid reply digest from RADIUS server");
143int add_msg_auth_attr(rc_handle * rh,
char * secret,
144 AUTH_HDR *auth,
int total_length)
146 size_t secretlen = rc_secret_len(secret);
147 uint8_t *msg_auth = (uint8_t *)auth + total_length;
148 msg_auth[0] = PW_MESSAGE_AUTHENTICATOR;
150 memset(&msg_auth[2], 0, MD5_DIGEST_SIZE);
152 auth->length = htons((
unsigned short)total_length);
155 uint8_t digest[MD5_DIGEST_SIZE];
156 rc_hmac_md5((uint8_t *)auth, (
size_t)total_length, (uint8_t *)secret, secretlen, digest);
157 memcpy(&msg_auth[2], digest, MD5_DIGEST_SIZE);
175int validate_message_authenticator(
const uint8_t *recv_buffer,
176 size_t length,
const char *secret,
177 const unsigned char *req_auth)
179 uint8_t verify_buffer[RC_BUFFER_LEN];
181 uint8_t ma_copy[MD5_DIGEST_SIZE];
182 uint8_t digest[MD5_DIGEST_SIZE];
183 uint8_t attr_type, attr_len;
186 if (AUTH_HDR_LEN + length >
sizeof(verify_buffer)) {
187 rc_log(LOG_ERR,
"%s: packet too large for verification buffer", __func__);
193 memcpy(verify_buffer, recv_buffer, AUTH_HDR_LEN + length);
194 memcpy(verify_buffer + 4, req_auth, AUTH_VECTOR_LEN);
195 pb_init_read(&vb, verify_buffer + AUTH_HDR_LEN, length, length);
197 while (pb_len(&vb) >= 2) {
198 attr_type = vb.data[0];
199 attr_len = vb.data[1];
200 if (attr_len < 2 || (
size_t)attr_len > pb_len(&vb))
203 if (attr_type == PW_MESSAGE_AUTHENTICATOR) {
204 if (attr_len != 2 + MD5_DIGEST_SIZE) {
205 rc_log(LOG_ERR,
"%s: Message-Authenticator has wrong length %u",
206 __func__, (
unsigned)(attr_len - 2));
210 memcpy(ma_copy, vb.data + 2, MD5_DIGEST_SIZE);
211 memset(vb.data + 2,
'\0', MD5_DIGEST_SIZE);
215 assert(pb_pull(&vb, attr_len) == 0);
221 rc_hmac_md5(verify_buffer, AUTH_HDR_LEN + length, (uint8_t *)secret, rc_secret_len(secret), digest);
222 return rc_memcmp(ma_copy, digest, MD5_DIGEST_SIZE);
309static int decode_reply(rc_handle *rh,
RC_AAA_CTX **ctx,
const char *server_name,
310 unsigned short svc_port,
rc_type type,
311 char secret[MAX_SECRET_LENGTH + 1],
const unsigned char *vector,
312 uint8_t *recv_buf,
size_t recv_buf_cap,
313 size_t *recv_len, uint8_t *out_code)
315 AUTH_HDR *recv_auth = (AUTH_HDR *)recv_buf;
316 int length = ntohs(recv_auth->length);
318 uint8_t attr_type, attr_len;
321 if ((
size_t)length > recv_buf_cap)
322 length = (int)recv_buf_cap;
325 pb_init_read(&rb, recv_buf, length, recv_buf_cap);
326 if (pb_pull(&rb, AUTH_HDR_LEN) != 0) {
327 rc_log(LOG_ERR,
"%s: %s:%d: reply shorter than the RADIUS header",
328 __func__, server_name, svc_port);
331 while (pb_len(&rb) > 0) {
332 if (pb_peek_byte(&rb, 0, &attr_type) < 0 || pb_peek_byte(&rb, 1, &attr_len) < 0) {
333 rc_log(LOG_ERR,
"%s: %s:%d: truncated attribute", __func__, server_name, svc_port);
336 if (attr_type == 0) {
337 rc_log(LOG_ERR,
"%s: %s:%d: attribute zero is invalid", __func__, server_name, svc_port);
341 rc_log(LOG_ERR,
"%s: %s:%d: attribute length is too small", __func__, server_name, svc_port);
344 if (attr_len > pb_len(&rb)) {
345 rc_log(LOG_ERR,
"%s: %s:%d: attribute overflows the packet", __func__, server_name, svc_port);
348 assert(pb_pull(&rb, attr_len) == 0);
351 length = ntohs(recv_auth->length) - AUTH_HDR_LEN;
355 result = populate_ctx(ctx, secret, (
unsigned char *)vector);
368 pb_init_read(&mb, recv_buf + AUTH_HDR_LEN, (
size_t)length, (
size_t)length);
369 while (pb_len(&mb) > 0) {
370 assert(pb_peek_byte(&mb, 0, &mtype) == 0);
371 assert(pb_peek_byte(&mb, 1, &mlen) == 0);
372 if (mtype == PW_MESSAGE_AUTHENTICATOR) {
376 assert(pb_pull(&mb, mlen) == 0);
380 if (validate_message_authenticator(recv_buf, (
size_t)length, secret, vector)) {
381 rc_log(LOG_ERR,
"%s: %s:%d: received attribute Message-Authenticator is incorrect",
382 __func__, server_name, svc_port);
388 if (length == 0 || recv_buf[AUTH_HDR_LEN] != PW_MESSAGE_AUTHENTICATOR) {
389 char *p = rc_conf_str_id(rh, OPT_REQUIRE_MESSAGE_AUTHENTICATOR);
390 if (p == NULL || (strcasecmp(p,
"false") != 0 &&
391 strcasecmp(p,
"no") != 0)) {
392 rc_log(LOG_ERR,
"%s: %s:%d: required attribute Message-Authenticator "
393 "is missing or not first", __func__, server_name, svc_port);
401 uint8_t code = recv_auth->code;
403 *recv_len = (size_t)length;
406 if (recv_buf_cap > (
size_t)AUTH_HDR_LEN)
407 memmove(recv_buf, recv_buf + AUTH_HDR_LEN, (
size_t)length);
410 case PW_ACCESS_ACCEPT:
411 case PW_PASSWORD_ACK:
412 case PW_ACCOUNTING_RESPONSE:
414 case PW_ACCESS_REJECT:
415 case PW_PASSWORD_REJECT:
417 case PW_ACCESS_CHALLENGE:
420 rc_log(LOG_ERR,
"%s: received RADIUS server response neither ACCEPT nor "
421 "REJECT, code=%d is invalid", __func__, code);
470int radcli_transport_exchange(rc_handle *rh,
RC_AAA_CTX **ctx,
471 char *server_name,
unsigned short svc_port,
472 char secret[MAX_SECRET_LENGTH + 1],
int mgmt_secret,
473 int timeout,
int retries,
int no_wait,
rc_type type,
474 const uint8_t *send_buf,
int send_len,
475 uint8_t *recv_buf,
size_t recv_buf_cap,
size_t *recv_len,
478 struct addrinfo *auth_addr = NULL, *cur_addr;
479 const rc_sockets_override *sfuncs;
484 char *server_type = (type ==
ACCT) ?
"acct" :
"auth";
485 const unsigned char *vector = send_buf + 4;
486 uint8_t seq_nbr = send_buf[1];
488 if (server_name == NULL || server_name[0] ==
'\0')
490 if (send_len < AUTH_HDR_LEN)
493 ns = rc_conf_str_id(rh, OPT_NAMESPACE);
495 if (-1 == rc_set_netns(ns, &ns_def_hdl)) {
496 rc_log(LOG_ERR,
"radcli_transport_exchange: namespace %s set failed", ns);
502 auth_addr = rc_getaddrinfo(server_name, type ==
AUTH ? PW_AI_AUTH : PW_AI_ACCT);
503 if (auth_addr == NULL) {
508 if (radcli2_priv_find_server_addr(rh, server_name, &auth_addr, secret, type) != 0) {
509 rc_log(LOG_ERR,
"radcli_transport_exchange: unable to find server: %s",
518 if (sfuncs->static_secret) {
520 strlcpy(secret, sfuncs->static_secret, MAX_SECRET_LENGTH + 1);
524 if (sfuncs->lock(sfuncs->ptr) != 0) {
525 rc_log(LOG_ERR,
"%s: lock error", __func__);
533 for (cur_addr = auth_addr; cur_addr != NULL; cur_addr = cur_addr->ai_next) {
534 struct sockaddr_storage our_sockaddr;
535 unsigned discover_local_ip;
536 int retry_max = retries;
537 int this_retries = 0;
540 if (cur_addr->ai_family == AF_INET)
541 ((
struct sockaddr_in *)cur_addr->ai_addr)->sin_port = htons(svc_port);
543 ((
struct sockaddr_in6 *)cur_addr->ai_addr)->sin6_port = htons(svc_port);
546 rc_own_bind_addr(rh, &our_sockaddr);
547 discover_local_ip = 0;
548 if (our_sockaddr.ss_family == AF_INET &&
549 ((
struct sockaddr_in *)(&our_sockaddr))->sin_addr.s_addr == INADDR_ANY)
550 discover_local_ip = 1;
552 if (discover_local_ip) {
553 result = radcli2_priv_get_srcaddr(SA(&our_sockaddr), cur_addr->ai_addr);
554 if (result != OK_RC) {
555 rc_log(LOG_ERR,
"radcli_transport_exchange: cannot figure our own address");
560 if (sfuncs->get_fd) {
561 sockfd = sfuncs->get_fd(sfuncs->ptr, SA(&our_sockaddr));
563 rc_log(LOG_ERR,
"radcli_transport_exchange: socket: %s", strerror(errno));
569 if (our_sockaddr.ss_family == AF_INET6) {
570 char *non_temp_addr = rc_conf_str_id(rh, OPT_USE_PUBLIC_ADDR);
571 if (non_temp_addr && strcasecmp(non_temp_addr,
"true") == 0) {
572#if defined(__linux__)
573 int sock_opt = IPV6_PREFER_SRC_PUBLIC;
574 if (setsockopt(sockfd, IPPROTO_IPV6, IPV6_ADDR_PREFERENCES,
575 &sock_opt,
sizeof(sock_opt)) != 0) {
576 rc_log(LOG_ERR,
"radcli_transport_exchange: setsockopt: %s",
582#elif defined(BSD) || defined(__APPLE__)
584 if (setsockopt(sockfd, IPPROTO_IPV6, IPV6_PREFER_TEMPADDR,
585 &sock_opt,
sizeof(sock_opt)) != 0) {
586 rc_log(LOG_ERR,
"radcli_transport_exchange: setsockopt: %s",
593 rc_log(LOG_INFO,
"radcli_transport_exchange: Usage of non-temporary "
594 "IPv6 address is not supported in this system");
600 char our_addr_txt[50] =
"", addr_txt[50] =
"";
602 getnameinfo(SA(&our_sockaddr), SS_LEN(&our_sockaddr), NULL, 0,
603 our_addr_txt,
sizeof(our_addr_txt), NI_NUMERICHOST);
604 getnameinfo(cur_addr->ai_addr, cur_addr->ai_addrlen, NULL, 0,
605 addr_txt,
sizeof(addr_txt), NI_NUMERICHOST);
607 "DEBUG: radcli_transport_exchange: timeout=%d retries=%d local %s : 0, "
608 "remote %s : %u\n", timeout, retry_max, our_addr_txt, addr_txt, svc_port);
615 double start_time, poll_timeout;
618 result = sfuncs->sendto(sfuncs->ptr, sockfd, (
const char *)send_buf,
619 (
unsigned int)send_len, 0,
620 SA(cur_addr->ai_addr), cur_addr->ai_addrlen);
621 }
while (result == -1 && errno == EINTR);
623 result = errno == ENETUNREACH ? NETUNREACH_RC : ERROR_RC;
624 rc_log(LOG_ERR,
"%s: socket: %s", __FUNCTION__, strerror(errno));
630 result = populate_ctx(ctx, secret, (
unsigned char *)vector);
634 if (sfuncs->get_active_fd) {
635 int new_fd = sfuncs->get_active_fd(sfuncs->ptr);
642 start_time = rc_getmtime();
643 for (poll_timeout = timeout; poll_timeout > 0;
644 poll_timeout -= rc_getmtime() - start_time) {
645 result = poll(&pfd, 1, poll_timeout * 1000);
646 if (result != -1 || errno != EINTR)
651 rc_log(LOG_ERR,
"radcli_transport_exchange: poll: %s", strerror(errno));
657 if (result == 1 && (pfd.revents & POLLIN) != 0) {
658 salen = cur_addr->ai_addrlen;
660 recv_length = sfuncs->recvfrom(sfuncs->ptr, sockfd,
662 (
int)recv_buf_cap, 0,
663 SA(cur_addr->ai_addr), &salen);
664 }
while (recv_length == -1 && errno == EINTR);
666 if (recv_length <= 0) {
668 rc_log(LOG_ERR,
"radcli_transport_exchange: recvfrom: %s:%d: %s",
669 server_name, svc_port, strerror(e));
670 if (recv_length == -1 && (e == EAGAIN || e == EINTR))
678 AUTH_HDR *recv_auth = (AUTH_HDR *)recv_buf;
680 if (recv_length < AUTH_HDR_LEN ||
681 recv_length < ntohs(recv_auth->length)) {
682 rc_log(LOG_ERR,
"radcli_transport_exchange: recvfrom: "
683 "%s:%d: reply is too short", server_name, svc_port);
689 result = rc_check_reply(recv_auth, (
int)recv_buf_cap, secret,
703 if (this_retries++ >= retry_max) {
705 struct sockaddr_in *si = (
struct sockaddr_in *)cur_addr->ai_addr;
707 inet_ntop(cur_addr->ai_family, &si->sin_addr, server_ip,
sizeof(server_ip));
708 rc_log(LOG_ERR,
"radcli_transport_exchange: no reply from RADIUS "
709 "%s server %s:%u", server_type, server_ip, svc_port);
722 result = decode_reply(rh, ctx, server_name, svc_port, type, secret, vector,
723 recv_buf, recv_buf_cap, recv_len, out_code);
730 freeaddrinfo(auth_addr);
731 if (sfuncs->unlock) {
732 if (sfuncs->unlock(sfuncs->ptr) != 0)
733 rc_log(LOG_ERR,
"%s: unlock error", __func__);
737 if (-1 == rc_reset_netns(&ns_def_hdl)) {
738 rc_log(LOG_ERR,
"radcli_transport_exchange: namespace %s reset failed", ns);
750static int reqreg_peer_matches(
const struct sockaddr *from,
const struct sockaddr *expected)
752 if (from->sa_family != expected->sa_family)
754 if (from->sa_family == AF_INET) {
755 const struct sockaddr_in *a = (
const struct sockaddr_in *)from;
756 const struct sockaddr_in *b = (
const struct sockaddr_in *)expected;
757 return a->sin_port == b->sin_port &&
758 memcmp(&a->sin_addr, &b->sin_addr,
sizeof(a->sin_addr)) == 0;
761 const struct sockaddr_in6 *a = (
const struct sockaddr_in6 *)from;
762 const struct sockaddr_in6 *b = (
const struct sockaddr_in6 *)expected;
763 return a->sin6_port == b->sin6_port &&
764 memcmp(&a->sin6_addr, &b->sin6_addr,
sizeof(a->sin6_addr)) == 0;
772static int reqreg_ensure(rc_handle *rh)
774 if (rh->reqreg != NULL)
777 pthread_mutex_lock(&rh->reqreg_init_lock);
778 if (rh->reqreg == NULL) {
779 struct radcli_reqreg *reg = calloc(1,
sizeof(*reg));
781 pthread_mutex_unlock(&rh->reqreg_init_lock);
784 pthread_mutex_init(®->lock, NULL);
787 pthread_mutex_unlock(&rh->reqreg_init_lock);
807int radcli2_priv_reqreg_reserve(rc_handle *rh,
struct radcli_async_send_st *owner, uint8_t *out_id)
809 struct radcli_reqreg *reg;
811 uint64_t best_seq = 0;
814 if (rh == NULL || owner == NULL || out_id == NULL)
816 if (reqreg_ensure(rh) != 0)
820 pthread_mutex_lock(®->lock);
821 for (i = 0; i < RADCLI_CTX_MAX_INFLIGHT; i++) {
822 if (reg->slots[i].valid)
826 if (best == -1 || reg->slots[i].free_seq < best_seq) {
828 best_seq = reg->slots[i].free_seq;
832 pthread_mutex_unlock(®->lock);
833 rc_log(LOG_ERR,
"%s: no free Identifier (%d requests already in flight)",
834 __func__, RADCLI_CTX_MAX_INFLIGHT);
837 reg->slots[best].valid = 1;
838 reg->slots[best].armed = 0;
839 reg->slots[best].owner = owner;
840 pthread_mutex_unlock(®->lock);
842 *out_id = (uint8_t)best;
851void radcli2_priv_reqreg_release(rc_handle *rh,
int slot)
853 struct radcli_reqreg *reg;
855 if (rh == NULL || rh->reqreg == NULL || slot < 0 || slot >= RADCLI_CTX_MAX_INFLIGHT)
859 pthread_mutex_lock(®->lock);
860 reg->slots[slot].valid = 0;
861 reg->slots[slot].armed = 0;
862 reg->slots[slot].owner = NULL;
863 memset(reg->slots[slot].secret, 0,
sizeof(reg->slots[slot].secret));
864 reg->slots[slot].free_seq = ++reg->free_seq_ctr;
865 pthread_mutex_unlock(®->lock);
874int radcli2_priv_reqreg_earliest_deadline_ms(rc_handle *rh)
876 struct radcli_reqreg *reg;
881 if (rh == NULL || rh->reqreg == NULL)
885 pthread_mutex_lock(®->lock);
886 for (i = 0; i < RADCLI_CTX_MAX_INFLIGHT; i++) {
887 if (!reg->slots[i].valid || !reg->slots[i].armed)
889 if (!have_one || reg->slots[i].deadline < earliest) {
890 earliest = reg->slots[i].deadline;
894 pthread_mutex_unlock(®->lock);
900 double remaining = earliest - rc_getmtime();
904 return (
int)(remaining * 1000) + 1;
918void radcli2_priv_reqreg_drain(rc_handle *rh)
920 struct radcli_reqreg *reg;
921 const rc_sockets_override *sfuncs;
925 if (rh == NULL || rh->reqreg == NULL)
930 ns = rc_conf_str_id(rh, OPT_NAMESPACE);
934 uint8_t recv_buf[RC_BUFFER_LEN];
935 struct sockaddr_storage from;
936 socklen_t fromlen =
sizeof(from);
940 struct radcli_reqreg_slot *rslot;
944 sockfd = is_radsec ? (sfuncs->get_active_fd ? sfuncs->get_active_fd(sfuncs->ptr) : -1)
949 if (ns != NULL && -1 == rc_set_netns(ns, &ns_def_hdl)) {
950 rc_log(LOG_ERR,
"%s: namespace %s set failed", __func__, ns);
959 sfuncs->lock(sfuncs->ptr);
962 recv_length = radcli2_priv_tls_try_recv(rh, recv_buf,
sizeof(recv_buf));
965 recv_length = sfuncs->recvfrom(sfuncs->ptr, sockfd, (
char *)recv_buf,
966 sizeof(recv_buf), 0, SA(&from), &fromlen);
967 }
while (recv_length == -1 && errno == EINTR);
968 if (recv_length == -1 && errno == EAGAIN)
973 sfuncs->unlock(sfuncs->ptr);
975 rc_reset_netns(&ns_def_hdl);
977 if (recv_length <= 0)
982 if ((
size_t)recv_length < AUTH_HDR_LEN)
985 recv_auth = (AUTH_HDR *)recv_buf;
988 pthread_mutex_lock(®->lock);
989 rslot = ®->slots[id];
990 if (!rslot->valid || !rslot->armed) {
991 pthread_mutex_unlock(®->lock);
994 if (!is_radsec && !reqreg_peer_matches(SA(&from), SA(&rslot->peer))) {
995 pthread_mutex_unlock(®->lock);
999 rc_result = rc_check_reply(recv_auth, (
int)
sizeof(recv_buf), rslot->secret,
1001 if (rc_result != OK_RC) {
1008 pthread_mutex_unlock(®->lock);
1013 struct radcli_async_send_st *owner = rslot->owner;
1014 char secret_copy[MAX_SECRET_LENGTH + 1];
1015 unsigned char vector_copy[AUTH_VECTOR_LEN];
1016 char server_name_copy[128];
1017 unsigned short svc_port_copy;
1019 size_t recv_len = 0;
1020 uint8_t reply_code = 0;
1022 radcli_avp_list *attrs = NULL;
1024 memcpy(secret_copy, rslot->secret,
sizeof(secret_copy));
1025 memcpy(vector_copy, rslot->vector,
sizeof(vector_copy));
1026 memcpy(server_name_copy, rslot->server_name,
sizeof(server_name_copy));
1027 svc_port_copy = rslot->svc_port;
1028 type_copy = rslot->type;
1036 rslot->owner = NULL;
1037 memset(rslot->secret, 0,
sizeof(rslot->secret));
1038 rslot->free_seq = ++reg->free_seq_ctr;
1039 pthread_mutex_unlock(®->lock);
1041 decode_result = decode_reply(rh, NULL, server_name_copy, svc_port_copy,
1042 type_copy, secret_copy, vector_copy,
1043 recv_buf,
sizeof(recv_buf), &recv_len, &reply_code);
1044 if (decode_result == OK_RC || decode_result == REJECT_RC ||
1045 decode_result == CHALLENGE_RC) {
1047 radcli_avp_decode(rh, secret_copy, vector_copy, recv_buf, recv_len, 0,
1049 decode_result = ERROR_RC;
1051 memset(secret_copy, 0,
sizeof(secret_copy));
1053 owner->result = decode_result;
1054 owner->reply_code = reply_code;
1055 owner->reply_attrs = attrs;
1056 owner->delivered = 1;
1065void radcli2_priv_reqreg_service_timeouts(rc_handle *rh)
1067 struct radcli_reqreg *reg;
1068 const rc_sockets_override *sfuncs;
1073 if (rh == NULL || rh->reqreg == NULL)
1078 ns = rc_conf_str_id(rh, OPT_NAMESPACE);
1080 for (i = 0; i < RADCLI_CTX_MAX_INFLIGHT; i++) {
1081 struct radcli_reqreg_slot *rslot = ®->slots[i];
1083 pthread_mutex_lock(®->lock);
1084 if (!rslot->valid || !rslot->armed || rc_getmtime() < rslot->deadline) {
1085 pthread_mutex_unlock(®->lock);
1089 if (rslot->retries_left-- <= 0) {
1090 struct radcli_async_send_st *owner = rslot->owner;
1091 char server_name_copy[128];
1092 unsigned short svc_port_copy = rslot->svc_port;
1094 memcpy(server_name_copy, rslot->server_name,
sizeof(server_name_copy));
1097 rslot->owner = NULL;
1098 memset(rslot->secret, 0,
sizeof(rslot->secret));
1099 rslot->free_seq = ++reg->free_seq_ctr;
1100 pthread_mutex_unlock(®->lock);
1102 rc_log(LOG_ERR,
"%s: no reply from RADIUS server %s:%u",
1103 __func__, server_name_copy, svc_port_copy);
1104 owner->result = TIMEOUT_RC;
1105 owner->reply_code = 0;
1106 owner->reply_attrs = NULL;
1107 owner->delivered = 1;
1117 uint8_t send_buf_copy[RC_BUFFER_LEN];
1118 int send_len_copy = rslot->send_len;
1119 struct sockaddr_storage peer_copy = rslot->peer;
1120 socklen_t peer_len_copy = rslot->peer_len;
1125 memcpy(send_buf_copy, rslot->send_buf, (
size_t)send_len_copy);
1126 pthread_mutex_unlock(®->lock);
1128 sockfd = is_radsec ? (sfuncs->get_active_fd ? sfuncs->get_active_fd(sfuncs->ptr) : -1)
1133 if (ns != NULL && -1 == rc_set_netns(ns, &ns_def_hdl)) {
1134 rc_log(LOG_ERR,
"%s: namespace %s set failed", __func__, ns);
1138 sfuncs->lock(sfuncs->ptr);
1141 sresult = sfuncs->sendto(sfuncs->ptr, sockfd, (
const char *)send_buf_copy,
1142 (
unsigned int)send_len_copy, 0,
1143 SA(&peer_copy), peer_len_copy);
1144 }
while (sresult == -1 && errno == EINTR);
1147 sfuncs->unlock(sfuncs->ptr);
1149 rc_reset_netns(&ns_def_hdl);
1151 if (sresult == -1) {
1152 rc_log(LOG_ERR,
"%s: sendto: %s", __func__, strerror(errno));
1156 pthread_mutex_lock(®->lock);
1157 if (rslot->valid && rslot->armed)
1158 rslot->deadline = rc_getmtime() + rslot->timeout;
1159 pthread_mutex_unlock(®->lock);
1201int radcli_transport_send_async(rc_handle *rh,
int slot,
char *server_name,
unsigned short svc_port,
1202 char secret[MAX_SECRET_LENGTH + 1],
rc_type type,
1203 const uint8_t *send_buf,
int send_len,
1204 int timeout,
int retries,
1205 struct radcli_async_send_st *out)
1207 struct addrinfo *auth_addr = NULL;
1208 const rc_sockets_override *sfuncs;
1209 struct sockaddr_storage our_sockaddr;
1210 unsigned discover_local_ip;
1211 struct radcli_reqreg *reg;
1212 struct radcli_reqreg_slot *rslot;
1219 memset(out, 0,
sizeof(*out));
1221 if (rh == NULL || rh->reqreg == NULL || slot < 0 || slot >= RADCLI_CTX_MAX_INFLIGHT)
1224 rslot = ®->slots[slot];
1227 if (server_name == NULL || server_name[0] ==
'\0')
1229 if (send_len < AUTH_HDR_LEN || (
size_t)send_len >
sizeof(rslot->send_buf))
1232 ns = rc_conf_str_id(rh, OPT_NAMESPACE);
1234 if (-1 == rc_set_netns(ns, &ns_def_hdl)) {
1235 rc_log(LOG_ERR,
"%s: namespace %s set failed", __func__, ns);
1240 if (radcli2_priv_find_server_addr(rh, server_name, &auth_addr, secret, type) != 0) {
1241 rc_log(LOG_ERR,
"%s: unable to find server: %s", __func__, server_name);
1248 if (sfuncs->static_secret)
1249 strlcpy(secret, sfuncs->static_secret, MAX_SECRET_LENGTH + 1);
1259 if (sfuncs->lock(sfuncs->ptr) != 0) {
1260 rc_log(LOG_ERR,
"%s: lock error", __func__);
1267 if (auth_addr->ai_family == AF_INET)
1268 ((
struct sockaddr_in *)auth_addr->ai_addr)->sin_port = htons(svc_port);
1270 ((
struct sockaddr_in6 *)auth_addr->ai_addr)->sin6_port = htons(svc_port);
1274 sockfd = sfuncs->get_active_fd ? sfuncs->get_active_fd(sfuncs->ptr) : -1;
1276 rc_log(LOG_ERR,
"%s: no established RadSec session", __func__);
1280 }
else if (rh->req_fd != -1) {
1281 sockfd = rh->req_fd;
1283 rc_own_bind_addr(rh, &our_sockaddr);
1284 discover_local_ip = 0;
1285 if (our_sockaddr.ss_family == AF_INET &&
1286 ((
struct sockaddr_in *)(&our_sockaddr))->sin_addr.s_addr == INADDR_ANY)
1287 discover_local_ip = 1;
1289 if (discover_local_ip) {
1299 result = radcli2_priv_get_srcaddr(SA(&our_sockaddr), auth_addr->ai_addr);
1300 if (result != OK_RC) {
1301 rc_log(LOG_ERR,
"%s: cannot figure our own address", __func__);
1307 if (sfuncs->get_fd) {
1308 sockfd = sfuncs->get_fd(sfuncs->ptr, SA(&our_sockaddr));
1310 rc_log(LOG_ERR,
"%s: socket: %s", __func__, strerror(errno));
1318 if (radcli2_priv_set_nonblock_cloexec(sockfd) != 0) {
1319 rc_log(LOG_ERR,
"%s: fcntl: %s", __func__, strerror(errno));
1321 if (sfuncs->close_fd)
1322 sfuncs->close_fd(sockfd);
1334 rh->req_fd = sockfd;
1337 if (sockfd >= 0 && our_sockaddr.ss_family == AF_INET6) {
1338 char *non_temp_addr = rc_conf_str_id(rh, OPT_USE_PUBLIC_ADDR);
1339 if (non_temp_addr && strcasecmp(non_temp_addr,
"true") == 0) {
1340#if defined(__linux__)
1341 int sock_opt = IPV6_PREFER_SRC_PUBLIC;
1342 if (setsockopt(sockfd, IPPROTO_IPV6, IPV6_ADDR_PREFERENCES,
1343 &sock_opt,
sizeof(sock_opt)) != 0) {
1344 rc_log(LOG_ERR,
"%s: setsockopt: %s", __func__, strerror(errno));
1348#elif defined(BSD) || defined(__APPLE__)
1350 if (setsockopt(sockfd, IPPROTO_IPV6, IPV6_PREFER_TEMPADDR,
1351 &sock_opt,
sizeof(sock_opt)) != 0) {
1352 rc_log(LOG_ERR,
"%s: setsockopt: %s", __func__, strerror(errno));
1357 rc_log(LOG_INFO,
"%s: Usage of non-temporary IPv6 address is not "
1358 "supported in this system", __func__);
1365 result = sfuncs->sendto(sfuncs->ptr, sockfd, (
const char *)send_buf,
1366 (
unsigned int)send_len, 0,
1367 SA(auth_addr->ai_addr), auth_addr->ai_addrlen);
1368 }
while (result == -1 && errno == EINTR);
1370 rc_log(LOG_ERR,
"%s: sendto: %s", __func__, strerror(errno));
1375 pthread_mutex_lock(®->lock);
1376 memcpy(&rslot->peer, auth_addr->ai_addr, auth_addr->ai_addrlen);
1377 rslot->peer_len = auth_addr->ai_addrlen;
1378 memcpy(rslot->send_buf, send_buf, (
size_t)send_len);
1379 rslot->send_len = send_len;
1380 memcpy(rslot->vector, send_buf + 4, AUTH_VECTOR_LEN);
1381 strlcpy(rslot->secret, secret,
sizeof(rslot->secret));
1382 strlcpy(rslot->server_name, server_name,
sizeof(rslot->server_name));
1383 rslot->svc_port = svc_port;
1385 rslot->timeout = timeout > 0 ? timeout : 1;
1386 rslot->retries_left = retries;
1387 rslot->deadline = rc_getmtime() + rslot->timeout;
1389 pthread_mutex_unlock(®->lock);
1392 sfuncs->unlock(sfuncs->ptr);
1404 sfuncs->unlock(sfuncs->ptr);
1406 memset(secret,
'\0', MAX_SECRET_LENGTH + 1);
1409 freeaddrinfo(auth_addr);
1412 if (-1 == rc_reset_netns(&ns_def_hdl))
1413 rc_log(LOG_ERR,
"%s: namespace %s reset failed", __func__, ns);
1443int radcli_transport_service_async(
struct radcli_async_send_st *st,
int fd_ready)
1445 if (st == NULL || !st->active)
1449 radcli2_priv_reqreg_drain(st->rh);
1451 radcli2_priv_reqreg_service_timeouts(st->rh);
1453 return RADCLI_ASYNC_AGAIN;
1467void radcli_transport_async_abort(
struct radcli_async_send_st *st)
1469 if (st == NULL || !st->active)
1473 radcli2_priv_reqreg_release(st->rh, st->slot);
1475 radcli_avp_list_free(st->reply_attrs);
struct rc_aaa_ctx_st RC_AAA_CTX
@ ACCT
Request for accounting server.
@ AUTH
Request for authentication server.
@ RC_SOCKET_DTLS
DTLS socket.
@ RC_SOCKET_TLS
TLS socket.