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