Radcli library 1.5.1
A simple radius library
Loading...
Searching...
No Matches
config.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
21
22#include <config.h>
23#include <includes.h>
24#include <radcli/radcli.h>
25#include <options.h>
26#include "util.h"
27#include "tls.h"
28#include "dict_rfc_gen.h"
29
30#ifndef TRUE
31#define TRUE 1
32#define FALSE 0
33#endif
34
35static int rc_conf_int_2(rc_handle const *rh, char const *optname, int complain);
36
44static OPTION *find_option(rc_handle const *rh, char const *optname, unsigned int type)
45{
46 int i;
47
48 /* there're so few options that a binary search seems not necessary */
49 for (i = 0; i < NUM_OPTIONS; i++) {
50 if (!strcmp(rh->config_options[i].name, optname) &&
51 (rh->config_options[i].type & type))
52 {
53 return &rh->config_options[i];
54 }
55 }
56
57 return NULL;
58}
59
68static int set_option_str(char const *filename, int line, OPTION *option, char const *p)
69{
70 if (p) {
71 option->val = (void *) strdup(p);
72 if (option->val == NULL) {
73 rc_log(LOG_CRIT, "read_config: out of memory");
74 return -1;
75 }
76 } else {
77 option->val = NULL;
78 }
79
80 return 0;
81}
82
83static int set_option_int(char const *filename, int line, OPTION *option, char const *p)
84{
85 int *iptr;
86
87 if (p == NULL) {
88 rc_log(LOG_ERR, "%s: line %d: bogus option value", filename, line);
89 return -1;
90 }
91
92 if ((iptr = malloc(sizeof(*iptr))) == NULL) {
93 rc_log(LOG_CRIT, "read_config: out of memory");
94 return -1;
95 }
96
97 *iptr = atoi(p);
98 option->val = (void *) iptr;
99
100 return 0;
101}
102
103static int set_option_srv(char const *filename, int line, OPTION *option, char const *p)
104{
105 SERVER *serv;
106 char *p_pointer;
107 char *p_dupe;
108 char *p_save;
109 char *q;
110 char *s;
111 struct servent *svp;
112
113 p_dupe = strdup(p);
114
115 if (p_dupe == NULL) {
116 rc_log(LOG_ERR, "%s: line %d: Invalid option or memory failure", filename, line);
117 return -1;
118 }
119
120 serv = (SERVER *) option->val;
121 if (serv == NULL) {
122 serv = calloc(1, sizeof(*serv));
123 if (serv == NULL) {
124 rc_log(LOG_CRIT, "read_config: out of memory");
125 free(p_dupe);
126 return -1;
127 }
128 serv->max = 0;
129 }
130
131 p_pointer = strtok_r(p_dupe, ", \t", &p_save);
132
133 while(p_pointer != NULL) {
134 if (serv->max > RC_SERVER_MAX) {
135 DEBUG(LOG_ERR, "cannot set more than %d servers", RC_SERVER_MAX);
136 goto fail;
137 }
138
139 DEBUG(LOG_ERR, "processing server: %s", p_pointer);
140 /* check to see for '[IPv6]:port' syntax */
141 if ((q = strchr(p_pointer,'[')) != NULL) {
142 *q = '\0';
143 q++;
144 p_pointer = q;
145
146 q = strchr(p_pointer, ']');
147 if (q == NULL) {
148 rc_log(LOG_CRIT, "read_config: IPv6 parse error");
149 goto fail;
150 }
151 *q = '\0';
152 q++;
153
154 if (q[0] == ':') {
155 q++;
156 }
157
158 /* Check to see if we have '[IPv6]:port:secret' syntax */
159 if((s=strchr(q, ':')) != NULL) {
160 *s = '\0';
161 s++;
162 serv->secret[serv->max] = strdup(s);
163 if (serv->secret[serv->max] == NULL) {
164 rc_log(LOG_CRIT, "read_config: out of memory");
165 goto fail;
166 }
167 }
168
169 } else /* Check to see if we have 'servername:port' syntax */
170 if ((q = strchr(p_pointer,':')) != NULL) {
171 *q = '\0';
172 q++;
173
174 /* Check to see if we have 'servername:port:secret' syntax */
175 if((s = strchr(q,':')) != NULL) {
176 *s = '\0';
177 s++;
178 serv->secret[serv->max] = strdup(s);
179 if (serv->secret[serv->max] == NULL) {
180 rc_log(LOG_CRIT, "read_config: out of memory");
181 goto fail;
182 }
183 }
184 }
185
186 if(q && strlen(q) > 0) {
187 serv->port[serv->max] = atoi(q);
188 } else {
189 if (!strcmp(option->name,"authserver"))
190 if ((svp = getservbyname ("radius", "udp")) == NULL)
191 serv->port[serv->max] = PW_AUTH_UDP_PORT;
192 else
193 serv->port[serv->max] = ntohs ((unsigned int) svp->s_port);
194 else if (!strcmp(option->name, "acctserver"))
195 if ((svp = getservbyname ("radacct", "udp")) == NULL)
196 serv->port[serv->max] = PW_ACCT_UDP_PORT;
197 else
198 serv->port[serv->max] = ntohs ((unsigned int) svp->s_port);
199 else {
200 rc_log(LOG_ERR, "%s: line %d: no default port for %s", filename, line, option->name);
201 goto fail;
202 }
203 }
204
205 serv->name[serv->max] = strdup(p_pointer);
206 if (serv->name[serv->max] == NULL) {
207 rc_log(LOG_CRIT, "read_config: out of memory");
208 goto fail;
209 }
210
211 serv->max++;
212 p_pointer = strtok_r(NULL, ", \t", &p_save);
213 }
214
215 free(p_dupe);
216 if (option->val == NULL)
217 option->val = (void *)serv;
218
219 return 0;
220 fail:
221 free(p_dupe);
222 if (option->val == NULL)
223 free(serv);
224 return -1;
225
226}
227
228static int set_option_auo(char const *filename, int line, OPTION *option, char const *p)
229{
230 int *iptr;
231 char *p_dupe = NULL;
232 char *p_pointer = NULL;
233 char *p_save = NULL;
234
235 p_dupe = strdup(p);
236
237 if (p_dupe == NULL) {
238 rc_log(LOG_WARNING, "%s: line %d: bogus option value", filename, line);
239 return -1;
240 }
241
242 if ((iptr = malloc(sizeof(*iptr))) == NULL) {
243 rc_log(LOG_CRIT, "read_config: out of memory");
244 free(p_dupe);
245 return -1;
246 }
247
248 *iptr = 0;
249 p_pointer = strtok_r(p_dupe, ", \t", &p_save);
250
251 if (!strncmp(p_pointer, "local", 5))
252 *iptr = AUTH_LOCAL_FST;
253 else if (!strncmp(p_pointer, "radius", 6))
254 *iptr = AUTH_RADIUS_FST;
255 else {
256 rc_log(LOG_ERR,"%s: auth_order: unknown keyword: %s", filename, p);
257 free(iptr);
258 free(p_dupe);
259 return -1;
260 }
261
262 p_pointer = strtok_r(NULL, ", \t", &p_save);
263
264 if (p_pointer && (*p_pointer != '\0')) {
265 if ((*iptr & AUTH_RADIUS_FST) && !strcmp(p_pointer, "local"))
266 *iptr = (*iptr) | AUTH_LOCAL_SND;
267 else if ((*iptr & AUTH_LOCAL_FST) && !strcmp(p_pointer, "radius"))
268 *iptr = (*iptr) | AUTH_RADIUS_SND;
269 else {
270 rc_log(LOG_ERR,"%s: auth_order: unknown or unexpected keyword: %s", filename, p);
271 free(iptr);
272 free(p_dupe);
273 return -1;
274 }
275 }
276
277 option->val = (void *) iptr;
278
279 free(p_dupe);
280 return 0;
281}
282
295int rc_add_config(rc_handle *rh, char const *option_name, char const *option_val, char const *source, int line)
296{
297 OPTION *option;
298
299 if ((option = find_option(rh, option_name, OT_ANY)) == NULL)
300 {
301 rc_log(LOG_ERR, "ERROR: unrecognized option: %s", option_name);
302 return -1;
303 }
304
305 if (option->status != ST_UNDEF)
306 {
307 rc_log(LOG_ERR, "ERROR: duplicate option: %s", option_name);
308 return -1;
309 }
310
311 switch (option->type) {
312 case OT_STR:
313 if (set_option_str(source, line, option, option_val) < 0) {
314 return -1;
315 }
316 break;
317 case OT_INT:
318 if (set_option_int(source, line, option, option_val) < 0) {
319 return -1;
320 }
321 break;
322 case OT_SRV:
323 if (set_option_srv(source, line, option, option_val) < 0) {
324 return -1;
325 }
326 break;
327 case OT_AUO:
328 if (set_option_auo(source, line, option, option_val) < 0) {
329 return -1;
330 }
331 break;
332 default:
333 rc_log(LOG_CRIT, "rc_add_config: impossible case branch!");
334 abort();
335 }
336
337 return 0;
338}
339
350rc_handle *rc_config_init(rc_handle *rh)
351{
352 SERVER *authservers = NULL;
353 SERVER *acctservers;
354 OPTION *acct;
355 OPTION *auth;
356
357 rh->config_options = malloc(sizeof(config_options_default));
358 if (rh->config_options == NULL)
359 {
360 rc_log(LOG_CRIT, "rc_config_init: out of memory");
361 rc_destroy(rh);
362 return NULL;
363 }
364 memcpy(rh->config_options, &config_options_default, sizeof(config_options_default));
365
366 auth = find_option(rh, "authserver", OT_ANY);
367 if (auth) {
368 authservers = calloc(1, sizeof(SERVER));
369 if(authservers == NULL) {
370 rc_log(LOG_CRIT, "rc_config_init: error initializing server structs");
371 rc_destroy(rh);
372 return NULL;
373 }
374 auth->val = authservers;
375 }
376
377 acct = find_option(rh, "acctserver", OT_ANY);
378 if (acct) {
379 acctservers = calloc(1, sizeof(SERVER));
380 if(acctservers == NULL) {
381 rc_log(LOG_CRIT, "rc_config_init: error initializing server structs");
382 rc_destroy(rh);
383 if(authservers) free(authservers);
384 return NULL;
385 }
386 acct->val = acctservers;
387 }
388
389 return rh;
390}
391
392static ssize_t plain_sendto(void *ptr, int sockfd,
393 const void *buf, size_t len, int flags,
394 const struct sockaddr *dest_addr, socklen_t addrlen)
395{
396 return sendto(sockfd, buf, len, flags, dest_addr, addrlen);
397}
398
399static ssize_t plain_tcp_sendto(void *ptr, int sockfd,
400 const void *buf, size_t len, int flags,
401 const struct sockaddr *dest_addr, socklen_t addrlen)
402{
403 if((connect(sockfd, dest_addr, addrlen)) != 0){
404 rc_log(LOG_ERR, "%s: Connect Call Failed : %s", __FUNCTION__, strerror(errno));
405 return -1;
406 }
407 return sendto(sockfd, buf, len, flags, dest_addr, addrlen);
408}
409
410static ssize_t plain_recvfrom(void *ptr, int sockfd,
411 void *buf, size_t len, int flags,
412 struct sockaddr *src_addr, socklen_t * addrlen)
413{
414 return recvfrom(sockfd, buf, len, flags, src_addr, addrlen);
415}
416
417static void plain_close_fd(int fd)
418{
419 close(fd);
420}
421
422static int plain_get_fd(void *ptr, struct sockaddr *our_sockaddr)
423{
424 int sockfd;
425
426 sockfd = socket(our_sockaddr->sa_family, SOCK_DGRAM, 0);
427 if (sockfd < 0) {
428 return -1;
429 }
430
431 if (our_sockaddr->sa_family == AF_INET)
432 ((struct sockaddr_in *)our_sockaddr)->sin_port = 0;
433 else
434 ((struct sockaddr_in6 *)our_sockaddr)->sin6_port = 0;
435
436 if (bind(sockfd, SA(our_sockaddr), SA_LEN(our_sockaddr)) < 0) {
437 close(sockfd);
438 return -1;
439 }
440 return sockfd;
441}
442
443static int plain_tcp_get_fd(void *ptr, struct sockaddr *our_sockaddr)
444{
445 int sockfd;
446
447 sockfd = socket(our_sockaddr->sa_family, SOCK_STREAM, 0);
448 if (sockfd < 0) {
449 return -1;
450 }
451
452 if (our_sockaddr->sa_family == AF_INET)
453 ((struct sockaddr_in *)our_sockaddr)->sin_port = 0;
454 else
455 ((struct sockaddr_in6 *)our_sockaddr)->sin6_port = 0;
456
457 if (bind(sockfd, SA(our_sockaddr), SA_LEN(our_sockaddr)) < 0) {
458 close(sockfd);
459 return -1;
460 }
461 return sockfd;
462}
463
464static const rc_sockets_override default_socket_funcs = {
465 .get_fd = plain_get_fd,
466 .close_fd = plain_close_fd,
467 .sendto = plain_sendto,
468 .recvfrom = plain_recvfrom
469};
470
471static const rc_sockets_override default_tcp_socket_funcs = {
472 .get_fd = plain_tcp_get_fd,
473 .close_fd = plain_close_fd,
474 .sendto = plain_tcp_sendto,
475 .recvfrom = plain_recvfrom
476};
477
478static int set_addr(struct sockaddr_storage *ss, const char *ip)
479{
480 memset(ss, 0, sizeof(*ss));
481 if (inet_pton(AF_INET, ip, &((struct sockaddr_in *)ss)->sin_addr) == 1) {
482 ss->ss_family = AF_INET;
483 } else if (inet_pton(AF_INET6, ip, &((struct sockaddr_in6 *)ss)->sin6_addr) == 1) {
484 ss->ss_family = AF_INET6;
485 } else {
486 rc_log(LOG_CRIT, "invalid IP address for nas-ip: %s", ip);
487 return -1;
488 }
489 return 0;
490}
491
501int rc_apply_config(rc_handle *rh)
502{
503 const char *txt;
504 int ret;
505
506 memset(&rh->own_bind_addr, 0, sizeof(rh->own_bind_addr));
507 rh->own_bind_addr_set = 0;
508 rc_own_bind_addr(rh, &rh->own_bind_addr);
509 rh->own_bind_addr_set = 1;
510
511 txt = rc_conf_str(rh, "nas-ip");
512 if (txt != NULL) {
513 if (set_addr(&rh->nas_addr, txt) < 0)
514 return -1;
515 rh->nas_addr_set = 1;
516 }
517
518 txt = rc_conf_str(rh, "serv-type");
519 if (txt == NULL)
520 txt = rc_conf_str(rh, "serv-auth-type");
521
522 if (txt == NULL)
523 txt = "udp";
524
525 if (strcasecmp(txt, "udp") == 0) {
526 memset(&rh->so, 0, sizeof(rh->so));
527 rh->so_type = RC_SOCKET_UDP;
528 memcpy(&rh->so, &default_socket_funcs, sizeof(rh->so));
529 ret = 0;
530 } else if (strcasecmp(txt, "tcp") == 0) {
531 memset(&rh->so, 0, sizeof(rh->so));
532 rh->so_type = RC_SOCKET_TCP;
533 memcpy(&rh->so, &default_tcp_socket_funcs, sizeof(rh->so));
534 ret = 0;
535#ifdef HAVE_GNUTLS
536 } else if (strcasecmp(txt, "dtls") == 0) {
537 ret = rc_init_tls(rh, SEC_FLAG_DTLS);
538 } else if (strcasecmp(txt, "tls") == 0) {
539 ret = rc_init_tls(rh, 0);
540#endif
541 } else {
542 rc_log(LOG_CRIT, "unknown server type: %s", txt);
543 return -1;
544 }
545
546 if (ret < 0) {
547 rc_log(LOG_CRIT, "error initializing %s", txt);
548 return -1;
549 }
550
551 return 0;
552
553}
554
585rc_handle *rc_read_config(char const *filename)
586{
587 FILE *configfd;
588 char buffer[512], *p;
589 OPTION *option;
590 int line;
591 size_t pos;
592 rc_handle *rh;
593
594
595 rh = rc_new();
596 if (rh == NULL)
597 return NULL;
598
599 rh->config_options = malloc(sizeof(config_options_default));
600 if (rh->config_options == NULL) {
601 rc_log(LOG_CRIT, "rc_read_config: out of memory");
602 rc_destroy(rh);
603 return NULL;
604 }
605 memcpy(rh->config_options, &config_options_default, sizeof(config_options_default));
606
607 if ((configfd = fopen(filename,"r")) == NULL)
608 {
609 rc_log(LOG_ERR,"rc_read_config: can't open %s: %s", filename, strerror(errno));
610 rc_destroy(rh);
611 return NULL;
612 }
613
614 line = 0;
615 while ((fgets(buffer, sizeof(buffer), configfd) != NULL))
616 {
617 line++;
618 p = buffer;
619
620 if ((*p == '\n') || (*p == '#') || (*p == '\0'))
621 continue;
622
623 p[strlen(p)-1] = '\0';
624
625
626 if ((pos = strcspn(p, "\t ")) == 0) {
627 rc_log(LOG_ERR, "%s: line %d: bogus format: %s", filename, line, p);
628 fclose(configfd);
629 rc_destroy(rh);
630 return NULL;
631 }
632
633 p[pos] = '\0';
634
635 if ((option = find_option(rh, p, OT_ANY)) == NULL) {
636 rc_log(LOG_ERR, "%s: line %d: unrecognized keyword: %s", filename, line, p);
637 fclose(configfd);
638 rc_destroy(rh);
639 return NULL;
640 }
641
642 if (option->status != ST_UNDEF) {
643 rc_log(LOG_ERR, "%s: line %d: duplicate option line: %s", filename, line, p);
644 fclose(configfd);
645 rc_destroy(rh);
646 return NULL;
647 }
648
649 p += pos+1;
650 while (isspace(*p))
651 p++;
652 pos = strlen(p) - 1;
653 while(pos != 0 && isspace(p[pos]))
654 pos--;
655 p[pos + 1] = '\0';
656
657 switch (option->type) {
658 case OT_STR:
659 if (set_option_str(filename, line, option, p) < 0) {
660 fclose(configfd);
661 rc_destroy(rh);
662 return NULL;
663 }
664 break;
665 case OT_INT:
666 if (set_option_int(filename, line, option, p) < 0) {
667 fclose(configfd);
668 rc_destroy(rh);
669 return NULL;
670 }
671 break;
672 case OT_SRV:
673 if (set_option_srv(filename, line, option, p) < 0) {
674 fclose(configfd);
675 rc_destroy(rh);
676 return NULL;
677 }
678 break;
679 case OT_AUO:
680 if (set_option_auo(filename, line, option, p) < 0) {
681 fclose(configfd);
682 rc_destroy(rh);
683 return NULL;
684 }
685 break;
686 default:
687 rc_log(LOG_CRIT, "rc_read_config: impossible case branch!");
688 abort();
689 }
690 }
691 fclose(configfd);
692
693 if (rc_test_config(rh, filename) == -1) {
694 rc_destroy(rh);
695 return NULL;
696 }
697
698 {
699 int clientdebug = rc_conf_int_2(rh, "clientdebug", FALSE);
700 if(clientdebug > 0) {
701 radcli_debug = clientdebug;
702 }
703 }
704
705 /* Always load the built-in RFC 2865/2866/2869 dictionary first so that
706 * applications need not ship a dictionary file for standard attributes. */
707 if (rc_read_dictionary_from_buffer(rh, rc_rfc_dictionary,
708 sizeof(rc_rfc_dictionary) - 1) != 0) {
709 rc_log(LOG_CRIT, "rc_read_config: failed to load built-in RFC dictionary");
710 rc_destroy(rh);
711 return NULL;
712 }
713
714 p = rc_conf_str(rh, "dictionary");
715 if (p != NULL) {
716 if (rc_read_dictionary(rh, p) != 0) {
717 rc_log(LOG_CRIT, "could not load dictionary");
718 rc_destroy(rh);
719 return NULL;
720 }
721 }
722
723 return rh;
724}
725
732char *rc_conf_str(rc_handle const *rh, char const *optname)
733{
734 OPTION *option;
735
736 option = find_option(rh, optname, OT_STR);
737
738 if (option != NULL) {
739 return (char *)option->val;
740 } else {
741 rc_log(LOG_CRIT, "rc_conf_str: unknown config option requested: %s", optname);
742 return NULL;
743 }
744}
745
746/*- Get the value of a config option
747 *
748 * @param rh a handle to parsed configuration.
749 * @param optname the name of an option.
750 * @return config option value.
751 */
752static int rc_conf_int_2(rc_handle const *rh, char const *optname, int complain)
753{
754 OPTION *option;
755
756 option = find_option(rh, optname, OT_INT|OT_AUO);
757
758 if (option != NULL) {
759 if (option->val) {
760 return *((int *)option->val);
761 } else if(complain) {
762 rc_log(LOG_ERR, "rc_conf_int: config option %s was not set", optname);
763 }
764 return 0;
765 } else {
766 rc_log(LOG_CRIT, "rc_conf_int: unknown config option requested: %s", optname);
767 return 0;
768 }
769}
770
771int rc_conf_int(rc_handle const *rh, char const *optname)
772{
773 return rc_conf_int_2(rh, optname, TRUE);
774}
775
782SERVER *rc_conf_srv(rc_handle const *rh, char const *optname)
783{
784 OPTION *option;
785
786 option = find_option(rh, optname, OT_SRV);
787
788 if (option != NULL) {
789 return (SERVER *)option->val;
790 } else {
791 rc_log(LOG_CRIT, "rc_conf_srv: unknown config option requested: %s", optname);
792 return NULL;
793 }
794}
795
802int rc_test_config(rc_handle *rh, char const *filename)
803{
804 SERVER *srv;
805
806 srv = rc_conf_srv(rh, "authserver");
807 if (!srv || !srv->max)
808 {
809 rc_log(LOG_ERR,"%s: no authserver specified", filename);
810 return -1;
811 }
812
813 srv = rc_conf_srv(rh, "acctserver");
814 if (!srv || !srv->max)
815 {
816 /* it is allowed not to have acct servers */
817 if (rh->so_type != RC_SOCKET_TLS && rh->so_type != RC_SOCKET_DTLS)
818 rc_log(LOG_DEBUG,"%s: no acctserver specified", filename);
819 }
820
821 if (rc_conf_int(rh, "radius_timeout") <= 0)
822 {
823 rc_log(LOG_ERR,"%s: radius_timeout <= 0 is illegal", filename);
824 return -1;
825 }
826 if (rc_conf_int(rh, "radius_retries") <= 0)
827 {
828 rc_log(LOG_ERR,"%s: radius_retries <= 0 is illegal", filename);
829 return -1;
830 }
831
832 if (rc_apply_config(rh) == -1) {
833 return -1;
834 }
835
836 return 0;
837}
838
845static int find_match (const struct addrinfo* addr, const struct addrinfo *hostname)
846{
847 const struct addrinfo *ptr, *ptr2;
848 unsigned len1, len2;
849
850 ptr = addr;
851 while(ptr) {
852 ptr2 = hostname;
853 while(ptr2) {
854 len1 = SA_GET_INLEN(ptr->ai_addr);
855 len2 = SA_GET_INLEN(ptr2->ai_addr);
856
857 if (len1 > 0 &&
858 len1 == len2 &&
859 memcmp(SA_GET_INADDR(ptr->ai_addr), SA_GET_INADDR(ptr2->ai_addr), len1) == 0) {
860 return 0;
861 }
862 ptr2 = ptr2->ai_next;
863 }
864 ptr = ptr->ai_next;
865 }
866 return -1;
867}
868
874static int rc_ipaddr_local(const struct sockaddr *addr)
875{
876 int temp_sock, res, serrno;
877 struct sockaddr_storage tmpaddr;
878
879 memcpy(&tmpaddr, addr, SA_LEN(addr));
880
881 temp_sock = socket(addr->sa_family, SOCK_DGRAM, 0);
882 if (temp_sock == -1)
883 return -1;
884
885 if (addr->sa_family == AF_INET) {
886 ((struct sockaddr_in*)&tmpaddr)->sin_port = 0;
887 } else {
888 ((struct sockaddr_in6*)&tmpaddr)->sin6_port = 0;
889 }
890 res = bind(temp_sock, SA(&tmpaddr), SS_LEN(&tmpaddr));
891 serrno = errno;
892 close(temp_sock);
893 if (res == 0)
894 return 0;
895 if (serrno == EADDRNOTAVAIL)
896 return 1;
897 return -1;
898}
899
905static int rc_is_myname(const struct addrinfo *info)
906{
907 const struct addrinfo *p;
908 int res;
909
910 p = info;
911 while(p != NULL) {
912 res = rc_ipaddr_local(p->ai_addr);
913 if (res == 0 || res == -1) {
914 return res;
915 }
916 p = p->ai_next;
917 }
918 return 1;
919}
920
931int rc_find_server_addr (rc_handle const *rh, char const *server_name,
932 struct addrinfo** info, char *secret, rc_type type)
933{
934 int result = 0;
935 FILE *clientfd;
936 char *h;
937 char *s;
938 char buffer[128];
939 char hostnm[AUTH_ID_LEN + 1];
940 char *buffer_save;
941 char *hostnm_save;
942 SERVER *servers;
943 struct addrinfo *tmpinfo = NULL;
944 const char *fservers;
945 char const *optname;
946
947 /* Lookup the IP address of the radius server */
948 if ((*info = rc_getaddrinfo (server_name, type==AUTH?PW_AI_AUTH:PW_AI_ACCT)) == NULL)
949 return -1;
950
951 switch (type)
952 {
953 case AUTH: optname = "authserver"; break;
954 case ACCT: optname = "acctserver"; break;
955 default: optname = NULL;
956 }
957
958 if ( (optname != NULL) &&
959 ((servers = rc_conf_srv(rh, optname)) != NULL) )
960 {
961 /* Check to see if the server secret is defined in the rh config */
962 unsigned servernum;
963 size_t server_name_len = strlen(server_name);
964 for (servernum = 0; servernum < servers->max; servernum++)
965 {
966 if( (strncmp(server_name, servers->name[servernum], server_name_len) == 0) &&
967 (servers->secret[servernum] != NULL) )
968 {
969 memset(secret, '\0', MAX_SECRET_LENGTH);
970 strlcpy(secret, servers->secret[servernum], MAX_SECRET_LENGTH);
971 return 0;
972 }
973 }
974 }
975
976 /* We didn't find it in the rh_config or the servername is too long so look for a
977 * servers file to define the secret(s)
978 */
979
980 fservers = rc_conf_str(rh, "servers");
981 if (fservers != NULL) {
982 if ((clientfd = fopen (fservers, "r")) == NULL)
983 {
984 rc_log(LOG_ERR, "rc_find_server: couldn't open file: %s: %s", strerror(errno), rc_conf_str(rh, "servers"));
985 goto fail;
986 }
987
988 while (fgets (buffer, sizeof (buffer), clientfd) != NULL)
989 {
990 if (*buffer == '#')
991 continue;
992
993 if ((h = strtok_r(buffer, " \t\n", &buffer_save)) == NULL) /* first hostname */
994 continue;
995
996 strlcpy (hostnm, h, AUTH_ID_LEN);
997
998 if ((s = strtok_r (NULL, " \t\n", &buffer_save)) == NULL) /* and secret field */
999 continue;
1000
1001 strlcpy (secret, s, MAX_SECRET_LENGTH);
1002
1003 if (!strchr (hostnm, '/')) /* If single name form */
1004 {
1005 tmpinfo = rc_getaddrinfo(hostnm, 0);
1006 if (tmpinfo)
1007 {
1008 result = find_match (*info, tmpinfo);
1009 if (result == 0)
1010 {
1011 result++;
1012 break;
1013 }
1014
1015 freeaddrinfo(tmpinfo);
1016 tmpinfo = NULL;
1017 }
1018 }
1019 else /* <name1>/<name2> "paired" form */
1020 {
1021 strtok_r(hostnm, "/", &hostnm_save);
1022 tmpinfo = rc_getaddrinfo(hostnm, 0);
1023 if (tmpinfo)
1024 {
1025 if (rc_is_myname(tmpinfo) == 0)
1026 { /* If we're the 1st name, target is 2nd */
1027 if (find_match (*info, tmpinfo) == 0)
1028 {
1029 result++;
1030 break;
1031 }
1032 }
1033 else /* If we were 2nd name, target is 1st name */
1034 {
1035 if (find_match (*info, tmpinfo) == 0)
1036 {
1037 result++;
1038 break;
1039 }
1040 }
1041 freeaddrinfo(tmpinfo);
1042 tmpinfo = NULL;
1043 }
1044 }
1045 }
1046 fclose (clientfd);
1047 }
1048 if (result == 0)
1049 {
1050 memset (buffer, '\0', sizeof (buffer));
1051 memset (secret, '\0', MAX_SECRET_LENGTH);
1052 rc_log(LOG_ERR, "rc_find_server: couldn't find RADIUS server %s in %s",
1053 server_name, rc_conf_str(rh, "servers"));
1054 goto fail;
1055 }
1056
1057 result = 0;
1058 goto cleanup;
1059
1060 fail:
1061 freeaddrinfo(*info);
1062 result = -1;
1063
1064 cleanup:
1065 if (tmpinfo)
1066 freeaddrinfo(tmpinfo);
1067
1068 return result;
1069}
1070
1081void rc_config_free(rc_handle *rh)
1082{
1083 int i, j;
1084 SERVER *serv;
1085
1086 if (rh->config_options == NULL)
1087 return;
1088
1089 for (i = 0; i < NUM_OPTIONS; i++) {
1090 if (rh->config_options[i].val == NULL)
1091 continue;
1092 if (rh->config_options[i].type == OT_SRV) {
1093 serv = (SERVER *)rh->config_options[i].val;
1094 for (j = 0; j < serv->max; j++) {
1095 free(serv->name[j]);
1096 if(serv->secret[j]) free(serv->secret[j]);
1097 }
1098 free(serv);
1099 } else {
1100 free(rh->config_options[i].val);
1101 }
1102 }
1103 free(rh->config_options);
1104 free(rh->first_dict_read);
1105 rh->config_options = NULL;
1106 rh->first_dict_read = NULL;
1107}
1108
1109static int _initialized = 0;
1110
1115rc_handle *rc_new(void)
1116{
1117 rc_handle *rh;
1118
1119 if (_initialized == 0) {
1120#if defined(HAVE_GNUTLS) && GNUTLS_VERSION_NUMBER < 0x030300
1121 int ret;
1122 ret = gnutls_global_init();
1123 if (ret < 0) {
1124 rc_log(LOG_ERR,
1125 "%s: error initializing gnutls: %s",
1126 __func__, gnutls_strerror(ret));
1127 return NULL;
1128 }
1129#endif
1130 srandom((unsigned int)(time(NULL)+getpid()));
1131 }
1132 _initialized++;
1133
1134 rh = calloc(1, sizeof(*rh));
1135 if (rh == NULL) {
1136 rc_log(LOG_CRIT, "rc_new: out of memory");
1137 return NULL;
1138 }
1139 return rh;
1140}
1141
1146void rc_destroy(rc_handle *rh)
1147{
1148 rc_dict_free(rh);
1149#ifdef HAVE_GNUTLS
1150 rc_deinit_tls(rh);
1151#endif
1152 rc_config_free(rh);
1153 free(rh);
1154
1155#if defined(HAVE_GNUTLS) && GNUTLS_VERSION_NUMBER < 0x030300
1156 _initialized--;
1157 if (_initialized == 0) {
1158 gnutls_global_deinit();
1159 }
1160#endif
1161}
1162
1171{
1172 return rh->so_type;
1173}
1174
1176 /*
1177 * Local Variables:
1178 * c-basic-offset:8
1179 * c-style: whitesmith
1180 * End:
1181 */
void rc_own_bind_addr(rc_handle *rh, struct sockaddr_storage *lia)
Definition ip_util.c:164
rc_socket_type rc_get_socket_type(rc_handle *rh)
Definition config.c:1170
rc_handle * rc_new(void)
Definition config.c:1115
rc_type
Definition radcli.h:70
void rc_destroy(rc_handle *rh)
Definition config.c:1146
int rc_read_dictionary_from_buffer(rc_handle *rh, char const *buf, size_t size)
Definition dict.c:507
rc_handle * rc_read_config(char const *filename)
Definition config.c:585
int rc_read_dictionary(rc_handle *rh, char const *filename)
Definition dict.c:472
char * rc_conf_str(rc_handle const *rh, char const *optname)
Definition config.c:732
int rc_test_config(rc_handle *rh, char const *filename)
Definition config.c:802
void rc_dict_free(rc_handle *rh)
Definition dict.c:653
rc_handle * rc_config_init(rc_handle *rh)
Definition config.c:350
void rc_config_free(rc_handle *rh)
Definition config.c:1081
int rc_find_server_addr(rc_handle const *rh, char const *server_name, struct addrinfo **info, char *secret, rc_type type)
Definition config.c:931
SERVER * rc_conf_srv(rc_handle const *rh, char const *optname)
Definition config.c:782
int rc_add_config(rc_handle *rh, char const *option_name, char const *option_val, char const *source, int line)
Definition config.c:295
rc_socket_type
Definition radcli.h:101
int rc_apply_config(rc_handle *rh)
Definition config.c:501
@ ACCT
Request for accounting server.
Definition radcli.h:72
@ AUTH
Request for authentication server.
Definition radcli.h:71
@ RC_SOCKET_UDP
Plain UDP socket.
Definition radcli.h:102
@ RC_SOCKET_TCP
Plain TCP socket.
Definition radcli.h:105
@ RC_SOCKET_DTLS
DTLS socket.
Definition radcli.h:104
@ RC_SOCKET_TLS
TLS socket.
Definition radcli.h:103