Radcli library 1.5.2
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
362rc_handle *rc_config_init(rc_handle *rh)
363{
364 SERVER *authservers = NULL;
365 SERVER *acctservers;
366 OPTION *acct;
367 OPTION *auth;
368
369 rh->config_options = malloc(sizeof(config_options_default));
370 if (rh->config_options == NULL)
371 {
372 rc_log(LOG_CRIT, "rc_config_init: out of memory");
373 rc_destroy(rh);
374 return NULL;
375 }
376 memcpy(rh->config_options, &config_options_default, sizeof(config_options_default));
377
378 auth = find_option(rh, "authserver", OT_ANY);
379 if (auth) {
380 authservers = calloc(1, sizeof(SERVER));
381 if(authservers == NULL) {
382 rc_log(LOG_CRIT, "rc_config_init: error initializing server structs");
383 rc_destroy(rh);
384 return NULL;
385 }
386 auth->val = authservers;
387 }
388
389 acct = find_option(rh, "acctserver", OT_ANY);
390 if (acct) {
391 acctservers = calloc(1, sizeof(SERVER));
392 if(acctservers == NULL) {
393 rc_log(LOG_CRIT, "rc_config_init: error initializing server structs");
394 rc_destroy(rh);
395 if(authservers) free(authservers);
396 return NULL;
397 }
398 acct->val = acctservers;
399 }
400
401 return rh;
402}
403
404static ssize_t plain_sendto(void *ptr, int sockfd,
405 const void *buf, size_t len, int flags,
406 const struct sockaddr *dest_addr, socklen_t addrlen)
407{
408 return sendto(sockfd, buf, len, flags, dest_addr, addrlen);
409}
410
411static ssize_t plain_tcp_sendto(void *ptr, int sockfd,
412 const void *buf, size_t len, int flags,
413 const struct sockaddr *dest_addr, socklen_t addrlen)
414{
415 if((connect(sockfd, dest_addr, addrlen)) != 0){
416 rc_log(LOG_ERR, "%s: Connect Call Failed : %s", __FUNCTION__, strerror(errno));
417 return -1;
418 }
419 return sendto(sockfd, buf, len, flags, dest_addr, addrlen);
420}
421
422static ssize_t plain_recvfrom(void *ptr, int sockfd,
423 void *buf, size_t len, int flags,
424 struct sockaddr *src_addr, socklen_t * addrlen)
425{
426 return recvfrom(sockfd, buf, len, flags, src_addr, addrlen);
427}
428
429static void plain_close_fd(int fd)
430{
431 close(fd);
432}
433
434static int plain_get_fd(void *ptr, struct sockaddr *our_sockaddr)
435{
436 int sockfd;
437
438 sockfd = socket(our_sockaddr->sa_family, SOCK_DGRAM, 0);
439 if (sockfd < 0) {
440 return -1;
441 }
442
443 if (our_sockaddr->sa_family == AF_INET)
444 ((struct sockaddr_in *)our_sockaddr)->sin_port = 0;
445 else
446 ((struct sockaddr_in6 *)our_sockaddr)->sin6_port = 0;
447
448 if (bind(sockfd, SA(our_sockaddr), SA_LEN(our_sockaddr)) < 0) {
449 close(sockfd);
450 return -1;
451 }
452 return sockfd;
453}
454
455static int plain_tcp_get_fd(void *ptr, struct sockaddr *our_sockaddr)
456{
457 int sockfd;
458
459 sockfd = socket(our_sockaddr->sa_family, SOCK_STREAM, 0);
460 if (sockfd < 0) {
461 return -1;
462 }
463
464 if (our_sockaddr->sa_family == AF_INET)
465 ((struct sockaddr_in *)our_sockaddr)->sin_port = 0;
466 else
467 ((struct sockaddr_in6 *)our_sockaddr)->sin6_port = 0;
468
469 if (bind(sockfd, SA(our_sockaddr), SA_LEN(our_sockaddr)) < 0) {
470 close(sockfd);
471 return -1;
472 }
473 return sockfd;
474}
475
476static const rc_sockets_override default_socket_funcs = {
477 .get_fd = plain_get_fd,
478 .close_fd = plain_close_fd,
479 .sendto = plain_sendto,
480 .recvfrom = plain_recvfrom
481};
482
483static const rc_sockets_override default_tcp_socket_funcs = {
484 .get_fd = plain_tcp_get_fd,
485 .close_fd = plain_close_fd,
486 .sendto = plain_tcp_sendto,
487 .recvfrom = plain_recvfrom
488};
489
490static int set_addr(struct sockaddr_storage *ss, const char *ip)
491{
492 memset(ss, 0, sizeof(*ss));
493 if (inet_pton(AF_INET, ip, &((struct sockaddr_in *)ss)->sin_addr) == 1) {
494 ss->ss_family = AF_INET;
495 } else if (inet_pton(AF_INET6, ip, &((struct sockaddr_in6 *)ss)->sin6_addr) == 1) {
496 ss->ss_family = AF_INET6;
497 } else {
498 rc_log(LOG_CRIT, "invalid IP address for nas-ip: %s", ip);
499 return -1;
500 }
501 return 0;
502}
503
519int rc_apply_config(rc_handle *rh)
520{
521 const char *txt;
522 int ret;
523
524 memset(&rh->own_bind_addr, 0, sizeof(rh->own_bind_addr));
525 rh->own_bind_addr_set = 0;
526 rc_own_bind_addr(rh, &rh->own_bind_addr);
527 rh->own_bind_addr_set = 1;
528
529 txt = rc_conf_str(rh, "nas-ip");
530 if (txt != NULL) {
531 if (set_addr(&rh->nas_addr, txt) < 0)
532 return -1;
533 rh->nas_addr_set = 1;
534 }
535
536 txt = rc_conf_str(rh, "serv-type");
537 if (txt == NULL)
538 txt = rc_conf_str(rh, "serv-auth-type");
539
540 if (txt == NULL)
541 txt = "udp";
542
543 if (strcasecmp(txt, "udp") == 0) {
544 memset(&rh->so, 0, sizeof(rh->so));
545 rh->so_type = RC_SOCKET_UDP;
546 memcpy(&rh->so, &default_socket_funcs, sizeof(rh->so));
547 ret = 0;
548 } else if (strcasecmp(txt, "tcp") == 0) {
549 memset(&rh->so, 0, sizeof(rh->so));
550 rh->so_type = RC_SOCKET_TCP;
551 memcpy(&rh->so, &default_tcp_socket_funcs, sizeof(rh->so));
552 ret = 0;
553#ifdef HAVE_GNUTLS
554 } else if (strcasecmp(txt, "dtls") == 0) {
555 ret = rc_init_tls(rh, SEC_FLAG_DTLS);
556 } else if (strcasecmp(txt, "tls") == 0) {
557 ret = rc_init_tls(rh, 0);
558#endif
559 } else {
560 rc_log(LOG_CRIT, "unknown server type: %s", txt);
561 return -1;
562 }
563
564 if (ret < 0) {
565 rc_log(LOG_CRIT, "error initializing %s", txt);
566 return -1;
567 }
568
569 return 0;
570
571}
572
618rc_handle *rc_read_config(char const *filename)
619{
620 FILE *configfd;
621 char buffer[512], *p;
622 OPTION *option;
623 int line;
624 size_t pos;
625 rc_handle *rh;
626
627
628 rh = rc_new();
629 if (rh == NULL)
630 return NULL;
631
632 rh->config_options = malloc(sizeof(config_options_default));
633 if (rh->config_options == NULL) {
634 rc_log(LOG_CRIT, "rc_read_config: out of memory");
635 rc_destroy(rh);
636 return NULL;
637 }
638 memcpy(rh->config_options, &config_options_default, sizeof(config_options_default));
639
640 if ((configfd = fopen(filename,"r")) == NULL)
641 {
642 rc_log(LOG_ERR,"rc_read_config: can't open %s: %s", filename, strerror(errno));
643 rc_destroy(rh);
644 return NULL;
645 }
646
647 line = 0;
648 while ((fgets(buffer, sizeof(buffer), configfd) != NULL))
649 {
650 line++;
651 p = buffer;
652
653 if ((*p == '\n') || (*p == '#') || (*p == '\0'))
654 continue;
655
656 p[strlen(p)-1] = '\0';
657
658
659 if ((pos = strcspn(p, "\t ")) == 0) {
660 rc_log(LOG_ERR, "%s: line %d: bogus format: %s", filename, line, p);
661 fclose(configfd);
662 rc_destroy(rh);
663 return NULL;
664 }
665
666 p[pos] = '\0';
667
668 if ((option = find_option(rh, p, OT_ANY)) == NULL) {
669 rc_log(LOG_ERR, "%s: line %d: unrecognized keyword: %s", filename, line, p);
670 fclose(configfd);
671 rc_destroy(rh);
672 return NULL;
673 }
674
675 if (option->status != ST_UNDEF) {
676 rc_log(LOG_ERR, "%s: line %d: duplicate option line: %s", filename, line, p);
677 fclose(configfd);
678 rc_destroy(rh);
679 return NULL;
680 }
681
682 p += pos+1;
683 while (isspace(*p))
684 p++;
685 pos = strlen(p) - 1;
686 while(pos != 0 && isspace(p[pos]))
687 pos--;
688 p[pos + 1] = '\0';
689
690 switch (option->type) {
691 case OT_STR:
692 if (set_option_str(filename, line, option, p) < 0) {
693 fclose(configfd);
694 rc_destroy(rh);
695 return NULL;
696 }
697 break;
698 case OT_INT:
699 if (set_option_int(filename, line, option, p) < 0) {
700 fclose(configfd);
701 rc_destroy(rh);
702 return NULL;
703 }
704 break;
705 case OT_SRV:
706 if (set_option_srv(filename, line, option, p) < 0) {
707 fclose(configfd);
708 rc_destroy(rh);
709 return NULL;
710 }
711 break;
712 case OT_AUO:
713 if (set_option_auo(filename, line, option, p) < 0) {
714 fclose(configfd);
715 rc_destroy(rh);
716 return NULL;
717 }
718 break;
719 default:
720 rc_log(LOG_CRIT, "rc_read_config: impossible case branch!");
721 abort();
722 }
723 }
724 fclose(configfd);
725
726 if (rc_test_config(rh, filename) == -1) {
727 rc_destroy(rh);
728 return NULL;
729 }
730
731 {
732 int clientdebug = rc_conf_int_2(rh, "clientdebug", FALSE);
733 if(clientdebug > 0) {
734 radcli_debug = clientdebug;
735 }
736 }
737
738 /* Always load the built-in RFC 2865/2866/2869 dictionary first so that
739 * applications need not ship a dictionary file for standard attributes. */
740 if (rc_read_dictionary_from_buffer(rh, rc_rfc_dictionary,
741 sizeof(rc_rfc_dictionary) - 1) != 0) {
742 rc_log(LOG_CRIT, "rc_read_config: failed to load built-in RFC dictionary");
743 rc_destroy(rh);
744 return NULL;
745 }
746
747 p = rc_conf_str(rh, "dictionary");
748 if (p != NULL) {
749 if (rc_read_dictionary(rh, p) != 0) {
750 rc_log(LOG_CRIT, "could not load dictionary");
751 rc_destroy(rh);
752 return NULL;
753 }
754 }
755
756 return rh;
757}
758
765char *rc_conf_str(rc_handle const *rh, char const *optname)
766{
767 OPTION *option;
768
769 option = find_option(rh, optname, OT_STR);
770
771 if (option != NULL) {
772 return (char *)option->val;
773 } else {
774 rc_log(LOG_CRIT, "rc_conf_str: unknown config option requested: %s", optname);
775 return NULL;
776 }
777}
778
779/*- Get the value of a config option
780 *
781 * @param rh a handle to parsed configuration.
782 * @param optname the name of an option.
783 * @return config option value.
784 */
785static int rc_conf_int_2(rc_handle const *rh, char const *optname, int complain)
786{
787 OPTION *option;
788
789 option = find_option(rh, optname, OT_INT|OT_AUO);
790
791 if (option != NULL) {
792 if (option->val) {
793 return *((int *)option->val);
794 } else if(complain) {
795 rc_log(LOG_ERR, "rc_conf_int: config option %s was not set", optname);
796 }
797 return 0;
798 } else {
799 rc_log(LOG_CRIT, "rc_conf_int: unknown config option requested: %s", optname);
800 return 0;
801 }
802}
803
804int rc_conf_int(rc_handle const *rh, char const *optname)
805{
806 return rc_conf_int_2(rh, optname, TRUE);
807}
808
815SERVER *rc_conf_srv(rc_handle const *rh, char const *optname)
816{
817 OPTION *option;
818
819 option = find_option(rh, optname, OT_SRV);
820
821 if (option != NULL) {
822 return (SERVER *)option->val;
823 } else {
824 rc_log(LOG_CRIT, "rc_conf_srv: unknown config option requested: %s", optname);
825 return NULL;
826 }
827}
828
835int rc_test_config(rc_handle *rh, char const *filename)
836{
837 SERVER *srv;
838
839 srv = rc_conf_srv(rh, "authserver");
840 if (!srv || !srv->max)
841 {
842 rc_log(LOG_ERR,"%s: no authserver specified", filename);
843 return -1;
844 }
845
846 srv = rc_conf_srv(rh, "acctserver");
847 if (!srv || !srv->max)
848 {
849 /* it is allowed not to have acct servers */
850 if (rh->so_type != RC_SOCKET_TLS && rh->so_type != RC_SOCKET_DTLS)
851 rc_log(LOG_DEBUG,"%s: no acctserver specified", filename);
852 }
853
854 if (rc_conf_int(rh, "radius_timeout") <= 0)
855 {
856 rc_log(LOG_ERR,"%s: radius_timeout <= 0 is illegal", filename);
857 return -1;
858 }
859 if (rc_conf_int(rh, "radius_retries") <= 0)
860 {
861 rc_log(LOG_ERR,"%s: radius_retries <= 0 is illegal", filename);
862 return -1;
863 }
864
865 if (rc_apply_config(rh) == -1) {
866 return -1;
867 }
868
869 return 0;
870}
871
878static int find_match (const struct addrinfo* addr, const struct addrinfo *hostname)
879{
880 const struct addrinfo *ptr, *ptr2;
881 unsigned len1, len2;
882
883 ptr = addr;
884 while(ptr) {
885 ptr2 = hostname;
886 while(ptr2) {
887 len1 = SA_GET_INLEN(ptr->ai_addr);
888 len2 = SA_GET_INLEN(ptr2->ai_addr);
889
890 if (len1 > 0 &&
891 len1 == len2 &&
892 memcmp(SA_GET_INADDR(ptr->ai_addr), SA_GET_INADDR(ptr2->ai_addr), len1) == 0) {
893 return 0;
894 }
895 ptr2 = ptr2->ai_next;
896 }
897 ptr = ptr->ai_next;
898 }
899 return -1;
900}
901
907static int rc_ipaddr_local(const struct sockaddr *addr)
908{
909 int temp_sock, res, serrno;
910 struct sockaddr_storage tmpaddr;
911
912 memcpy(&tmpaddr, addr, SA_LEN(addr));
913
914 temp_sock = socket(addr->sa_family, SOCK_DGRAM, 0);
915 if (temp_sock == -1)
916 return -1;
917
918 if (addr->sa_family == AF_INET) {
919 ((struct sockaddr_in*)&tmpaddr)->sin_port = 0;
920 } else {
921 ((struct sockaddr_in6*)&tmpaddr)->sin6_port = 0;
922 }
923 res = bind(temp_sock, SA(&tmpaddr), SS_LEN(&tmpaddr));
924 serrno = errno;
925 close(temp_sock);
926 if (res == 0)
927 return 0;
928 if (serrno == EADDRNOTAVAIL)
929 return 1;
930 return -1;
931}
932
938static int rc_is_myname(const struct addrinfo *info)
939{
940 const struct addrinfo *p;
941 int res;
942
943 p = info;
944 while(p != NULL) {
945 res = rc_ipaddr_local(p->ai_addr);
946 if (res == 0 || res == -1) {
947 return res;
948 }
949 p = p->ai_next;
950 }
951 return 1;
952}
953
964int rc_find_server_addr (rc_handle const *rh, char const *server_name,
965 struct addrinfo** info, char *secret, rc_type type)
966{
967 int result = 0;
968 FILE *clientfd;
969 char *h;
970 char *s;
971 char buffer[128];
972 char hostnm[AUTH_ID_LEN + 1];
973 char *buffer_save;
974 char *hostnm_save;
975 SERVER *servers;
976 struct addrinfo *tmpinfo = NULL;
977 const char *fservers;
978 char const *optname;
979
980 /* Lookup the IP address of the radius server */
981 if ((*info = rc_getaddrinfo (server_name, type==AUTH?PW_AI_AUTH:PW_AI_ACCT)) == NULL)
982 return -1;
983
984 switch (type)
985 {
986 case AUTH: optname = "authserver"; break;
987 case ACCT: optname = "acctserver"; break;
988 default: optname = NULL;
989 }
990
991 if ( (optname != NULL) &&
992 ((servers = rc_conf_srv(rh, optname)) != NULL) )
993 {
994 /* Check to see if the server secret is defined in the rh config */
995 unsigned servernum;
996 size_t server_name_len = strlen(server_name);
997 for (servernum = 0; servernum < servers->max; servernum++)
998 {
999 if( (strncmp(server_name, servers->name[servernum], server_name_len) == 0) &&
1000 (servers->secret[servernum] != NULL) )
1001 {
1002 memset(secret, '\0', MAX_SECRET_LENGTH);
1003 strlcpy(secret, servers->secret[servernum], MAX_SECRET_LENGTH);
1004 return 0;
1005 }
1006 }
1007 }
1008
1009 /* We didn't find it in the rh_config or the servername is too long so look for a
1010 * servers file to define the secret(s)
1011 */
1012
1013 fservers = rc_conf_str(rh, "servers");
1014 if (fservers != NULL) {
1015 if ((clientfd = fopen (fservers, "r")) == NULL)
1016 {
1017 rc_log(LOG_ERR, "rc_find_server: couldn't open file: %s: %s", strerror(errno), rc_conf_str(rh, "servers"));
1018 goto fail;
1019 }
1020
1021 while (fgets (buffer, sizeof (buffer), clientfd) != NULL)
1022 {
1023 if (*buffer == '#')
1024 continue;
1025
1026 if ((h = strtok_r(buffer, " \t\n", &buffer_save)) == NULL) /* first hostname */
1027 continue;
1028
1029 strlcpy (hostnm, h, AUTH_ID_LEN);
1030
1031 if ((s = strtok_r (NULL, " \t\n", &buffer_save)) == NULL) /* and secret field */
1032 continue;
1033
1034 strlcpy (secret, s, MAX_SECRET_LENGTH);
1035
1036 if (!strchr (hostnm, '/')) /* If single name form */
1037 {
1038 tmpinfo = rc_getaddrinfo(hostnm, 0);
1039 if (tmpinfo)
1040 {
1041 result = find_match (*info, tmpinfo);
1042 if (result == 0)
1043 {
1044 result++;
1045 break;
1046 }
1047
1048 freeaddrinfo(tmpinfo);
1049 tmpinfo = NULL;
1050 }
1051 }
1052 else /* <name1>/<name2> "paired" form */
1053 {
1054 strtok_r(hostnm, "/", &hostnm_save);
1055 tmpinfo = rc_getaddrinfo(hostnm, 0);
1056 if (tmpinfo)
1057 {
1058 if (rc_is_myname(tmpinfo) == 0)
1059 { /* If we're the 1st name, target is 2nd */
1060 if (find_match (*info, tmpinfo) == 0)
1061 {
1062 result++;
1063 break;
1064 }
1065 }
1066 else /* If we were 2nd name, target is 1st name */
1067 {
1068 if (find_match (*info, tmpinfo) == 0)
1069 {
1070 result++;
1071 break;
1072 }
1073 }
1074 freeaddrinfo(tmpinfo);
1075 tmpinfo = NULL;
1076 }
1077 }
1078 }
1079 fclose (clientfd);
1080 }
1081 if (result == 0)
1082 {
1083 memset (buffer, '\0', sizeof (buffer));
1084 memset (secret, '\0', MAX_SECRET_LENGTH);
1085 rc_log(LOG_ERR, "rc_find_server: couldn't find RADIUS server %s in %s",
1086 server_name, rc_conf_str(rh, "servers"));
1087 goto fail;
1088 }
1089
1090 result = 0;
1091 goto cleanup;
1092
1093 fail:
1094 freeaddrinfo(*info);
1095 result = -1;
1096
1097 cleanup:
1098 if (tmpinfo)
1099 freeaddrinfo(tmpinfo);
1100
1101 return result;
1102}
1103
1114void rc_config_free(rc_handle *rh)
1115{
1116 int i, j;
1117 SERVER *serv;
1118
1119 if (rh->config_options == NULL)
1120 return;
1121
1122 for (i = 0; i < NUM_OPTIONS; i++) {
1123 if (rh->config_options[i].val == NULL)
1124 continue;
1125 if (rh->config_options[i].type == OT_SRV) {
1126 serv = (SERVER *)rh->config_options[i].val;
1127 for (j = 0; j < serv->max; j++) {
1128 free(serv->name[j]);
1129 if(serv->secret[j]) free(serv->secret[j]);
1130 }
1131 free(serv);
1132 } else {
1133 free(rh->config_options[i].val);
1134 }
1135 }
1136 free(rh->config_options);
1137 free(rh->first_dict_read);
1138 rh->config_options = NULL;
1139 rh->first_dict_read = NULL;
1140}
1141
1142static int _initialized = 0;
1143
1148rc_handle *rc_new(void)
1149{
1150 rc_handle *rh;
1151
1152 if (_initialized == 0) {
1153#if defined(HAVE_GNUTLS) && GNUTLS_VERSION_NUMBER < 0x030300
1154 int ret;
1155 ret = gnutls_global_init();
1156 if (ret < 0) {
1157 rc_log(LOG_ERR,
1158 "%s: error initializing gnutls: %s",
1159 __func__, gnutls_strerror(ret));
1160 return NULL;
1161 }
1162#endif
1163 srandom((unsigned int)(time(NULL)+getpid()));
1164 }
1165 _initialized++;
1166
1167 rh = calloc(1, sizeof(*rh));
1168 if (rh == NULL) {
1169 rc_log(LOG_CRIT, "rc_new: out of memory");
1170 return NULL;
1171 }
1172 return rh;
1173}
1174
1179void rc_destroy(rc_handle *rh)
1180{
1181 rc_dict_free(rh);
1182#ifdef HAVE_GNUTLS
1183 rc_deinit_tls(rh);
1184#endif
1185 rc_config_free(rh);
1186 free(rh);
1187
1188#if defined(HAVE_GNUTLS) && GNUTLS_VERSION_NUMBER < 0x030300
1189 _initialized--;
1190 if (_initialized == 0) {
1191 gnutls_global_deinit();
1192 }
1193#endif
1194}
1195
1204{
1205 return rh->so_type;
1206}
1207
1209 /*
1210 * Local Variables:
1211 * c-basic-offset:8
1212 * c-style: whitesmith
1213 * End:
1214 */
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:1203
rc_handle * rc_new(void)
Definition config.c:1148
rc_type
Definition radcli.h:70
void rc_destroy(rc_handle *rh)
Definition config.c:1179
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:618
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:765
int rc_test_config(rc_handle *rh, char const *filename)
Definition config.c:835
void rc_dict_free(rc_handle *rh)
Definition dict.c:653
rc_handle * rc_config_init(rc_handle *rh)
Definition config.c:362
void rc_config_free(rc_handle *rh)
Definition config.c:1114
int rc_find_server_addr(rc_handle const *rh, char const *server_name, struct addrinfo **info, char *secret, rc_type type)
Definition config.c:964
SERVER * rc_conf_srv(rc_handle const *rh, char const *optname)
Definition config.c:815
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:519
@ 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