Radcli library 1.5.0
A simple radius library
Loading...
Searching...
No Matches
tls.c
1/*
2 * Copyright (c) 2014, 2015, 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 ses->init = 0;
230 pthread_mutex_destroy(&ses->lock);
231 if (ses->sockfd != -1)
232 close(ses->sockfd);
233 if (ses->session)
234 gnutls_deinit(ses->session);
235 }
236}
237
238static int init_session(rc_handle *rh, tls_int_st *ses,
239 const char *hostname, unsigned port,
240 struct sockaddr_storage *our_sockaddr,
241 int timeout,
242 unsigned secflags)
243{
244 int sockfd, ret, e;
245 struct addrinfo *info;
246 char *p;
247 unsigned flags = 0;
248 unsigned cred_set = 0;
249 tls_st *st = rh->so.ptr;
250
251 ses->sockfd = -1;
252 ses->init = 1;
253
254 pthread_mutex_init(&ses->lock, NULL);
255 sockfd = socket(our_sockaddr->ss_family, (secflags&SEC_FLAG_DTLS)?SOCK_DGRAM:SOCK_STREAM, 0);
256 if (sockfd < 0) {
257 rc_log(LOG_ERR,
258 "%s: cannot open socket", __func__);
259 ret = -1;
260 goto cleanup;
261 }
262
263 if (our_sockaddr->ss_family == AF_INET)
264 ((struct sockaddr_in *)our_sockaddr)->sin_port = 0;
265 else
266 ((struct sockaddr_in6 *)our_sockaddr)->sin6_port = 0;
267
268 ses->sockfd = sockfd;
269
270 /* Initialize DTLS */
271
272 flags = GNUTLS_CLIENT;
273 if (secflags&SEC_FLAG_DTLS)
274 flags |= GNUTLS_DATAGRAM;
275 ret = gnutls_init(&ses->session, flags);
276 if (ret < 0) {
277 rc_log(LOG_ERR,
278 "%s: error in gnutls_init(): %s", __func__, gnutls_strerror(ret));
279 ret = -1;
280 goto cleanup;
281 }
282
283 memcpy(&ses->our_sockaddr, our_sockaddr, sizeof(*our_sockaddr));
284 if (!(secflags&SEC_FLAG_DTLS)) {
285 if (timeout > 0) {
286 gnutls_handshake_set_timeout(ses->session, timeout*1000);
287 } else {
288 gnutls_handshake_set_timeout(ses->session, GNUTLS_DEFAULT_HANDSHAKE_TIMEOUT);
289 }
290 } else { /* DTLS */
291 if (timeout > 0)
292 gnutls_dtls_set_timeouts(ses->session, 1000, timeout*1000);
293 }
294
295 gnutls_transport_set_int(ses->session, sockfd);
296 gnutls_session_set_ptr(ses->session, ses);
297 /* we only initiate heartbeat messages */
298 gnutls_heartbeat_enable(ses->session, GNUTLS_HB_LOCAL_ALLOWED_TO_SEND);
299
300 p = rc_conf_str(rh, "tls-verify-hostname");
301 if (p && (strcasecmp(p, "false") == 0 || strcasecmp(p, "no"))) {
302 ses->skip_hostname_check = 1;
303 }
304
305 if (st && st->psk_cred) {
306 cred_set = 1;
307 gnutls_credentials_set(ses->session,
308 GNUTLS_CRD_PSK, st->psk_cred);
309
310 ret = gnutls_priority_set_direct(ses->session, "NORMAL:-KX-ALL:+ECDHE-PSK:+DHE-PSK:+PSK:-VERS-TLS1.0", NULL);
311 if (ret < 0) {
312 ret = -1;
313 rc_log(LOG_ERR,
314 "%s: error in setting PSK priorities: %s",
315 __func__, gnutls_strerror(ret));
316 goto cleanup;
317 }
318 } else if (st) {
319 cred_set = 1;
320 if (st->x509_cred) {
321 gnutls_credentials_set(ses->session,
322 GNUTLS_CRD_CERTIFICATE,
323 st->x509_cred);
324 }
325
326 gnutls_set_default_priority(ses->session);
327 }
328
329 gnutls_server_name_set(ses->session, GNUTLS_NAME_DNS,
330 hostname, strlen(hostname));
331
332 info =
333 rc_getaddrinfo(hostname, PW_AI_AUTH);
334 if (info == NULL) {
335 ret = -1;
336 rc_log(LOG_ERR, "%s: cannot resolve %s", __func__,
337 hostname);
338 goto cleanup;
339 }
340
341 if (port != 0) {
342 if (info->ai_addr->sa_family == AF_INET)
343 ((struct sockaddr_in *)info->ai_addr)->sin_port =
344 htons(port);
345 else
346 ((struct sockaddr_in6 *)info->ai_addr)->sin6_port =
347 htons(port);
348 } else {
349 rc_log(LOG_ERR, "%s: no port specified for server %s",
350 __func__, hostname);
351 ret = -1;
352 goto cleanup;
353 }
354
355 strlcpy(ses->hostname, hostname, sizeof(ses->hostname));
356 ses->port = port;
357
358 if (cred_set == 0) {
359 rc_log(LOG_CRIT,
360 "%s: neither tls-ca-file or a PSK key are configured",
361 __func__);
362 ret = -1;
363 goto cleanup;
364 }
365
366 /* we connect since we are talking to a single server */
367 ret = connect(sockfd, info->ai_addr, info->ai_addrlen);
368 freeaddrinfo(info);
369 if (ret == -1) {
370 e = errno;
371 ret = -1;
372 rc_log(LOG_CRIT, "%s: cannot connect to %s: %s",
373 __func__, hostname, strerror(e));
374 goto cleanup;
375 }
376
377 rc_log(LOG_DEBUG,
378 "%s: performing TLS/DTLS handshake with [%s]:%d",
379 __func__, hostname, port);
380 do {
381 ret = gnutls_handshake(ses->session);
382 if (ret == GNUTLS_E_LARGE_PACKET)
383 break;
384 } while (ret < 0 && gnutls_error_is_fatal(ret) == 0);
385
386 if (ret < 0) {
387 rc_log(LOG_ERR, "%s: error in handshake: %s",
388 __func__, gnutls_strerror(ret));
389 ret = -1;
390 goto cleanup;
391 }
392
393 return 0;
394 cleanup:
395 deinit_session(ses);
396 return ret;
397
398}
399
400/* The time after the last message was received, that
401 * we will try heartbeats */
402#define TIME_ALIVE 120
403
404static int restart_session(rc_handle *rh, tls_st *st)
405{
406 struct tls_int_st tmps;
407 time_t now = time(0);
408 int ret;
409 int timeout;
410
411 /* Bypass the time guard when need_restart is set: the session is
412 * known to be broken (a send or recv already failed), so we must
413 * attempt reconnection regardless of how recently we last tried.
414 * When need_restart is 0 (proactive check from rc_check_tls via a
415 * failed heartbeat), keep the guard to avoid rapid reconnect loops. */
416 if (now - st->ctx.last_restart < TIME_ALIVE && !st->ctx.need_restart)
417 return -1;
418
419 st->ctx.last_restart = now;
420
421 timeout = rc_conf_int(rh, "radius_timeout");
422
423 /* reinitialize this session */
424 ret = init_session(rh, &tmps, st->ctx.hostname, st->ctx.port, &st->ctx.our_sockaddr, timeout, st->flags);
425 if (ret < 0) {
426 rc_log(LOG_ERR, "%s: error in re-initializing TLS session", __func__);
427 return -1;
428 }
429
430 if (tmps.sockfd == st->ctx.sockfd)
431 st->ctx.sockfd = -1;
432 deinit_session(&st->ctx);
433 memcpy(&st->ctx, &tmps, sizeof(tmps));
434 st->ctx.need_restart = 0;
435
436 return 0;
437}
438
447int rc_tls_fd(rc_handle * rh)
448{
449 tls_st *st;
450
451 if (rh->so_type != RC_SOCKET_TLS && rh->so_type != RC_SOCKET_DTLS)
452 return -1;
453
454 st = rh->so.ptr;
455
456 if (st->ctx.init != 0) {
457 return st->ctx.sockfd;
458 }
459 return -1;
460}
461
478int rc_check_tls(rc_handle * rh)
479{
480 tls_st *st;
481 time_t now = time(0);
482 int ret;
483
484 if (rh->so_type != RC_SOCKET_TLS && rh->so_type != RC_SOCKET_DTLS)
485 return 0;
486
487 st = rh->so.ptr;
488
489 if (st->ctx.init != 0) {
490 if (st->ctx.need_restart != 0) {
491 restart_session(rh, st);
492 } else if (now - st->ctx.last_msg > TIME_ALIVE) {
493 ret = gnutls_heartbeat_ping(st->ctx.session, 64, 4, GNUTLS_HEARTBEAT_WAIT);
494 if (ret < 0) {
495 restart_session(rh, st);
496 }
497 st->ctx.last_msg = now;
498 }
499 }
500 return 0;
501}
502
504
505/*- This function will deinitialize a previously initialed DTLS or TLS session.
506 *
507 * @param rh the configuration handle.
508 -*/
509void rc_deinit_tls(rc_handle * rh)
510{
511 tls_st *st = rh->so.ptr;
512 char *ns = NULL;
513 int ns_def_hdl = 0;
514
515 if (st) {
516 ns = rc_conf_str(rh, "namespace"); /* Check for namespace config */
517 if (ns != NULL) {
518 if(-1 == rc_set_netns(ns, &ns_def_hdl)) {
519 rc_log(LOG_ERR, "rc_send_server: namespace %s set failed", ns);
520 return;
521 }
522 }
523 if (st->ctx.init != 0)
524 deinit_session(&st->ctx);
525 if (st->x509_cred)
526 gnutls_certificate_free_credentials(st->x509_cred);
527 if (st->psk_cred)
528 gnutls_psk_free_client_credentials(st->psk_cred);
529 if (ns != NULL) {
530 if(-1 == rc_reset_netns(&ns_def_hdl))
531 rc_log(LOG_ERR, "rc_send_server: namespace %s reset failed", ns);
532 }
533 }
534 free(st);
535}
536
537/*- Initialize a configuration for TLS or DTLS
538 *
539 * This function will initialize the handle for TLS or DTLS.
540 *
541 * @param rh a handle to parsed configuration
542 * @param flags must be zero or SEC_FLAG_DTLS
543 * @return 0 on success, -1 on failure.
544 -*/
545int rc_init_tls(rc_handle * rh, unsigned flags)
546{
547 int ret;
548 tls_st *st = NULL;
549 struct sockaddr_storage our_sockaddr;
550 const char *ca_file = rc_conf_str(rh, "tls-ca-file");
551 const char *cert_file = rc_conf_str(rh, "tls-cert-file");
552 const char *key_file = rc_conf_str(rh, "tls-key-file");
553 const char *pskkey = NULL;
554 SERVER *authservers;
555 char hostname[256]; /* server's hostname */
556 unsigned port; /* server's port */
557 char *ns = NULL;
558 int ns_def_hdl = 0;
559
560 memset(&rh->so, 0, sizeof(rh->so));
561
562 ns = rc_conf_str(rh, "namespace"); /* Check for namespace config */
563 if (ns != NULL) {
564 if(-1 == rc_set_netns(ns, &ns_def_hdl)) {
565 rc_log(LOG_ERR, "rc_send_server: namespace %s set failed", ns);
566 return -1;
567 }
568 }
569
570 if (flags & SEC_FLAG_DTLS) {
571 rh->so_type = RC_SOCKET_DTLS;
572 rh->so.static_secret = DEFAULT_DTLS_SECRET;
573 } else {
574 rh->so_type = RC_SOCKET_TLS;
575 rh->so.static_secret = DEFAULT_TLS_SECRET;
576 }
577
578 rc_own_bind_addr(rh, &our_sockaddr);
579
580 st = calloc(1, sizeof(tls_st));
581 if (st == NULL) {
582 ret = -1;
583 goto cleanup;
584 }
585
586 st->rh = rh;
587 st->flags = flags;
588
589 rh->so.ptr = st;
590
591 if (ca_file || (key_file && cert_file)) {
592 ret = gnutls_certificate_allocate_credentials(&st->x509_cred);
593 if (ret < 0) {
594 ret = -1;
595 rc_log(LOG_ERR,
596 "%s: error in setting X.509 credentials: %s",
597 __func__, gnutls_strerror(ret));
598 goto cleanup;
599 }
600
601 if (ca_file) {
602 ret =
603 gnutls_certificate_set_x509_trust_file(st->x509_cred,
604 ca_file,
605 GNUTLS_X509_FMT_PEM);
606 if (ret < 0) {
607 ret = -1;
608 rc_log(LOG_ERR,
609 "%s: error in setting X.509 trust file: %s: %s",
610 __func__, gnutls_strerror(ret), ca_file);
611 goto cleanup;
612 }
613 }
614
615 if (cert_file && key_file) {
616 ret =
617 gnutls_certificate_set_x509_key_file(st->x509_cred,
618 cert_file,
619 key_file,
620 GNUTLS_X509_FMT_PEM);
621 if (ret < 0) {
622 ret = -1;
623 rc_log(LOG_ERR,
624 "%s: error in setting X.509 cert and key files: %s: %s - %s",
625 __func__, gnutls_strerror(ret), cert_file, key_file);
626 goto cleanup;
627 }
628 }
629
630 gnutls_certificate_set_verify_function(st->x509_cred,
631 cert_verify_callback);
632 }
633
634 /* Read the PSK key if any */
635 authservers = rc_conf_srv(rh, "authserver");
636 if (authservers == NULL) {
637 rc_log(LOG_ERR,
638 "%s: cannot find authserver", __func__);
639 ret = -1;
640 goto cleanup;
641 }
642 if (authservers->max > 1) {
643 ret = -1;
644 rc_log(LOG_ERR,
645 "%s: too many auth servers for TLS/DTLS; only one is allowed",
646 __func__);
647 goto cleanup;
648 }
649 strlcpy(hostname, authservers->name[0], sizeof(hostname));
650 port = authservers->port[0];
651 if (authservers->secret[0])
652 pskkey = authservers->secret[0];
653
654 if (pskkey && pskkey[0] != 0) {
655 char *p;
656 char username[64];
657 gnutls_datum_t hexkey;
658 int username_len;
659
660 if (strncmp(pskkey, "psk@", 4) != 0) {
661 ret = -1;
662 rc_log(LOG_ERR,
663 "%s: server secret is set but does not start with 'psk@'",
664 __func__);
665 goto cleanup;
666 }
667 pskkey+=4;
668
669 if ((p = strchr(pskkey, '@')) == NULL) {
670 ret = -1;
671 rc_log(LOG_ERR,
672 "%s: PSK key is not in 'username@hexkey' format",
673 __func__);
674 goto cleanup;
675 }
676
677 username_len = p - pskkey;
678 if (username_len + 1 > sizeof(username)) {
679 rc_log(LOG_ERR,
680 "%s: PSK username too big", __func__);
681 ret = -1;
682 goto cleanup;
683 }
684
685 strlcpy(username, pskkey, username_len + 1);
686
687 p++;
688 hexkey.data = (uint8_t*)p;
689 hexkey.size = strlen(p);
690
691 ret = gnutls_psk_allocate_client_credentials(&st->psk_cred);
692 if (ret < 0) {
693 ret = -1;
694 rc_log(LOG_ERR,
695 "%s: error in setting PSK credentials: %s",
696 __func__, gnutls_strerror(ret));
697 goto cleanup;
698 }
699
700 ret =
701 gnutls_psk_set_client_credentials(st->psk_cred,
702 username, &hexkey,
703 GNUTLS_PSK_KEY_HEX);
704 if (ret < 0) {
705 ret = -1;
706 rc_log(LOG_ERR,
707 "%s: error in setting PSK key: %s",
708 __func__, gnutls_strerror(ret));
709 goto cleanup;
710 }
711 }
712
713 ret = init_session(rh, &st->ctx, hostname, port, &our_sockaddr, 0, flags);
714 if (ret < 0) {
715 ret = -1;
716 goto cleanup;
717 }
718
719 rh->so.get_fd = tls_get_fd;
720 rh->so.get_active_fd = tls_get_active_fd;
721 rh->so.sendto = tls_sendto;
722 rh->so.recvfrom = tls_recvfrom;
723 rh->so.lock = tls_lock;
724 rh->so.unlock = tls_unlock;
725 if (ns != NULL) {
726 if(-1 == rc_reset_netns(&ns_def_hdl)) {
727 rc_log(LOG_ERR, "rc_send_server: namespace %s reset failed", ns);
728 goto cleanup;
729 }
730 }
731 return 0;
732 cleanup:
733 if (st) {
734 if (st->ctx.init != 0)
735 deinit_session(&st->ctx);
736 if (st->x509_cred)
737 gnutls_certificate_free_credentials(st->x509_cred);
738 if (st->psk_cred)
739 gnutls_psk_free_client_credentials(st->psk_cred);
740 }
741 free(st);
742 if (ns != NULL) {
743 if(-1 == rc_reset_netns(&ns_def_hdl))
744 rc_log(LOG_ERR, "rc_send_server: namespace %s reset failed", ns);
745 }
746 return ret;
747}
748
749#endif
750
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:719
SERVER * rc_conf_srv(rc_handle const *rh, char const *optname)
Definition config.c:769
@ RC_SOCKET_DTLS
DTLS socket.
Definition radcli.h:103
@ RC_SOCKET_TLS
TLS socket.
Definition radcli.h:102
int rc_tls_fd(rc_handle *rh)
Definition tls.c:447
int rc_check_tls(rc_handle *rh)
Definition tls.c:478