Radcli library 1.5.1
A simple radius library
Loading...
Searching...
No Matches
tls.c
1/*
2 * Copyright (c) 2014-2026, Nikos Mavrogiannopoulos. All rights reserved.
3 * Copyright (c) 2015, Red Hat, Inc. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
18 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#include <config.h>
27#include <includes.h>
28#include <radcli/radcli.h>
29#include "util.h"
30#include "tls.h"
31
32#ifdef HAVE_GNUTLS
33
46
47#include <gnutls/gnutls.h>
48#include <gnutls/dtls.h>
49#include <pthread.h>
50#include <time.h>
51
52#define DEFAULT_DTLS_SECRET "radius/dtls"
53#define DEFAULT_TLS_SECRET "radsec"
54
55typedef struct tls_int_st {
56 char hostname[256]; /* server's hostname */
57 unsigned port; /* server's port */
58 struct sockaddr_storage our_sockaddr;
59 gnutls_session_t session;
60 int sockfd;
61 unsigned init;
62 unsigned need_restart;
63 unsigned skip_hostname_check; /* whether to verify hostname */
64 pthread_mutex_t lock;
65 time_t last_msg;
66 time_t last_restart;
67} tls_int_st;
68
69typedef struct tls_st {
70 gnutls_psk_client_credentials_t psk_cred;
71 gnutls_certificate_credentials_t x509_cred;
72 struct tls_int_st ctx; /* one for ACCT and another for AUTH */
73 unsigned flags; /* the flags set on init */
74 rc_handle *rh; /* a pointer to our owner */
75} tls_st;
76
77static int restart_session(rc_handle *rh, tls_st *st);
78
79static int tls_get_fd(void *ptr, struct sockaddr *our_sockaddr)
80{
81 tls_st *st = ptr;
82 return st->ctx.sockfd;
83}
84
85static int tls_get_active_fd(void *ptr)
86{
87 tls_st *st = ptr;
88 return st->ctx.sockfd;
89}
90
91static ssize_t tls_sendto(void *ptr, int sockfd,
92 const void *buf, size_t len,
93 int flags, const struct sockaddr *dest_addr,
94 socklen_t addrlen)
95{
96 tls_st *st = ptr;
97 int ret;
98
99 if (st->ctx.need_restart != 0) {
100 if (restart_session(st->rh, st) < 0) {
101 errno = EIO;
102 return -1;
103 }
104 }
105
106 ret = gnutls_record_send(st->ctx.session, buf, len);
107 if (ret == GNUTLS_E_AGAIN || ret == GNUTLS_E_INTERRUPTED) {
108 errno = EINTR;
109 return -1;
110 }
111
112 if (ret < 0) {
113 rc_log(LOG_ERR, "%s: error in sending: %s", __func__,
114 gnutls_strerror(ret));
115 errno = EIO;
116 st->ctx.need_restart = 1;
117 return -1;
118 }
119
120 st->ctx.last_msg = time(0);
121 return ret;
122}
123
124static int tls_lock(void *ptr)
125{
126 tls_st *st = ptr;
127
128 return pthread_mutex_lock(&st->ctx.lock);
129}
130
131static int tls_unlock(void *ptr)
132{
133 tls_st *st = ptr;
134
135 return pthread_mutex_unlock(&st->ctx.lock);
136}
137
138static ssize_t tls_recvfrom(void *ptr, int sockfd,
139 void *buf, size_t len,
140 int flags, struct sockaddr *src_addr,
141 socklen_t * addrlen)
142{
143 tls_st *st = ptr;
144 int ret;
145
146 ret = gnutls_record_recv(st->ctx.session, buf, len);
147 if (ret == GNUTLS_E_AGAIN || ret == GNUTLS_E_INTERRUPTED ||
148 ret == GNUTLS_E_HEARTBEAT_PING_RECEIVED || ret == GNUTLS_E_HEARTBEAT_PONG_RECEIVED) {
149 errno = EINTR;
150 return -1;
151 }
152
153 if (ret == GNUTLS_E_WARNING_ALERT_RECEIVED) {
154 rc_log(LOG_ERR, "%s: received alert: %s", __func__,
155 gnutls_alert_get_name(gnutls_alert_get(st->ctx.session)));
156 errno = EINTR;
157 return -1;
158 }
159
160 /* RFC6614 says: "After the TLS session is established, RADIUS packet payloads are
161 * exchanged over the encrypted TLS tunnel. In RADIUS/UDP, the
162 * packet size can be determined by evaluating the size of the
163 * datagram that arrived. Due to the stream nature of TCP and TLS,
164 * this does not hold true for RADIUS/TLS packet exchange.",
165 *
166 * That is correct in principle but it fails to associate the length with
167 * the TLS record boundaries. Here, when in TLS, we assume that a single TLS
168 * record holds a single radius packet. It wouldn't make sense anyway to send
169 * multiple TLS records for a single packet.
170 */
171
172 if (ret <= 0) {
173 rc_log(LOG_ERR, "%s: error in receiving: %s", __func__,
174 gnutls_strerror(ret));
175 errno = EIO;
176 st->ctx.need_restart = 1;
177 return -1;
178 }
179
180 st->ctx.last_msg = time(0);
181 return ret;
182}
183
184/* This function will verify the peer's certificate, and check
185 * if the hostname matches.
186 */
187static int cert_verify_callback(gnutls_session_t session)
188{
189 unsigned int status;
190 int ret;
191 struct tls_int_st *ctx;
192 gnutls_datum_t out;
193
194 /* read hostname */
195 ctx = gnutls_session_get_ptr(session);
196 if (ctx == NULL)
197 return GNUTLS_E_CERTIFICATE_ERROR;
198
199 if (ctx->skip_hostname_check)
200 ret = gnutls_certificate_verify_peers2(session, &status);
201 else
202 ret = gnutls_certificate_verify_peers3(session, ctx->hostname, &status);
203 if (ret < 0) {
204 rc_log(LOG_ERR, "%s: error in certificate verification: %s",
205 __func__, gnutls_strerror(ret));
206 return GNUTLS_E_CERTIFICATE_ERROR;
207 }
208
209 if (status != 0) {
210 ret =
211 gnutls_certificate_verification_status_print(status,
212 gnutls_certificate_type_get
213 (session),
214 &out, 0);
215 if (ret < 0) {
216 return GNUTLS_E_CERTIFICATE_ERROR;
217 }
218 rc_log(LOG_INFO, "%s: certificate: %s", __func__, out.data);
219 gnutls_free(out.data);
220 return GNUTLS_E_CERTIFICATE_ERROR;
221 }
222
223 return 0;
224}
225
226static void deinit_session(tls_int_st *ses)
227{
228 if (ses->init != 0) {
229 int ret;
230 ses->init = 0;
231 if (ses->session) {
232 /* Send close_notify before closing the socket so the peer
233 * receives a proper TLS/DTLS shutdown alert. */
234 if (ses->sockfd != -1) {
235 do {
236 ret = gnutls_bye(ses->session, GNUTLS_SHUT_WR);
237 } while (ret == GNUTLS_E_INTERRUPTED);
238 }
239 gnutls_deinit(ses->session);
240 }
241 pthread_mutex_destroy(&ses->lock);
242 if (ses->sockfd != -1)
243 close(ses->sockfd);
244 }
245}
246
247static int init_session(rc_handle *rh, tls_int_st *ses,
248 const char *hostname, unsigned port,
249 struct sockaddr_storage *our_sockaddr,
250 int timeout,
251 unsigned secflags)
252{
253 int sockfd, ret, e;
254 struct addrinfo *info;
255 char *p;
256 unsigned flags = 0;
257 unsigned cred_set = 0;
258 tls_st *st = rh->so.ptr;
259
260 ses->sockfd = -1;
261 ses->init = 1;
262
263 pthread_mutex_init(&ses->lock, NULL);
264 sockfd = socket(our_sockaddr->ss_family, (secflags&SEC_FLAG_DTLS)?SOCK_DGRAM:SOCK_STREAM, 0);
265 if (sockfd < 0) {
266 rc_log(LOG_ERR,
267 "%s: cannot open socket", __func__);
268 ret = -1;
269 goto cleanup;
270 }
271
272 if (our_sockaddr->ss_family == AF_INET)
273 ((struct sockaddr_in *)our_sockaddr)->sin_port = 0;
274 else
275 ((struct sockaddr_in6 *)our_sockaddr)->sin6_port = 0;
276
277 ses->sockfd = sockfd;
278
279 /* Initialize DTLS */
280
281 flags = GNUTLS_CLIENT;
282 if (secflags&SEC_FLAG_DTLS)
283 flags |= GNUTLS_DATAGRAM;
284 ret = gnutls_init(&ses->session, flags);
285 if (ret < 0) {
286 rc_log(LOG_ERR,
287 "%s: error in gnutls_init(): %s", __func__, gnutls_strerror(ret));
288 ret = -1;
289 goto cleanup;
290 }
291
292 memcpy(&ses->our_sockaddr, our_sockaddr, sizeof(*our_sockaddr));
293 if (!(secflags&SEC_FLAG_DTLS)) {
294 if (timeout > 0) {
295 gnutls_handshake_set_timeout(ses->session, timeout*1000);
296 } else {
297 gnutls_handshake_set_timeout(ses->session, GNUTLS_DEFAULT_HANDSHAKE_TIMEOUT);
298 }
299 } else { /* DTLS */
300 if (timeout > 0)
301 gnutls_dtls_set_timeouts(ses->session, 1000, timeout*1000);
302 }
303
304 gnutls_transport_set_int(ses->session, sockfd);
305 gnutls_session_set_ptr(ses->session, ses);
306 /* we only initiate heartbeat messages */
307 gnutls_heartbeat_enable(ses->session, GNUTLS_HB_LOCAL_ALLOWED_TO_SEND);
308
309 p = rc_conf_str(rh, "tls-verify-hostname");
310 if (p && (strcasecmp(p, "false") == 0 || strcasecmp(p, "no"))) {
311 ses->skip_hostname_check = 1;
312 }
313
314 if (st && st->psk_cred) {
315 cred_set = 1;
316 gnutls_credentials_set(ses->session,
317 GNUTLS_CRD_PSK, st->psk_cred);
318
319 ret = gnutls_priority_set_direct(ses->session, "NORMAL:-KX-ALL:+ECDHE-PSK:+DHE-PSK:+PSK:-VERS-TLS1.0", NULL);
320 if (ret < 0) {
321 ret = -1;
322 rc_log(LOG_ERR,
323 "%s: error in setting PSK priorities: %s",
324 __func__, gnutls_strerror(ret));
325 goto cleanup;
326 }
327 } else if (st) {
328 cred_set = 1;
329 if (st->x509_cred) {
330 gnutls_credentials_set(ses->session,
331 GNUTLS_CRD_CERTIFICATE,
332 st->x509_cred);
333 }
334
335 gnutls_set_default_priority(ses->session);
336 }
337
338 gnutls_server_name_set(ses->session, GNUTLS_NAME_DNS,
339 hostname, strlen(hostname));
340
341 info =
342 rc_getaddrinfo(hostname, PW_AI_AUTH);
343 if (info == NULL) {
344 ret = -1;
345 rc_log(LOG_ERR, "%s: cannot resolve %s", __func__,
346 hostname);
347 goto cleanup;
348 }
349
350 if (port != 0) {
351 if (info->ai_addr->sa_family == AF_INET)
352 ((struct sockaddr_in *)info->ai_addr)->sin_port =
353 htons(port);
354 else
355 ((struct sockaddr_in6 *)info->ai_addr)->sin6_port =
356 htons(port);
357 } else {
358 rc_log(LOG_ERR, "%s: no port specified for server %s",
359 __func__, hostname);
360 ret = -1;
361 goto cleanup;
362 }
363
364 strlcpy(ses->hostname, hostname, sizeof(ses->hostname));
365 ses->port = port;
366
367 if (cred_set == 0) {
368 rc_log(LOG_CRIT,
369 "%s: neither tls-ca-file or a PSK key are configured",
370 __func__);
371 ret = -1;
372 goto cleanup;
373 }
374
375 /* we connect since we are talking to a single server */
376 ret = connect(sockfd, info->ai_addr, info->ai_addrlen);
377 freeaddrinfo(info);
378 if (ret == -1) {
379 e = errno;
380 ret = -1;
381 rc_log(LOG_CRIT, "%s: cannot connect to %s: %s",
382 __func__, hostname, strerror(e));
383 goto cleanup;
384 }
385
386 rc_log(LOG_DEBUG,
387 "%s: performing TLS/DTLS handshake with [%s]:%d",
388 __func__, hostname, port);
389 do {
390 ret = gnutls_handshake(ses->session);
391 if (ret == GNUTLS_E_LARGE_PACKET)
392 break;
393 } while (ret < 0 && gnutls_error_is_fatal(ret) == 0);
394
395 if (ret < 0) {
396 rc_log(LOG_ERR, "%s: error in handshake: %s",
397 __func__, gnutls_strerror(ret));
398 ret = -1;
399 goto cleanup;
400 }
401
402 return 0;
403 cleanup:
404 deinit_session(ses);
405 return ret;
406
407}
408
409/* The time after the last message was received, that
410 * we will try heartbeats */
411#define TIME_ALIVE 120
412
413static int restart_session(rc_handle *rh, tls_st *st)
414{
415 struct tls_int_st tmps;
416 time_t now = time(0);
417 int ret;
418 int timeout;
419
420 /* Bypass the time guard when need_restart is set: the session is
421 * known to be broken (a send or recv already failed), so we must
422 * attempt reconnection regardless of how recently we last tried.
423 * When need_restart is 0 (proactive check from rc_check_tls via a
424 * failed heartbeat), keep the guard to avoid rapid reconnect loops. */
425 if (now - st->ctx.last_restart < TIME_ALIVE && !st->ctx.need_restart)
426 return -1;
427
428 st->ctx.last_restart = now;
429
430 timeout = rc_conf_int(rh, "radius_timeout");
431
432 /* reinitialize this session */
433 ret = init_session(rh, &tmps, st->ctx.hostname, st->ctx.port, &st->ctx.our_sockaddr, timeout, st->flags);
434 if (ret < 0) {
435 rc_log(LOG_ERR, "%s: error in re-initializing TLS session", __func__);
436 return -1;
437 }
438
439 if (tmps.sockfd == st->ctx.sockfd)
440 st->ctx.sockfd = -1;
441 deinit_session(&st->ctx);
442 memcpy(&st->ctx, &tmps, sizeof(tmps));
443 st->ctx.need_restart = 0;
444
445 return 0;
446}
447
456int rc_tls_fd(rc_handle * rh)
457{
458 tls_st *st;
459
460 if (rh->so_type != RC_SOCKET_TLS && rh->so_type != RC_SOCKET_DTLS)
461 return -1;
462
463 st = rh->so.ptr;
464
465 if (st->ctx.init != 0) {
466 return st->ctx.sockfd;
467 }
468 return -1;
469}
470
487int rc_check_tls(rc_handle * rh)
488{
489 tls_st *st;
490 time_t now = time(0);
491 int ret;
492
493 if (rh->so_type != RC_SOCKET_TLS && rh->so_type != RC_SOCKET_DTLS)
494 return 0;
495
496 st = rh->so.ptr;
497
498 if (st->ctx.init != 0) {
499 if (st->ctx.need_restart != 0) {
500 restart_session(rh, st);
501 } else if (now - st->ctx.last_msg > TIME_ALIVE) {
502 ret = gnutls_heartbeat_ping(st->ctx.session, 64, 4, GNUTLS_HEARTBEAT_WAIT);
503 if (ret < 0) {
504 restart_session(rh, st);
505 }
506 st->ctx.last_msg = now;
507 }
508 }
509 return 0;
510}
511
513
514/*- This function will deinitialize a previously initialed DTLS or TLS session.
515 *
516 * @param rh the configuration handle.
517 -*/
518void rc_deinit_tls(rc_handle * rh)
519{
520 tls_st *st = rh->so.ptr;
521 char *ns = NULL;
522 int ns_def_hdl = 0;
523
524 if (st) {
525 ns = rc_conf_str(rh, "namespace"); /* Check for namespace config */
526 if (ns != NULL) {
527 if(-1 == rc_set_netns(ns, &ns_def_hdl)) {
528 rc_log(LOG_ERR, "rc_send_server: namespace %s set failed", ns);
529 return;
530 }
531 }
532 if (st->ctx.init != 0)
533 deinit_session(&st->ctx);
534 if (st->x509_cred)
535 gnutls_certificate_free_credentials(st->x509_cred);
536 if (st->psk_cred)
537 gnutls_psk_free_client_credentials(st->psk_cred);
538 if (ns != NULL) {
539 if(-1 == rc_reset_netns(&ns_def_hdl))
540 rc_log(LOG_ERR, "rc_send_server: namespace %s reset failed", ns);
541 }
542 }
543 free(st);
544}
545
546/*- Initialize a configuration for TLS or DTLS
547 *
548 * This function will initialize the handle for TLS or DTLS.
549 *
550 * @param rh a handle to parsed configuration
551 * @param flags must be zero or SEC_FLAG_DTLS
552 * @return 0 on success, -1 on failure.
553 -*/
554int rc_init_tls(rc_handle * rh, unsigned flags)
555{
556 int ret;
557 tls_st *st = NULL;
558 struct sockaddr_storage our_sockaddr;
559 const char *ca_file = rc_conf_str(rh, "tls-ca-file");
560 const char *cert_file = rc_conf_str(rh, "tls-cert-file");
561 const char *key_file = rc_conf_str(rh, "tls-key-file");
562 const char *pskkey = NULL;
563 SERVER *authservers;
564 char hostname[256]; /* server's hostname */
565 unsigned port; /* server's port */
566 char *ns = NULL;
567 int ns_def_hdl = 0;
568
569 memset(&rh->so, 0, sizeof(rh->so));
570
571 ns = rc_conf_str(rh, "namespace"); /* Check for namespace config */
572 if (ns != NULL) {
573 if(-1 == rc_set_netns(ns, &ns_def_hdl)) {
574 rc_log(LOG_ERR, "rc_send_server: namespace %s set failed", ns);
575 return -1;
576 }
577 }
578
579 if (flags & SEC_FLAG_DTLS) {
580 rh->so_type = RC_SOCKET_DTLS;
581 rh->so.static_secret = DEFAULT_DTLS_SECRET;
582 } else {
583 rh->so_type = RC_SOCKET_TLS;
584 rh->so.static_secret = DEFAULT_TLS_SECRET;
585 }
586
587 rc_own_bind_addr(rh, &our_sockaddr);
588
589 st = calloc(1, sizeof(tls_st));
590 if (st == NULL) {
591 ret = -1;
592 goto cleanup;
593 }
594
595 st->rh = rh;
596 st->flags = flags;
597
598 rh->so.ptr = st;
599
600 if (ca_file || (key_file && cert_file)) {
601 ret = gnutls_certificate_allocate_credentials(&st->x509_cred);
602 if (ret < 0) {
603 ret = -1;
604 rc_log(LOG_ERR,
605 "%s: error in setting X.509 credentials: %s",
606 __func__, gnutls_strerror(ret));
607 goto cleanup;
608 }
609
610 if (ca_file) {
611 ret =
612 gnutls_certificate_set_x509_trust_file(st->x509_cred,
613 ca_file,
614 GNUTLS_X509_FMT_PEM);
615 if (ret < 0) {
616 ret = -1;
617 rc_log(LOG_ERR,
618 "%s: error in setting X.509 trust file: %s: %s",
619 __func__, gnutls_strerror(ret), ca_file);
620 goto cleanup;
621 }
622 }
623
624 if (cert_file && key_file) {
625 ret =
626 gnutls_certificate_set_x509_key_file(st->x509_cred,
627 cert_file,
628 key_file,
629 GNUTLS_X509_FMT_PEM);
630 if (ret < 0) {
631 ret = -1;
632 rc_log(LOG_ERR,
633 "%s: error in setting X.509 cert and key files: %s: %s - %s",
634 __func__, gnutls_strerror(ret), cert_file, key_file);
635 goto cleanup;
636 }
637 }
638
639 gnutls_certificate_set_verify_function(st->x509_cred,
640 cert_verify_callback);
641 }
642
643 /* Read the PSK key if any */
644 authservers = rc_conf_srv(rh, "authserver");
645 if (authservers == NULL) {
646 rc_log(LOG_ERR,
647 "%s: cannot find authserver", __func__);
648 ret = -1;
649 goto cleanup;
650 }
651 if (authservers->max > 1) {
652 ret = -1;
653 rc_log(LOG_ERR,
654 "%s: too many auth servers for TLS/DTLS; only one is allowed",
655 __func__);
656 goto cleanup;
657 }
658 strlcpy(hostname, authservers->name[0], sizeof(hostname));
659 port = authservers->port[0];
660 if (authservers->secret[0])
661 pskkey = authservers->secret[0];
662
663 if (pskkey && pskkey[0] != 0) {
664 char *p;
665 char username[64];
666 gnutls_datum_t hexkey;
667 int username_len;
668
669 if (strncmp(pskkey, "psk@", 4) != 0) {
670 ret = -1;
671 rc_log(LOG_ERR,
672 "%s: server secret is set but does not start with 'psk@'",
673 __func__);
674 goto cleanup;
675 }
676 pskkey+=4;
677
678 if ((p = strchr(pskkey, '@')) == NULL) {
679 ret = -1;
680 rc_log(LOG_ERR,
681 "%s: PSK key is not in 'username@hexkey' format",
682 __func__);
683 goto cleanup;
684 }
685
686 username_len = p - pskkey;
687 if (username_len + 1 > sizeof(username)) {
688 rc_log(LOG_ERR,
689 "%s: PSK username too big", __func__);
690 ret = -1;
691 goto cleanup;
692 }
693
694 strlcpy(username, pskkey, username_len + 1);
695
696 p++;
697 hexkey.data = (uint8_t*)p;
698 hexkey.size = strlen(p);
699
700 ret = gnutls_psk_allocate_client_credentials(&st->psk_cred);
701 if (ret < 0) {
702 ret = -1;
703 rc_log(LOG_ERR,
704 "%s: error in setting PSK credentials: %s",
705 __func__, gnutls_strerror(ret));
706 goto cleanup;
707 }
708
709 ret =
710 gnutls_psk_set_client_credentials(st->psk_cred,
711 username, &hexkey,
712 GNUTLS_PSK_KEY_HEX);
713 if (ret < 0) {
714 ret = -1;
715 rc_log(LOG_ERR,
716 "%s: error in setting PSK key: %s",
717 __func__, gnutls_strerror(ret));
718 goto cleanup;
719 }
720 }
721
722 ret = init_session(rh, &st->ctx, hostname, port, &our_sockaddr, 0, flags);
723 if (ret < 0) {
724 ret = -1;
725 goto cleanup;
726 }
727
728 rh->so.get_fd = tls_get_fd;
729 rh->so.get_active_fd = tls_get_active_fd;
730 rh->so.sendto = tls_sendto;
731 rh->so.recvfrom = tls_recvfrom;
732 rh->so.lock = tls_lock;
733 rh->so.unlock = tls_unlock;
734 if (ns != NULL) {
735 if(-1 == rc_reset_netns(&ns_def_hdl)) {
736 rc_log(LOG_ERR, "rc_send_server: namespace %s reset failed", ns);
737 goto cleanup;
738 }
739 }
740 return 0;
741 cleanup:
742 if (st) {
743 if (st->ctx.init != 0)
744 deinit_session(&st->ctx);
745 if (st->x509_cred)
746 gnutls_certificate_free_credentials(st->x509_cred);
747 if (st->psk_cred)
748 gnutls_psk_free_client_credentials(st->psk_cred);
749 }
750 free(st);
751 rh->so.ptr = NULL;
752 if (ns != NULL) {
753 if(-1 == rc_reset_netns(&ns_def_hdl))
754 rc_log(LOG_ERR, "rc_send_server: namespace %s reset failed", ns);
755 }
756 return ret;
757}
758
759#endif
760
void rc_own_bind_addr(rc_handle *rh, struct sockaddr_storage *lia)
Definition ip_util.c:164
char * rc_conf_str(rc_handle const *rh, char const *optname)
Definition config.c:732
SERVER * rc_conf_srv(rc_handle const *rh, char const *optname)
Definition config.c:782
@ RC_SOCKET_DTLS
DTLS socket.
Definition radcli.h:104
@ RC_SOCKET_TLS
TLS socket.
Definition radcli.h:103
int rc_tls_fd(rc_handle *rh)
Definition tls.c:456
int rc_check_tls(rc_handle *rh)
Definition tls.c:487