60#include <radcli/radcli.h>
61#include <radcli/radcli2.h>
72#define RADCLI_DAE_DEFAULT_PORT 3799
76#define RADCLI_DAE_MAX_DACS 64
103#define RADCLI_DAE_SLOTS 256
105struct radcli_dae_slot {
108 uint8_t dedup_key[RC_SHA256_DIGEST_SIZE];
116 uint32_t error_cause;
119struct radcli_dae_dac {
120 struct sockaddr_storage addr;
136#define RADCLI_DAE_RADSEC_QUEUE_SIZE 8
150#define RADCLI_DAE_RADSEC_REPLY_QUEUE_SIZE 8
151#define RADCLI_DAE_RADSEC_REPLY_MAX_LEN 512
153struct radcli_dae_pending_reply {
154 uint8_t buf[RADCLI_DAE_RADSEC_REPLY_MAX_LEN];
158struct radcli_dae_st {
161 struct radcli_dae_dac *dacs;
163 struct radcli_dae_slot *slots;
167 int require_message_authenticator;
168 unsigned no_nas_check;
200 struct radcli_dae_request_st *radsec_queue[RADCLI_DAE_RADSEC_QUEUE_SIZE];
201 unsigned radsec_queue_len;
209 struct radcli_dae_pending_reply radsec_reply_queue[RADCLI_DAE_RADSEC_REPLY_QUEUE_SIZE];
210 unsigned radsec_reply_queue_len;
212 pthread_mutex_t radsec_lock;
215struct radcli_dae_request_st {
216 struct radcli_dae_st *dae;
217 struct radcli_dae_dac *dac;
220 uint8_t request_authenticator[AUTH_VECTOR_LEN];
221 uint8_t dedup_key[RC_SHA256_DIGEST_SIZE];
228 struct sockaddr_storage from;
230 char secret[MAX_SECRET_LENGTH + 1];
231 radcli_avp_list *attrs;
244 unsigned is_cached_duplicate;
245 uint8_t cached_reply_code;
246 uint32_t cached_error_cause;
254static void free_dacs(
struct radcli_dae_dac *dacs,
unsigned n)
260 for (i = 0; i < n; i++)
261 free(dacs[i].secret);
273static void radsec_queue_push(
struct radcli_dae_st *dae,
struct radcli_dae_request_st *req)
277 if (dae->radsec_queue_len == RADCLI_DAE_RADSEC_QUEUE_SIZE) {
278 rc_log(LOG_WARNING,
"radcli_ctx_dispatch: RadSec dynamic-authorization "
279 "queue full (%u), dropping the oldest undelivered request",
280 (
unsigned)RADCLI_DAE_RADSEC_QUEUE_SIZE);
282 for (i = 1; i < dae->radsec_queue_len; i++)
283 dae->radsec_queue[i - 1] = dae->radsec_queue[i];
284 dae->radsec_queue_len--;
286 dae->radsec_queue[dae->radsec_queue_len++] = req;
294static struct radcli_dae_request_st *radsec_queue_pop(
struct radcli_dae_st *dae)
296 struct radcli_dae_request_st *req;
299 if (dae->radsec_queue_len == 0)
301 req = dae->radsec_queue[0];
302 for (i = 1; i < dae->radsec_queue_len; i++)
303 dae->radsec_queue[i - 1] = dae->radsec_queue[i];
304 dae->radsec_queue_len--;
323static void radsec_reply_queue_push_locked(
struct radcli_dae_st *dae,
const uint8_t *buf,
size_t len)
327 if (len > RADCLI_DAE_RADSEC_REPLY_MAX_LEN) {
328 rc_log(LOG_ERR,
"radcli_ctx_dispatch: RadSec reply of %zu bytes exceeds "
329 "the %d-byte queue slot size, dropping", len,
330 RADCLI_DAE_RADSEC_REPLY_MAX_LEN);
333 if (dae->radsec_reply_queue_len == RADCLI_DAE_RADSEC_REPLY_QUEUE_SIZE) {
334 rc_log(LOG_WARNING,
"radcli_ctx_dispatch: RadSec reply queue full (%u), "
335 "dropping the oldest unsent reply", (
unsigned)RADCLI_DAE_RADSEC_REPLY_QUEUE_SIZE);
336 for (i = 1; i < dae->radsec_reply_queue_len; i++)
337 dae->radsec_reply_queue[i - 1] = dae->radsec_reply_queue[i];
338 dae->radsec_reply_queue_len--;
340 memcpy(dae->radsec_reply_queue[dae->radsec_reply_queue_len].buf, buf, len);
341 dae->radsec_reply_queue[dae->radsec_reply_queue_len].len = len;
342 dae->radsec_reply_queue_len++;
359static void radsec_flush_reply_queue_locked(
struct radcli_dae_st *dae)
361 while (dae->radsec_reply_queue_len > 0) {
362 struct radcli_dae_pending_reply *p = &dae->radsec_reply_queue[0];
363 int ret = radcli2_priv_tls_dae_send(dae->rh, p->buf, p->len);
368 for (i = 1; i < dae->radsec_reply_queue_len; i++)
369 dae->radsec_reply_queue[i - 1] = dae->radsec_reply_queue[i];
370 dae->radsec_reply_queue_len--;
379static void radsec_flush_reply_queue(
struct radcli_dae_st *dae)
381 pthread_mutex_lock(&dae->radsec_lock);
382 radsec_flush_reply_queue_locked(dae);
383 pthread_mutex_unlock(&dae->radsec_lock);
407static int parse_dae_server_token(
const char *token,
char **name,
char **secret)
409 const char *close, *colon;
415 if (token[0] ==
'\0' || strchr(token,
'/') != NULL)
418 if (token[0] ==
'[') {
419 close = strchr(token,
']');
420 if (close == NULL || close == token + 1)
422 namelen = (size_t)(close - (token + 1));
423 *name = malloc(namelen + 1);
426 memcpy(*name, token + 1, namelen);
427 (*name)[namelen] =
'\0';
429 if (close[1] ==
':') {
430 if (close[2] ==
'\0')
432 if (strlen(close + 2) > MAX_SECRET_LENGTH) {
433 rc_log(LOG_ERR,
"radcli_dae_new: dae-server: secret override for "
434 "\"%s\" is longer than %d bytes", *name, MAX_SECRET_LENGTH);
437 *secret = strdup(close + 2);
440 }
else if (close[1] !=
'\0') {
446 colon = strchr(token,
':');
447 if (colon != NULL && strchr(colon + 1,
':') == NULL) {
448 if (colon == token || colon[1] ==
'\0')
450 namelen = (size_t)(colon - token);
451 *name = malloc(namelen + 1);
454 memcpy(*name, token, namelen);
455 (*name)[namelen] =
'\0';
456 if (strlen(colon + 1) > MAX_SECRET_LENGTH) {
457 rc_log(LOG_ERR,
"radcli_dae_new: dae-server: secret override for "
458 "\"%s\" is longer than %d bytes", *name, MAX_SECRET_LENGTH);
461 *secret = strdup(colon + 1);
467 *name = strdup(token);
494static int add_dac_addrs(
struct radcli_dae_st *dae,
const char *name,
495 const char *secret_override)
497 struct addrinfo hints, *res, *rp;
499 struct radcli_dae_dac *tmp;
502 memset(&hints, 0,
sizeof(hints));
503 hints.ai_family = AF_UNSPEC;
504 hints.ai_socktype = SOCK_DGRAM;
506 err = getaddrinfo(name, NULL, &hints, &res);
508 rc_log(LOG_ERR,
"radcli_dae_new: dae-server: cannot resolve %s: %s",
509 name, gai_strerror(err));
513 for (rp = res; rp != NULL; rp = rp->ai_next) {
514 if (dae->n_dacs >= RADCLI_DAE_MAX_DACS) {
515 rc_log(LOG_ERR,
"radcli_dae_new: dae-server: too many resolved "
516 "addresses (max %d)", RADCLI_DAE_MAX_DACS);
520 tmp = realloc(dae->dacs, (dae->n_dacs + 1) *
sizeof(*tmp));
526 memset(&dae->dacs[dae->n_dacs], 0,
sizeof(*tmp));
527 memcpy(&dae->dacs[dae->n_dacs].addr, rp->ai_addr, rp->ai_addrlen);
528 dae->dacs[dae->n_dacs].addrlen = rp->ai_addrlen;
529 if (secret_override != NULL) {
530 dae->dacs[dae->n_dacs].secret = strdup(secret_override);
531 if (dae->dacs[dae->n_dacs].secret == NULL) {
542 rc_log(LOG_ERR,
"radcli_dae_new: dae-server: %s resolved to no addresses", name);
557static int parse_dae_listen(
const char *spec,
char **host,
int *port)
559 const char *close, *colon;
564 *port = RADCLI_DAE_DEFAULT_PORT;
566 if (spec == NULL || spec[0] ==
'\0')
569 if (spec[0] ==
'[') {
570 close = strchr(spec,
']');
571 if (close == NULL || close == spec + 1)
573 *host = malloc((
size_t)(close - (spec + 1)) + 1);
576 memcpy(*host, spec + 1, (
size_t)(close - (spec + 1)));
577 (*host)[close - (spec + 1)] =
'\0';
579 if (close[1] ==
':') {
580 p = strtol(close + 2, &end, 10);
581 if (*end !=
'\0' || p < 0 || p > 65535)
584 }
else if (close[1] !=
'\0') {
590 colon = strrchr(spec,
':');
592 *host = strdup(spec);
599 *host = malloc((
size_t)(colon - spec) + 1);
602 memcpy(*host, spec, (
size_t)(colon - spec));
603 (*host)[colon - spec] =
'\0';
605 if (colon[1] !=
'\0') {
606 p = strtol(colon + 1, &end, 10);
607 if (*end !=
'\0' || p < 0 || p > 65535)
640 rc_handle *rh = (rc_handle *)ctx;
641 struct radcli_dae_st *dae = NULL;
642 const char *accept_str, *secret, *server_str, *require_ma_str, *listen_str;
643 char *server_dup = NULL, *saveptr, *tok;
644 int force_udp, radsec_mode;
652 accept_str = rc_conf_str_id(rh, OPT_DAE_ACCEPT);
653 if (accept_str == NULL || strcasecmp(accept_str,
"no") == 0) {
659 if (strcasecmp(accept_str,
"yes") == 0) {
661 }
else if (strcasecmp(accept_str,
"udp") == 0) {
664 rc_log(LOG_ERR,
"radcli_dae_new: dae-accept: invalid value \"%s\" "
665 "(must be no, yes, or udp)", accept_str);
678 radsec_mode = (!force_udp && (rh->so_type == RC_SOCKET_TLS || rh->so_type == RC_SOCKET_DTLS));
680 if (rh->active_dae != NULL) {
681 rc_log(LOG_ERR,
"radcli_dae_new: a radcli_dae is already active on this context");
690 const char *verify_str = rc_conf_str_id(rh, OPT_TLS_VERIFY_HOSTNAME);
692 if (verify_str != NULL &&
693 (strcasecmp(verify_str,
"false") == 0 || strcasecmp(verify_str,
"no") == 0)) {
694 rc_log(LOG_ERR,
"radcli_dae_new: dae-accept=yes under serv-type "
695 "tls/dtls needs tls-verify-hostname enabled: RadSec's "
696 "verified peer identity is what authorizes a "
697 "CoA/Disconnect-Request sender, replacing dae-server");
707 static const struct {
711 { OPT_DAE_LISTEN,
"dae-listen" },
712 { OPT_DAE_SERVER,
"dae-server" },
713 { OPT_DAE_SECRET,
"dae-secret" },
714 { OPT_DAE_REQUIRE_MESSAGE_AUTHENTICATOR,
"dae-require-message-authenticator" }
718 for (i = 0; i <
sizeof(inapplicable) /
sizeof(inapplicable[0]); i++) {
719 const char *v = rc_conf_str_id(rh, inapplicable[i].
id);
721 if (v != NULL && v[0] !=
'\0')
722 rc_log(LOG_WARNING,
"radcli_dae_new: %s is set but has no "
723 "effect under serv-type tls/dtls (RadSec replaces "
724 "it)", inapplicable[i].name);
728 dae = calloc(1,
sizeof(*dae));
735 if (pthread_mutex_init(&dae->radsec_lock, NULL) != 0) {
743 dae->slots = calloc(RADCLI_DAE_SLOTS,
sizeof(*dae->slots));
744 if (dae->slots == NULL)
747 dae->max_clock_skew = rc_conf_int_id(rh, OPT_DAE_MAX_CLOCK_SKEW);
748 if (dae->max_clock_skew < 0) {
749 rc_log(LOG_ERR,
"radcli_dae_new: dae-max-clock-skew must not be negative");
753 rh->active_dae = dae;
757 secret = rc_conf_str_id(rh, OPT_DAE_SECRET);
758 server_str = rc_conf_str_id(rh, OPT_DAE_SERVER);
759 if (secret == NULL || secret[0] ==
'\0' || server_str == NULL || server_str[0] ==
'\0') {
760 rc_log(LOG_ERR,
"radcli_dae_new: dae-accept is enabled but dae-server "
761 "and/or dae-secret is not set");
764 if (strlen(secret) > MAX_SECRET_LENGTH) {
765 rc_log(LOG_ERR,
"radcli_dae_new: dae-secret is longer than %d bytes",
770 dae = calloc(1,
sizeof(*dae));
777 dae->secret = strdup(secret);
778 if (dae->secret == NULL)
781 server_dup = strdup(server_str);
782 if (server_dup == NULL)
785 for (tok = strtok_r(server_dup,
",", &saveptr); tok != NULL;
786 tok = strtok_r(NULL,
",", &saveptr)) {
787 char *name = NULL, *secret_override = NULL;
790 while (*tok ==
' ' || *tok ==
'\t')
793 if (parse_dae_server_token(tok, &name, &secret_override) != 0) {
794 rc_log(LOG_ERR,
"radcli_dae_new: dae-server: invalid entry \"%s\"", tok);
798 ret = add_dac_addrs(dae, name, secret_override);
800 free(secret_override);
807 if (dae->n_dacs == 0) {
808 rc_log(LOG_ERR,
"radcli_dae_new: dae-server produced no authorized senders");
816 dae->slots = calloc(RADCLI_DAE_SLOTS,
sizeof(*dae->slots));
817 if (dae->slots == NULL)
820 dae->max_clock_skew = rc_conf_int_id(rh, OPT_DAE_MAX_CLOCK_SKEW);
821 if (dae->max_clock_skew < 0) {
822 rc_log(LOG_ERR,
"radcli_dae_new: dae-max-clock-skew must not be negative");
826 require_ma_str = rc_conf_str_id(rh, OPT_DAE_REQUIRE_MESSAGE_AUTHENTICATOR);
827 dae->require_message_authenticator =
828 (require_ma_str != NULL && strcasecmp(require_ma_str,
"yes") == 0);
830 listen_str = rc_conf_str_id(rh, OPT_DAE_LISTEN);
831 if (parse_dae_listen(listen_str, &dae->listen_host, &dae->listen_port) != 0) {
832 rc_log(LOG_ERR,
"radcli_dae_new: dae-listen: invalid value \"%s\"",
833 listen_str ? listen_str :
"");
837 rh->active_dae = dae;
858 dae->handler_user = user;
879int radcli2_priv_set_nonblock_cloexec(
int fd)
883 flags = fcntl(fd, F_GETFL, 0);
884 if (flags == -1 || fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1)
886 flags = fcntl(fd, F_GETFD, 0);
887 if (flags == -1 || fcntl(fd, F_SETFD, flags | FD_CLOEXEC) == -1)
898 struct addrinfo hints, *res, *rp;
901 char addr_txt[NI_MAXHOST] =
"?";
906 rc_log(LOG_ERR,
"radcli_dae_start: already started");
916 if (radcli2_priv_tls_ensure_connected(dae->rh) != 0) {
917 rc_log(LOG_ERR,
"radcli_dae_start: could not establish the "
918 "RadSec (TLS/DTLS) session");
925 snprintf(portstr,
sizeof(portstr),
"%d", dae->listen_port);
927 memset(&hints, 0,
sizeof(hints));
928 hints.ai_family = AF_UNSPEC;
929 hints.ai_socktype = SOCK_DGRAM;
930 hints.ai_flags = AI_PASSIVE;
932 err = getaddrinfo(dae->listen_host, portstr, &hints, &res);
934 rc_log(LOG_ERR,
"radcli_dae_start: dae-listen: %s", gai_strerror(err));
938 for (rp = res; rp != NULL; rp = rp->ai_next) {
939 fd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
942 if (radcli2_priv_set_nonblock_cloexec(fd) != 0) {
947 if (bind(fd, rp->ai_addr, rp->ai_addrlen) == 0) {
948 getnameinfo(rp->ai_addr, rp->ai_addrlen, addr_txt,
sizeof(addr_txt),
949 NULL, 0, NI_NUMERICHOST);
958 rc_log(LOG_ERR,
"radcli_dae_start: bind: %s", strerror(errno));
967 rc_log(LOG_INFO,
"radcli_dae_start: listening on %s port %d", addr_txt, dae->listen_port);
984 if (dae->rh != NULL && dae->rh->active_dae == dae)
985 dae->rh->active_dae = NULL;
998 pthread_mutex_lock(&dae->radsec_lock);
999 for (i = 0; i < dae->radsec_queue_len; i++)
1001 dae->radsec_queue_len = 0;
1002 pthread_mutex_unlock(&dae->radsec_lock);
1003 pthread_mutex_destroy(&dae->radsec_lock);
1005 for (i = 0; i < dae->radsec_queue_len; i++)
1008 free_dacs(dae->dacs, dae->n_dacs);
1011 free(dae->listen_host);
1020static int watchdog_deadline_ms(rc_handle *rh,
int fd)
1030 interval = rc_conf_int_id(rh, OPT_WATCHDOG_INTERVAL);
1032 time_t last = radcli2_priv_tls_last_msg(rh);
1033 long elapsed_ms = (long)(time(0) - last) * 1000L;
1034 long remaining_ms = (long)interval * 1000L - elapsed_ms;
1036 return (remaining_ms > 0) ? (int)remaining_ms : 0;
1043static void fold_timeout(
int *timeout_ms,
int candidate)
1047 if (*timeout_ms < 0 || candidate < *timeout_ms)
1048 *timeout_ms = candidate;
1092 size_t *nfds,
int *timeout_ms)
1094 rc_handle *rh = (rc_handle *)ctx;
1097 if (rh == NULL || pfds == NULL || nfds == NULL || timeout_ms == NULL)
1104 if (rh->so_type == RC_SOCKET_TLS || rh->so_type == RC_SOCKET_DTLS) {
1115 int dae_radsec = (rh->active_dae != NULL && rh->active_dae->radsec);
1116 int fd = radcli2_priv_tls_fd(rh);
1117 unsigned events = (fd != -1) ? POLLIN : 0;
1124 if (dae_radsec && fd != -1 && rh->active_dae->radsec_reply_queue_len > 0)
1129 pfds[n].events = (short)events;
1130 pfds[n].revents = 0;
1143 if (dae_radsec && (rh->active_dae->radsec_queue_len > 0 ||
1144 rh->active_dae->radsec_reply_queue_len > 0))
1147 fold_timeout(timeout_ms, watchdog_deadline_ms(rh, fd));
1149 fold_timeout(timeout_ms, radcli2_priv_reqreg_earliest_deadline_ms(rh));
1158 if (rh->active_dae != NULL && rh->active_dae->fd != -1) {
1159 pfds[n].fd = rh->active_dae->fd;
1160 pfds[n].events = POLLIN;
1161 pfds[n].revents = 0;
1164 if (rh->req_fd != -1) {
1165 pfds[n].fd = rh->req_fd;
1166 pfds[n].events = POLLIN;
1167 pfds[n].revents = 0;
1175 fold_timeout(timeout_ms, radcli2_priv_reqreg_earliest_deadline_ms(rh));
1241int radcli2_priv_dae_send_watchdog(radcli_ctx *ctx)
1243 rc_handle *rh = (rc_handle *)ctx;
1244 uint8_t send_buffer[RC_BUFFER_LEN];
1245 unsigned char vector[AUTH_VECTOR_LEN];
1246 char secret[MAX_SECRET_LENGTH + 1];
1247 radcli_avp_list *empty;
1254 if (rh->so_type != RC_SOCKET_TLS && rh->so_type != RC_SOCKET_DTLS)
1257 if (radcli2_priv_tls_fd(rh) == -1)
1261 int interval = rc_conf_int_id(rh, OPT_WATCHDOG_INTERVAL);
1264 (
double)(time(0) - radcli2_priv_tls_last_recv(rh)) >= interval * 2.5) {
1265 rc_log(LOG_WARNING,
"radcli2_priv_dae_send_watchdog: no record received in "
1266 "%.1fx watchdog-interval -- presuming the peer dead "
1267 "and reconnecting", 2.5);
1268 if (radcli2_priv_tls_force_reconnect(rh) < 0)
1273 if (radcli2_priv_tls_fd(rh) == -1)
1276 if (rh->so.static_secret == NULL)
1278 strlcpy(secret, rh->so.static_secret,
sizeof(secret));
1291 ret = radcli_encode_request(rh, PW_STATUS_SERVER, empty, secret,
1292 send_buffer, rc_get_random_byte(), vector, &total_length);
1297 return radcli2_priv_tls_dae_send(rh, send_buffer, (
size_t)total_length);
1312static int get_v4_mapped(
const struct sockaddr *sa,
struct in_addr *out)
1314 const struct sockaddr_in6 *sin6;
1316 if (sa->sa_family != AF_INET6)
1318 sin6 = (
const struct sockaddr_in6 *)sa;
1319 if (!IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr))
1321 memcpy(out, &sin6->sin6_addr.s6_addr[12],
sizeof(*out));
1335static struct radcli_dae_dac *find_dac(
struct radcli_dae_st *dae,
1336 const struct sockaddr *from)
1339 struct in_addr mapped;
1340 int have_mapped = get_v4_mapped(from, &mapped);
1342 for (i = 0; i < dae->n_dacs; i++) {
1343 const struct sockaddr *caddr = (
const struct sockaddr *)&dae->dacs[i].addr;
1345 if (caddr->sa_family == from->sa_family) {
1346 if (memcmp(SA_GET_INADDR(caddr), SA_GET_INADDR(from), SA_GET_INLEN(from)) == 0)
1347 return &dae->dacs[i];
1354 if (have_mapped && caddr->sa_family == AF_INET &&
1355 memcmp(&((
const struct sockaddr_in *)caddr)->sin_addr, &mapped,
1356 sizeof(mapped)) == 0)
1357 return &dae->dacs[i];
1377static char *dup_avp_str(rc_handle *rh,
const radcli_avp_list *attrs, uint32_t attrid)
1380 const radcli_avp *a;
1390 s = malloc(len + 1);
1393 memcpy(s, val, len);
1413static int verify_request_authenticator(uint8_t *buf,
size_t length,
const char *secret)
1415 uint8_t received[AUTH_VECTOR_LEN];
1416 uint8_t calc[AUTH_VECTOR_LEN];
1417 size_t secretlen = rc_secret_len(secret);
1419 if (length < AUTH_HDR_LEN)
1422 memcpy(received, buf + 4, AUTH_VECTOR_LEN);
1423 memset(buf + 4, 0, AUTH_VECTOR_LEN);
1424 memcpy(buf + length, secret, secretlen);
1425 rc_md5_calc(calc, buf, length + secretlen);
1426 memcpy(buf + 4, received, AUTH_VECTOR_LEN);
1428 return rc_memcmp(received, calc, AUTH_VECTOR_LEN) == 0 ? 0 : -1;
1449static int build_reply(
struct radcli_dae_request_st *req, uint8_t reply_code, uint32_t error_cause,
1450 uint8_t *out_buf,
size_t out_cap,
int *out_len)
1452 rc_handle *rh = req->dae->rh;
1453 AUTH_HDR *auth = (AUTH_HDR *)out_buf;
1454 radcli_avp_list *reply_attrs;
1455 const radcli_avp *a;
1456 const radcli_attr_def *d_proxy_state;
1457 int encoded_len, total_length;
1459 uint8_t digest[AUTH_VECTOR_LEN];
1468 if (out_cap < (
size_t)(AUTH_HDR_LEN + 2 + MD5_DIGEST_SIZE))
1472 if (reply_attrs == NULL)
1475 if (error_cause != 0) {
1483 if (d_proxy_state != NULL) {
1497 auth->code = reply_code;
1499 memcpy(auth->vector, req->request_authenticator, AUTH_VECTOR_LEN);
1501 encoded_len = radcli_avp_encode(rh, reply_attrs, req->secret, req->request_authenticator,
1502 auth->data, out_cap - AUTH_HDR_LEN - (2 + MD5_DIGEST_SIZE), NULL);
1504 if (encoded_len < 0)
1507 total_length = AUTH_HDR_LEN + encoded_len;
1508 auth->length = htons((uint16_t)total_length);
1510 if (out_cap < total_length + (2 + MD5_DIGEST_SIZE))
1512 total_length = add_msg_auth_attr(rh, req->secret, auth, total_length);
1514 secretlen = rc_secret_len(req->secret);
1515 if ((
size_t)(out_cap - total_length) < secretlen)
1517 memcpy(out_buf + total_length, req->secret, secretlen);
1518 rc_md5_calc(digest, out_buf, (
size_t)total_length + secretlen);
1519 memcpy(auth->vector, digest, AUTH_VECTOR_LEN);
1521 *out_len = total_length;
1533static int send_reply(
struct radcli_dae_request_st *req, uint8_t reply_code, uint32_t error_cause)
1535 uint8_t send_buffer[RC_BUFFER_LEN];
1538 if (build_reply(req, reply_code, error_cause, send_buffer,
sizeof(send_buffer),
1539 &total_length) != 0)
1542 if (req->dae->radsec) {
1558 struct radcli_dae_st *dae = req->dae;
1561 pthread_mutex_lock(&dae->radsec_lock);
1562 radsec_flush_reply_queue_locked(dae);
1563 if (dae->radsec_reply_queue_len > 0) {
1564 radsec_reply_queue_push_locked(dae, send_buffer, (
size_t)total_length);
1565 pthread_mutex_unlock(&dae->radsec_lock);
1568 pthread_mutex_unlock(&dae->radsec_lock);
1570 ret = radcli2_priv_tls_dae_send(dae->rh, send_buffer, (
size_t)total_length);
1572 pthread_mutex_lock(&dae->radsec_lock);
1573 radsec_reply_queue_push_locked(dae, send_buffer, (
size_t)total_length);
1574 pthread_mutex_unlock(&dae->radsec_lock);
1577 return (ret > 0) ? 0 : -1;
1580 if (sendto(req->dae->fd, send_buffer, (
size_t)total_length, 0,
1581 (
struct sockaddr *)&req->from, req->fromlen) != total_length)
1626 return req->session_id;
1639 return req->user_name;
1652 const radcli_attr_def *d;
1653 const radcli_avp *a;
1655 if (req == NULL || out == NULL)
1665 struct sockaddr_in sin;
1667 memset(&sin, 0,
sizeof(sin));
1668 sin.sin_family = AF_INET;
1669 sin.sin_addr.s_addr = htonl(val);
1670 memset(out, 0,
sizeof(*out));
1671 memcpy(out, &sin,
sizeof(sin));
1679 struct in6_addr addr;
1683 struct sockaddr_in6 sin6;
1685 memset(&sin6, 0,
sizeof(sin6));
1686 sin6.sin6_family = AF_INET6;
1687 sin6.sin6_addr = addr;
1688 memset(out, 0,
sizeof(*out));
1689 memcpy(out, &sin6,
sizeof(sin6));
1707 const radcli_attr_def *d;
1708 const radcli_avp *a;
1740static void record_reply_decision(
struct radcli_dae_request_st *req, uint8_t reply_code,
1741 uint32_t error_cause)
1743 struct radcli_dae_slot *slot;
1745 if (req->dae == NULL)
1747 slot = &req->dae->slots[req->id];
1748 if (slot->valid && slot->pending &&
1749 rc_memcmp(slot->dedup_key, req->dedup_key,
1750 RC_SHA256_DIGEST_SIZE) == 0) {
1752 slot->reply_code = reply_code;
1753 slot->error_cause = error_cause;
1766static int reply_and_record(
struct radcli_dae_request_st *req, uint8_t reply_code, uint32_t error_cause)
1770 if (req == NULL || req->replied)
1774 ret = send_reply(req, reply_code, error_cause);
1775 record_reply_decision(req, reply_code, error_cause);
1788static uint8_t select_reply_code(
const struct radcli_dae_request_st *req,
int ack)
1791 ? (req->code == RADCLI_DISCONNECT_REQUEST ? RADCLI_DISCONNECT_ACK : RADCLI_COA_ACK)
1792 : (req->code == RADCLI_DISCONNECT_REQUEST ? RADCLI_DISCONNECT_NAK : RADCLI_COA_NAK);
1811 return reply_and_record(req, select_reply_code(req, ack), 0);
1827 reply_code = (req->code == RADCLI_DISCONNECT_REQUEST) ? RADCLI_DISCONNECT_NAK : RADCLI_COA_NAK;
1828 return reply_and_record(req, reply_code, error_cause);
1853 void *buf,
size_t *len)
1858 if (req == NULL || buf == NULL || len == NULL)
1861 if (req->is_cached_duplicate) {
1865 reply_code = req->cached_reply_code;
1866 error_cause = req->cached_error_cause;
1870 reply_code = select_reply_code(req, ack);
1873 if (build_reply(req, reply_code, error_cause, (uint8_t *)buf, *len, &out_len) != 0)
1875 *len = (size_t)out_len;
1877 if (!req->is_cached_duplicate) {
1879 record_reply_decision(req, reply_code, error_cause);
1896 free(req->session_id);
1897 free(req->user_name);
1908enum process_result {
1911 PROCESS_DUP_ANSWERED,
1936static enum process_result process_packet(
struct radcli_dae_st *dae, uint8_t *buf,
size_t len,
1937 const struct sockaddr *from, socklen_t fromlen,
1938 struct radcli_dae_request_st **out_req)
1940 rc_handle *rh = dae->rh;
1941 size_t length = len;
1942 struct radcli_dae_dac *dac;
1943 struct radcli_dae_slot *slot;
1946 struct radcli_dae_request_st *req;
1947 radcli_avp_list *attrs = NULL;
1948 const radcli_attr_def *d;
1949 const radcli_avp *a;
1962 secret = rh->so.static_secret;
1967 dac = find_dac(dae, from);
1969 return PROCESS_DROP;
1970 secret = (dac->secret != NULL) ? dac->secret : dae->secret;
1979 if (length < AUTH_HDR_LEN)
1980 return PROCESS_DROP;
1982 uint16_t wire_length;
1984 memcpy(&wire_length, buf + 2,
sizeof(wire_length));
1985 wire_length = ntohs(wire_length);
1986 if (wire_length < AUTH_HDR_LEN || wire_length > length ||
1987 wire_length > RC_MAX_PACKET_LEN)
1988 return PROCESS_DROP;
1989 length = wire_length;
1991 if (buf[0] != RADCLI_DISCONNECT_REQUEST && buf[0] != RADCLI_COA_REQUEST)
1992 return PROCESS_DROP;
1995 if (verify_request_authenticator(buf, length, secret) != 0)
1996 return PROCESS_DROP;
1998 if (radcli_avp_decode(rh, secret, buf + 4, buf + AUTH_HDR_LEN,
1999 length - AUTH_HDR_LEN, 0, &attrs) != 0)
2000 return PROCESS_DROP;
2018 uint8_t zero_vector[AUTH_VECTOR_LEN];
2020 memset(zero_vector, 0,
sizeof(zero_vector));
2021 if (validate_message_authenticator(buf, length - AUTH_HDR_LEN, secret,
2022 zero_vector) != 0) {
2024 return PROCESS_DROP;
2026 }
else if (dae->require_message_authenticator) {
2028 return PROCESS_DROP;
2034 if (dae->max_clock_skew > 0) {
2043 return PROCESS_DROP;
2046 diff = (long)now - (
long)ts;
2049 if (diff > dae->max_clock_skew) {
2051 return PROCESS_DROP;
2075 retention = (dae->max_clock_skew > 0) ? dae->max_clock_skew : 30;
2076 slot = &dae->slots[buf[1]];
2078 req = calloc(1,
sizeof(*req));
2081 return PROCESS_DROP;
2087 memcpy(req->request_authenticator, buf + 4, AUTH_VECTOR_LEN);
2088 rc_sha256_calc(req->dedup_key, buf, length);
2095 if (!dae->radsec && from != NULL) {
2096 memcpy(&req->from, from, fromlen);
2097 req->fromlen = fromlen;
2099 strlcpy(req->secret, secret,
sizeof(req->secret));
2102 req->session_id = dup_avp_str(rh, req->attrs, PW_ACCT_SESSION_ID);
2103 req->user_name = dup_avp_str(rh, req->attrs, PW_USER_NAME);
2105 if (slot->valid && (now - slot->timestamp) <= retention &&
2106 rc_memcmp(slot->dedup_key, req->dedup_key,
2107 RC_SHA256_DIGEST_SIZE) == 0) {
2108 if (!slot->pending) {
2109 req->is_cached_duplicate = 1;
2110 req->cached_reply_code = slot->reply_code;
2111 req->cached_error_cause = slot->error_cause;
2113 return PROCESS_DUP_ANSWERED;
2118 return PROCESS_DROP;
2130 if (!dae->no_nas_check) {
2131 const char *cfg_id = rc_conf_str_id(rh, OPT_NAS_IDENTIFIER);
2133 if (cfg_id != NULL) {
2141 (vlen != strlen(cfg_id) || memcmp(val, cfg_id, vlen) != 0)) {
2142 req->cached_reply_code = (req->code == RADCLI_DISCONNECT_REQUEST)
2143 ? RADCLI_DISCONNECT_NAK : RADCLI_COA_NAK;
2144 req->cached_error_cause = RADCLI_ERROR_NAS_IDENTIFICATION_MISMATCH;
2146 slot->timestamp = now;
2147 memcpy(slot->dedup_key, req->dedup_key, RC_SHA256_DIGEST_SIZE);
2149 slot->reply_code = req->cached_reply_code;
2150 slot->error_cause = req->cached_error_cause;
2151 req->is_cached_duplicate = 1;
2153 return PROCESS_DUP_ANSWERED;
2160 slot->timestamp = now;
2161 memcpy(slot->dedup_key, req->dedup_key, RC_SHA256_DIGEST_SIZE);
2187static void send_radsec_unsupported_nak(rc_handle *rh,
const uint8_t *reqbuf,
size_t reqlen)
2189 uint8_t out[AUTH_HDR_LEN + 6 + 2 + MD5_DIGEST_SIZE];
2190 AUTH_HDR *auth = (AUTH_HDR *)out;
2191 radcli_avp_list *reply_attrs;
2192 const radcli_attr_def *d_ec;
2193 int encoded_len, total_length;
2195 uint8_t digest[AUTH_VECTOR_LEN];
2196 const char *secret = rh->so.static_secret;
2198 if (reqlen < AUTH_HDR_LEN || secret == NULL)
2202 if (reply_attrs == NULL)
2209 auth->code = (reqbuf[0] == RADCLI_DISCONNECT_REQUEST) ? RADCLI_DISCONNECT_NAK : RADCLI_COA_NAK;
2210 auth->id = reqbuf[1];
2211 memcpy(auth->vector, reqbuf + 4, AUTH_VECTOR_LEN);
2213 encoded_len = radcli_avp_encode(rh, reply_attrs, secret, reqbuf + 4,
2214 auth->data,
sizeof(out) - AUTH_HDR_LEN - (2 + MD5_DIGEST_SIZE), NULL);
2216 if (encoded_len < 0)
2219 total_length = AUTH_HDR_LEN + encoded_len;
2220 auth->length = htons((uint16_t)total_length);
2221 total_length = add_msg_auth_attr(rh, (
char *)secret, auth, total_length);
2223 secretlen = rc_secret_len(secret);
2224 if ((
size_t)(
sizeof(out) - total_length) < secretlen)
2226 memcpy(out + total_length, secret, secretlen);
2227 rc_md5_calc(digest, out, (
size_t)total_length + secretlen);
2228 memcpy(auth->vector, digest, AUTH_VECTOR_LEN);
2237 radcli2_priv_tls_dae_send(rh, out, (
size_t)total_length);
2256void radcli2_priv_dae_on_radsec_packet(rc_handle *rh,
const uint8_t *buf,
size_t len)
2258 struct radcli_dae_st *dae = rh->active_dae;
2259 uint8_t local_buf[RC_BUFFER_LEN];
2260 struct radcli_dae_request_st *req = NULL;
2262 if (dae == NULL || !dae->radsec) {
2263 send_radsec_unsupported_nak(rh, buf, len);
2267 if (len == 0 || len >
sizeof(local_buf) - 1)
2273 memcpy(local_buf, buf, len);
2283 pthread_mutex_lock(&dae->radsec_lock);
2284 switch (process_packet(dae, local_buf, len, NULL, 0, &req)) {
2286 radsec_queue_push(dae, req);
2288 case PROCESS_DUP_ANSWERED:
2290 send_reply(req, req->cached_reply_code, req->cached_error_cause);
2296 pthread_mutex_unlock(&dae->radsec_lock);
2326 rc_handle *rh = (rc_handle *)ctx;
2327 struct radcli_dae_st *dae;
2328 uint8_t buf[RC_BUFFER_LEN];
2329 struct sockaddr_storage from;
2332 struct radcli_dae_request_st *req = NULL;
2337 if (rh->in_dispatch) {
2338 rc_log(LOG_ERR,
"radcli_ctx_dispatch: reentrant call");
2342 rh->in_dispatch = 1;
2347 radcli2_priv_reqreg_drain(rh);
2348 radcli2_priv_reqreg_service_timeouts(rh);
2350 if (rh->so_type == RC_SOCKET_TLS || rh->so_type == RC_SOCKET_DTLS) {
2358 if (watchdog_deadline_ms(rh, radcli2_priv_tls_fd(rh)) == 0)
2359 radcli2_priv_dae_send_watchdog(ctx);
2362 dae = rh->active_dae;
2364 rh->in_dispatch = 0;
2374 radsec_flush_reply_queue(dae);
2383 int ret = radcli2_priv_tls_dae_poll(rh, buf,
sizeof(buf) - 1);
2386 if (buf[0] == RADCLI_DISCONNECT_REQUEST || buf[0] == RADCLI_COA_REQUEST) {
2387 radcli2_priv_dae_on_radsec_packet(rh, buf, (
size_t)ret);
2389 rc_log(LOG_INFO,
"radcli_ctx_dispatch: unexpected packet code "
2390 "%u on the RadSec session while idle, ignored",
2393 radcli2_priv_tls_dae_poll_done(rh);
2403 pthread_mutex_lock(&dae->radsec_lock);
2404 req = radsec_queue_pop(dae);
2405 pthread_mutex_unlock(&dae->radsec_lock);
2408 if (dae->handler != NULL)
2414 rh->in_dispatch = 0;
2418 if (dae->fd == -1) {
2422 rh->in_dispatch = 0;
2426 fromlen =
sizeof(from);
2427 n = recvfrom(dae->fd, buf,
sizeof(buf) - 1, 0, (
struct sockaddr *)&from, &fromlen);
2433 rh->in_dispatch = 0;
2437 switch (process_packet(dae, buf, (
size_t)n, (
struct sockaddr *)&from, fromlen, &req)) {
2439 if (dae->handler != NULL)
2444 case PROCESS_DUP_ANSWERED:
2446 send_reply(req, req->cached_reply_code, req->cached_error_cause);
2453 rh->in_dispatch = 0;
2488 const struct sockaddr *from, socklen_t fromlen,
2491 struct radcli_dae_request_st *built_req = NULL;
2492 uint8_t local_buf[RC_BUFFER_LEN];
2493 enum process_result result;
2495 if (dae == NULL || buf == NULL || from == NULL || req == NULL ||
2496 len == 0 || len >
sizeof(local_buf) - 1)
2522 if (fromlen <
sizeof(
struct sockaddr_in) || fromlen >
sizeof(
struct sockaddr_storage))
2524 if (from->sa_family == AF_INET6 && fromlen <
sizeof(
struct sockaddr_in6))
2526 if (from->sa_family != AF_INET && from->sa_family != AF_INET6)
2532 memcpy(local_buf, buf, len);
2534 result = process_packet(dae, local_buf, len, from, fromlen, &built_req);
2535 if (result == PROCESS_DROP)
int radcli_dae_req_nas_port(const radcli_dae_request *req, uint32_t *out)
Return the request's NAS-Port.
void radcli_dae_free(radcli_dae *dae)
Release a listener, closing its socket if radcli_dae_start() opened one.
const char * radcli_dae_req_session_id(const radcli_dae_request *req)
Return the request's Acct-Session-Id, if it carried one.
void(* radcli_dae_handler)(radcli_dae_request *req, void *user)
Application callback invoked by radcli_ctx_dispatch() for a validated request.
int radcli_ctx_get_poll(radcli_ctx *ctx, struct pollfd *pfds, size_t max_pfds, size_t *nfds, int *timeout_ms)
Report what to wait for on ctx's behalf, for the caller's own event loop – radcli never calls poll()/...
void radcli_dae_set_handler(radcli_dae *dae, radcli_dae_handler cb, void *user)
Register the callback radcli_ctx_dispatch() invokes for each validated request. May be called before ...
radcli_code radcli_dae_req_code(const radcli_dae_request *req)
Return the received packet's RADIUS code.
int radcli_ctx_dispatch(radcli_ctx *ctx)
Read what is ready on ctx's descriptor(s), validate it, and invoke the registered handler for anythin...
int radcli_dae_reply(radcli_dae_request *req, int ack)
Answer a request with an ACK or NAK, selecting 41/42 or 44/45 from the request's own code,...
struct radcli_dae_st radcli_dae
const char * radcli_dae_req_user_name(const radcli_dae_request *req)
Return the request's User-Name, if it carried one.
int radcli_dae_start(radcli_dae *dae)
Start receiving: binds the socket described by dae-listen.
const radcli_avp_list * radcli_dae_req_attrs(const radcli_dae_request *req)
Return the request's decoded attributes.
int radcli_dae_reply_to_buffer(radcli_dae_request *req, int ack, uint32_t error_cause, void *buf, size_t *len)
Produce a reply as bytes instead of sending it – the L0 counterpart of radcli_dae_reply()/radcli_dae_...
#define RADCLI_CTX_MAX_POLLFDS
int radcli_dae_process(radcli_dae *dae, const void *buf, size_t len, const struct sockaddr *from, socklen_t fromlen, radcli_dae_request **req)
Validate a caller-supplied packet, without a radcli-owned socket – the L0 counterpart of radcli_ctx_d...
#define RADCLI_DAE_DUPLICATE
int radcli_dae_reply_error(radcli_dae_request *req, uint32_t error_cause)
Answer a request with a NAK carrying the given Error-Cause.
radcli_dae * radcli_dae_new(radcli_ctx *ctx, unsigned flags)
Validate dae-* configuration and build a dynamic-authorization listener. Opens no socket – see radcli...
int radcli_dae_req_framed_ip(const radcli_dae_request *req, struct sockaddr_storage *out)
Return the request's Framed-IP-Address or Framed-IPv6-Address.
struct radcli_dae_request_st radcli_dae_request
void radcli_dae_request_free(radcli_dae_request *req)
Release a request.
@ RADCLI_DAE_NO_NAS_CHECK
void radcli_avp_list_free(radcli_avp_list *list)
Free a list and every attribute it holds.
radcli_avp_iter radcli_avp_list_iter(const radcli_avp_list *list)
Begin iterating list.
const radcli_avp * radcli_avp_get(const radcli_avp_list *list, const radcli_attr_def *def, unsigned idx)
Find the idx-th occurrence of an attribute in a list.
int radcli_avp_get_ip6(const radcli_avp *a, struct in6_addr *out, unsigned *prefix)
Read an attribute's value as an IPv6 address or prefix.
int radcli_avp_add_bytes(radcli_avp_list *list, const radcli_attr_def *def, const void *value, size_t len)
Append an attribute holding an arbitrary byte string.
int radcli_avp_get_uint32(const radcli_avp *a, uint32_t *out)
Read an attribute's value as an integer/IPv4-address/date.
radcli_avp_list * radcli_avp_list_new(void)
Create an empty attribute-value pair list.
const radcli_attr_def * radcli_avp_def(const radcli_avp *a)
Return the attribute definition of a.
int radcli_avp_add_uint32(radcli_avp_list *list, const radcli_attr_def *def, uint32_t value)
Append an integer/IPv4-address/date-typed attribute.
const radcli_avp * radcli_avp_iter_next(radcli_avp_iter *it)
Return the current attribute and advance.
int radcli_avp_get_bytes(const radcli_avp *a, const void **out, size_t *len)
Read an attribute's value as raw bytes.
const radcli_attr_def * radcli_dict_lookup_num(const radcli_ctx *ctx, uint32_t attrid, uint32_t vendor)
Look up a dictionary attribute by its legacy numeric ID and vendor.