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