Radcli library 1.5.3
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
36static int rc_conf_int_2(rc_handle const *rh, char const *optname, int complain);
38
39/* Find an option in the option list
40 *
41 * @param rh a handle to parsed configuration.
42 * @param optname the name of the option.
43 * @param type the option type.
44 * @return pointer to option on success, NULL otherwise.
45 */
47static OPTION *find_option(rc_handle const *rh, char const *optname, unsigned int type)
48{
49 int i;
50
51 /* there're so few options that a binary search seems not necessary */
52 for (i = 0; i < NUM_OPTIONS; i++) {
53 if (!strcmp(rh->config_options[i].name, optname) &&
54 (rh->config_options[i].type & type))
55 {
56 return &rh->config_options[i];
57 }
58 }
59
60 return NULL;
61}
63
64/* Set a specific option doing type conversions
65 *
66 * @param filename the name of the config file (for logging purposes).
67 * @param line the line number in the file.
68 * @param option option to set.
69 * @param p Value.
70 * @return 0 on success, -1 on failure.
71 */
73static int set_option_str(char const *filename, int line, OPTION *option, char const *p)
74{
75 if (p) {
76 option->val = (void *) strdup(p);
77 if (option->val == NULL) {
78 rc_log(LOG_CRIT, "read_config: out of memory");
79 return -1;
80 }
81 } else {
82 option->val = NULL;
83 }
84
85 return 0;
86}
88
90static int set_option_int(char const *filename, int line, OPTION *option, char const *p)
91{
92 int *iptr;
93
94 if (p == NULL) {
95 rc_log(LOG_ERR, "%s: line %d: bogus option value", filename, line);
96 return -1;
97 }
98
99 if ((iptr = malloc(sizeof(*iptr))) == NULL) {
100 rc_log(LOG_CRIT, "read_config: out of memory");
101 return -1;
102 }
103
104 *iptr = atoi(p);
105 option->val = (void *) iptr;
106
107 return 0;
108}
110
111/* Frees serv->name[i]/secret[i] for i in [from, to), nulling each pointer
112 * afterwards. Shared by set_option_srv()'s parse-failure cleanup and
113 * rc_config_free(), which both need to release the same per-entry
114 * allocations. */
115static void server_free_entries(SERVER *serv, unsigned from, unsigned to)
116{
117 unsigned i;
118
119 for (i = from; i < to; i++) {
120 free(serv->name[i]);
121 free(serv->secret[i]);
122 serv->name[i] = NULL;
123 serv->secret[i] = NULL;
124 }
125}
126
128static int set_option_srv(char const *filename, int line, OPTION *option, char const *p)
129{
130 SERVER *serv;
131 char *p_pointer;
132 char *p_dupe;
133 char *p_save;
134 char *q;
135 char *s;
136 struct servent *svp;
137 unsigned start_max;
138
139 p_dupe = strdup(p);
140
141 if (p_dupe == NULL) {
142 rc_log(LOG_ERR, "%s: line %d: Invalid option or memory failure", filename, line);
143 return -1;
144 }
145
146 serv = (SERVER *) option->val;
147 if (serv == NULL) {
148 serv = calloc(1, sizeof(*serv));
149 if (serv == NULL) {
150 rc_log(LOG_CRIT, "read_config: out of memory");
151 free(p_dupe);
152 return -1;
153 }
154 serv->max = 0;
155 }
156 start_max = serv->max;
157
158 p_pointer = strtok_r(p_dupe, ", \t", &p_save);
159
160 while(p_pointer != NULL) {
161 if (serv->max >= RC_SERVER_MAX) {
162 DEBUG(LOG_ERR, "cannot set more than %d servers", RC_SERVER_MAX);
163 goto fail;
164 }
165
166 DEBUG(LOG_ERR, "processing server: %s", p_pointer);
167 /* check to see for '[IPv6]:port' syntax */
168 if ((q = strchr(p_pointer,'[')) != NULL) {
169 *q = '\0';
170 q++;
171 p_pointer = q;
172
173 q = strchr(p_pointer, ']');
174 if (q == NULL) {
175 rc_log(LOG_CRIT, "read_config: IPv6 parse error");
176 goto fail;
177 }
178 *q = '\0';
179 q++;
180
181 if (q[0] == ':') {
182 q++;
183 }
184
185 /* Check to see if we have '[IPv6]:port:secret' syntax */
186 if((s=strchr(q, ':')) != NULL) {
187 *s = '\0';
188 s++;
189 serv->secret[serv->max] = strdup(s);
190 if (serv->secret[serv->max] == NULL) {
191 rc_log(LOG_CRIT, "read_config: out of memory");
192 goto fail;
193 }
194 }
195
196 } else /* Check to see if we have 'servername:port' syntax */
197 if ((q = strchr(p_pointer,':')) != NULL) {
198 *q = '\0';
199 q++;
200
201 /* Check to see if we have 'servername:port:secret' syntax */
202 if((s = strchr(q,':')) != NULL) {
203 *s = '\0';
204 s++;
205 serv->secret[serv->max] = strdup(s);
206 if (serv->secret[serv->max] == NULL) {
207 rc_log(LOG_CRIT, "read_config: out of memory");
208 goto fail;
209 }
210 }
211 }
212
213 if(q && strlen(q) > 0) {
214 serv->port[serv->max] = atoi(q);
215 } else {
216 if (!strcmp(option->name,"authserver"))
217 if ((svp = getservbyname ("radius", "udp")) == NULL)
218 serv->port[serv->max] = PW_AUTH_UDP_PORT;
219 else
220 serv->port[serv->max] = ntohs ((unsigned int) svp->s_port);
221 else if (!strcmp(option->name, "acctserver"))
222 if ((svp = getservbyname ("radacct", "udp")) == NULL)
223 serv->port[serv->max] = PW_ACCT_UDP_PORT;
224 else
225 serv->port[serv->max] = ntohs ((unsigned int) svp->s_port);
226 else {
227 rc_log(LOG_ERR, "%s: line %d: no default port for %s", filename, line, option->name);
228 goto fail;
229 }
230 }
231
232 serv->name[serv->max] = strdup(p_pointer);
233 if (serv->name[serv->max] == NULL) {
234 rc_log(LOG_CRIT, "read_config: out of memory");
235 goto fail;
236 }
237
238 serv->max++;
239 p_pointer = strtok_r(NULL, ", \t", &p_save);
240 }
241
242 free(p_dupe);
243 if (option->val == NULL)
244 option->val = (void *)serv;
245
246 return 0;
247 fail:
248 free(p_dupe);
249 /* Release whatever this call already committed (start_max..max),
250 * plus the in-progress entry's secret if it was parsed before the
251 * failure (name[] is only ever set last, right before max++, so
252 * it never needs freeing here). Without this, a config line that
253 * fails partway through (e.g. more than RC_SERVER_MAX servers)
254 * leaks every entry already parsed. */
255 server_free_entries(serv, start_max, serv->max);
256 serv->max = start_max;
257 if (serv->max < RC_SERVER_MAX) {
258 free(serv->secret[serv->max]);
259 serv->secret[serv->max] = NULL;
260 }
261 if (option->val == NULL)
262 free(serv);
263 return -1;
264
265}
267
269static int set_option_auo(char const *filename, int line, OPTION *option, char const *p)
270{
271 int *iptr;
272 char *p_dupe = NULL;
273 char *p_pointer = NULL;
274 char *p_save = NULL;
275
276 p_dupe = strdup(p);
277
278 if (p_dupe == NULL) {
279 rc_log(LOG_WARNING, "%s: line %d: bogus option value", filename, line);
280 return -1;
281 }
282
283 if ((iptr = malloc(sizeof(*iptr))) == NULL) {
284 rc_log(LOG_CRIT, "read_config: out of memory");
285 free(p_dupe);
286 return -1;
287 }
288
289 *iptr = 0;
290 p_pointer = strtok_r(p_dupe, ", \t", &p_save);
291
292 if (!strncmp(p_pointer, "local", 5))
293 *iptr = AUTH_LOCAL_FST;
294 else if (!strncmp(p_pointer, "radius", 6))
295 *iptr = AUTH_RADIUS_FST;
296 else {
297 rc_log(LOG_ERR,"%s: auth_order: unknown keyword: %s", filename, p);
298 free(iptr);
299 free(p_dupe);
300 return -1;
301 }
302
303 p_pointer = strtok_r(NULL, ", \t", &p_save);
304
305 if (p_pointer && (*p_pointer != '\0')) {
306 if ((*iptr & AUTH_RADIUS_FST) && !strcmp(p_pointer, "local"))
307 *iptr = (*iptr) | AUTH_LOCAL_SND;
308 else if ((*iptr & AUTH_LOCAL_FST) && !strcmp(p_pointer, "radius"))
309 *iptr = (*iptr) | AUTH_RADIUS_SND;
310 else {
311 rc_log(LOG_ERR,"%s: auth_order: unknown or unexpected keyword: %s", filename, p);
312 free(iptr);
313 free(p_dupe);
314 return -1;
315 }
316 }
317
318 option->val = (void *) iptr;
319
320 free(p_dupe);
321 return 0;
322}
324
337int rc_add_config(rc_handle *rh, char const *option_name, char const *option_val, char const *source, int line)
338{
339 OPTION *option;
340
341 if ((option = find_option(rh, option_name, OT_ANY)) == NULL)
342 {
343 rc_log(LOG_ERR, "ERROR: unrecognized option: %s", option_name);
344 return -1;
345 }
346
347 if (option->status != ST_UNDEF)
348 {
349 rc_log(LOG_ERR, "ERROR: duplicate option: %s", option_name);
350 return -1;
351 }
352
353 switch (option->type) {
354 case OT_STR:
355 if (set_option_str(source, line, option, option_val) < 0) {
356 return -1;
357 }
358 break;
359 case OT_INT:
360 if (set_option_int(source, line, option, option_val) < 0) {
361 return -1;
362 }
363 break;
364 case OT_SRV:
365 if (set_option_srv(source, line, option, option_val) < 0) {
366 return -1;
367 }
368 break;
369 case OT_AUO:
370 if (set_option_auo(source, line, option, option_val) < 0) {
371 return -1;
372 }
373 break;
374 default:
375 rc_log(LOG_CRIT, "rc_add_config: impossible case branch!");
376 abort();
377 }
378
379 return 0;
380}
381
404rc_handle *rc_config_init(rc_handle *rh)
405{
406 SERVER *authservers = NULL;
407 SERVER *acctservers;
408 OPTION *acct;
409 OPTION *auth;
410
411 rh->config_options = malloc(sizeof(config_options_default));
412 if (rh->config_options == NULL)
413 {
414 rc_log(LOG_CRIT, "rc_config_init: out of memory");
415 rc_destroy(rh);
416 return NULL;
417 }
418 memcpy(rh->config_options, &config_options_default, sizeof(config_options_default));
419
420 auth = find_option(rh, "authserver", OT_ANY);
421 if (auth) {
422 authservers = calloc(1, sizeof(SERVER));
423 if(authservers == NULL) {
424 rc_log(LOG_CRIT, "rc_config_init: error initializing server structs");
425 rc_destroy(rh);
426 return NULL;
427 }
428 auth->val = authservers;
429 }
430
431 acct = find_option(rh, "acctserver", OT_ANY);
432 if (acct) {
433 acctservers = calloc(1, sizeof(SERVER));
434 if(acctservers == NULL) {
435 rc_log(LOG_CRIT, "rc_config_init: error initializing server structs");
436 rc_destroy(rh);
437 if(authservers) free(authservers);
438 return NULL;
439 }
440 acct->val = acctservers;
441 }
442
443 return rh;
444}
445
447static ssize_t plain_sendto(void *ptr, int sockfd,
448 const void *buf, size_t len, int flags,
449 const struct sockaddr *dest_addr, socklen_t addrlen)
450{
451 return sendto(sockfd, buf, len, flags, dest_addr, addrlen);
452}
454
456static ssize_t plain_tcp_sendto(void *ptr, int sockfd,
457 const void *buf, size_t len, int flags,
458 const struct sockaddr *dest_addr, socklen_t addrlen)
459{
460 if((connect(sockfd, dest_addr, addrlen)) != 0){
461 rc_log(LOG_ERR, "%s: Connect Call Failed : %s", __FUNCTION__, strerror(errno));
462 return -1;
463 }
464 return sendto(sockfd, buf, len, flags, dest_addr, addrlen);
465}
467
469static ssize_t plain_recvfrom(void *ptr, int sockfd,
470 void *buf, size_t len, int flags,
471 struct sockaddr *src_addr, socklen_t * addrlen)
472{
473 return recvfrom(sockfd, buf, len, flags, src_addr, addrlen);
474}
476
478static void plain_close_fd(int fd)
479{
480 close(fd);
481}
483
485static int plain_get_fd(void *ptr, struct sockaddr *our_sockaddr)
486{
487 int sockfd;
488
489 sockfd = socket(our_sockaddr->sa_family, SOCK_DGRAM, 0);
490 if (sockfd < 0) {
491 return -1;
492 }
493
494 if (our_sockaddr->sa_family == AF_INET)
495 ((struct sockaddr_in *)our_sockaddr)->sin_port = 0;
496 else
497 ((struct sockaddr_in6 *)our_sockaddr)->sin6_port = 0;
498
499 if (bind(sockfd, SA(our_sockaddr), SA_LEN(our_sockaddr)) < 0) {
500 close(sockfd);
501 return -1;
502 }
503 return sockfd;
504}
506
508static int plain_tcp_get_fd(void *ptr, struct sockaddr *our_sockaddr)
509{
510 int sockfd;
511
512 sockfd = socket(our_sockaddr->sa_family, SOCK_STREAM, 0);
513 if (sockfd < 0) {
514 return -1;
515 }
516
517 if (our_sockaddr->sa_family == AF_INET)
518 ((struct sockaddr_in *)our_sockaddr)->sin_port = 0;
519 else
520 ((struct sockaddr_in6 *)our_sockaddr)->sin6_port = 0;
521
522 if (bind(sockfd, SA(our_sockaddr), SA_LEN(our_sockaddr)) < 0) {
523 close(sockfd);
524 return -1;
525 }
526 return sockfd;
527}
529
530static const rc_sockets_override default_socket_funcs = {
531 .get_fd = plain_get_fd,
532 .close_fd = plain_close_fd,
533 .sendto = plain_sendto,
534 .recvfrom = plain_recvfrom
535};
536
537static const rc_sockets_override default_tcp_socket_funcs = {
538 .get_fd = plain_tcp_get_fd,
539 .close_fd = plain_close_fd,
540 .sendto = plain_tcp_sendto,
541 .recvfrom = plain_recvfrom
542};
543
545static int set_addr(struct sockaddr_storage *ss, const char *ip)
546{
547 memset(ss, 0, sizeof(*ss));
548 if (inet_pton(AF_INET, ip, &((struct sockaddr_in *)ss)->sin_addr) == 1) {
549 ss->ss_family = AF_INET;
550 } else if (inet_pton(AF_INET6, ip, &((struct sockaddr_in6 *)ss)->sin6_addr) == 1) {
551 ss->ss_family = AF_INET6;
552 } else {
553 rc_log(LOG_CRIT, "invalid IP address for nas-ip: %s", ip);
554 return -1;
555 }
556 return 0;
557}
559
575int rc_apply_config(rc_handle *rh)
576{
577 const char *txt;
578 int ret;
579
580 memset(&rh->own_bind_addr, 0, sizeof(rh->own_bind_addr));
581 rh->own_bind_addr_set = 0;
582 rc_own_bind_addr(rh, &rh->own_bind_addr);
583 rh->own_bind_addr_set = 1;
584
585 txt = rc_conf_str(rh, "nas-ip");
586 if (txt != NULL) {
587 if (set_addr(&rh->nas_addr, txt) < 0)
588 return -1;
589 rh->nas_addr_set = 1;
590 }
591
592 txt = rc_conf_str(rh, "serv-type");
593 if (txt == NULL)
594 txt = rc_conf_str(rh, "serv-auth-type");
595
596 if (txt == NULL)
597 txt = "udp";
598
599 if (strcasecmp(txt, "udp") == 0) {
600 memset(&rh->so, 0, sizeof(rh->so));
601 rh->so_type = RC_SOCKET_UDP;
602 memcpy(&rh->so, &default_socket_funcs, sizeof(rh->so));
603 ret = 0;
604 } else if (strcasecmp(txt, "tcp") == 0) {
605 memset(&rh->so, 0, sizeof(rh->so));
606 rh->so_type = RC_SOCKET_TCP;
607 memcpy(&rh->so, &default_tcp_socket_funcs, sizeof(rh->so));
608 ret = 0;
609#ifdef HAVE_GNUTLS
610 } else if (strcasecmp(txt, "dtls") == 0) {
611 ret = rc_init_tls(rh, SEC_FLAG_DTLS);
612 } else if (strcasecmp(txt, "tls") == 0) {
613 ret = rc_init_tls(rh, 0);
614#endif
615 } else {
616 rc_log(LOG_CRIT, "unknown server type: %s", txt);
617 return -1;
618 }
619
620 if (ret < 0) {
621 rc_log(LOG_CRIT, "error initializing %s", txt);
622 return -1;
623 }
624
625 return 0;
626
627}
628
676rc_handle *rc_read_config(char const *filename)
677{
678 FILE *configfd;
679 char *buffer = NULL, *p;
680 size_t bufsize = 0;
681 ssize_t nread;
682 OPTION *option;
683 int line;
684 size_t pos;
685 rc_handle *rh;
686
687
688 rh = rc_new();
689 if (rh == NULL)
690 return NULL;
691
692 rh->config_options = malloc(sizeof(config_options_default));
693 if (rh->config_options == NULL) {
694 rc_log(LOG_CRIT, "rc_read_config: out of memory");
695 rc_destroy(rh);
696 return NULL;
697 }
698 memcpy(rh->config_options, &config_options_default, sizeof(config_options_default));
699
700 if ((configfd = fopen(filename,"r")) == NULL)
701 {
702 rc_log(LOG_ERR,"rc_read_config: can't open %s: %s", filename, strerror(errno));
703 rc_destroy(rh);
704 return NULL;
705 }
706
707 line = 0;
708 while ((nread = getline(&buffer, &bufsize, configfd)) != -1)
709 {
710 line++;
711
712 if (nread > 0 && buffer[nread-1] == '\n')
713 buffer[--nread] = '\0';
714
715 p = buffer;
716
717 if ((*p == '#') || (*p == '\0'))
718 continue;
719
720 if ((pos = strcspn(p, "\t ")) == 0) {
721 rc_log(LOG_ERR, "%s: line %d: bogus format: %s", filename, line, p);
722 goto error;
723 }
724
725 p[pos] = '\0';
726
727 if ((option = find_option(rh, p, OT_ANY)) == NULL) {
728 rc_log(LOG_ERR, "%s: line %d: unrecognized keyword: %s", filename, line, p);
729 goto error;
730 }
731
732 if (option->status != ST_UNDEF) {
733 rc_log(LOG_ERR, "%s: line %d: duplicate option line: %s", filename, line, p);
734 goto error;
735 }
736
737 p += pos+1;
738 while (isspace(*p))
739 p++;
740 if (*p != '\0') {
741 pos = strlen(p) - 1;
742 while (pos != 0 && isspace(p[pos]))
743 pos--;
744 p[pos + 1] = '\0';
745 }
746
747 switch (option->type) {
748 case OT_STR:
749 if (set_option_str(filename, line, option, p) < 0)
750 goto error;
751 break;
752 case OT_INT:
753 if (set_option_int(filename, line, option, p) < 0)
754 goto error;
755 break;
756 case OT_SRV:
757 if (set_option_srv(filename, line, option, p) < 0)
758 goto error;
759 break;
760 case OT_AUO:
761 if (set_option_auo(filename, line, option, p) < 0)
762 goto error;
763 break;
764 default:
765 rc_log(LOG_CRIT, "rc_read_config: impossible case branch!");
766 abort();
767 }
768 }
769 free(buffer);
770 fclose(configfd);
771
772 if (rc_test_config(rh, filename) == -1) {
773 rc_destroy(rh);
774 return NULL;
775 }
776
777 {
778 int clientdebug = rc_conf_int_2(rh, "clientdebug", FALSE);
779 if(clientdebug > 0) {
780 radcli_debug = clientdebug;
781 }
782 }
783
784 /* Always load the built-in RFC 2865/2866/2869 dictionary first so that
785 * applications need not ship a dictionary file for standard attributes. */
786 if (rc_read_dictionary_from_buffer(rh, rc_rfc_dictionary,
787 sizeof(rc_rfc_dictionary) - 1) != 0) {
788 rc_log(LOG_CRIT, "rc_read_config: failed to load built-in RFC dictionary");
789 rc_destroy(rh);
790 return NULL;
791 }
792
793 p = rc_conf_str(rh, "dictionary");
794 if (p != NULL) {
795 if (rc_read_dictionary(rh, p) != 0) {
796 rc_log(LOG_CRIT, "could not load dictionary");
797 rc_destroy(rh);
798 return NULL;
799 }
800 }
801
802 return rh;
803
804error:
805 free(buffer);
806 fclose(configfd);
807 rc_destroy(rh);
808 return NULL;
809}
810
817char *rc_conf_str(rc_handle const *rh, char const *optname)
818{
819 OPTION *option;
820
821 option = find_option(rh, optname, OT_STR);
822
823 if (option != NULL) {
824 return (char *)option->val;
825 } else {
826 rc_log(LOG_CRIT, "rc_conf_str: unknown config option requested: %s", optname);
827 return NULL;
828 }
829}
830
831/*- Get the value of a config option
832 *
833 * @param rh a handle to parsed configuration.
834 * @param optname the name of an option.
835 * @return config option value.
836 */
838static int rc_conf_int_2(rc_handle const *rh, char const *optname, int complain)
839{
840 OPTION *option;
841
842 option = find_option(rh, optname, OT_INT|OT_AUO);
843
844 if (option != NULL) {
845 if (option->val) {
846 return *((int *)option->val);
847 } else if(complain) {
848 rc_log(LOG_ERR, "rc_conf_int: config option %s was not set", optname);
849 }
850 return 0;
851 } else {
852 rc_log(LOG_CRIT, "rc_conf_int: unknown config option requested: %s", optname);
853 return 0;
854 }
855}
857
864int rc_conf_int(rc_handle const *rh, char const *optname)
865{
866 return rc_conf_int_2(rh, optname, TRUE);
867}
868
875SERVER *rc_conf_srv(rc_handle const *rh, char const *optname)
876{
877 OPTION *option;
878
879 option = find_option(rh, optname, OT_SRV);
880
881 if (option != NULL) {
882 return (SERVER *)option->val;
883 } else {
884 rc_log(LOG_CRIT, "rc_conf_srv: unknown config option requested: %s", optname);
885 return NULL;
886 }
887}
888
895int rc_test_config(rc_handle *rh, char const *filename)
896{
897 SERVER *srv;
898
899 srv = rc_conf_srv(rh, "authserver");
900 if (!srv || !srv->max)
901 {
902 rc_log(LOG_ERR,"%s: no authserver specified", filename);
903 return -1;
904 }
905
906 srv = rc_conf_srv(rh, "acctserver");
907 if (!srv || !srv->max)
908 {
909 /* it is allowed not to have acct servers under TLS/DTLS. rh->so_type
910 * isn't set until rc_apply_config() below, so check the configured
911 * serv-type string directly rather than the not-yet-initialized
912 * transport state. */
913 const char *stype = rc_conf_str(rh, "serv-type");
914 if (stype == NULL)
915 stype = rc_conf_str(rh, "serv-auth-type");
916 if (stype == NULL ||
917 (strcasecmp(stype, "tls") != 0 && strcasecmp(stype, "dtls") != 0))
918 rc_log(LOG_DEBUG,"%s: no acctserver specified", filename);
919 }
920
921 if (rc_conf_int(rh, "radius_timeout") <= 0)
922 {
923 rc_log(LOG_ERR,"%s: radius_timeout <= 0 is illegal", filename);
924 return -1;
925 }
926 if (rc_conf_int(rh, "radius_retries") <= 0)
927 {
928 rc_log(LOG_ERR,"%s: radius_retries <= 0 is illegal", filename);
929 return -1;
930 }
931
932 if (rc_apply_config(rh) == -1) {
933 return -1;
934 }
935
936 return 0;
937}
938
939/* See if info matches hostname
940 *
941 * @param addr a struct addrinfo
942 * @param hostname the name of the host.
943 * @return 0 on success, -1 when failure.
944 */
946static int find_match (const struct addrinfo* addr, const struct addrinfo *hostname)
947{
948 const struct addrinfo *ptr, *ptr2;
949 unsigned len1, len2;
950
951 ptr = addr;
952 while(ptr) {
953 ptr2 = hostname;
954 while(ptr2) {
955 len1 = SA_GET_INLEN(ptr->ai_addr);
956 len2 = SA_GET_INLEN(ptr2->ai_addr);
957
958 if (len1 > 0 &&
959 len1 == len2 &&
960 memcmp(SA_GET_INADDR(ptr->ai_addr), SA_GET_INADDR(ptr2->ai_addr), len1) == 0) {
961 return 0;
962 }
963 ptr2 = ptr2->ai_next;
964 }
965 ptr = ptr->ai_next;
966 }
967 return -1;
968}
970
971/* Checks if provided address is local address
972 *
973 * @param addr an %AF_INET or %AF_INET6 address
974 * @return 0 if local, 1 if not local, -1 on failure.
975 */
977static int rc_ipaddr_local(const struct sockaddr *addr)
978{
979 int temp_sock, res, serrno;
980 struct sockaddr_storage tmpaddr;
981
982 memcpy(&tmpaddr, addr, SA_LEN(addr));
983
984 temp_sock = socket(addr->sa_family, SOCK_DGRAM, 0);
985 if (temp_sock == -1)
986 return -1;
987
988 if (addr->sa_family == AF_INET) {
989 ((struct sockaddr_in*)&tmpaddr)->sin_port = 0;
990 } else {
991 ((struct sockaddr_in6*)&tmpaddr)->sin6_port = 0;
992 }
993 res = bind(temp_sock, SA(&tmpaddr), SS_LEN(&tmpaddr));
994 serrno = errno;
995 close(temp_sock);
996 if (res == 0)
997 return 0;
998 if (serrno == EADDRNOTAVAIL)
999 return 1;
1000 return -1;
1001}
1003
1004/* Checks if provided name refers to ourselves
1005 *
1006 * @param info an addrinfo of the host to check
1007 * @return 0 if yes, 1 if no and -1 on failure.
1008 */
1010static int rc_is_myname(const struct addrinfo *info)
1011{
1012 const struct addrinfo *p;
1013 int res;
1014
1015 p = info;
1016 while(p != NULL) {
1017 res = rc_ipaddr_local(p->ai_addr);
1018 if (res == 0 || res == -1) {
1019 return res;
1020 }
1021 p = p->ai_next;
1022 }
1023 return 1;
1024}
1026
1037int rc_find_server_addr (rc_handle const *rh, char const *server_name,
1038 struct addrinfo** info, char *secret, rc_type type)
1039{
1040 int result = 0;
1041 FILE *clientfd;
1042 char *h;
1043 char *s;
1044 char *buffer = NULL;
1045 size_t bufsize = 0;
1046 char hostnm[AUTH_ID_LEN + 1];
1047 char *buffer_save;
1048 char *hostnm_save;
1049 SERVER *servers;
1050 struct addrinfo *tmpinfo = NULL;
1051 const char *fservers;
1052 char const *optname;
1053
1054 /* Lookup the IP address of the radius server */
1055 if ((*info = rc_getaddrinfo (server_name, type==AUTH?PW_AI_AUTH:PW_AI_ACCT)) == NULL)
1056 return -1;
1057
1058 switch (type)
1059 {
1060 case AUTH: optname = "authserver"; break;
1061 case ACCT: optname = "acctserver"; break;
1062 default: optname = NULL;
1063 }
1064
1065 if ( (optname != NULL) &&
1066 ((servers = rc_conf_srv(rh, optname)) != NULL) )
1067 {
1068 /* Check to see if the server secret is defined in the rh config */
1069 unsigned servernum;
1070 for (servernum = 0; servernum < servers->max; servernum++)
1071 {
1072 if( (strcmp(server_name, servers->name[servernum]) == 0) &&
1073 (servers->secret[servernum] != NULL) )
1074 {
1075 memset(secret, '\0', MAX_SECRET_LENGTH);
1076 strlcpy(secret, servers->secret[servernum], MAX_SECRET_LENGTH);
1077 return 0;
1078 }
1079 }
1080 }
1081
1082 /* We didn't find it in the rh_config or the servername is too long so look for a
1083 * servers file to define the secret(s)
1084 */
1085
1086 fservers = rc_conf_str(rh, "servers");
1087 if (fservers != NULL) {
1088 if ((clientfd = fopen (fservers, "r")) == NULL)
1089 {
1090 rc_log(LOG_ERR, "rc_find_server: couldn't open file: %s: %s", strerror(errno), rc_conf_str(rh, "servers"));
1091 goto fail;
1092 }
1093
1094 while (getline (&buffer, &bufsize, clientfd) != -1)
1095 {
1096 if (*buffer == '#')
1097 continue;
1098
1099 if ((h = strtok_r(buffer, " \t\n", &buffer_save)) == NULL) /* first hostname */
1100 continue;
1101
1102 strlcpy (hostnm, h, AUTH_ID_LEN);
1103
1104 if ((s = strtok_r (NULL, " \t\n", &buffer_save)) == NULL) /* and secret field */
1105 continue;
1106
1107 strlcpy (secret, s, MAX_SECRET_LENGTH);
1108
1109 if (!strchr (hostnm, '/')) /* If single name form */
1110 {
1111 tmpinfo = rc_getaddrinfo(hostnm, 0);
1112 if (tmpinfo)
1113 {
1114 result = find_match (*info, tmpinfo);
1115 if (result == 0)
1116 {
1117 result++;
1118 break;
1119 }
1120
1121 freeaddrinfo(tmpinfo);
1122 tmpinfo = NULL;
1123 }
1124 }
1125 else /* <name1>/<name2> "paired" form */
1126 {
1127 strtok_r(hostnm, "/", &hostnm_save);
1128 tmpinfo = rc_getaddrinfo(hostnm, 0);
1129 if (tmpinfo)
1130 {
1131 if (rc_is_myname(tmpinfo) == 0)
1132 { /* If we're the 1st name, target is 2nd */
1133 if (find_match (*info, tmpinfo) == 0)
1134 {
1135 result++;
1136 break;
1137 }
1138 }
1139 else /* If we were 2nd name, target is 1st name */
1140 {
1141 if (find_match (*info, tmpinfo) == 0)
1142 {
1143 result++;
1144 break;
1145 }
1146 }
1147 freeaddrinfo(tmpinfo);
1148 tmpinfo = NULL;
1149 }
1150 }
1151 }
1152 fclose (clientfd);
1153 }
1154 if (result == 0)
1155 {
1156 memset (secret, '\0', MAX_SECRET_LENGTH);
1157 rc_log(LOG_ERR, "rc_find_server: couldn't find RADIUS server %s in %s",
1158 server_name, rc_conf_str(rh, "servers"));
1159 goto fail;
1160 }
1161
1162 result = 0;
1163 goto cleanup;
1164
1165 fail:
1166 freeaddrinfo(*info);
1167 result = -1;
1168
1169 cleanup:
1170 if (tmpinfo)
1171 freeaddrinfo(tmpinfo);
1172 free(buffer);
1173
1174 return result;
1175}
1176
1187void rc_config_free(rc_handle *rh)
1188{
1189 int i;
1190 SERVER *serv;
1191
1192 if (rh->config_options == NULL)
1193 return;
1194
1195 for (i = 0; i < NUM_OPTIONS; i++) {
1196 if (rh->config_options[i].val == NULL)
1197 continue;
1198 if (rh->config_options[i].type == OT_SRV) {
1199 serv = (SERVER *)rh->config_options[i].val;
1200 server_free_entries(serv, 0, serv->max);
1201 free(serv);
1202 } else {
1203 free(rh->config_options[i].val);
1204 }
1205 }
1206 free(rh->config_options);
1207 free(rh->first_dict_read);
1208 rh->config_options = NULL;
1209 rh->first_dict_read = NULL;
1210}
1211
1212static int _initialized = 0;
1213
1218rc_handle *rc_new(void)
1219{
1220 rc_handle *rh;
1221
1222 if (_initialized == 0) {
1223#if defined(HAVE_GNUTLS) && GNUTLS_VERSION_NUMBER < 0x030300
1224 int ret;
1225 ret = gnutls_global_init();
1226 if (ret < 0) {
1227 rc_log(LOG_ERR,
1228 "%s: error initializing gnutls: %s",
1229 __func__, gnutls_strerror(ret));
1230 return NULL;
1231 }
1232#endif
1233 srandom((unsigned int)(time(NULL)+getpid()));
1234 }
1235 _initialized++;
1236
1237 rh = calloc(1, sizeof(*rh));
1238 if (rh == NULL) {
1239 rc_log(LOG_CRIT, "rc_new: out of memory");
1240 return NULL;
1241 }
1242 return rh;
1243}
1244
1249void rc_destroy(rc_handle *rh)
1250{
1251 rc_dict_free(rh);
1252#ifdef HAVE_GNUTLS
1253 rc_deinit_tls(rh);
1254#endif
1255 rc_config_free(rh);
1256 free(rh);
1257
1258#if defined(HAVE_GNUTLS) && GNUTLS_VERSION_NUMBER < 0x030300
1259 _initialized--;
1260 if (_initialized == 0) {
1261 gnutls_global_deinit();
1262 }
1263#endif
1264}
1265
1274{
1275 return rh->so_type;
1276}
1277
1279 /*
1280 * Local Variables:
1281 * c-basic-offset:8
1282 * c-style: whitesmith
1283 * End:
1284 */
rc_socket_type rc_get_socket_type(rc_handle *rh)
Returns the type of the socket used.
Definition config.c:1273
rc_handle * rc_new(void)
Initialises new Radius Client handle.
Definition config.c:1218
rc_type
Definition radcli.h:74
void rc_destroy(rc_handle *rh)
Destroys Radius Client handle reclaiming all memory.
Definition config.c:1249
int rc_read_dictionary_from_buffer(rc_handle *rh, char const *buf, size_t size)
Initialize the dictionary from Buffer.
Definition dict.c:579
rc_handle * rc_read_config(char const *filename)
Read the global config file.
Definition config.c:676
int rc_read_dictionary(rc_handle *rh, char const *filename)
Initialize the dictionary.
Definition dict.c:544
int rc_conf_int(rc_handle const *rh, char const *optname)
Get the value of a config option as an integer.
Definition config.c:864
char * rc_conf_str(rc_handle const *rh, char const *optname)
Get the value of a config option.
Definition config.c:817
int rc_test_config(rc_handle *rh, char const *filename)
Tests the configuration the user supplied.
Definition config.c:895
void rc_dict_free(rc_handle *rh)
Frees the allocated dictionary.
Definition dict.c:725
rc_handle * rc_config_init(rc_handle *rh)
Initialise a configuration structure for programmatic configuration.
Definition config.c:404
void rc_config_free(rc_handle *rh)
Frees allocated config values.
Definition config.c:1187
int rc_find_server_addr(rc_handle const *rh, char const *server_name, struct addrinfo **info, char *secret, rc_type type)
Locate a server in the rh config or if not found, check for a servers file.
Definition config.c:1037
SERVER * rc_conf_srv(rc_handle const *rh, char const *optname)
Get the value of a config option.
Definition config.c:875
int rc_add_config(rc_handle *rh, char const *option_name, char const *option_val, char const *source, int line)
Allow a config option to be added to rc_handle from inside a program.
Definition config.c:337
rc_socket_type
Definition radcli.h:105
int rc_apply_config(rc_handle *rh)
Apply configuration and initialise the transport.
Definition config.c:575
@ ACCT
Request for accounting server.
Definition radcli.h:76
@ AUTH
Request for authentication server.
Definition radcli.h:75
@ RC_SOCKET_UDP
Plain UDP socket.
Definition radcli.h:106
@ RC_SOCKET_TCP
Plain TCP socket.
Definition radcli.h:109
Public API of the radcli library.