Radcli library 1.5.1
A simple radius library
Loading...
Searching...
No Matches
sendserver.c
1/*
2 * Copyright (C) 1995,1996,1997 Lars Fenneberg
3 * Copyright (C) 2015,2016 Nikos Mavrogiannopoulos
4 *
5 * Copyright 1992 Livingston Enterprises, Inc.
6 *
7 * Copyright 1992,1993, 1994,1995 The Regents of the University of Michigan
8 * and Merit Network, Inc. All Rights Reserved
9 *
10 * See the file COPYRIGHT for the respective terms and conditions.
11 *
12 */
13
14#include <includes.h>
15#include <radcli/radcli.h>
16#include <pathnames.h>
17#include <poll.h>
18#include "util.h"
19#include "rc-md5.h"
20#include "rc-hmac.h"
21
22#if defined(HAVE_GNUTLS)
23# include <gnutls/gnutls.h>
24# include <gnutls/crypto.h>
25#endif
26
27#if defined(__linux__)
28#include <linux/in6.h>
29#endif
30
31
32#define SCLOSE(fd) if (sfuncs->close_fd) sfuncs->close_fd(fd)
33
34static void rc_random_vector(unsigned char[AUTH_VECTOR_LEN]);
35static int rc_check_reply(AUTH_HDR *, int, char const *, unsigned char const *,
36 unsigned char);
37
44
56int rc_pack_list(VALUE_PAIR * vp, char *secret, AUTH_HDR * auth, int max_len)
57{
58 int length, i, pc, padded_length;
59 size_t secretlen;
60 uint32_t lvalue, vendor;
61 unsigned char passbuf[RC_MAX(AUTH_PASS_LEN, CHAP_VALUE_LENGTH)];
62 unsigned char md5buf[MAX_SECRET_LENGTH + AUTH_VECTOR_LEN];
63 unsigned char *vector;
64 pkt_buf pb;
65 uint8_t *attr_start, *attr_len_ptr, *vsa_len_ptr;
66
67 /* head = start of RADIUS packet; tail starts after the fixed header;
68 * pb_written() will return the total packet length (header + attrs). */
69 pb.head = (uint8_t *)auth;
70 pb.data = (uint8_t *)auth;
71 pb.tail = auth->data;
72 pb.end = (uint8_t *)auth + max_len;
73
74 while (vp != NULL) {
75 vsa_len_ptr = NULL;
76 unsigned max_vlen = AUTH_STRING_LEN; /* 253: RFC 2865 per-attribute value limit */
77
78 if (VENDOR(vp->attribute) != 0) {
79 max_vlen = AUTH_STRING_LEN - VSA_HDR_LEN; /* 247: VSA envelope consumes 6 bytes */
80 if (pb_put_byte(&pb, PW_VENDOR_SPECIFIC) < 0) goto too_large;
81 vsa_len_ptr = pb.tail;
82 if (pb_put_byte(&pb, 6) < 0) goto too_large;
83 vendor = htonl(VENDOR(vp->attribute));
84 if (pb_put_bytes(&pb, &vendor, sizeof(uint32_t)) < 0) goto too_large;
85 }
86
87 attr_start = pb.tail;
88 if (pb_put_byte(&pb, vp->attribute & 0xff) < 0) goto too_large;
89 attr_len_ptr = pb.tail;
90 if (pb_put_byte(&pb, 2) < 0) goto too_large; /* placeholder; patched below */
91
92 switch (vp->attribute) {
94 length = vp->lvalue;
95 if (length > AUTH_PASS_LEN)
96 length = AUTH_PASS_LEN;
97 padded_length =
98 (length + (AUTH_VECTOR_LEN - 1)) & ~(AUTH_VECTOR_LEN - 1);
99
100 if (pb.tail + padded_length > pb.end) goto too_large;
101
102 /* Pad the password with zeros */
103 memset((char *)passbuf, '\0', AUTH_PASS_LEN);
104 memcpy((char *)passbuf, vp->strvalue, (size_t) length);
105
106 secretlen = strlen(secret);
107 if (secretlen > MAX_SECRET_LENGTH)
108 secretlen = MAX_SECRET_LENGTH;
109 vector = (unsigned char *)auth->vector;
110 for (i = 0; i < padded_length; i += AUTH_VECTOR_LEN) {
111 /* Build hash input: secret || vector */
112 memcpy(md5buf, secret, secretlen);
113 memcpy(md5buf + secretlen, vector, AUTH_VECTOR_LEN);
114 rc_md5_calc(pb.tail, md5buf, secretlen + AUTH_VECTOR_LEN);
115
116 /* Remember the start of the digest */
117 vector = pb.tail;
118
119 /* Xor the password into the MD5 digest */
120 for (pc = i; pc < (i + AUTH_VECTOR_LEN); pc++)
121 *pb.tail++ ^= passbuf[pc];
122 }
123 break;
124
125 default:
126 switch (vp->type) {
127 case PW_TYPE_STRING:
129 if (vp->lvalue > max_vlen) goto too_large;
130 if (pb_put_bytes(&pb, vp->strvalue, (int)vp->lvalue) < 0)
131 goto too_large;
132 break;
133
134 case PW_TYPE_IPV6ADDR:
135 if (pb_put_bytes(&pb, vp->strvalue, 16) < 0)
136 goto too_large;
137 break;
138
139 case PW_TYPE_INTEGER:
140 case PW_TYPE_IPADDR:
141 case PW_TYPE_DATE:
142 lvalue = htonl(vp->lvalue);
143 if (pb_put_bytes(&pb, &lvalue, sizeof(uint32_t)) < 0)
144 goto too_large;
145 break;
146
147 default:
148 break;
149 }
150 break;
151 }
152
153 /* Patch back lengths: attr_len = type(1) + len(1) + value */
154 *attr_len_ptr = (uint8_t)(pb.tail - attr_start);
155 if (vsa_len_ptr != NULL)
156 *vsa_len_ptr += *attr_len_ptr;
157
158 vp = vp->next;
159 }
160 return (int)pb_written(&pb); /* total packet bytes: AUTH_HDR_LEN + attrs */
161
162too_large:
163 rc_log(LOG_ERR, "rc_pack_list: attribute value too large or packet would exceed %d bytes", max_len);
164 return -1;
165}
166
174static void strappend(char *dest, unsigned max_size, int *pos, const char *src)
175{
176 unsigned len = strlen(src) + 1;
177
178 if (*pos == -1)
179 return;
180
181 if (len + *pos > max_size) {
182 *pos = -1;
183 return;
184 }
185
186 memcpy(&dest[*pos], src, len);
187 *pos += len - 1;
188 return;
189}
190
191
192static int populate_ctx(RC_AAA_CTX ** ctx, char secret[MAX_SECRET_LENGTH + 1],
193 uint8_t vector[AUTH_VECTOR_LEN])
194{
195 if (ctx) {
196 if (*ctx != NULL)
197 return ERROR_RC;
198
199 *ctx = malloc(sizeof(RC_AAA_CTX));
200 if (*ctx) {
201 memcpy((*ctx)->secret, secret, sizeof((*ctx)->secret));
202 memcpy((*ctx)->request_vector, vector,
203 sizeof((*ctx)->request_vector));
204 } else {
205 return ERROR_RC;
206 }
207 }
208 return OK_RC;
209}
210
221int rc_send_server(rc_handle * rh, SEND_DATA * data, char *msg, rc_type type)
222{
223 return rc_send_server_ctx(rh, NULL, data, msg, type);
224}
225
235static int rc_check_reply(AUTH_HDR * auth, int bufferlen, char const *secret,
236 unsigned char const *vector, uint8_t seq_nbr)
237{
238 int secretlen;
239 int totallen;
240 unsigned char calc_digest[AUTH_VECTOR_LEN];
241 unsigned char reply_digest[AUTH_VECTOR_LEN];
242
243 totallen = ntohs(auth->length);
244 secretlen = (int)strlen(secret);
245
246 /* Do sanity checks on packet length */
247 if ((totallen < 20) || (totallen > 4096)) {
248 rc_log(LOG_ERR,
249 "rc_check_reply: received RADIUS server response with invalid length");
250 return BADRESP_RC;
251 }
252
253 /* Verify buffer space, should never trigger with current buffer size and check above */
254 if ((totallen + secretlen) > bufferlen) {
255 rc_log(LOG_ERR,
256 "rc_check_reply: not enough buffer space to verify RADIUS server response");
257 return BADRESP_RC;
258 }
259
260 /* Verify that id (seq. number) matches what we sent */
261 if (auth->id != seq_nbr) {
262 rc_log(LOG_ERR,
263 "rc_check_reply: received non-matching id in RADIUS server response");
264 return BADRESPID_RC;
265 }
266 /* Verify the reply digest */
267 memcpy((char *)reply_digest, (char *)auth->vector, AUTH_VECTOR_LEN);
268 memcpy((char *)auth->vector, (char *)vector, AUTH_VECTOR_LEN);
269 memcpy((char *)auth + totallen, secret, secretlen);
270 rc_md5_calc(calc_digest, (unsigned char *)auth, totallen + secretlen);
271
272 if (rc_memcmp((char *)reply_digest, (char *)calc_digest,
273 AUTH_VECTOR_LEN) != 0) {
274 rc_log(LOG_ERR,
275 "rc_check_reply: received invalid reply digest from RADIUS server");
276 return BADRESP_RC;
277 }
278
279 return OK_RC;
280
281}
282
287static void rc_random_vector(unsigned char vector[AUTH_VECTOR_LEN])
288{
289#if defined(HAVE_GNUTLS)
290 int ret = gnutls_rnd(GNUTLS_RND_NONCE, vector, AUTH_VECTOR_LEN);
291 assert(ret >= 0);
292#else
293 int ret = getentropy(vector, AUTH_VECTOR_LEN);
294 assert(ret == 0);
295#endif
296}
297
299
300
313static int add_msg_auth_attr(rc_handle * rh, char * secret,
314 AUTH_HDR *auth, int total_length)
315{
316 size_t secretlen = strlen(secret);
317 uint8_t *msg_auth = (uint8_t *)auth + total_length;
318 msg_auth[0] = PW_MESSAGE_AUTHENTICATOR;
319 msg_auth[1] = 18;
320 memset(&msg_auth[2], 0, MD5_DIGEST_SIZE);
321 total_length += 18;
322 auth->length = htons((unsigned short)total_length);
323
324 /* Calculate HMAC-MD5 [RFC2104] hash */
325 uint8_t digest[MD5_DIGEST_SIZE];
326 rc_hmac_md5((uint8_t *)auth, (size_t)total_length, (uint8_t *)secret, secretlen, digest);
327 memcpy(&msg_auth[2], digest, MD5_DIGEST_SIZE);
328
329 return total_length;
330}
331
343static int validate_message_authenticator(const uint8_t *recv_buffer,
344 size_t length, const char *secret,
345 const unsigned char *req_auth)
346{
347 uint8_t verify_buffer[RC_BUFFER_LEN];
348 pkt_buf vb;
349 uint8_t ma_copy[MD5_DIGEST_SIZE];
350 uint8_t digest[MD5_DIGEST_SIZE];
351 uint8_t attr_type, attr_len;
352 int ma_found = 0;
353
354 if (AUTH_HDR_LEN + length > sizeof(verify_buffer)) {
355 rc_log(LOG_ERR, "%s: packet too large for verification buffer", __func__);
356 return -1;
357 }
358
359 /* Copy the packet, substitute the Request Authenticator per RFC 3579 ยง3.2,
360 * and zero the Message-Authenticator value before computing HMAC-MD5. */
361 memcpy(verify_buffer, recv_buffer, AUTH_HDR_LEN + length);
362 memcpy(verify_buffer + 4, req_auth, AUTH_VECTOR_LEN);
363 pb_init_read(&vb, verify_buffer + AUTH_HDR_LEN, length, length);
364
365 while (pb_len(&vb) >= 2) {
366 attr_type = vb.data[0];
367 attr_len = vb.data[1];
368 if (attr_len < 2 || (size_t)attr_len > pb_len(&vb))
369 break; /* malformed; already rejected by upstream attr-loop */
370
371 if (attr_type == PW_MESSAGE_AUTHENTICATOR) {
372 if (attr_len != 2 + MD5_DIGEST_SIZE) {
373 rc_log(LOG_ERR, "%s: Message-Authenticator has wrong length %u",
374 __func__, (unsigned)(attr_len - 2));
375 return -1;
376 }
377 /* Save original value before zeroing in the verification copy */
378 memcpy(ma_copy, vb.data + 2, MD5_DIGEST_SIZE);
379 memset(vb.data + 2, '\0', MD5_DIGEST_SIZE);
380 ma_found = 1;
381 break;
382 }
383 assert(pb_pull(&vb, attr_len) == 0);
384 }
385
386 if (!ma_found)
387 return -1;
388
389 rc_hmac_md5(verify_buffer, AUTH_HDR_LEN + length, (uint8_t *)secret, strlen(secret), digest);
390 return rc_memcmp(ma_copy, digest, MD5_DIGEST_SIZE);
391}
392
405int rc_send_server_ctx(rc_handle * rh, RC_AAA_CTX ** ctx, SEND_DATA * data,
406 char *msg, rc_type type)
407{
408 int sockfd = -1;
409 AUTH_HDR *auth, *recv_auth;
410 char *server_name, *p; /* Name of server to query */
411 struct sockaddr_storage our_sockaddr;
412 struct addrinfo *auth_addr = NULL;
413 socklen_t salen;
414 int result = 0;
415 int total_length;
416 int length, pos;
417 int retry_max;
418 const rc_sockets_override *sfuncs;
419 unsigned discover_local_ip;
420 size_t secretlen;
421 char secret[MAX_SECRET_LENGTH + 1];
422 unsigned char vector[AUTH_VECTOR_LEN];
423 uint8_t recv_buffer[RC_BUFFER_LEN];
424 uint8_t send_buffer[RC_BUFFER_LEN];
425 uint16_t tlen;
426 pkt_buf rb;
427 uint8_t attr_type, attr_len;
428 int retries;
429 VALUE_PAIR *vp;
430 struct pollfd pfd;
431 double start_time, timeout;
432 struct sockaddr_storage *ss_set = NULL;
433 char *server_type = "auth";
434 char *ns = NULL;
435 int ns_def_hdl = 0;
436
437 server_name = data->server;
438 if (server_name == NULL || server_name[0] == '\0')
439 return ERROR_RC;
440
441 ns = rc_conf_str(rh, "namespace"); /* Check for namespace config */
442 if (ns != NULL) {
443 if(-1 == rc_set_netns(ns, &ns_def_hdl)) {
444 rc_log(LOG_ERR, "rc_send_server: namespace %s set failed", ns);
445 return ERROR_RC;
446 }
447 }
448 if ((vp = rc_avpair_get(data->send_pairs, PW_SERVICE_TYPE, 0)) &&
449 (vp->lvalue == PW_ADMINISTRATIVE)) {
450 strlcpy(secret, MGMT_POLL_SECRET, sizeof(secret));
451 auth_addr =
452 rc_getaddrinfo(server_name,
453 type == AUTH ? PW_AI_AUTH : PW_AI_ACCT);
454 if (auth_addr == NULL) {
455 result = ERROR_RC;
456 goto exit_error;
457 }
458 } else {
459 if (data->secret != NULL) {
460 strlcpy(secret, data->secret, sizeof(secret));
461 }
462 /*
463 else
464 {
465 */
467 (rh, server_name, &auth_addr, secret, type) != 0) {
468 rc_log(LOG_ERR,
469 "rc_send_server: unable to find server: %s",
470 server_name);
471 result = ERROR_RC;
472 goto exit_error;
473 }
474 /*} */
475 }
476
477 sfuncs = &rh->so;
478
479 if (sfuncs->static_secret) {
480 /* any static secret set in sfuncs overrides the configured */
481 strlcpy(secret, sfuncs->static_secret, sizeof(secret));
482 }
483
484 if (sfuncs->lock) {
485 if (sfuncs->lock(sfuncs->ptr) != 0) {
486 rc_log(LOG_ERR, "%s: lock error", __func__);
487 result = ERROR_RC;
488 goto exit_error;
489 }
490 }
491
492 rc_own_bind_addr(rh, &our_sockaddr);
493 discover_local_ip = 0;
494 if (our_sockaddr.ss_family == AF_INET) {
495 if (((struct sockaddr_in *)(&our_sockaddr))->sin_addr.s_addr ==
496 INADDR_ANY) {
497 discover_local_ip = 1;
498 }
499 }
500
501 DEBUG(LOG_ERR, "DEBUG: rc_send_server: creating socket to: %s",
502 server_name);
503 if (discover_local_ip) {
504 result = rc_get_srcaddr(SA(&our_sockaddr), auth_addr->ai_addr);
505 if (result != OK_RC) {
506 memset(secret, '\0', sizeof(secret));
507 rc_log(LOG_ERR,
508 "rc_send_server: cannot figure our own address");
509 goto cleanup;
510 }
511 }
512
513 if (sfuncs->get_fd) {
514 sockfd = sfuncs->get_fd(sfuncs->ptr, SA(&our_sockaddr));
515 if (sockfd < 0) {
516 memset(secret, '\0', sizeof(secret));
517 rc_log(LOG_ERR, "rc_send_server: socket: %s",
518 strerror(errno));
519 result = ERROR_RC;
520 goto cleanup;
521 }
522 }
523
524 if(our_sockaddr.ss_family == AF_INET6) {
525 /* Check for IPv6 non-temporary address support */
526 char *non_temp_addr = rc_conf_str(rh, "use-public-addr");
527 if (non_temp_addr && (strcasecmp(non_temp_addr, "true") == 0)) {
528#if defined(__linux__)
529 int sock_opt = IPV6_PREFER_SRC_PUBLIC;
530 if (setsockopt(sockfd, IPPROTO_IPV6, IPV6_ADDR_PREFERENCES,
531 &sock_opt, sizeof(sock_opt)) != 0) {
532 rc_log(LOG_ERR, "rc_send_server: setsockopt: %s",
533 strerror(errno));
534 result = ERROR_RC;
535 goto cleanup;
536 }
537#elif defined(BSD) || defined(__APPLE__)
538 int sock_opt = 0;
539 if (setsockopt(sockfd, IPPROTO_IPV6, IPV6_PREFER_TEMPADDR,
540 &sock_opt, sizeof(sock_opt)) != 0) {
541 rc_log(LOG_ERR, "rc_send_server: setsockopt: %s",
542 strerror(errno));
543 result = ERROR_RC;
544 goto cleanup;
545 }
546#else
547 rc_log(LOG_INFO, "rc_send_server: Usage of non-temporary IPv6"
548 " address is not supported in this system");
549#endif
550 }
551 }
552
553 retry_max = data->retries; /* Max. numbers to try for reply */
554 retries = 0; /* Init retry cnt for blocking call */
555
556 if (data->svc_port) {
557 if (our_sockaddr.ss_family == AF_INET)
558 ((struct sockaddr_in *)auth_addr->ai_addr)->sin_port =
559 htons((unsigned short)data->svc_port);
560 else
561 ((struct sockaddr_in6 *)auth_addr->ai_addr)->sin6_port =
562 htons((unsigned short)data->svc_port);
563 }
564
565 /*
566 * Fill in NAS-IP-Address (if needed)
567 */
568 if (rh->nas_addr_set) {
571
572 ss_set = &rh->nas_addr;
573 } else if (rc_avpair_get(data->send_pairs, PW_NAS_IP_ADDRESS, 0) == NULL &&
574 rc_avpair_get(data->send_pairs, PW_NAS_IPV6_ADDRESS, 0) == NULL) {
575
576 ss_set = &our_sockaddr;
577 }
578
579 if (ss_set) {
580 if (ss_set->ss_family == AF_INET) {
581 uint32_t ip;
582 ip = *((uint32_t
583 *) (&((struct sockaddr_in *)ss_set)->
584 sin_addr));
585 ip = ntohl(ip);
586
587 rc_avpair_add(rh, &(data->send_pairs),
588 PW_NAS_IP_ADDRESS, &ip, 0, 0);
589 } else {
590 void *p;
591 p = &((struct sockaddr_in6 *)ss_set)->sin6_addr;
592
593 rc_avpair_add(rh, &(data->send_pairs),
594 PW_NAS_IPV6_ADDRESS, p, 16, 0);
595 }
596 }
597
598 /*
599 * Fill in NAS-Identifier (if needed)
600 */
601 p = rc_conf_str(rh, "nas-identifier");
602 if (p != NULL) {
604 rc_avpair_add(rh, &(data->send_pairs),
605 PW_NAS_IDENTIFIER, p, -1, 0);
606 }
607
608 /* Build a request */
609 auth = (AUTH_HDR *) send_buffer;
610 auth->code = data->code;
611 auth->id = data->seq_nbr;
612
613 if (data->code == PW_ACCOUNTING_REQUEST) {
614 server_type = "acct";
615 total_length = rc_pack_list(data->send_pairs, secret, auth, RC_MAX_PACKET_LEN);
616 if (total_length < 0) {
617 result = ERROR_RC;
618 goto cleanup;
619 }
620
621 tlen = htons((unsigned short)total_length);
622 memcpy(&auth->length, &tlen, sizeof(uint16_t));
623
624 memset((char *)auth->vector, 0, AUTH_VECTOR_LEN);
625 secretlen = strlen(secret);
626 memcpy((char *)auth + total_length, secret, secretlen);
627 rc_md5_calc(vector, (unsigned char *)auth,
628 total_length + secretlen);
629 memcpy((char *)auth->vector, (char *)vector, AUTH_VECTOR_LEN);
630 } else {
631 rc_random_vector(vector);
632 memcpy((char *)auth->vector, (char *)vector, AUTH_VECTOR_LEN);
633
634 /* Leave 2+MD5_DIGEST_SIZE bytes for Message-Authenticator (added below) */
635 total_length = rc_pack_list(data->send_pairs, secret, auth,
636 RC_MAX_PACKET_LEN - (2 + MD5_DIGEST_SIZE));
637 if (total_length < 0) {
638 result = ERROR_RC;
639 goto cleanup;
640 }
641
642 total_length = add_msg_auth_attr(rh, secret, auth, total_length);
643
644 auth->length = htons((unsigned short)total_length);
645 }
646
647 if (radcli_debug) {
648 char our_addr_txt[50] = ""; /* hold a text IP */
649 char auth_addr_txt[50] = ""; /* hold a text IP */
650
651 getnameinfo(SA(&our_sockaddr), SS_LEN(&our_sockaddr), NULL, 0,
652 our_addr_txt, sizeof(our_addr_txt), NI_NUMERICHOST);
653 getnameinfo(auth_addr->ai_addr, auth_addr->ai_addrlen, NULL, 0,
654 auth_addr_txt, sizeof(auth_addr_txt),
655 NI_NUMERICHOST);
656
657 DEBUG(LOG_ERR,
658 "DEBUG: timeout=%d retries=%d local %s : 0, remote %s : %u\n",
659 data->timeout, retry_max, our_addr_txt, auth_addr_txt,
660 data->svc_port);
661 }
662
663 for (;;) {
664 do {
665 result =
666 sfuncs->sendto(sfuncs->ptr, sockfd, (char *)auth,
667 (unsigned int)total_length, (int)0,
668 SA(auth_addr->ai_addr),
669 auth_addr->ai_addrlen);
670 } while (result == -1 && errno == EINTR);
671 if (result == -1) {
672 result = errno == ENETUNREACH ? NETUNREACH_RC : ERROR_RC;
673 rc_log(LOG_ERR, "%s: socket: %s", __FUNCTION__,
674 strerror(errno));
675 goto cleanup;
676 }
677
678 /* Re-fetch fd: sendto() may have triggered a TLS session
679 * restart (restart_session), replacing the underlying socket. */
680 if (sfuncs->get_active_fd) {
681 int new_fd = sfuncs->get_active_fd(sfuncs->ptr);
682 if (new_fd >= 0)
683 sockfd = new_fd;
684 }
685 pfd.fd = sockfd;
686 pfd.events = POLLIN;
687 pfd.revents = 0;
688 start_time = rc_getmtime();
689 for (timeout = data->timeout; timeout > 0;
690 timeout -= rc_getmtime() - start_time) {
691 result = poll(&pfd, 1, timeout * 1000);
692 if (result != -1 || errno != EINTR)
693 break;
694 }
695
696 if (result == -1) {
697 rc_log(LOG_ERR, "rc_send_server: poll: %s",
698 strerror(errno));
699 memset(secret, '\0', sizeof(secret));
700 SCLOSE(sockfd);
701 result = ERROR_RC;
702 goto cleanup;
703 }
704
705 if (result == 1 && (pfd.revents & POLLIN) != 0) {
706 salen = auth_addr->ai_addrlen;
707 do {
708 length = sfuncs->recvfrom(sfuncs->ptr, sockfd,
709 (char *)recv_buffer,
710 (int)
711 sizeof(recv_buffer),
712 (int)0,
713 SA(auth_addr->
714 ai_addr), &salen);
715 } while (length == -1 && errno == EINTR);
716
717 if (length <= 0) {
718 int e = errno;
719 rc_log(LOG_ERR,
720 "rc_send_server: recvfrom: %s:%d: %s",
721 server_name, data->svc_port,
722 strerror(e));
723 if (length == -1 && (e == EAGAIN || e == EINTR))
724 continue;
725 SCLOSE(sockfd);
726 memset(secret, '\0', sizeof(secret));
727 result = ERROR_RC;
728 goto cleanup;
729 }
730
731 recv_auth = (AUTH_HDR *) recv_buffer;
732
733 if (length < AUTH_HDR_LEN
734 || length < ntohs(recv_auth->length)) {
735 rc_log(LOG_ERR,
736 "rc_send_server: recvfrom: %s:%d: reply is too short",
737 server_name, data->svc_port);
738 SCLOSE(sockfd);
739 memset(secret, '\0', sizeof(secret));
740 result = ERROR_RC;
741 goto cleanup;
742 }
743
744 result =
745 rc_check_reply(recv_auth, RC_BUFFER_LEN, secret,
746 vector, data->seq_nbr);
747 if (result != BADRESPID_RC) {
748 /* if a message that doesn't match our ID was received, then ignore
749 * it, and try to receive more, until timeout. That is because in
750 * DTLS the channel is shared, and we may receive duplicates or
751 * out-of-order packets. */
752 break;
753 }
754 }
755
756 /*
757 * Timed out waiting for response. Retry "retry_max" times
758 * before giving up. If retry_max = 0, don't retry at all.
759 */
760 if (retries++ >= retry_max) {
761 char radius_server_ip[128];
762 struct sockaddr_in *si =
763 (struct sockaddr_in *)auth_addr->ai_addr;
764 inet_ntop(auth_addr->ai_family, &si->sin_addr,
765 radius_server_ip, sizeof(radius_server_ip));
766 rc_log(LOG_ERR,
767 "rc_send_server: no reply from RADIUS %s server %s:%u",
768 server_type, radius_server_ip, data->svc_port);
769 SCLOSE(sockfd);
770 memset(secret, '\0', sizeof(secret));
771 result = TIMEOUT_RC;
772 goto cleanup;
773 }
774 }
775
776 /*
777 * If UDP is larger than RADIUS, shorten it to RADIUS.
778 */
779 if (length > ntohs(recv_auth->length))
780 length = ntohs(recv_auth->length);
781
782 /*
783 * Verify that it's a valid RADIUS packet before doing ANYTHING with it.
784 */
785 pb_init_read(&rb, recv_buffer, length, RC_BUFFER_LEN);
786 assert(pb_pull(&rb, AUTH_HDR_LEN) == 0);
787 while (pb_len(&rb) > 0) {
788 if (pb_peek_byte(&rb, 0, &attr_type) < 0 ||
789 pb_peek_byte(&rb, 1, &attr_len) < 0) {
790 rc_log(LOG_ERR,
791 "rc_send_server: recvfrom: %s:%d: truncated attribute",
792 server_name, data->svc_port);
793 SCLOSE(sockfd);
794 memset(secret, '\0', sizeof(secret));
795 result = ERROR_RC;
796 goto cleanup;
797 }
798 if (attr_type == 0) {
799 rc_log(LOG_ERR,
800 "rc_send_server: recvfrom: %s:%d: attribute zero is invalid",
801 server_name, data->svc_port);
802 SCLOSE(sockfd);
803 memset(secret, '\0', sizeof(secret));
804 result = ERROR_RC;
805 goto cleanup;
806 }
807 if (attr_len < 2) {
808 rc_log(LOG_ERR,
809 "rc_send_server: recvfrom: %s:%d: attribute length is too small",
810 server_name, data->svc_port);
811 SCLOSE(sockfd);
812 memset(secret, '\0', sizeof(secret));
813 result = ERROR_RC;
814 goto cleanup;
815 }
816 if (attr_len > pb_len(&rb)) {
817 rc_log(LOG_ERR,
818 "rc_send_server: recvfrom: %s:%d: attribute overflows the packet",
819 server_name, data->svc_port);
820 SCLOSE(sockfd);
821 memset(secret, '\0', sizeof(secret));
822 result = ERROR_RC;
823 goto cleanup;
824 }
825 assert(pb_pull(&rb, attr_len) == 0);
826 }
827
828 length = ntohs(recv_auth->length) - AUTH_HDR_LEN;
829 if (length > 0) {
830 data->receive_pairs = rc_avpair_gen(rh, NULL, recv_auth->data,
831 length, 0);
832 } else {
833 data->receive_pairs = NULL;
834 }
835
836 SCLOSE(sockfd);
837 result = populate_ctx(ctx, secret, vector);
838 if (result != OK_RC) {
839 memset(secret, '\0', sizeof(secret));
840 goto cleanup;
841 }
842
843 /* Per draft-ietf-radext-deprecating-radius, Message-Authenticator MUST
844 * be the first attribute in Access-Request responses to prevent MD5
845 * prefix attacks (BLAST RADIUS). Not required for Accounting-Response. */
846 if (type == AUTH) {
847 /* Verify MA whenever present, regardless of position.
848 * An incorrect MA always causes rejection. */
850 if (validate_message_authenticator(recv_buffer, length, secret, vector)) {
851 rc_log(LOG_ERR,
852 "rc_send_server: recvfrom: %s:%d: received attribute Message-Authenticator is incorrect",
853 server_name, data->svc_port);
854 memset(secret, '\0', sizeof(secret));
855 result = ERROR_RC;
856 goto cleanup;
857 }
858 }
859
860 /* Enforce BLAST RADIUS: MA must also be the first attribute. */
861 if (length == 0 ||
862 recv_buffer[AUTH_HDR_LEN] != PW_MESSAGE_AUTHENTICATOR) {
863 p = rc_conf_str(rh, "require-message-authenticator");
864 if (p == NULL || (strcasecmp(p, "false") != 0 && strcasecmp(p, "no") != 0)) {
865 rc_log(LOG_ERR,
866 "rc_send_server: recvfrom: %s:%d: required attribute Message-Authenticator is missing or not first",
867 server_name, data->svc_port);
868 memset(secret, '\0', sizeof(secret));
869 result = ERROR_RC;
870 goto cleanup;
871 }
872 }
873 }
874
875 memset(secret, '\0', sizeof(secret));
876
877 if (msg) {
878 *msg = '\0';
879 pos = 0;
880 vp = data->receive_pairs;
881 while (vp) {
882 if ((vp = rc_avpair_get(vp, PW_REPLY_MESSAGE, 0))) {
883 strappend(msg, PW_MAX_MSG_SIZE, &pos,
884 vp->strvalue);
885 strappend(msg, PW_MAX_MSG_SIZE, &pos, "\n");
886 vp = vp->next;
887 }
888 }
889 }
890
891 switch (recv_auth->code) {
892 case PW_ACCESS_ACCEPT:
893 case PW_PASSWORD_ACK:
894 case PW_ACCOUNTING_RESPONSE:
895 result = OK_RC;
896 break;
897
898 case PW_ACCESS_REJECT:
899 case PW_PASSWORD_REJECT:
900 result = REJECT_RC;
901 break;
902
903 case PW_ACCESS_CHALLENGE:
904 result = CHALLENGE_RC;
905 break;
906
907 default:
908 rc_log(LOG_ERR, "rc_send_server: received RADIUS server response neither ACCEPT nor REJECT, code=%d is invalid",
909 recv_auth->code);
910 result = BADRESP_RC;
911 }
912
913 cleanup:
914 if (auth_addr)
915 freeaddrinfo(auth_addr);
916
917 if (sfuncs->unlock) {
918 if (sfuncs->unlock(sfuncs->ptr) != 0) {
919 rc_log(LOG_ERR, "%s: unlock error", __func__);
920 }
921 }
922 exit_error:
923 if (ns != NULL) {
924 if(-1 == rc_reset_netns(&ns_def_hdl)) {
925 rc_log(LOG_ERR, "rc_send_server: namespace %s reset failed", ns);
926 result = ERROR_RC;
927 }
928 }
929
930 return result;
931}
int rc_get_srcaddr(struct sockaddr *lia, const struct sockaddr *ria)
Definition ip_util.c:124
void rc_own_bind_addr(rc_handle *rh, struct sockaddr_storage *lia)
Definition ip_util.c:164
void rc_avpair_remove(VALUE_PAIR **list, uint32_t attrid, uint32_t vendorspec)
Definition avpair.c:69
rc_type
Definition radcli.h:70
int rc_pack_list(VALUE_PAIR *vp, char *secret, AUTH_HDR *auth, int max_len)
Definition sendserver.c:56
#define MGMT_POLL_SECRET
Default for Merit radiusd.
Definition radcli.h:458
int rc_send_server(rc_handle *rh, SEND_DATA *data, char *msg, rc_type type)
Definition sendserver.c:221
char * rc_conf_str(rc_handle const *rh, char const *optname)
Definition config.c:732
int rc_find_server_addr(rc_handle const *rh, char const *server_name, struct addrinfo **info, char *secret, rc_type type)
Definition config.c:931
VALUE_PAIR * rc_avpair_add(rc_handle const *rh, VALUE_PAIR **list, uint32_t attrid, void const *pval, int len, uint32_t vendorspec)
Definition avpair.c:46
VALUE_PAIR * rc_avpair_get(VALUE_PAIR *vp, uint32_t attrid, uint32_t vendorspec)
Definition avpair.c:467
@ AUTH
Request for authentication server.
Definition radcli.h:71
@ PW_NAS_IDENTIFIER
Its type is string.
Definition radcli.h:178
@ PW_NAS_IP_ADDRESS
Its type is ipaddr.
Definition radcli.h:150
@ PW_SERVICE_TYPE
Its type is integer.
Definition radcli.h:152
@ PW_NAS_IPV6_ADDRESS
Its type is string.
Definition radcli.h:240
@ PW_MESSAGE_AUTHENTICATOR
Its type is string.
Definition radcli.h:225
@ PW_REPLY_MESSAGE
Its type is string.
Definition radcli.h:164
@ PW_VENDOR_SPECIFIC
Its type is string.
Definition radcli.h:172
@ PW_USER_PASSWORD
Its type is string.
Definition radcli.h:148
@ PW_TYPE_IPADDR
The attribute is an IPv4 address in host-byte order.
Definition radcli.h:119
@ PW_TYPE_IPV6ADDR
The attribute is an 128-bit IPv6 address.
Definition radcli.h:121
@ PW_TYPE_IPV6PREFIX
The attribute is an IPv6 prefix; the lvalue will indicate its size.
Definition radcli.h:122
@ PW_TYPE_INTEGER
The attribute is a 32-bit integer.
Definition radcli.h:118
@ PW_TYPE_DATE
The attribute contains a 32-bit number indicating the seconds since epoch.
Definition radcli.h:120
@ PW_TYPE_STRING
The attribute is a printable string.
Definition radcli.h:117
rc_attr_type type
attribute type.
Definition radcli.h:483
uint64_t attribute
attribute numeric value of type rc_attr_id including vendor; use VENDOR() and ATTRID() to separate.
Definition radcli.h:482
uint32_t lvalue
attribute value if type is PW_TYPE_INTEGER, PW_TYPE_DATE or PW_TYPE_IPADDR.
Definition radcli.h:484
char strvalue[AUTH_STRING_LEN+1]
contains attribute value in other cases.
Definition radcli.h:485
int timeout
Session timeout in seconds.
Definition radcli.h:497
char * secret
Shared secret of RADIUS server.
Definition radcli.h:496
uint8_t seq_nbr
Packet sequence number.
Definition radcli.h:493
int svc_port
RADIUS protocol destination port.
Definition radcli.h:495
char * server
Name/address of RADIUS server.
Definition radcli.h:494
VALUE_PAIR * send_pairs
More a/v pairs to send.
Definition radcli.h:499
VALUE_PAIR * receive_pairs
Where to place received a/v pairs.
Definition radcli.h:500
uint8_t code
RADIUS packet code.
Definition radcli.h:492