Radcli library 1.5.0
A simple radius library
Loading...
Searching...
No Matches
sendserver.c
1/*
2 * Copyright (C) 1995,1996,1997 Lars Fenneberg
3 *
4 * Copyright 1992 Livingston Enterprises, Inc.
5 *
6 * Copyright 1992,1993, 1994,1995 The Regents of the University of Michigan
7 * and Merit Network, Inc. All Rights Reserved
8 *
9 * See the file COPYRIGHT for the respective terms and conditions.
10 * If the file is missing contact me at lf@elemental.net
11 * and I'll send you a copy.
12 *
13 */
14
15#include <includes.h>
16#include <radcli/radcli.h>
17#include <pathnames.h>
18#include <poll.h>
19#include "util.h"
20#include "rc-md5.h"
21#include "rc-hmac.h"
22
23#if defined(HAVE_GNUTLS)
24# include <gnutls/gnutls.h>
25# include <gnutls/crypto.h>
26#endif
27
28#if defined(__linux__)
29#include <linux/in6.h>
30#endif
31
32
33#define SCLOSE(fd) if (sfuncs->close_fd) sfuncs->close_fd(fd)
34
35static void rc_random_vector(unsigned char *);
36static int rc_check_reply(AUTH_HDR *, int, char const *, unsigned char const *,
37 unsigned char);
38
45
53static int rc_pack_list(VALUE_PAIR * vp, char *secret, AUTH_HDR * auth)
54{
55 int length, i, pc, padded_length;
56 int total_length = 0;
57 size_t secretlen;
58 uint32_t lvalue, vendor;
59 unsigned char passbuf[RC_MAX(AUTH_PASS_LEN, CHAP_VALUE_LENGTH)];
60 unsigned char md5buf[256];
61 unsigned char *buf, *vector, *vsa_length_ptr;
62
63 buf = auth->data;
64
65 while (vp != NULL) {
66 vsa_length_ptr = NULL;
67 if (VENDOR(vp->attribute) != 0) {
68 *buf++ = PW_VENDOR_SPECIFIC;
69 vsa_length_ptr = buf;
70 *buf++ = 6;
71 vendor = htonl(VENDOR(vp->attribute));
72 memcpy(buf, &vendor, sizeof(uint32_t));
73 buf += 4;
74 total_length += 6;
75 }
76 *buf++ = (vp->attribute & 0xff);
77
78 switch (vp->attribute) {
80
81 /* Encrypt the password */
82
83 /* Chop off password at AUTH_PASS_LEN */
84 length = vp->lvalue;
85 if (length > AUTH_PASS_LEN)
86 length = AUTH_PASS_LEN;
87
88 /* Calculate the padded length */
89 padded_length =
90 (length +
91 (AUTH_VECTOR_LEN - 1)) & ~(AUTH_VECTOR_LEN - 1);
92
93 /* Record the attribute length */
94 *buf++ = padded_length + 2;
95 if (vsa_length_ptr != NULL)
96 *vsa_length_ptr += padded_length + 2;
97
98 /* Pad the password with zeros */
99 memset((char *)passbuf, '\0', AUTH_PASS_LEN);
100 memcpy((char *)passbuf, vp->strvalue, (size_t) length);
101
102 secretlen = strlen(secret);
103 vector = (unsigned char *)auth->vector;
104 for (i = 0; i < padded_length; i += AUTH_VECTOR_LEN) {
105 /* Calculate the MD5 digest */
106 strcpy((char *)md5buf, secret);
107 memcpy((char *)md5buf + secretlen, vector,
108 AUTH_VECTOR_LEN);
109 rc_md5_calc(buf, md5buf,
110 secretlen + AUTH_VECTOR_LEN);
111
112 /* Remember the start of the digest */
113 vector = buf;
114
115 /* Xor the password into the MD5 digest */
116 for (pc = i; pc < (i + AUTH_VECTOR_LEN); pc++) {
117 *buf++ ^= passbuf[pc];
118 }
119 }
120
121 total_length += padded_length + 2;
122
123 break;
124 default:
125 switch (vp->type) {
126 case PW_TYPE_STRING:
127 length = vp->lvalue;
128 *buf++ = length + 2;
129 if (vsa_length_ptr != NULL)
130 *vsa_length_ptr += length + 2;
131 memcpy(buf, vp->strvalue, (size_t) length);
132 buf += length;
133 total_length += length + 2;
134 break;
135
136 case PW_TYPE_IPV6ADDR:
137 length = 16;
138 *buf++ = length + 2;
139 if (vsa_length_ptr != NULL)
140 *vsa_length_ptr += length + 2;
141 memcpy(buf, vp->strvalue, (size_t) length);
142 buf += length;
143 total_length += length + 2;
144 break;
145
147 length = vp->lvalue;
148 *buf++ = length + 2;
149 if (vsa_length_ptr != NULL)
150 *vsa_length_ptr += length + 2;
151 memcpy(buf, vp->strvalue, (size_t) length);
152 buf += length;
153 total_length += length + 2;
154 break;
155
156 case PW_TYPE_INTEGER:
157 case PW_TYPE_IPADDR:
158 case PW_TYPE_DATE:
159 *buf++ = sizeof(uint32_t) + 2;
160 if (vsa_length_ptr != NULL)
161 *vsa_length_ptr += sizeof(uint32_t) + 2;
162 lvalue = htonl(vp->lvalue);
163 memcpy(buf, (char *)&lvalue, sizeof(uint32_t));
164 buf += sizeof(uint32_t);
165 total_length += sizeof(uint32_t) + 2;
166 break;
167
168 default:
169 break;
170 }
171 break;
172 }
173 vp = vp->next;
174 }
175 return total_length;
176}
177
185static void strappend(char *dest, unsigned max_size, int *pos, const char *src)
186{
187 unsigned len = strlen(src) + 1;
188
189 if (*pos == -1)
190 return;
191
192 if (len + *pos > max_size) {
193 *pos = -1;
194 return;
195 }
196
197 memcpy(&dest[*pos], src, len);
198 *pos += len - 1;
199 return;
200}
201
202
203static int populate_ctx(RC_AAA_CTX ** ctx, char secret[MAX_SECRET_LENGTH + 1],
204 uint8_t vector[AUTH_VECTOR_LEN])
205{
206 if (ctx) {
207 if (*ctx != NULL)
208 return ERROR_RC;
209
210 *ctx = malloc(sizeof(RC_AAA_CTX));
211 if (*ctx) {
212 memcpy((*ctx)->secret, secret, sizeof((*ctx)->secret));
213 memcpy((*ctx)->request_vector, vector,
214 sizeof((*ctx)->request_vector));
215 } else {
216 return ERROR_RC;
217 }
218 }
219 return OK_RC;
220}
221
232int rc_send_server(rc_handle * rh, SEND_DATA * data, char *msg, rc_type type)
233{
234 return rc_send_server_ctx(rh, NULL, data, msg, type);
235}
236
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#ifdef DIGEST_DEBUG
254 uint8_t *ptr;
255#endif
256
257 totallen = ntohs(auth->length);
258 secretlen = (int)strlen(secret);
259
260 /* Do sanity checks on packet length */
261 if ((totallen < 20) || (totallen > 4096)) {
262 rc_log(LOG_ERR,
263 "rc_check_reply: received RADIUS server response with invalid length");
264 return BADRESP_RC;
265 }
266
267 /* Verify buffer space, should never trigger with current buffer size and check above */
268 if ((totallen + secretlen) > bufferlen) {
269 rc_log(LOG_ERR,
270 "rc_check_reply: not enough buffer space to verify RADIUS server response");
271 return BADRESP_RC;
272 }
273
274 /* Verify that id (seq. number) matches what we sent */
275 if (auth->id != seq_nbr) {
276 rc_log(LOG_ERR,
277 "rc_check_reply: received non-matching id in RADIUS server response");
278 return BADRESPID_RC;
279 }
280 /* Verify the reply digest */
281 memcpy((char *)reply_digest, (char *)auth->vector, AUTH_VECTOR_LEN);
282 memcpy((char *)auth->vector, (char *)vector, AUTH_VECTOR_LEN);
283 memcpy((char *)auth + totallen, secret, secretlen);
284#ifdef DIGEST_DEBUG
285 rc_log(LOG_ERR, "Calculating digest on:");
286 for (ptr = (u_char *) auth;
287 ptr < ((u_char *) auth) + totallen + secretlen; ptr += 32) {
288 char buf[65];
289 int i;
290
291 buf[0] = '\0';
292 for (i = 0; i < 32; i++) {
293 if (ptr + i >= ((u_char *) auth) + totallen + secretlen)
294 break;
295 sprintf(buf + i * 2, "%.2X", ptr[i]);
296 }
297 rc_log(LOG_ERR, " %s", buf);
298 }
299#endif
300 rc_md5_calc(calc_digest, (unsigned char *)auth, totallen + secretlen);
301#ifdef DIGEST_DEBUG
302 rc_log(LOG_ERR, "Calculated digest is:");
303 for (ptr = (u_char *) calc_digest; ptr < ((u_char *) calc_digest) + 16;
304 ptr += 32) {
305 char buf[65];
306 int i;
307
308 buf[0] = '\0';
309 for (i = 0; i < 32; i++) {
310 if (ptr + i >= ((u_char *) calc_digest) + 16)
311 break;
312 sprintf(buf + i * 2, "%.2X", ptr[i]);
313 }
314 rc_log(LOG_ERR, " %s", buf);
315 }
316 rc_log(LOG_ERR, "Reply digest is:");
317 for (ptr = (u_char *) reply_digest;
318 ptr < ((u_char *) reply_digest) + 16; ptr += 32) {
319 char buf[65];
320 int i;
321
322 buf[0] = '\0';
323 for (i = 0; i < 32; i++) {
324 if (ptr + i >= ((u_char *) reply_digest) + 16)
325 break;
326 sprintf(buf + i * 2, "%.2X", ptr[i]);
327 }
328 rc_log(LOG_ERR, " %s", buf);
329 }
330#endif
331
332 if (rc_memcmp((char *)reply_digest, (char *)calc_digest,
333 AUTH_VECTOR_LEN) != 0) {
334 rc_log(LOG_ERR,
335 "rc_check_reply: received invalid reply digest from RADIUS server");
336 return BADRESP_RC;
337 }
338
339 return OK_RC;
340
341}
342
347static void rc_random_vector(unsigned char *vector)
348{
349 int randno;
350 int i;
351#if defined(HAVE_GNUTLS)
352 if (gnutls_rnd(GNUTLS_RND_NONCE, vector, AUTH_VECTOR_LEN) >= 0) {
353 return;
354 }
355#elif defined(HAVE_GETENTROPY)
356 if (getentropy(vector, AUTH_VECTOR_LEN) >= 0) {
357 return;
358 } /* else fall through */
359#elif defined(HAVE_DEV_URANDOM)
360 int fd;
361
362/* well, I added this to increase the security for user passwords.
363 we use /dev/urandom here, as /dev/random might block and we don't
364 need that much randomness. BTW, great idea, Ted! -lf, 03/18/95 */
365
366 if ((fd = open(_PATH_DEV_URANDOM, O_RDONLY)) >= 0) {
367 unsigned char *pos;
368 int readcount;
369
370 i = AUTH_VECTOR_LEN;
371 pos = vector;
372 while (i > 0) {
373 readcount = read(fd, (char *)pos, i);
374 if (readcount >= 0) {
375 pos += readcount;
376 i -= readcount;
377 } else {
378 if (errno != EINTR && errno != EAGAIN)
379 goto fallback;
380 }
381 }
382
383 close(fd);
384 return;
385 } /* else fall through */
386 fallback:
387#endif
388 for (i = 0; i < AUTH_VECTOR_LEN;) {
389 randno = random();
390 memcpy((char *)vector, (char *)&randno, sizeof(int));
391 vector += sizeof(int);
392 i += sizeof(int);
393 }
394
395 return;
396}
397
399
400
413static int add_msg_auth_attr(rc_handle * rh, char * secret,
414 AUTH_HDR *auth, int total_length)
415{
416 size_t secretlen = strlen(secret);
417 uint8_t *msg_auth = (uint8_t *)auth + total_length;
418 msg_auth[0] = PW_MESSAGE_AUTHENTICATOR;
419 msg_auth[1] = 18;
420 memset(&msg_auth[2], 0, MD5_DIGEST_SIZE);
421 total_length += 18;
422 auth->length = htons((unsigned short)total_length);
423
424 /* Calculate HMAC-MD5 [RFC2104] hash */
425 uint8_t digest[MD5_DIGEST_SIZE];
426 rc_hmac_md5((uint8_t *)auth, (size_t)total_length, (uint8_t *)secret, secretlen, digest);
427 memcpy(&msg_auth[2], digest, MD5_DIGEST_SIZE);
428
429 return total_length;
430}
431
443static int validate_message_authenticator(VALUE_PAIR *vp, const uint8_t *recv_buffer,
444 const size_t length, const char *secret,
445 const unsigned char *req_auth)
446{
447 uint8_t verify_buffer[RC_BUFFER_LEN];
448 uint8_t *idx = verify_buffer + AUTH_HDR_LEN;
449 const uint8_t *verify_end = verify_buffer + sizeof(verify_buffer);
450 const char *received_message_authenticator = NULL;
451 uint8_t digest[MD5_DIGEST_SIZE];
452 unsigned attr_len;
453
454 if (AUTH_HDR_LEN + length > sizeof(verify_buffer)) {
455 rc_log(LOG_ERR, "%s: packet too large for verification buffer", __func__);
456 return -1;
457 }
458
459 /* Copy the original packet, then substitute the Request Authenticator
460 * per RFC 3579 ยง3.2, and clear the Message-Authenticator value */
461 memcpy(verify_buffer, recv_buffer, AUTH_HDR_LEN + length);
462 memcpy(verify_buffer + 4, req_auth, AUTH_VECTOR_LEN);
463 for (; vp != NULL; vp = vp->next) {
464 if (vp->type == PW_TYPE_INTEGER || vp->type == PW_TYPE_DATE ||
465 vp->type == PW_TYPE_IPADDR) {
466 attr_len = 4;
467 } else {
468 attr_len = vp->lvalue;
469 }
470
471 /* type (1) + length (1) + value */
472 if (idx + 2 + attr_len > verify_end) {
473 rc_log(LOG_ERR, "%s: attribute overflows verification buffer", __func__);
474 return -1;
475 }
476 idx += 2;
477
479 if (vp->lvalue != MD5_DIGEST_SIZE) {
480 rc_log(LOG_ERR, "%s: Message-Authenticator has wrong length %u",
481 __func__, vp->lvalue);
482 return -1;
483 }
484 memset(idx, '\0', MD5_DIGEST_SIZE);
485 received_message_authenticator = vp->strvalue;
486 break;
487 } else {
488 idx += attr_len;
489 }
490 }
491
492 if (received_message_authenticator == NULL) {
493 return -1;
494 }
495
496 /* Calculate HMAC-MD5 [RFC2104] hash */
497 rc_hmac_md5(verify_buffer, AUTH_HDR_LEN + length, (uint8_t *)secret, strlen(secret), digest);
498 return rc_memcmp(received_message_authenticator, digest, MD5_DIGEST_SIZE);
499}
500
513int rc_send_server_ctx(rc_handle * rh, RC_AAA_CTX ** ctx, SEND_DATA * data,
514 char *msg, rc_type type)
515{
516 int sockfd = -1;
517 AUTH_HDR *auth, *recv_auth;
518 char *server_name, *p; /* Name of server to query */
519 struct sockaddr_storage our_sockaddr;
520 struct addrinfo *auth_addr = NULL;
521 socklen_t salen;
522 int result = 0;
523 int total_length;
524 int length, pos;
525 int retry_max;
526 const rc_sockets_override *sfuncs;
527 unsigned discover_local_ip;
528 size_t secretlen;
529 char secret[MAX_SECRET_LENGTH + 1];
530 unsigned char vector[AUTH_VECTOR_LEN];
531 uint8_t recv_buffer[RC_BUFFER_LEN];
532 uint8_t send_buffer[RC_BUFFER_LEN];
533 uint8_t *attr;
534 uint16_t tlen;
535 int retries;
536 VALUE_PAIR *vp;
537 struct pollfd pfd;
538 double start_time, timeout;
539 struct sockaddr_storage *ss_set = NULL;
540 char *server_type = "auth";
541 char *ns = NULL;
542 int ns_def_hdl = 0;
543
544 server_name = data->server;
545 if (server_name == NULL || server_name[0] == '\0')
546 return ERROR_RC;
547
548 ns = rc_conf_str(rh, "namespace"); /* Check for namespace config */
549 if (ns != NULL) {
550 if(-1 == rc_set_netns(ns, &ns_def_hdl)) {
551 rc_log(LOG_ERR, "rc_send_server: namespace %s set failed", ns);
552 return ERROR_RC;
553 }
554 }
555 if ((vp = rc_avpair_get(data->send_pairs, PW_SERVICE_TYPE, 0)) &&
556 (vp->lvalue == PW_ADMINISTRATIVE)) {
557 strcpy(secret, MGMT_POLL_SECRET);
558 auth_addr =
559 rc_getaddrinfo(server_name,
560 type == AUTH ? PW_AI_AUTH : PW_AI_ACCT);
561 if (auth_addr == NULL) {
562 result = ERROR_RC;
563 goto exit_error;
564 }
565 } else {
566 if (data->secret != NULL) {
567 strlcpy(secret, data->secret, MAX_SECRET_LENGTH);
568 }
569 /*
570 else
571 {
572 */
574 (rh, server_name, &auth_addr, secret, type) != 0) {
575 rc_log(LOG_ERR,
576 "rc_send_server: unable to find server: %s",
577 server_name);
578 result = ERROR_RC;
579 goto exit_error;
580 }
581 /*} */
582 }
583
584 sfuncs = &rh->so;
585
586 if (sfuncs->static_secret) {
587 /* any static secret set in sfuncs overrides the configured */
588 strlcpy(secret, sfuncs->static_secret,
589 MAX_SECRET_LENGTH);
590 }
591
592 if (sfuncs->lock) {
593 if (sfuncs->lock(sfuncs->ptr) != 0) {
594 rc_log(LOG_ERR, "%s: lock error", __func__);
595 result = ERROR_RC;
596 goto exit_error;
597 }
598 }
599
600 rc_own_bind_addr(rh, &our_sockaddr);
601 discover_local_ip = 0;
602 if (our_sockaddr.ss_family == AF_INET) {
603 if (((struct sockaddr_in *)(&our_sockaddr))->sin_addr.s_addr ==
604 INADDR_ANY) {
605 discover_local_ip = 1;
606 }
607 }
608
609 DEBUG(LOG_ERR, "DEBUG: rc_send_server: creating socket to: %s",
610 server_name);
611 if (discover_local_ip) {
612 result = rc_get_srcaddr(SA(&our_sockaddr), auth_addr->ai_addr);
613 if (result != OK_RC) {
614 memset(secret, '\0', sizeof(secret));
615 rc_log(LOG_ERR,
616 "rc_send_server: cannot figure our own address");
617 goto cleanup;
618 }
619 }
620
621 if (sfuncs->get_fd) {
622 sockfd = sfuncs->get_fd(sfuncs->ptr, SA(&our_sockaddr));
623 if (sockfd < 0) {
624 memset(secret, '\0', sizeof(secret));
625 rc_log(LOG_ERR, "rc_send_server: socket: %s",
626 strerror(errno));
627 result = ERROR_RC;
628 goto cleanup;
629 }
630 }
631
632 if(our_sockaddr.ss_family == AF_INET6) {
633 /* Check for IPv6 non-temporary address support */
634 char *non_temp_addr = rc_conf_str(rh, "use-public-addr");
635 if (non_temp_addr && (strcasecmp(non_temp_addr, "true") == 0)) {
636#if defined(__linux__)
637 int sock_opt = IPV6_PREFER_SRC_PUBLIC;
638 if (setsockopt(sockfd, IPPROTO_IPV6, IPV6_ADDR_PREFERENCES,
639 &sock_opt, sizeof(sock_opt)) != 0) {
640 rc_log(LOG_ERR, "rc_send_server: setsockopt: %s",
641 strerror(errno));
642 result = ERROR_RC;
643 goto cleanup;
644 }
645#elif defined(BSD) || defined(__APPLE__)
646 int sock_opt = 0;
647 if (setsockopt(sockfd, IPPROTO_IPV6, IPV6_PREFER_TEMPADDR,
648 &sock_opt, sizeof(sock_opt)) != 0) {
649 rc_log(LOG_ERR, "rc_send_server: setsockopt: %s",
650 strerror(errno));
651 result = ERROR_RC;
652 goto cleanup;
653 }
654#else
655 rc_log(LOG_INFO, "rc_send_server: Usage of non-temporary IPv6"
656 " address is not supported in this system");
657#endif
658 }
659 }
660
661 retry_max = data->retries; /* Max. numbers to try for reply */
662 retries = 0; /* Init retry cnt for blocking call */
663
664 if (data->svc_port) {
665 if (our_sockaddr.ss_family == AF_INET)
666 ((struct sockaddr_in *)auth_addr->ai_addr)->sin_port =
667 htons((unsigned short)data->svc_port);
668 else
669 ((struct sockaddr_in6 *)auth_addr->ai_addr)->sin6_port =
670 htons((unsigned short)data->svc_port);
671 }
672
673 /*
674 * Fill in NAS-IP-Address (if needed)
675 */
676 if (rh->nas_addr_set) {
679
680 ss_set = &rh->nas_addr;
681 } else if (rc_avpair_get(data->send_pairs, PW_NAS_IP_ADDRESS, 0) == NULL &&
682 rc_avpair_get(data->send_pairs, PW_NAS_IPV6_ADDRESS, 0) == NULL) {
683
684 ss_set = &our_sockaddr;
685 }
686
687 if (ss_set) {
688 if (ss_set->ss_family == AF_INET) {
689 uint32_t ip;
690 ip = *((uint32_t
691 *) (&((struct sockaddr_in *)ss_set)->
692 sin_addr));
693 ip = ntohl(ip);
694
695 rc_avpair_add(rh, &(data->send_pairs),
696 PW_NAS_IP_ADDRESS, &ip, 0, 0);
697 } else {
698 void *p;
699 p = &((struct sockaddr_in6 *)ss_set)->sin6_addr;
700
701 rc_avpair_add(rh, &(data->send_pairs),
702 PW_NAS_IPV6_ADDRESS, p, 16, 0);
703 }
704 }
705
706 /*
707 * Fill in NAS-Identifier (if needed)
708 */
709 p = rc_conf_str(rh, "nas-identifier");
710 if (p != NULL) {
712 rc_avpair_add(rh, &(data->send_pairs),
713 PW_NAS_IDENTIFIER, p, -1, 0);
714 }
715
716 /* Build a request */
717 auth = (AUTH_HDR *) send_buffer;
718 auth->code = data->code;
719 auth->id = data->seq_nbr;
720
721 if (data->code == PW_ACCOUNTING_REQUEST) {
722 server_type = "acct";
723 total_length =
724 rc_pack_list(data->send_pairs, secret, auth) + AUTH_HDR_LEN;
725
726 tlen = htons((unsigned short)total_length);
727 memcpy(&auth->length, &tlen, sizeof(uint16_t));
728
729 memset((char *)auth->vector, 0, AUTH_VECTOR_LEN);
730 secretlen = strlen(secret);
731 memcpy((char *)auth + total_length, secret, secretlen);
732 rc_md5_calc(vector, (unsigned char *)auth,
733 total_length + secretlen);
734 memcpy((char *)auth->vector, (char *)vector, AUTH_VECTOR_LEN);
735 } else {
736 rc_random_vector(vector);
737 memcpy((char *)auth->vector, (char *)vector, AUTH_VECTOR_LEN);
738
739 total_length =
740 rc_pack_list(data->send_pairs, secret, auth) + AUTH_HDR_LEN;
741
742 total_length = add_msg_auth_attr(rh, secret, auth, total_length);
743
744 auth->length = htons((unsigned short)total_length);
745 }
746
747 if (radcli_debug) {
748 char our_addr_txt[50] = ""; /* hold a text IP */
749 char auth_addr_txt[50] = ""; /* hold a text IP */
750
751 getnameinfo(SA(&our_sockaddr), SS_LEN(&our_sockaddr), NULL, 0,
752 our_addr_txt, sizeof(our_addr_txt), NI_NUMERICHOST);
753 getnameinfo(auth_addr->ai_addr, auth_addr->ai_addrlen, NULL, 0,
754 auth_addr_txt, sizeof(auth_addr_txt),
755 NI_NUMERICHOST);
756
757 DEBUG(LOG_ERR,
758 "DEBUG: timeout=%d retries=%d local %s : 0, remote %s : %u\n",
759 data->timeout, retry_max, our_addr_txt, auth_addr_txt,
760 data->svc_port);
761 }
762
763 for (;;) {
764 do {
765 result =
766 sfuncs->sendto(sfuncs->ptr, sockfd, (char *)auth,
767 (unsigned int)total_length, (int)0,
768 SA(auth_addr->ai_addr),
769 auth_addr->ai_addrlen);
770 } while (result == -1 && errno == EINTR);
771 if (result == -1) {
772 result = errno == ENETUNREACH ? NETUNREACH_RC : ERROR_RC;
773 rc_log(LOG_ERR, "%s: socket: %s", __FUNCTION__,
774 strerror(errno));
775 goto cleanup;
776 }
777
778 /* Re-fetch fd: sendto() may have triggered a TLS session
779 * restart (restart_session), replacing the underlying socket. */
780 if (sfuncs->get_active_fd) {
781 int new_fd = sfuncs->get_active_fd(sfuncs->ptr);
782 if (new_fd >= 0)
783 sockfd = new_fd;
784 }
785 pfd.fd = sockfd;
786 pfd.events = POLLIN;
787 pfd.revents = 0;
788 start_time = rc_getmtime();
789 for (timeout = data->timeout; timeout > 0;
790 timeout -= rc_getmtime() - start_time) {
791 result = poll(&pfd, 1, timeout * 1000);
792 if (result != -1 || errno != EINTR)
793 break;
794 }
795
796 if (result == -1) {
797 rc_log(LOG_ERR, "rc_send_server: poll: %s",
798 strerror(errno));
799 memset(secret, '\0', sizeof(secret));
800 SCLOSE(sockfd);
801 result = ERROR_RC;
802 goto cleanup;
803 }
804
805 if (result == 1 && (pfd.revents & POLLIN) != 0) {
806 salen = auth_addr->ai_addrlen;
807 do {
808 length = sfuncs->recvfrom(sfuncs->ptr, sockfd,
809 (char *)recv_buffer,
810 (int)
811 sizeof(recv_buffer),
812 (int)0,
813 SA(auth_addr->
814 ai_addr), &salen);
815 } while (length == -1 && errno == EINTR);
816
817 if (length <= 0) {
818 int e = errno;
819 rc_log(LOG_ERR,
820 "rc_send_server: recvfrom: %s:%d: %s",
821 server_name, data->svc_port,
822 strerror(e));
823 if (length == -1 && (e == EAGAIN || e == EINTR))
824 continue;
825 SCLOSE(sockfd);
826 memset(secret, '\0', sizeof(secret));
827 result = ERROR_RC;
828 goto cleanup;
829 }
830
831 recv_auth = (AUTH_HDR *) recv_buffer;
832
833 if (length < AUTH_HDR_LEN
834 || length < ntohs(recv_auth->length)) {
835 rc_log(LOG_ERR,
836 "rc_send_server: recvfrom: %s:%d: reply is too short",
837 server_name, data->svc_port);
838 SCLOSE(sockfd);
839 memset(secret, '\0', sizeof(secret));
840 result = ERROR_RC;
841 goto cleanup;
842 }
843
844 result =
845 rc_check_reply(recv_auth, RC_BUFFER_LEN, secret,
846 vector, data->seq_nbr);
847 if (result != BADRESPID_RC) {
848 /* if a message that doesn't match our ID was received, then ignore
849 * it, and try to receive more, until timeout. That is because in
850 * DTLS the channel is shared, and we may receive duplicates or
851 * out-of-order packets. */
852 break;
853 }
854 }
855
856 /*
857 * Timed out waiting for response. Retry "retry_max" times
858 * before giving up. If retry_max = 0, don't retry at all.
859 */
860 if (retries++ >= retry_max) {
861 char radius_server_ip[128];
862 struct sockaddr_in *si =
863 (struct sockaddr_in *)auth_addr->ai_addr;
864 inet_ntop(auth_addr->ai_family, &si->sin_addr,
865 radius_server_ip, sizeof(radius_server_ip));
866 rc_log(LOG_ERR,
867 "rc_send_server: no reply from RADIUS %s server %s:%u",
868 server_type, radius_server_ip, data->svc_port);
869 SCLOSE(sockfd);
870 memset(secret, '\0', sizeof(secret));
871 result = TIMEOUT_RC;
872 goto cleanup;
873 }
874 }
875
876 /*
877 * If UDP is larger than RADIUS, shorten it to RADIUS.
878 */
879 if (length > ntohs(recv_auth->length))
880 length = ntohs(recv_auth->length);
881
882 /*
883 * Verify that it's a valid RADIUS packet before doing ANYTHING with it.
884 */
885 attr = recv_buffer + AUTH_HDR_LEN;
886 while (attr < (recv_buffer + length)) {
887 if (attr[0] == 0) {
888 rc_log(LOG_ERR,
889 "rc_send_server: recvfrom: %s:%d: attribute zero is invalid",
890 server_name, data->svc_port);
891 SCLOSE(sockfd);
892 memset(secret, '\0', sizeof(secret));
893 result = ERROR_RC;
894 goto cleanup;
895 }
896
897 if (attr[1] < 2) {
898 rc_log(LOG_ERR,
899 "rc_send_server: recvfrom: %s:%d: attribute length is too small",
900 server_name, data->svc_port);
901 SCLOSE(sockfd);
902 memset(secret, '\0', sizeof(secret));
903 result = ERROR_RC;
904 goto cleanup;
905 }
906
907 if ((attr + attr[1]) > (recv_buffer + length)) {
908 rc_log(LOG_ERR,
909 "rc_send_server: recvfrom: %s:%d: attribute overflows the packet",
910 server_name, data->svc_port);
911 SCLOSE(sockfd);
912 memset(secret, '\0', sizeof(secret));
913 result = ERROR_RC;
914 goto cleanup;
915 }
916
917 attr += attr[1];
918 }
919
920 length = ntohs(recv_auth->length) - AUTH_HDR_LEN;
921 if (length > 0) {
922 data->receive_pairs = rc_avpair_gen(rh, NULL, recv_auth->data,
923 length, 0);
924 } else {
925 data->receive_pairs = NULL;
926 }
927
928 SCLOSE(sockfd);
929 result = populate_ctx(ctx, secret, vector);
930 if (result != OK_RC) {
931 memset(secret, '\0', sizeof(secret));
932 goto cleanup;
933 }
934
935 /* Per draft-ietf-radext-deprecating-radius, Message-Authenticator MUST
936 * be the first attribute in Access-Request responses to prevent MD5
937 * prefix attacks (BLAST RADIUS). Not required for Accounting-Response. */
938 if (type == AUTH) {
939 if (length > 0 && recv_buffer[AUTH_HDR_LEN] == PW_MESSAGE_AUTHENTICATOR &&
941
942 if (validate_message_authenticator(data->receive_pairs, recv_buffer, length, secret, vector)) {
943 rc_log(LOG_ERR,
944 "rc_send_server: recvfrom: %s:%d: received attribute Message-Authenticator is incorrect",
945 server_name, data->svc_port);
946 memset(secret, '\0', sizeof(secret));
947 result = ERROR_RC;
948 goto cleanup;
949 }
950 } else {
951 p = rc_conf_str(rh, "require-message-authenticator");
952 if (p == NULL || (strcasecmp(p, "false") != 0 && strcasecmp(p, "no") != 0)) {
953 rc_log(LOG_ERR,
954 "rc_send_server: recvfrom: %s:%d: required attribute Message-Authenticator is missing or not first",
955 server_name, data->svc_port);
956 memset(secret, '\0', sizeof(secret));
957 result = ERROR_RC;
958 goto cleanup;
959 }
960 }
961 }
962
963 memset(secret, '\0', sizeof(secret));
964
965 if (msg) {
966 *msg = '\0';
967 pos = 0;
968 vp = data->receive_pairs;
969 while (vp) {
970 if ((vp = rc_avpair_get(vp, PW_REPLY_MESSAGE, 0))) {
971 strappend(msg, PW_MAX_MSG_SIZE, &pos,
972 vp->strvalue);
973 strappend(msg, PW_MAX_MSG_SIZE, &pos, "\n");
974 vp = vp->next;
975 }
976 }
977 }
978
979 switch (recv_auth->code) {
980 case PW_ACCESS_ACCEPT:
981 case PW_PASSWORD_ACK:
982 case PW_ACCOUNTING_RESPONSE:
983 result = OK_RC;
984 break;
985
986 case PW_ACCESS_REJECT:
987 case PW_PASSWORD_REJECT:
988 result = REJECT_RC;
989 break;
990
991 case PW_ACCESS_CHALLENGE:
992 result = CHALLENGE_RC;
993 break;
994
995 default:
996 rc_log(LOG_ERR, "rc_send_server: received RADIUS server response neither ACCEPT nor REJECT, code=%d is invalid",
997 recv_auth->code);
998 result = BADRESP_RC;
999 }
1000
1001 cleanup:
1002 if (auth_addr)
1003 freeaddrinfo(auth_addr);
1004
1005 if (sfuncs->unlock) {
1006 if (sfuncs->unlock(sfuncs->ptr) != 0) {
1007 rc_log(LOG_ERR, "%s: unlock error", __func__);
1008 }
1009 }
1010 exit_error:
1011 if (ns != NULL) {
1012 if(-1 == rc_reset_netns(&ns_def_hdl)) {
1013 rc_log(LOG_ERR, "rc_send_server: namespace %s reset failed", ns);
1014 result = ERROR_RC;
1015 }
1016 }
1017
1018 return result;
1019}
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:69
VALUE_PAIR * rc_avpair_gen(rc_handle const *rh, VALUE_PAIR *pair, unsigned char const *ptr, int length, uint32_t vendorspec)
Definition avpair.c:271
#define MGMT_POLL_SECRET
Default for Merit radiusd.
Definition radcli.h:457
int rc_send_server(rc_handle *rh, SEND_DATA *data, char *msg, rc_type type)
Definition sendserver.c:232
char * rc_conf_str(rc_handle const *rh, char const *optname)
Definition config.c:719
int rc_find_server_addr(rc_handle const *rh, char const *server_name, struct addrinfo **info, char *secret, rc_type type)
Definition config.c:923
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:433
@ AUTH
Request for authentication server.
Definition radcli.h:70
@ PW_NAS_IDENTIFIER
Its type is string.
Definition radcli.h:177
@ PW_NAS_IP_ADDRESS
Its type is ipaddr.
Definition radcli.h:149
@ PW_SERVICE_TYPE
Its type is integer.
Definition radcli.h:151
@ PW_NAS_IPV6_ADDRESS
Its type is string.
Definition radcli.h:239
@ PW_MESSAGE_AUTHENTICATOR
Its type is string.
Definition radcli.h:224
@ PW_REPLY_MESSAGE
Its type is string.
Definition radcli.h:163
@ PW_VENDOR_SPECIFIC
Its type is string.
Definition radcli.h:171
@ PW_USER_PASSWORD
Its type is string.
Definition radcli.h:147
@ PW_TYPE_IPADDR
The attribute is an IPv4 address in host-byte order.
Definition radcli.h:118
@ PW_TYPE_IPV6ADDR
The attribute is an 128-bit IPv6 address.
Definition radcli.h:120
@ PW_TYPE_IPV6PREFIX
The attribute is an IPv6 prefix; the lvalue will indicate its size.
Definition radcli.h:121
@ PW_TYPE_INTEGER
The attribute is a 32-bit integer.
Definition radcli.h:117
@ PW_TYPE_DATE
The attribute contains a 32-bit number indicating the seconds since epoch.
Definition radcli.h:119
@ PW_TYPE_STRING
The attribute is a printable string.
Definition radcli.h:116
rc_attr_type type
attribute type.
Definition radcli.h:482
uint64_t attribute
attribute numeric value of type rc_attr_id including vendor; use VENDOR() and ATTRID() to separate.
Definition radcli.h:481
uint32_t lvalue
attribute value if type is PW_TYPE_INTEGER, PW_TYPE_DATE or PW_TYPE_IPADDR.
Definition radcli.h:483
char strvalue[AUTH_STRING_LEN+1]
contains attribute value in other cases.
Definition radcli.h:484
int timeout
Session timeout in seconds.
Definition radcli.h:496
char * secret
Shared secret of RADIUS server.
Definition radcli.h:495
uint8_t seq_nbr
Packet sequence number.
Definition radcli.h:492
int svc_port
RADIUS protocol destination port.
Definition radcli.h:494
char * server
Name/address of RADIUS server.
Definition radcli.h:493
VALUE_PAIR * send_pairs
More a/v pairs to send.
Definition radcli.h:498
VALUE_PAIR * receive_pairs
Where to place received a/v pairs.
Definition radcli.h:499
uint8_t code
RADIUS packet code.
Definition radcli.h:491