Radcli library 1.5.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
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
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
579rc_handle *rc_read_config(char const *filename)
580{
581 FILE *configfd;
582 char buffer[512], *p;
583 OPTION *option;
584 int line;
585 size_t pos;
586 rc_handle *rh;
587
588
589 rh = rc_new();
590 if (rh == NULL)
591 return NULL;
592
593 rh->config_options = malloc(sizeof(config_options_default));
594 if (rh->config_options == NULL) {
595 rc_log(LOG_CRIT, "rc_read_config: out of memory");
596 rc_destroy(rh);
597 return NULL;
598 }
599 memcpy(rh->config_options, &config_options_default, sizeof(config_options_default));
600
601 if ((configfd = fopen(filename,"r")) == NULL)
602 {
603 rc_log(LOG_ERR,"rc_read_config: can't open %s: %s", filename, strerror(errno));
604 rc_destroy(rh);
605 return NULL;
606 }
607
608 line = 0;
609 while ((fgets(buffer, sizeof(buffer), configfd) != NULL))
610 {
611 line++;
612 p = buffer;
613
614 if ((*p == '\n') || (*p == '#') || (*p == '\0'))
615 continue;
616
617 p[strlen(p)-1] = '\0';
618
619
620 if ((pos = strcspn(p, "\t ")) == 0) {
621 rc_log(LOG_ERR, "%s: line %d: bogus format: %s", filename, line, p);
622 fclose(configfd);
623 rc_destroy(rh);
624 return NULL;
625 }
626
627 p[pos] = '\0';
628
629 if ((option = find_option(rh, p, OT_ANY)) == NULL) {
630 rc_log(LOG_ERR, "%s: line %d: unrecognized keyword: %s", filename, line, p);
631 fclose(configfd);
632 rc_destroy(rh);
633 return NULL;
634 }
635
636 if (option->status != ST_UNDEF) {
637 rc_log(LOG_ERR, "%s: line %d: duplicate option line: %s", filename, line, p);
638 fclose(configfd);
639 rc_destroy(rh);
640 return NULL;
641 }
642
643 p += pos+1;
644 while (isspace(*p))
645 p++;
646 pos = strlen(p) - 1;
647 while(pos != 0 && isspace(p[pos]))
648 pos--;
649 p[pos + 1] = '\0';
650
651 switch (option->type) {
652 case OT_STR:
653 if (set_option_str(filename, line, option, p) < 0) {
654 fclose(configfd);
655 rc_destroy(rh);
656 return NULL;
657 }
658 break;
659 case OT_INT:
660 if (set_option_int(filename, line, option, p) < 0) {
661 fclose(configfd);
662 rc_destroy(rh);
663 return NULL;
664 }
665 break;
666 case OT_SRV:
667 if (set_option_srv(filename, line, option, p) < 0) {
668 fclose(configfd);
669 rc_destroy(rh);
670 return NULL;
671 }
672 break;
673 case OT_AUO:
674 if (set_option_auo(filename, line, option, p) < 0) {
675 fclose(configfd);
676 rc_destroy(rh);
677 return NULL;
678 }
679 break;
680 default:
681 rc_log(LOG_CRIT, "rc_read_config: impossible case branch!");
682 abort();
683 }
684 }
685 fclose(configfd);
686
687 if (rc_test_config(rh, filename) == -1) {
688 rc_destroy(rh);
689 return NULL;
690 }
691
692 {
693 int clientdebug = rc_conf_int_2(rh, "clientdebug", FALSE);
694 if(clientdebug > 0) {
695 radcli_debug = clientdebug;
696 }
697 }
698
699 p = rc_conf_str(rh, "dictionary");
700 if (p != NULL) {
701 if (rc_read_dictionary(rh, p) != 0) {
702 rc_log(LOG_CRIT, "could not load dictionary");
703 rc_destroy(rh);
704 return NULL;
705 }
706 } else {
707 rc_log(LOG_INFO, "rc_read_config: no dictionary was specified");
708 }
709
710 return rh;
711}
712
719char *rc_conf_str(rc_handle const *rh, char const *optname)
720{
721 OPTION *option;
722
723 option = find_option(rh, optname, OT_STR);
724
725 if (option != NULL) {
726 return (char *)option->val;
727 } else {
728 rc_log(LOG_CRIT, "rc_conf_str: unknown config option requested: %s", optname);
729 return NULL;
730 }
731}
732
733/*- Get the value of a config option
734 *
735 * @param rh a handle to parsed configuration.
736 * @param optname the name of an option.
737 * @return config option value.
738 */
739static int rc_conf_int_2(rc_handle const *rh, char const *optname, int complain)
740{
741 OPTION *option;
742
743 option = find_option(rh, optname, OT_INT|OT_AUO);
744
745 if (option != NULL) {
746 if (option->val) {
747 return *((int *)option->val);
748 } else if(complain) {
749 rc_log(LOG_ERR, "rc_conf_int: config option %s was not set", optname);
750 }
751 return 0;
752 } else {
753 rc_log(LOG_CRIT, "rc_conf_int: unknown config option requested: %s", optname);
754 return 0;
755 }
756}
757
758int rc_conf_int(rc_handle const *rh, char const *optname)
759{
760 return rc_conf_int_2(rh, optname, TRUE);
761}
762
769SERVER *rc_conf_srv(rc_handle const *rh, char const *optname)
770{
771 OPTION *option;
772
773 option = find_option(rh, optname, OT_SRV);
774
775 if (option != NULL) {
776 return (SERVER *)option->val;
777 } else {
778 rc_log(LOG_CRIT, "rc_conf_srv: unknown config option requested: %s", optname);
779 return NULL;
780 }
781}
782
789int rc_test_config(rc_handle *rh, char const *filename)
790{
791 SERVER *srv;
792
793 srv = rc_conf_srv(rh, "authserver");
794 if (!srv || !srv->max)
795 {
796 rc_log(LOG_ERR,"%s: no authserver specified", filename);
797 return -1;
798 }
799
800 srv = rc_conf_srv(rh, "acctserver");
801 if (!srv || !srv->max)
802 {
803 /* it is allowed not to have acct servers */
804 if (rh->so_type != RC_SOCKET_TLS && rh->so_type != RC_SOCKET_DTLS)
805 rc_log(LOG_DEBUG,"%s: no acctserver specified", filename);
806 }
807 if (!rc_conf_str(rh, "dictionary"))
808 {
809 rc_log(LOG_ERR,"%s: no dictionary specified", filename);
810 return -1;
811 }
812
813 if (rc_conf_int(rh, "radius_timeout") <= 0)
814 {
815 rc_log(LOG_ERR,"%s: radius_timeout <= 0 is illegal", filename);
816 return -1;
817 }
818 if (rc_conf_int(rh, "radius_retries") <= 0)
819 {
820 rc_log(LOG_ERR,"%s: radius_retries <= 0 is illegal", filename);
821 return -1;
822 }
823
824 if (rc_apply_config(rh) == -1) {
825 return -1;
826 }
827
828 return 0;
829}
830
837static int find_match (const struct addrinfo* addr, const struct addrinfo *hostname)
838{
839 const struct addrinfo *ptr, *ptr2;
840 unsigned len1, len2;
841
842 ptr = addr;
843 while(ptr) {
844 ptr2 = hostname;
845 while(ptr2) {
846 len1 = SA_GET_INLEN(ptr->ai_addr);
847 len2 = SA_GET_INLEN(ptr2->ai_addr);
848
849 if (len1 > 0 &&
850 len1 == len2 &&
851 memcmp(SA_GET_INADDR(ptr->ai_addr), SA_GET_INADDR(ptr2->ai_addr), len1) == 0) {
852 return 0;
853 }
854 ptr2 = ptr2->ai_next;
855 }
856 ptr = ptr->ai_next;
857 }
858 return -1;
859}
860
866static int rc_ipaddr_local(const struct sockaddr *addr)
867{
868 int temp_sock, res, serrno;
869 struct sockaddr_storage tmpaddr;
870
871 memcpy(&tmpaddr, addr, SA_LEN(addr));
872
873 temp_sock = socket(addr->sa_family, SOCK_DGRAM, 0);
874 if (temp_sock == -1)
875 return -1;
876
877 if (addr->sa_family == AF_INET) {
878 ((struct sockaddr_in*)&tmpaddr)->sin_port = 0;
879 } else {
880 ((struct sockaddr_in6*)&tmpaddr)->sin6_port = 0;
881 }
882 res = bind(temp_sock, SA(&tmpaddr), SS_LEN(&tmpaddr));
883 serrno = errno;
884 close(temp_sock);
885 if (res == 0)
886 return 0;
887 if (serrno == EADDRNOTAVAIL)
888 return 1;
889 return -1;
890}
891
897static int rc_is_myname(const struct addrinfo *info)
898{
899 const struct addrinfo *p;
900 int res;
901
902 p = info;
903 while(p != NULL) {
904 res = rc_ipaddr_local(p->ai_addr);
905 if (res == 0 || res == -1) {
906 return res;
907 }
908 p = p->ai_next;
909 }
910 return 1;
911}
912
923int rc_find_server_addr (rc_handle const *rh, char const *server_name,
924 struct addrinfo** info, char *secret, rc_type type)
925{
926 int result = 0;
927 FILE *clientfd;
928 char *h;
929 char *s;
930 char buffer[128];
931 char hostnm[AUTH_ID_LEN + 1];
932 char *buffer_save;
933 char *hostnm_save;
934 SERVER *servers;
935 struct addrinfo *tmpinfo = NULL;
936 const char *fservers;
937 char const *optname;
938
939 /* Lookup the IP address of the radius server */
940 if ((*info = rc_getaddrinfo (server_name, type==AUTH?PW_AI_AUTH:PW_AI_ACCT)) == NULL)
941 return -1;
942
943 switch (type)
944 {
945 case AUTH: optname = "authserver"; break;
946 case ACCT: optname = "acctserver"; break;
947 default: optname = NULL;
948 }
949
950 if ( (optname != NULL) &&
951 ((servers = rc_conf_srv(rh, optname)) != NULL) )
952 {
953 /* Check to see if the server secret is defined in the rh config */
954 unsigned servernum;
955 size_t server_name_len = strlen(server_name);
956 for (servernum = 0; servernum < servers->max; servernum++)
957 {
958 if( (strncmp(server_name, servers->name[servernum], server_name_len) == 0) &&
959 (servers->secret[servernum] != NULL) )
960 {
961 memset(secret, '\0', MAX_SECRET_LENGTH);
962 strlcpy(secret, servers->secret[servernum], MAX_SECRET_LENGTH);
963 return 0;
964 }
965 }
966 }
967
968 /* We didn't find it in the rh_config or the servername is too long so look for a
969 * servers file to define the secret(s)
970 */
971
972 fservers = rc_conf_str(rh, "servers");
973 if (fservers != NULL) {
974 if ((clientfd = fopen (fservers, "r")) == NULL)
975 {
976 rc_log(LOG_ERR, "rc_find_server: couldn't open file: %s: %s", strerror(errno), rc_conf_str(rh, "servers"));
977 goto fail;
978 }
979
980 while (fgets (buffer, sizeof (buffer), clientfd) != NULL)
981 {
982 if (*buffer == '#')
983 continue;
984
985 if ((h = strtok_r(buffer, " \t\n", &buffer_save)) == NULL) /* first hostname */
986 continue;
987
988 strlcpy (hostnm, h, AUTH_ID_LEN);
989
990 if ((s = strtok_r (NULL, " \t\n", &buffer_save)) == NULL) /* and secret field */
991 continue;
992
993 strlcpy (secret, s, MAX_SECRET_LENGTH);
994
995 if (!strchr (hostnm, '/')) /* If single name form */
996 {
997 tmpinfo = rc_getaddrinfo(hostnm, 0);
998 if (tmpinfo)
999 {
1000 result = find_match (*info, tmpinfo);
1001 if (result == 0)
1002 {
1003 result++;
1004 break;
1005 }
1006
1007 freeaddrinfo(tmpinfo);
1008 tmpinfo = NULL;
1009 }
1010 }
1011 else /* <name1>/<name2> "paired" form */
1012 {
1013 strtok_r(hostnm, "/", &hostnm_save);
1014 tmpinfo = rc_getaddrinfo(hostnm, 0);
1015 if (tmpinfo)
1016 {
1017 if (rc_is_myname(tmpinfo) == 0)
1018 { /* If we're the 1st name, target is 2nd */
1019 if (find_match (*info, tmpinfo) == 0)
1020 {
1021 result++;
1022 break;
1023 }
1024 }
1025 else /* If we were 2nd name, target is 1st name */
1026 {
1027 if (find_match (*info, tmpinfo) == 0)
1028 {
1029 result++;
1030 break;
1031 }
1032 }
1033 freeaddrinfo(tmpinfo);
1034 tmpinfo = NULL;
1035 }
1036 }
1037 }
1038 fclose (clientfd);
1039 }
1040 if (result == 0)
1041 {
1042 memset (buffer, '\0', sizeof (buffer));
1043 memset (secret, '\0', MAX_SECRET_LENGTH);
1044 rc_log(LOG_ERR, "rc_find_server: couldn't find RADIUS server %s in %s",
1045 server_name, rc_conf_str(rh, "servers"));
1046 goto fail;
1047 }
1048
1049 result = 0;
1050 goto cleanup;
1051
1052 fail:
1053 freeaddrinfo(*info);
1054 result = -1;
1055
1056 cleanup:
1057 if (tmpinfo)
1058 freeaddrinfo(tmpinfo);
1059
1060 return result;
1061}
1062
1073void rc_config_free(rc_handle *rh)
1074{
1075 int i, j;
1076 SERVER *serv;
1077
1078 if (rh->config_options == NULL)
1079 return;
1080
1081 for (i = 0; i < NUM_OPTIONS; i++) {
1082 if (rh->config_options[i].val == NULL)
1083 continue;
1084 if (rh->config_options[i].type == OT_SRV) {
1085 serv = (SERVER *)rh->config_options[i].val;
1086 for (j = 0; j < serv->max; j++) {
1087 free(serv->name[j]);
1088 if(serv->secret[j]) free(serv->secret[j]);
1089 }
1090 free(serv);
1091 } else {
1092 free(rh->config_options[i].val);
1093 }
1094 }
1095 free(rh->config_options);
1096 free(rh->first_dict_read);
1097 rh->config_options = NULL;
1098 rh->first_dict_read = NULL;
1099}
1100
1101static int _initialized = 0;
1102
1107rc_handle *rc_new(void)
1108{
1109 rc_handle *rh;
1110
1111 if (_initialized == 0) {
1112#if defined(HAVE_GNUTLS) && GNUTLS_VERSION_NUMBER < 0x030300
1113 int ret;
1114 ret = gnutls_global_init();
1115 if (ret < 0) {
1116 rc_log(LOG_ERR,
1117 "%s: error initializing gnutls: %s",
1118 __func__, gnutls_strerror(ret));
1119 return NULL;
1120 }
1121#endif
1122 srandom((unsigned int)(time(NULL)+getpid()));
1123 }
1124 _initialized++;
1125
1126 rh = calloc(1, sizeof(*rh));
1127 if (rh == NULL) {
1128 rc_log(LOG_CRIT, "rc_new: out of memory");
1129 return NULL;
1130 }
1131 return rh;
1132}
1133
1138void rc_destroy(rc_handle *rh)
1139{
1140 rc_dict_free(rh);
1141#ifdef HAVE_GNUTLS
1142 rc_deinit_tls(rh);
1143#endif
1144 rc_config_free(rh);
1145 free(rh);
1146
1147#if defined(HAVE_GNUTLS) && GNUTLS_VERSION_NUMBER < 0x030300
1148 _initialized--;
1149 if (_initialized == 0) {
1150 gnutls_global_deinit();
1151 }
1152#endif
1153}
1154
1163{
1164 return rh->so_type;
1165}
1166
1168 /*
1169 * Local Variables:
1170 * c-basic-offset:8
1171 * c-style: whitesmith
1172 * End:
1173 */
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:1162
rc_handle * rc_new(void)
Definition config.c:1107
rc_type
Definition radcli.h:69
void rc_destroy(rc_handle *rh)
Definition config.c:1138
rc_handle * rc_read_config(char const *filename)
Definition config.c:579
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:719
int rc_test_config(rc_handle *rh, char const *filename)
Definition config.c:789
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:1073
int rc_find_server_addr(rc_handle const *rh, char const *server_name, struct addrinfo **info, char *secret, rc_type type)
Definition config.c:923
SERVER * rc_conf_srv(rc_handle const *rh, char const *optname)
Definition config.c:769
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