24#include <radcli/radcli.h>
34static int rc_conf_int_2(rc_handle
const *rh,
char const *optname,
int complain);
43static OPTION *find_option(rc_handle
const *rh,
char const *optname,
unsigned int type)
48 for (i = 0; i < NUM_OPTIONS; i++) {
49 if (!strcmp(rh->config_options[i].name, optname) &&
50 (rh->config_options[i].type & type))
52 return &rh->config_options[i];
67static int set_option_str(
char const *filename,
int line, OPTION *option,
char const *p)
70 option->val = (
void *) strdup(p);
71 if (option->val == NULL) {
72 rc_log(LOG_CRIT,
"read_config: out of memory");
82static int set_option_int(
char const *filename,
int line, OPTION *option,
char const *p)
87 rc_log(LOG_ERR,
"%s: line %d: bogus option value", filename, line);
91 if ((iptr = malloc(
sizeof(*iptr))) == NULL) {
92 rc_log(LOG_CRIT,
"read_config: out of memory");
97 option->val = (
void *) iptr;
102static int set_option_srv(
char const *filename,
int line, OPTION *option,
char const *p)
114 if (p_dupe == NULL) {
115 rc_log(LOG_ERR,
"%s: line %d: Invalid option or memory failure", filename, line);
119 serv = (
SERVER *) option->val;
121 serv = calloc(1,
sizeof(*serv));
123 rc_log(LOG_CRIT,
"read_config: out of memory");
130 p_pointer = strtok_r(p_dupe,
", \t", &p_save);
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);
138 DEBUG(LOG_ERR,
"processing server: %s", p_pointer);
140 if ((q = strchr(p_pointer,
'[')) != NULL) {
145 q = strchr(p_pointer,
']');
147 rc_log(LOG_CRIT,
"read_config: IPv6 parse error");
158 if((s=strchr(q,
':')) != NULL) {
161 serv->secret[serv->max] = strdup(s);
162 if (serv->secret[serv->max] == NULL) {
163 rc_log(LOG_CRIT,
"read_config: out of memory");
169 if ((q = strchr(p_pointer,
':')) != NULL) {
174 if((s = strchr(q,
':')) != NULL) {
177 serv->secret[serv->max] = strdup(s);
178 if (serv->secret[serv->max] == NULL) {
179 rc_log(LOG_CRIT,
"read_config: out of memory");
185 if(q && strlen(q) > 0) {
186 serv->port[serv->max] = atoi(q);
188 if (!strcmp(option->name,
"authserver"))
189 if ((svp = getservbyname (
"radius",
"udp")) == NULL)
190 serv->port[serv->max] = PW_AUTH_UDP_PORT;
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;
197 serv->port[serv->max] = ntohs ((
unsigned int) svp->s_port);
199 rc_log(LOG_ERR,
"%s: line %d: no default port for %s", filename, line, option->name);
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");
211 p_pointer = strtok_r(NULL,
", \t", &p_save);
215 if (option->val == NULL)
216 option->val = (
void *)serv;
221 if (option->val == NULL)
227static int set_option_auo(
char const *filename,
int line, OPTION *option,
char const *p)
231 char *p_pointer = NULL;
236 if (p_dupe == NULL) {
237 rc_log(LOG_WARNING,
"%s: line %d: bogus option value", filename, line);
241 if ((iptr = malloc(
sizeof(*iptr))) == NULL) {
242 rc_log(LOG_CRIT,
"read_config: out of memory");
248 p_pointer = strtok_r(p_dupe,
", \t", &p_save);
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;
255 rc_log(LOG_ERR,
"%s: auth_order: unknown keyword: %s", filename, p);
261 p_pointer = strtok_r(NULL,
", \t", &p_save);
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;
269 rc_log(LOG_ERR,
"%s: auth_order: unknown or unexpected keyword: %s", filename, p);
276 option->val = (
void *) iptr;
294int rc_add_config(rc_handle *rh,
char const *option_name,
char const *option_val,
char const *source,
int line)
298 if ((option = find_option(rh, option_name, OT_ANY)) == NULL)
300 rc_log(LOG_ERR,
"ERROR: unrecognized option: %s", option_name);
304 if (option->status != ST_UNDEF)
306 rc_log(LOG_ERR,
"ERROR: duplicate option: %s", option_name);
310 switch (option->type) {
312 if (set_option_str(source, line, option, option_val) < 0) {
317 if (set_option_int(source, line, option, option_val) < 0) {
322 if (set_option_srv(source, line, option, option_val) < 0) {
327 if (set_option_auo(source, line, option, option_val) < 0) {
332 rc_log(LOG_CRIT,
"rc_add_config: impossible case branch!");
351 SERVER *authservers = NULL;
356 rh->config_options = malloc(
sizeof(config_options_default));
357 if (rh->config_options == NULL)
359 rc_log(LOG_CRIT,
"rc_config_init: out of memory");
363 memcpy(rh->config_options, &config_options_default,
sizeof(config_options_default));
365 auth = find_option(rh,
"authserver", OT_ANY);
367 authservers = calloc(1,
sizeof(
SERVER));
368 if(authservers == NULL) {
369 rc_log(LOG_CRIT,
"rc_config_init: error initializing server structs");
373 auth->val = authservers;
376 acct = find_option(rh,
"acctserver", OT_ANY);
378 acctservers = calloc(1,
sizeof(
SERVER));
379 if(acctservers == NULL) {
380 rc_log(LOG_CRIT,
"rc_config_init: error initializing server structs");
382 if(authservers) free(authservers);
385 acct->val = acctservers;
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)
395 return sendto(sockfd, buf, len, flags, dest_addr, addrlen);
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)
402 if((connect(sockfd, dest_addr, addrlen)) != 0){
403 rc_log(LOG_ERR,
"%s: Connect Call Failed : %s", __FUNCTION__, strerror(errno));
406 return sendto(sockfd, buf, len, flags, dest_addr, addrlen);
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)
413 return recvfrom(sockfd, buf, len, flags, src_addr, addrlen);
416static void plain_close_fd(
int fd)
421static int plain_get_fd(
void *ptr,
struct sockaddr *our_sockaddr)
425 sockfd = socket(our_sockaddr->sa_family, SOCK_DGRAM, 0);
430 if (our_sockaddr->sa_family == AF_INET)
431 ((
struct sockaddr_in *)our_sockaddr)->sin_port = 0;
433 ((
struct sockaddr_in6 *)our_sockaddr)->sin6_port = 0;
435 if (bind(sockfd, SA(our_sockaddr), SA_LEN(our_sockaddr)) < 0) {
442static int plain_tcp_get_fd(
void *ptr,
struct sockaddr *our_sockaddr)
446 sockfd = socket(our_sockaddr->sa_family, SOCK_STREAM, 0);
451 if (our_sockaddr->sa_family == AF_INET)
452 ((
struct sockaddr_in *)our_sockaddr)->sin_port = 0;
454 ((
struct sockaddr_in6 *)our_sockaddr)->sin6_port = 0;
456 if (bind(sockfd, SA(our_sockaddr), SA_LEN(our_sockaddr)) < 0) {
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
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
477static int set_addr(
struct sockaddr_storage *ss,
const char *ip)
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;
485 rc_log(LOG_CRIT,
"invalid IP address for nas-ip: %s", ip);
505 memset(&rh->own_bind_addr, 0,
sizeof(rh->own_bind_addr));
506 rh->own_bind_addr_set = 0;
508 rh->own_bind_addr_set = 1;
512 if (set_addr(&rh->nas_addr, txt) < 0)
514 rh->nas_addr_set = 1;
524 if (strcasecmp(txt,
"udp") == 0) {
525 memset(&rh->so, 0,
sizeof(rh->so));
527 memcpy(&rh->so, &default_socket_funcs,
sizeof(rh->so));
529 }
else if (strcasecmp(txt,
"tcp") == 0) {
530 memset(&rh->so, 0,
sizeof(rh->so));
532 memcpy(&rh->so, &default_tcp_socket_funcs,
sizeof(rh->so));
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);
541 rc_log(LOG_CRIT,
"unknown server type: %s", txt);
546 rc_log(LOG_CRIT,
"error initializing %s", txt);
571 char buffer[512], *p;
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");
588 memcpy(rh->config_options, &config_options_default,
sizeof(config_options_default));
590 if ((configfd = fopen(filename,
"r")) == NULL)
592 rc_log(LOG_ERR,
"rc_read_config: can't open %s: %s", filename, strerror(errno));
598 while ((fgets(buffer,
sizeof(buffer), configfd) != NULL))
603 if ((*p ==
'\n') || (*p ==
'#') || (*p ==
'\0'))
606 p[strlen(p)-1] =
'\0';
609 if ((pos = strcspn(p,
"\t ")) == 0) {
610 rc_log(LOG_ERR,
"%s: line %d: bogus format: %s", filename, line, p);
618 if ((option = find_option(rh, p, OT_ANY)) == NULL) {
619 rc_log(LOG_ERR,
"%s: line %d: unrecognized keyword: %s", filename, line, p);
625 if (option->status != ST_UNDEF) {
626 rc_log(LOG_ERR,
"%s: line %d: duplicate option line: %s", filename, line, p);
636 while(pos != 0 && isspace(p[pos]))
640 switch (option->type) {
642 if (set_option_str(filename, line, option, p) < 0) {
649 if (set_option_int(filename, line, option, p) < 0) {
656 if (set_option_srv(filename, line, option, p) < 0) {
663 if (set_option_auo(filename, line, option, p) < 0) {
670 rc_log(LOG_CRIT,
"rc_read_config: impossible case branch!");
682 int clientdebug = rc_conf_int_2(rh,
"clientdebug", FALSE);
683 if(clientdebug > 0) {
684 radcli_debug = clientdebug;
691 rc_log(LOG_CRIT,
"could not load dictionary");
696 rc_log(LOG_INFO,
"rc_read_config: no dictionary was specified");
712 option = find_option(rh, optname, OT_STR);
714 if (option != NULL) {
715 return (
char *)option->val;
717 rc_log(LOG_CRIT,
"rc_conf_str: unknown config option requested: %s", optname);
728static int rc_conf_int_2(rc_handle
const *rh,
char const *optname,
int complain)
732 option = find_option(rh, optname, OT_INT|OT_AUO);
734 if (option != NULL) {
736 return *((
int *)option->val);
737 }
else if(complain) {
738 rc_log(LOG_ERR,
"rc_conf_int: config option %s was not set", optname);
742 rc_log(LOG_CRIT,
"rc_conf_int: unknown config option requested: %s", optname);
747int rc_conf_int(rc_handle
const *rh,
char const *optname)
749 return rc_conf_int_2(rh, optname, TRUE);
762 option = find_option(rh, optname, OT_SRV);
764 if (option != NULL) {
765 return (
SERVER *)option->val;
767 rc_log(LOG_CRIT,
"rc_conf_srv: unknown config option requested: %s", optname);
783 if (!srv || !srv->max)
785 rc_log(LOG_ERR,
"%s: no authserver specified", filename);
790 if (!srv || !srv->max)
794 rc_log(LOG_DEBUG,
"%s: no acctserver specified", filename);
798 rc_log(LOG_ERR,
"%s: no dictionary specified", filename);
802 if (rc_conf_int(rh,
"radius_timeout") <= 0)
804 rc_log(LOG_ERR,
"%s: radius_timeout <= 0 is illegal", filename);
807 if (rc_conf_int(rh,
"radius_retries") <= 0)
809 rc_log(LOG_ERR,
"%s: radius_retries <= 0 is illegal", filename);
826static int find_match (
const struct addrinfo* addr,
const struct addrinfo *hostname)
828 const struct addrinfo *ptr, *ptr2;
835 len1 = SA_GET_INLEN(ptr->ai_addr);
836 len2 = SA_GET_INLEN(ptr2->ai_addr);
840 memcmp(SA_GET_INADDR(ptr->ai_addr), SA_GET_INADDR(ptr2->ai_addr), len1) == 0) {
843 ptr2 = ptr2->ai_next;
855static int rc_ipaddr_local(
const struct sockaddr *addr)
857 int temp_sock, res, serrno;
858 struct sockaddr_storage tmpaddr;
860 memcpy(&tmpaddr, addr, SA_LEN(addr));
862 temp_sock = socket(addr->sa_family, SOCK_DGRAM, 0);
866 if (addr->sa_family == AF_INET) {
867 ((
struct sockaddr_in*)&tmpaddr)->sin_port = 0;
869 ((
struct sockaddr_in6*)&tmpaddr)->sin6_port = 0;
871 res = bind(temp_sock, SA(&tmpaddr), SS_LEN(&tmpaddr));
876 if (serrno == EADDRNOTAVAIL)
886static int rc_is_myname(
const struct addrinfo *info)
888 const struct addrinfo *p;
893 res = rc_ipaddr_local(p->ai_addr);
894 if (res == 0 || res == -1) {
913 struct addrinfo** info,
char *secret,
rc_type type)
920 char hostnm[AUTH_ID_LEN + 1];
924 struct addrinfo *tmpinfo = NULL;
925 const char *fservers;
929 if ((*info = rc_getaddrinfo (server_name, type==
AUTH?PW_AI_AUTH:PW_AI_ACCT)) == NULL)
934 case AUTH: optname =
"authserver";
break;
935 case ACCT: optname =
"acctserver";
break;
936 default: optname = NULL;
939 if ( (optname != NULL) &&
944 size_t server_name_len = strlen(server_name);
945 for (servernum = 0; servernum < servers->max; servernum++)
947 if( (strncmp(server_name, servers->name[servernum], server_name_len) == 0) &&
948 (servers->secret[servernum] != NULL) )
950 memset(secret,
'\0', MAX_SECRET_LENGTH);
951 strlcpy(secret, servers->secret[servernum], MAX_SECRET_LENGTH);
962 if (fservers != NULL) {
963 if ((clientfd = fopen (fservers,
"r")) == NULL)
965 rc_log(LOG_ERR,
"rc_find_server: couldn't open file: %s: %s", strerror(errno),
rc_conf_str(rh,
"servers"));
969 while (fgets (buffer,
sizeof (buffer), clientfd) != NULL)
974 if ((h = strtok_r(buffer,
" \t\n", &buffer_save)) == NULL)
977 strlcpy (hostnm, h, AUTH_ID_LEN);
979 if ((s = strtok_r (NULL,
" \t\n", &buffer_save)) == NULL)
982 strlcpy (secret, s, MAX_SECRET_LENGTH);
984 if (!strchr (hostnm,
'/'))
986 tmpinfo = rc_getaddrinfo(hostnm, 0);
989 result = find_match (*info, tmpinfo);
996 freeaddrinfo(tmpinfo);
1002 strtok_r(hostnm,
"/", &hostnm_save);
1003 tmpinfo = rc_getaddrinfo(hostnm, 0);
1006 if (rc_is_myname(tmpinfo) == 0)
1008 if (find_match (*info, tmpinfo) == 0)
1016 if (find_match (*info, tmpinfo) == 0)
1022 freeaddrinfo(tmpinfo);
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",
1042 freeaddrinfo(*info);
1047 freeaddrinfo(tmpinfo);
1067 if (rh->config_options == NULL)
1070 for (i = 0; i < NUM_OPTIONS; i++) {
1071 if (rh->config_options[i].val == NULL)
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]);
1081 free(rh->config_options[i].val);
1084 free(rh->config_options);
1085 free(rh->first_dict_read);
1086 rh->config_options = NULL;
1087 rh->first_dict_read = NULL;
1090static int _initialized = 0;
1100 if (_initialized == 0) {
1101#if defined(HAVE_GNUTLS) && GNUTLS_VERSION_NUMBER < 0x030300
1103 ret = gnutls_global_init();
1106 "%s: error initializing gnutls: %s",
1107 __func__, gnutls_strerror(ret));
1111 srandom((
unsigned int)(time(NULL)+getpid()));
1115 rh = calloc(1,
sizeof(*rh));
1117 rc_log(LOG_CRIT,
"rc_new: out of memory");
1133#if defined(HAVE_GNUTLS) && GNUTLS_VERSION_NUMBER < 0x030300
1135 if (_initialized == 0) {
1136 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)
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.