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!");
364 SERVER *authservers = NULL;
369 rh->config_options = malloc(
sizeof(config_options_default));
370 if (rh->config_options == NULL)
372 rc_log(LOG_CRIT,
"rc_config_init: out of memory");
376 memcpy(rh->config_options, &config_options_default,
sizeof(config_options_default));
378 auth = find_option(rh,
"authserver", OT_ANY);
380 authservers = calloc(1,
sizeof(SERVER));
381 if(authservers == NULL) {
382 rc_log(LOG_CRIT,
"rc_config_init: error initializing server structs");
386 auth->val = authservers;
389 acct = find_option(rh,
"acctserver", OT_ANY);
391 acctservers = calloc(1,
sizeof(SERVER));
392 if(acctservers == NULL) {
393 rc_log(LOG_CRIT,
"rc_config_init: error initializing server structs");
395 if(authservers) free(authservers);
398 acct->val = acctservers;
404static ssize_t plain_sendto(
void *ptr,
int sockfd,
405 const void *buf,
size_t len,
int flags,
406 const struct sockaddr *dest_addr, socklen_t addrlen)
408 return sendto(sockfd, buf, len, flags, dest_addr, addrlen);
411static ssize_t plain_tcp_sendto(
void *ptr,
int sockfd,
412 const void *buf,
size_t len,
int flags,
413 const struct sockaddr *dest_addr, socklen_t addrlen)
415 if((connect(sockfd, dest_addr, addrlen)) != 0){
416 rc_log(LOG_ERR,
"%s: Connect Call Failed : %s", __FUNCTION__, strerror(errno));
419 return sendto(sockfd, buf, len, flags, dest_addr, addrlen);
422static ssize_t plain_recvfrom(
void *ptr,
int sockfd,
423 void *buf,
size_t len,
int flags,
424 struct sockaddr *src_addr, socklen_t * addrlen)
426 return recvfrom(sockfd, buf, len, flags, src_addr, addrlen);
429static void plain_close_fd(
int fd)
434static int plain_get_fd(
void *ptr,
struct sockaddr *our_sockaddr)
438 sockfd = socket(our_sockaddr->sa_family, SOCK_DGRAM, 0);
443 if (our_sockaddr->sa_family == AF_INET)
444 ((
struct sockaddr_in *)our_sockaddr)->sin_port = 0;
446 ((
struct sockaddr_in6 *)our_sockaddr)->sin6_port = 0;
448 if (bind(sockfd, SA(our_sockaddr), SA_LEN(our_sockaddr)) < 0) {
455static int plain_tcp_get_fd(
void *ptr,
struct sockaddr *our_sockaddr)
459 sockfd = socket(our_sockaddr->sa_family, SOCK_STREAM, 0);
464 if (our_sockaddr->sa_family == AF_INET)
465 ((
struct sockaddr_in *)our_sockaddr)->sin_port = 0;
467 ((
struct sockaddr_in6 *)our_sockaddr)->sin6_port = 0;
469 if (bind(sockfd, SA(our_sockaddr), SA_LEN(our_sockaddr)) < 0) {
476static const rc_sockets_override default_socket_funcs = {
477 .get_fd = plain_get_fd,
478 .close_fd = plain_close_fd,
479 .sendto = plain_sendto,
480 .recvfrom = plain_recvfrom
483static const rc_sockets_override default_tcp_socket_funcs = {
484 .get_fd = plain_tcp_get_fd,
485 .close_fd = plain_close_fd,
486 .sendto = plain_tcp_sendto,
487 .recvfrom = plain_recvfrom
490static int set_addr(
struct sockaddr_storage *ss,
const char *ip)
492 memset(ss, 0,
sizeof(*ss));
493 if (inet_pton(AF_INET, ip, &((
struct sockaddr_in *)ss)->sin_addr) == 1) {
494 ss->ss_family = AF_INET;
495 }
else if (inet_pton(AF_INET6, ip, &((
struct sockaddr_in6 *)ss)->sin6_addr) == 1) {
496 ss->ss_family = AF_INET6;
498 rc_log(LOG_CRIT,
"invalid IP address for nas-ip: %s", ip);
524 memset(&rh->own_bind_addr, 0,
sizeof(rh->own_bind_addr));
525 rh->own_bind_addr_set = 0;
527 rh->own_bind_addr_set = 1;
531 if (set_addr(&rh->nas_addr, txt) < 0)
533 rh->nas_addr_set = 1;
543 if (strcasecmp(txt,
"udp") == 0) {
544 memset(&rh->so, 0,
sizeof(rh->so));
546 memcpy(&rh->so, &default_socket_funcs,
sizeof(rh->so));
548 }
else if (strcasecmp(txt,
"tcp") == 0) {
549 memset(&rh->so, 0,
sizeof(rh->so));
551 memcpy(&rh->so, &default_tcp_socket_funcs,
sizeof(rh->so));
554 }
else if (strcasecmp(txt,
"dtls") == 0) {
555 ret = rc_init_tls(rh, SEC_FLAG_DTLS);
556 }
else if (strcasecmp(txt,
"tls") == 0) {
557 ret = rc_init_tls(rh, 0);
560 rc_log(LOG_CRIT,
"unknown server type: %s", txt);
565 rc_log(LOG_CRIT,
"error initializing %s", txt);
621 char buffer[512], *p;
632 rh->config_options = malloc(
sizeof(config_options_default));
633 if (rh->config_options == NULL) {
634 rc_log(LOG_CRIT,
"rc_read_config: out of memory");
638 memcpy(rh->config_options, &config_options_default,
sizeof(config_options_default));
640 if ((configfd = fopen(filename,
"r")) == NULL)
642 rc_log(LOG_ERR,
"rc_read_config: can't open %s: %s", filename, strerror(errno));
648 while ((fgets(buffer,
sizeof(buffer), configfd) != NULL))
653 if ((*p ==
'\n') || (*p ==
'#') || (*p ==
'\0'))
656 p[strlen(p)-1] =
'\0';
659 if ((pos = strcspn(p,
"\t ")) == 0) {
660 rc_log(LOG_ERR,
"%s: line %d: bogus format: %s", filename, line, p);
668 if ((option = find_option(rh, p, OT_ANY)) == NULL) {
669 rc_log(LOG_ERR,
"%s: line %d: unrecognized keyword: %s", filename, line, p);
675 if (option->status != ST_UNDEF) {
676 rc_log(LOG_ERR,
"%s: line %d: duplicate option line: %s", filename, line, p);
686 while(pos != 0 && isspace(p[pos]))
690 switch (option->type) {
692 if (set_option_str(filename, line, option, p) < 0) {
699 if (set_option_int(filename, line, option, p) < 0) {
706 if (set_option_srv(filename, line, option, p) < 0) {
713 if (set_option_auo(filename, line, option, p) < 0) {
720 rc_log(LOG_CRIT,
"rc_read_config: impossible case branch!");
732 int clientdebug = rc_conf_int_2(rh,
"clientdebug", FALSE);
733 if(clientdebug > 0) {
734 radcli_debug = clientdebug;
741 sizeof(rc_rfc_dictionary) - 1) != 0) {
742 rc_log(LOG_CRIT,
"rc_read_config: failed to load built-in RFC dictionary");
750 rc_log(LOG_CRIT,
"could not load dictionary");
769 option = find_option(rh, optname, OT_STR);
771 if (option != NULL) {
772 return (
char *)option->val;
774 rc_log(LOG_CRIT,
"rc_conf_str: unknown config option requested: %s", optname);
785static int rc_conf_int_2(rc_handle
const *rh,
char const *optname,
int complain)
789 option = find_option(rh, optname, OT_INT|OT_AUO);
791 if (option != NULL) {
793 return *((
int *)option->val);
794 }
else if(complain) {
795 rc_log(LOG_ERR,
"rc_conf_int: config option %s was not set", optname);
799 rc_log(LOG_CRIT,
"rc_conf_int: unknown config option requested: %s", optname);
804int rc_conf_int(rc_handle
const *rh,
char const *optname)
806 return rc_conf_int_2(rh, optname, TRUE);
819 option = find_option(rh, optname, OT_SRV);
821 if (option != NULL) {
822 return (SERVER *)option->val;
824 rc_log(LOG_CRIT,
"rc_conf_srv: unknown config option requested: %s", optname);
840 if (!srv || !srv->max)
842 rc_log(LOG_ERR,
"%s: no authserver specified", filename);
847 if (!srv || !srv->max)
851 rc_log(LOG_DEBUG,
"%s: no acctserver specified", filename);
854 if (rc_conf_int(rh,
"radius_timeout") <= 0)
856 rc_log(LOG_ERR,
"%s: radius_timeout <= 0 is illegal", filename);
859 if (rc_conf_int(rh,
"radius_retries") <= 0)
861 rc_log(LOG_ERR,
"%s: radius_retries <= 0 is illegal", filename);
878static int find_match (
const struct addrinfo* addr,
const struct addrinfo *hostname)
880 const struct addrinfo *ptr, *ptr2;
887 len1 = SA_GET_INLEN(ptr->ai_addr);
888 len2 = SA_GET_INLEN(ptr2->ai_addr);
892 memcmp(SA_GET_INADDR(ptr->ai_addr), SA_GET_INADDR(ptr2->ai_addr), len1) == 0) {
895 ptr2 = ptr2->ai_next;
907static int rc_ipaddr_local(
const struct sockaddr *addr)
909 int temp_sock, res, serrno;
910 struct sockaddr_storage tmpaddr;
912 memcpy(&tmpaddr, addr, SA_LEN(addr));
914 temp_sock = socket(addr->sa_family, SOCK_DGRAM, 0);
918 if (addr->sa_family == AF_INET) {
919 ((
struct sockaddr_in*)&tmpaddr)->sin_port = 0;
921 ((
struct sockaddr_in6*)&tmpaddr)->sin6_port = 0;
923 res = bind(temp_sock, SA(&tmpaddr), SS_LEN(&tmpaddr));
928 if (serrno == EADDRNOTAVAIL)
938static int rc_is_myname(
const struct addrinfo *info)
940 const struct addrinfo *p;
945 res = rc_ipaddr_local(p->ai_addr);
946 if (res == 0 || res == -1) {
965 struct addrinfo** info,
char *secret,
rc_type type)
972 char hostnm[AUTH_ID_LEN + 1];
976 struct addrinfo *tmpinfo = NULL;
977 const char *fservers;
981 if ((*info = rc_getaddrinfo (server_name, type==
AUTH?PW_AI_AUTH:PW_AI_ACCT)) == NULL)
986 case AUTH: optname =
"authserver";
break;
987 case ACCT: optname =
"acctserver";
break;
988 default: optname = NULL;
991 if ( (optname != NULL) &&
996 size_t server_name_len = strlen(server_name);
997 for (servernum = 0; servernum < servers->max; servernum++)
999 if( (strncmp(server_name, servers->name[servernum], server_name_len) == 0) &&
1000 (servers->secret[servernum] != NULL) )
1002 memset(secret,
'\0', MAX_SECRET_LENGTH);
1003 strlcpy(secret, servers->secret[servernum], MAX_SECRET_LENGTH);
1014 if (fservers != NULL) {
1015 if ((clientfd = fopen (fservers,
"r")) == NULL)
1017 rc_log(LOG_ERR,
"rc_find_server: couldn't open file: %s: %s", strerror(errno),
rc_conf_str(rh,
"servers"));
1021 while (fgets (buffer,
sizeof (buffer), clientfd) != NULL)
1026 if ((h = strtok_r(buffer,
" \t\n", &buffer_save)) == NULL)
1029 strlcpy (hostnm, h, AUTH_ID_LEN);
1031 if ((s = strtok_r (NULL,
" \t\n", &buffer_save)) == NULL)
1034 strlcpy (secret, s, MAX_SECRET_LENGTH);
1036 if (!strchr (hostnm,
'/'))
1038 tmpinfo = rc_getaddrinfo(hostnm, 0);
1041 result = find_match (*info, tmpinfo);
1048 freeaddrinfo(tmpinfo);
1054 strtok_r(hostnm,
"/", &hostnm_save);
1055 tmpinfo = rc_getaddrinfo(hostnm, 0);
1058 if (rc_is_myname(tmpinfo) == 0)
1060 if (find_match (*info, tmpinfo) == 0)
1068 if (find_match (*info, tmpinfo) == 0)
1074 freeaddrinfo(tmpinfo);
1083 memset (buffer,
'\0',
sizeof (buffer));
1084 memset (secret,
'\0', MAX_SECRET_LENGTH);
1085 rc_log(LOG_ERR,
"rc_find_server: couldn't find RADIUS server %s in %s",
1094 freeaddrinfo(*info);
1099 freeaddrinfo(tmpinfo);
1119 if (rh->config_options == NULL)
1122 for (i = 0; i < NUM_OPTIONS; i++) {
1123 if (rh->config_options[i].val == NULL)
1125 if (rh->config_options[i].type == OT_SRV) {
1126 serv = (SERVER *)rh->config_options[i].val;
1127 for (j = 0; j < serv->max; j++) {
1128 free(serv->name[j]);
1129 if(serv->secret[j]) free(serv->secret[j]);
1133 free(rh->config_options[i].val);
1136 free(rh->config_options);
1137 free(rh->first_dict_read);
1138 rh->config_options = NULL;
1139 rh->first_dict_read = NULL;
1142static int _initialized = 0;
1152 if (_initialized == 0) {
1153#if defined(HAVE_GNUTLS) && GNUTLS_VERSION_NUMBER < 0x030300
1155 ret = gnutls_global_init();
1158 "%s: error initializing gnutls: %s",
1159 __func__, gnutls_strerror(ret));
1163 srandom((
unsigned int)(time(NULL)+getpid()));
1167 rh = calloc(1,
sizeof(*rh));
1169 rc_log(LOG_CRIT,
"rc_new: out of memory");
1188#if defined(HAVE_GNUTLS) && GNUTLS_VERSION_NUMBER < 0x030300
1190 if (_initialized == 0) {
1191 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.