24#include <radcli/radcli.h>
28#include "dict_rfc_gen.h"
35static int rc_conf_int_2(rc_handle
const *rh,
char const *optname,
int complain);
44static OPTION *find_option(rc_handle
const *rh,
char const *optname,
unsigned int type)
49 for (i = 0; i < NUM_OPTIONS; i++) {
50 if (!strcmp(rh->config_options[i].name, optname) &&
51 (rh->config_options[i].type & type))
53 return &rh->config_options[i];
68static int set_option_str(
char const *filename,
int line, OPTION *option,
char const *p)
71 option->val = (
void *) strdup(p);
72 if (option->val == NULL) {
73 rc_log(LOG_CRIT,
"read_config: out of memory");
83static int set_option_int(
char const *filename,
int line, OPTION *option,
char const *p)
88 rc_log(LOG_ERR,
"%s: line %d: bogus option value", filename, line);
92 if ((iptr = malloc(
sizeof(*iptr))) == NULL) {
93 rc_log(LOG_CRIT,
"read_config: out of memory");
98 option->val = (
void *) iptr;
103static int set_option_srv(
char const *filename,
int line, OPTION *option,
char const *p)
115 if (p_dupe == NULL) {
116 rc_log(LOG_ERR,
"%s: line %d: Invalid option or memory failure", filename, line);
120 serv = (SERVER *) option->val;
122 serv = calloc(1,
sizeof(*serv));
124 rc_log(LOG_CRIT,
"read_config: out of memory");
131 p_pointer = strtok_r(p_dupe,
", \t", &p_save);
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);
139 DEBUG(LOG_ERR,
"processing server: %s", p_pointer);
141 if ((q = strchr(p_pointer,
'[')) != NULL) {
146 q = strchr(p_pointer,
']');
148 rc_log(LOG_CRIT,
"read_config: IPv6 parse error");
159 if((s=strchr(q,
':')) != NULL) {
162 serv->secret[serv->max] = strdup(s);
163 if (serv->secret[serv->max] == NULL) {
164 rc_log(LOG_CRIT,
"read_config: out of memory");
170 if ((q = strchr(p_pointer,
':')) != NULL) {
175 if((s = strchr(q,
':')) != NULL) {
178 serv->secret[serv->max] = strdup(s);
179 if (serv->secret[serv->max] == NULL) {
180 rc_log(LOG_CRIT,
"read_config: out of memory");
186 if(q && strlen(q) > 0) {
187 serv->port[serv->max] = atoi(q);
189 if (!strcmp(option->name,
"authserver"))
190 if ((svp = getservbyname (
"radius",
"udp")) == NULL)
191 serv->port[serv->max] = PW_AUTH_UDP_PORT;
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;
198 serv->port[serv->max] = ntohs ((
unsigned int) svp->s_port);
200 rc_log(LOG_ERR,
"%s: line %d: no default port for %s", filename, line, option->name);
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");
212 p_pointer = strtok_r(NULL,
", \t", &p_save);
216 if (option->val == NULL)
217 option->val = (
void *)serv;
222 if (option->val == NULL)
228static int set_option_auo(
char const *filename,
int line, OPTION *option,
char const *p)
232 char *p_pointer = NULL;
237 if (p_dupe == NULL) {
238 rc_log(LOG_WARNING,
"%s: line %d: bogus option value", filename, line);
242 if ((iptr = malloc(
sizeof(*iptr))) == NULL) {
243 rc_log(LOG_CRIT,
"read_config: out of memory");
249 p_pointer = strtok_r(p_dupe,
", \t", &p_save);
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;
256 rc_log(LOG_ERR,
"%s: auth_order: unknown keyword: %s", filename, p);
262 p_pointer = strtok_r(NULL,
", \t", &p_save);
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;
270 rc_log(LOG_ERR,
"%s: auth_order: unknown or unexpected keyword: %s", filename, p);
277 option->val = (
void *) iptr;
295int rc_add_config(rc_handle *rh,
char const *option_name,
char const *option_val,
char const *source,
int line)
299 if ((option = find_option(rh, option_name, OT_ANY)) == NULL)
301 rc_log(LOG_ERR,
"ERROR: unrecognized option: %s", option_name);
305 if (option->status != ST_UNDEF)
307 rc_log(LOG_ERR,
"ERROR: duplicate option: %s", option_name);
311 switch (option->type) {
313 if (set_option_str(source, line, option, option_val) < 0) {
318 if (set_option_int(source, line, option, option_val) < 0) {
323 if (set_option_srv(source, line, option, option_val) < 0) {
328 if (set_option_auo(source, line, option, option_val) < 0) {
333 rc_log(LOG_CRIT,
"rc_add_config: impossible case branch!");
352 SERVER *authservers = NULL;
357 rh->config_options = malloc(
sizeof(config_options_default));
358 if (rh->config_options == NULL)
360 rc_log(LOG_CRIT,
"rc_config_init: out of memory");
364 memcpy(rh->config_options, &config_options_default,
sizeof(config_options_default));
366 auth = find_option(rh,
"authserver", OT_ANY);
368 authservers = calloc(1,
sizeof(SERVER));
369 if(authservers == NULL) {
370 rc_log(LOG_CRIT,
"rc_config_init: error initializing server structs");
374 auth->val = authservers;
377 acct = find_option(rh,
"acctserver", OT_ANY);
379 acctservers = calloc(1,
sizeof(SERVER));
380 if(acctservers == NULL) {
381 rc_log(LOG_CRIT,
"rc_config_init: error initializing server structs");
383 if(authservers) free(authservers);
386 acct->val = acctservers;
392static ssize_t plain_sendto(
void *ptr,
int sockfd,
393 const void *buf,
size_t len,
int flags,
394 const struct sockaddr *dest_addr, socklen_t addrlen)
396 return sendto(sockfd, buf, len, flags, dest_addr, addrlen);
399static ssize_t plain_tcp_sendto(
void *ptr,
int sockfd,
400 const void *buf,
size_t len,
int flags,
401 const struct sockaddr *dest_addr, socklen_t addrlen)
403 if((connect(sockfd, dest_addr, addrlen)) != 0){
404 rc_log(LOG_ERR,
"%s: Connect Call Failed : %s", __FUNCTION__, strerror(errno));
407 return sendto(sockfd, buf, len, flags, dest_addr, addrlen);
410static ssize_t plain_recvfrom(
void *ptr,
int sockfd,
411 void *buf,
size_t len,
int flags,
412 struct sockaddr *src_addr, socklen_t * addrlen)
414 return recvfrom(sockfd, buf, len, flags, src_addr, addrlen);
417static void plain_close_fd(
int fd)
422static int plain_get_fd(
void *ptr,
struct sockaddr *our_sockaddr)
426 sockfd = socket(our_sockaddr->sa_family, SOCK_DGRAM, 0);
431 if (our_sockaddr->sa_family == AF_INET)
432 ((
struct sockaddr_in *)our_sockaddr)->sin_port = 0;
434 ((
struct sockaddr_in6 *)our_sockaddr)->sin6_port = 0;
436 if (bind(sockfd, SA(our_sockaddr), SA_LEN(our_sockaddr)) < 0) {
443static int plain_tcp_get_fd(
void *ptr,
struct sockaddr *our_sockaddr)
447 sockfd = socket(our_sockaddr->sa_family, SOCK_STREAM, 0);
452 if (our_sockaddr->sa_family == AF_INET)
453 ((
struct sockaddr_in *)our_sockaddr)->sin_port = 0;
455 ((
struct sockaddr_in6 *)our_sockaddr)->sin6_port = 0;
457 if (bind(sockfd, SA(our_sockaddr), SA_LEN(our_sockaddr)) < 0) {
464static const rc_sockets_override default_socket_funcs = {
465 .get_fd = plain_get_fd,
466 .close_fd = plain_close_fd,
467 .sendto = plain_sendto,
468 .recvfrom = plain_recvfrom
471static const rc_sockets_override default_tcp_socket_funcs = {
472 .get_fd = plain_tcp_get_fd,
473 .close_fd = plain_close_fd,
474 .sendto = plain_tcp_sendto,
475 .recvfrom = plain_recvfrom
478static int set_addr(
struct sockaddr_storage *ss,
const char *ip)
480 memset(ss, 0,
sizeof(*ss));
481 if (inet_pton(AF_INET, ip, &((
struct sockaddr_in *)ss)->sin_addr) == 1) {
482 ss->ss_family = AF_INET;
483 }
else if (inet_pton(AF_INET6, ip, &((
struct sockaddr_in6 *)ss)->sin6_addr) == 1) {
484 ss->ss_family = AF_INET6;
486 rc_log(LOG_CRIT,
"invalid IP address for nas-ip: %s", ip);
506 memset(&rh->own_bind_addr, 0,
sizeof(rh->own_bind_addr));
507 rh->own_bind_addr_set = 0;
509 rh->own_bind_addr_set = 1;
513 if (set_addr(&rh->nas_addr, txt) < 0)
515 rh->nas_addr_set = 1;
525 if (strcasecmp(txt,
"udp") == 0) {
526 memset(&rh->so, 0,
sizeof(rh->so));
528 memcpy(&rh->so, &default_socket_funcs,
sizeof(rh->so));
530 }
else if (strcasecmp(txt,
"tcp") == 0) {
531 memset(&rh->so, 0,
sizeof(rh->so));
533 memcpy(&rh->so, &default_tcp_socket_funcs,
sizeof(rh->so));
536 }
else if (strcasecmp(txt,
"dtls") == 0) {
537 ret = rc_init_tls(rh, SEC_FLAG_DTLS);
538 }
else if (strcasecmp(txt,
"tls") == 0) {
539 ret = rc_init_tls(rh, 0);
542 rc_log(LOG_CRIT,
"unknown server type: %s", txt);
547 rc_log(LOG_CRIT,
"error initializing %s", txt);
588 char buffer[512], *p;
599 rh->config_options = malloc(
sizeof(config_options_default));
600 if (rh->config_options == NULL) {
601 rc_log(LOG_CRIT,
"rc_read_config: out of memory");
605 memcpy(rh->config_options, &config_options_default,
sizeof(config_options_default));
607 if ((configfd = fopen(filename,
"r")) == NULL)
609 rc_log(LOG_ERR,
"rc_read_config: can't open %s: %s", filename, strerror(errno));
615 while ((fgets(buffer,
sizeof(buffer), configfd) != NULL))
620 if ((*p ==
'\n') || (*p ==
'#') || (*p ==
'\0'))
623 p[strlen(p)-1] =
'\0';
626 if ((pos = strcspn(p,
"\t ")) == 0) {
627 rc_log(LOG_ERR,
"%s: line %d: bogus format: %s", filename, line, p);
635 if ((option = find_option(rh, p, OT_ANY)) == NULL) {
636 rc_log(LOG_ERR,
"%s: line %d: unrecognized keyword: %s", filename, line, p);
642 if (option->status != ST_UNDEF) {
643 rc_log(LOG_ERR,
"%s: line %d: duplicate option line: %s", filename, line, p);
653 while(pos != 0 && isspace(p[pos]))
657 switch (option->type) {
659 if (set_option_str(filename, line, option, p) < 0) {
666 if (set_option_int(filename, line, option, p) < 0) {
673 if (set_option_srv(filename, line, option, p) < 0) {
680 if (set_option_auo(filename, line, option, p) < 0) {
687 rc_log(LOG_CRIT,
"rc_read_config: impossible case branch!");
699 int clientdebug = rc_conf_int_2(rh,
"clientdebug", FALSE);
700 if(clientdebug > 0) {
701 radcli_debug = clientdebug;
708 sizeof(rc_rfc_dictionary) - 1) != 0) {
709 rc_log(LOG_CRIT,
"rc_read_config: failed to load built-in RFC dictionary");
717 rc_log(LOG_CRIT,
"could not load dictionary");
736 option = find_option(rh, optname, OT_STR);
738 if (option != NULL) {
739 return (
char *)option->val;
741 rc_log(LOG_CRIT,
"rc_conf_str: unknown config option requested: %s", optname);
752static int rc_conf_int_2(rc_handle
const *rh,
char const *optname,
int complain)
756 option = find_option(rh, optname, OT_INT|OT_AUO);
758 if (option != NULL) {
760 return *((
int *)option->val);
761 }
else if(complain) {
762 rc_log(LOG_ERR,
"rc_conf_int: config option %s was not set", optname);
766 rc_log(LOG_CRIT,
"rc_conf_int: unknown config option requested: %s", optname);
771int rc_conf_int(rc_handle
const *rh,
char const *optname)
773 return rc_conf_int_2(rh, optname, TRUE);
786 option = find_option(rh, optname, OT_SRV);
788 if (option != NULL) {
789 return (SERVER *)option->val;
791 rc_log(LOG_CRIT,
"rc_conf_srv: unknown config option requested: %s", optname);
807 if (!srv || !srv->max)
809 rc_log(LOG_ERR,
"%s: no authserver specified", filename);
814 if (!srv || !srv->max)
818 rc_log(LOG_DEBUG,
"%s: no acctserver specified", filename);
821 if (rc_conf_int(rh,
"radius_timeout") <= 0)
823 rc_log(LOG_ERR,
"%s: radius_timeout <= 0 is illegal", filename);
826 if (rc_conf_int(rh,
"radius_retries") <= 0)
828 rc_log(LOG_ERR,
"%s: radius_retries <= 0 is illegal", filename);
845static int find_match (
const struct addrinfo* addr,
const struct addrinfo *hostname)
847 const struct addrinfo *ptr, *ptr2;
854 len1 = SA_GET_INLEN(ptr->ai_addr);
855 len2 = SA_GET_INLEN(ptr2->ai_addr);
859 memcmp(SA_GET_INADDR(ptr->ai_addr), SA_GET_INADDR(ptr2->ai_addr), len1) == 0) {
862 ptr2 = ptr2->ai_next;
874static int rc_ipaddr_local(
const struct sockaddr *addr)
876 int temp_sock, res, serrno;
877 struct sockaddr_storage tmpaddr;
879 memcpy(&tmpaddr, addr, SA_LEN(addr));
881 temp_sock = socket(addr->sa_family, SOCK_DGRAM, 0);
885 if (addr->sa_family == AF_INET) {
886 ((
struct sockaddr_in*)&tmpaddr)->sin_port = 0;
888 ((
struct sockaddr_in6*)&tmpaddr)->sin6_port = 0;
890 res = bind(temp_sock, SA(&tmpaddr), SS_LEN(&tmpaddr));
895 if (serrno == EADDRNOTAVAIL)
905static int rc_is_myname(
const struct addrinfo *info)
907 const struct addrinfo *p;
912 res = rc_ipaddr_local(p->ai_addr);
913 if (res == 0 || res == -1) {
932 struct addrinfo** info,
char *secret,
rc_type type)
939 char hostnm[AUTH_ID_LEN + 1];
943 struct addrinfo *tmpinfo = NULL;
944 const char *fservers;
948 if ((*info = rc_getaddrinfo (server_name, type==
AUTH?PW_AI_AUTH:PW_AI_ACCT)) == NULL)
953 case AUTH: optname =
"authserver";
break;
954 case ACCT: optname =
"acctserver";
break;
955 default: optname = NULL;
958 if ( (optname != NULL) &&
963 size_t server_name_len = strlen(server_name);
964 for (servernum = 0; servernum < servers->max; servernum++)
966 if( (strncmp(server_name, servers->name[servernum], server_name_len) == 0) &&
967 (servers->secret[servernum] != NULL) )
969 memset(secret,
'\0', MAX_SECRET_LENGTH);
970 strlcpy(secret, servers->secret[servernum], MAX_SECRET_LENGTH);
981 if (fservers != NULL) {
982 if ((clientfd = fopen (fservers,
"r")) == NULL)
984 rc_log(LOG_ERR,
"rc_find_server: couldn't open file: %s: %s", strerror(errno),
rc_conf_str(rh,
"servers"));
988 while (fgets (buffer,
sizeof (buffer), clientfd) != NULL)
993 if ((h = strtok_r(buffer,
" \t\n", &buffer_save)) == NULL)
996 strlcpy (hostnm, h, AUTH_ID_LEN);
998 if ((s = strtok_r (NULL,
" \t\n", &buffer_save)) == NULL)
1001 strlcpy (secret, s, MAX_SECRET_LENGTH);
1003 if (!strchr (hostnm,
'/'))
1005 tmpinfo = rc_getaddrinfo(hostnm, 0);
1008 result = find_match (*info, tmpinfo);
1015 freeaddrinfo(tmpinfo);
1021 strtok_r(hostnm,
"/", &hostnm_save);
1022 tmpinfo = rc_getaddrinfo(hostnm, 0);
1025 if (rc_is_myname(tmpinfo) == 0)
1027 if (find_match (*info, tmpinfo) == 0)
1035 if (find_match (*info, tmpinfo) == 0)
1041 freeaddrinfo(tmpinfo);
1050 memset (buffer,
'\0',
sizeof (buffer));
1051 memset (secret,
'\0', MAX_SECRET_LENGTH);
1052 rc_log(LOG_ERR,
"rc_find_server: couldn't find RADIUS server %s in %s",
1061 freeaddrinfo(*info);
1066 freeaddrinfo(tmpinfo);
1086 if (rh->config_options == NULL)
1089 for (i = 0; i < NUM_OPTIONS; i++) {
1090 if (rh->config_options[i].val == NULL)
1092 if (rh->config_options[i].type == OT_SRV) {
1093 serv = (SERVER *)rh->config_options[i].val;
1094 for (j = 0; j < serv->max; j++) {
1095 free(serv->name[j]);
1096 if(serv->secret[j]) free(serv->secret[j]);
1100 free(rh->config_options[i].val);
1103 free(rh->config_options);
1104 free(rh->first_dict_read);
1105 rh->config_options = NULL;
1106 rh->first_dict_read = NULL;
1109static int _initialized = 0;
1119 if (_initialized == 0) {
1120#if defined(HAVE_GNUTLS) && GNUTLS_VERSION_NUMBER < 0x030300
1122 ret = gnutls_global_init();
1125 "%s: error initializing gnutls: %s",
1126 __func__, gnutls_strerror(ret));
1130 srandom((
unsigned int)(time(NULL)+getpid()));
1134 rh = calloc(1,
sizeof(*rh));
1136 rc_log(LOG_CRIT,
"rc_new: out of memory");
1155#if defined(HAVE_GNUTLS) && GNUTLS_VERSION_NUMBER < 0x030300
1157 if (_initialized == 0) {
1158 gnutls_global_deinit();
void rc_own_bind_addr(rc_handle *rh, struct sockaddr_storage *lia)
rc_socket_type rc_get_socket_type(rc_handle *rh)
void rc_destroy(rc_handle *rh)
int rc_read_dictionary_from_buffer(rc_handle *rh, char const *buf, size_t size)
rc_handle * rc_read_config(char const *filename)
int rc_read_dictionary(rc_handle *rh, char const *filename)
char * rc_conf_str(rc_handle const *rh, char const *optname)
int rc_test_config(rc_handle *rh, char const *filename)
void rc_dict_free(rc_handle *rh)
rc_handle * rc_config_init(rc_handle *rh)
void rc_config_free(rc_handle *rh)
int rc_find_server_addr(rc_handle const *rh, char const *server_name, struct addrinfo **info, char *secret, rc_type type)
SERVER * rc_conf_srv(rc_handle const *rh, char const *optname)
int rc_add_config(rc_handle *rh, char const *option_name, char const *option_val, char const *source, int line)
int rc_apply_config(rc_handle *rh)
@ ACCT
Request for accounting server.
@ AUTH
Request for authentication server.
@ RC_SOCKET_UDP
Plain UDP socket.
@ RC_SOCKET_TCP
Plain TCP socket.
@ RC_SOCKET_DTLS
DTLS socket.
@ RC_SOCKET_TLS
TLS socket.