28#include "dict_rfc_gen.h"
36static int rc_conf_int_2(rc_handle
const *rh,
char const *optname,
int complain);
47static OPTION *find_option(rc_handle
const *rh,
char const *optname,
unsigned int type)
52 for (i = 0; i < NUM_OPTIONS; i++) {
53 if (!strcmp(rh->config_options[i].name, optname) &&
54 (rh->config_options[i].type & type))
56 return &rh->config_options[i];
73static int set_option_str(
char const *filename,
int line, OPTION *option,
char const *p)
76 option->val = (
void *) strdup(p);
77 if (option->val == NULL) {
78 rc_log(LOG_CRIT,
"read_config: out of memory");
90static int set_option_int(
char const *filename,
int line, OPTION *option,
char const *p)
95 rc_log(LOG_ERR,
"%s: line %d: bogus option value", filename, line);
99 if ((iptr = malloc(
sizeof(*iptr))) == NULL) {
100 rc_log(LOG_CRIT,
"read_config: out of memory");
105 option->val = (
void *) iptr;
115static void server_free_entries(SERVER *serv,
unsigned from,
unsigned to)
119 for (i = from; i < to; i++) {
121 free(serv->secret[i]);
122 serv->name[i] = NULL;
123 serv->secret[i] = NULL;
128static int set_option_srv(
char const *filename,
int line, OPTION *option,
char const *p)
141 if (p_dupe == NULL) {
142 rc_log(LOG_ERR,
"%s: line %d: Invalid option or memory failure", filename, line);
146 serv = (SERVER *) option->val;
148 serv = calloc(1,
sizeof(*serv));
150 rc_log(LOG_CRIT,
"read_config: out of memory");
156 start_max = serv->max;
158 p_pointer = strtok_r(p_dupe,
", \t", &p_save);
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);
166 DEBUG(LOG_ERR,
"processing server: %s", p_pointer);
168 if ((q = strchr(p_pointer,
'[')) != NULL) {
173 q = strchr(p_pointer,
']');
175 rc_log(LOG_CRIT,
"read_config: IPv6 parse error");
186 if((s=strchr(q,
':')) != NULL) {
189 serv->secret[serv->max] = strdup(s);
190 if (serv->secret[serv->max] == NULL) {
191 rc_log(LOG_CRIT,
"read_config: out of memory");
197 if ((q = strchr(p_pointer,
':')) != NULL) {
202 if((s = strchr(q,
':')) != NULL) {
205 serv->secret[serv->max] = strdup(s);
206 if (serv->secret[serv->max] == NULL) {
207 rc_log(LOG_CRIT,
"read_config: out of memory");
213 if(q && strlen(q) > 0) {
214 serv->port[serv->max] = atoi(q);
216 if (!strcmp(option->name,
"authserver"))
217 if ((svp = getservbyname (
"radius",
"udp")) == NULL)
218 serv->port[serv->max] = PW_AUTH_UDP_PORT;
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;
225 serv->port[serv->max] = ntohs ((
unsigned int) svp->s_port);
227 rc_log(LOG_ERR,
"%s: line %d: no default port for %s", filename, line, option->name);
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");
239 p_pointer = strtok_r(NULL,
", \t", &p_save);
243 if (option->val == NULL)
244 option->val = (
void *)serv;
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;
261 if (option->val == NULL)
269static int set_option_auo(
char const *filename,
int line, OPTION *option,
char const *p)
273 char *p_pointer = NULL;
278 if (p_dupe == NULL) {
279 rc_log(LOG_WARNING,
"%s: line %d: bogus option value", filename, line);
283 if ((iptr = malloc(
sizeof(*iptr))) == NULL) {
284 rc_log(LOG_CRIT,
"read_config: out of memory");
290 p_pointer = strtok_r(p_dupe,
", \t", &p_save);
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;
297 rc_log(LOG_ERR,
"%s: auth_order: unknown keyword: %s", filename, p);
303 p_pointer = strtok_r(NULL,
", \t", &p_save);
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;
311 rc_log(LOG_ERR,
"%s: auth_order: unknown or unexpected keyword: %s", filename, p);
318 option->val = (
void *) iptr;
337int rc_add_config(rc_handle *rh,
char const *option_name,
char const *option_val,
char const *source,
int line)
341 if ((option = find_option(rh, option_name, OT_ANY)) == NULL)
343 rc_log(LOG_ERR,
"ERROR: unrecognized option: %s", option_name);
347 if (option->status != ST_UNDEF)
349 rc_log(LOG_ERR,
"ERROR: duplicate option: %s", option_name);
353 switch (option->type) {
355 if (set_option_str(source, line, option, option_val) < 0) {
360 if (set_option_int(source, line, option, option_val) < 0) {
365 if (set_option_srv(source, line, option, option_val) < 0) {
370 if (set_option_auo(source, line, option, option_val) < 0) {
375 rc_log(LOG_CRIT,
"rc_add_config: impossible case branch!");
406 SERVER *authservers = NULL;
411 rh->config_options = malloc(
sizeof(config_options_default));
412 if (rh->config_options == NULL)
414 rc_log(LOG_CRIT,
"rc_config_init: out of memory");
418 memcpy(rh->config_options, &config_options_default,
sizeof(config_options_default));
420 auth = find_option(rh,
"authserver", OT_ANY);
422 authservers = calloc(1,
sizeof(SERVER));
423 if(authservers == NULL) {
424 rc_log(LOG_CRIT,
"rc_config_init: error initializing server structs");
428 auth->val = authservers;
431 acct = find_option(rh,
"acctserver", OT_ANY);
433 acctservers = calloc(1,
sizeof(SERVER));
434 if(acctservers == NULL) {
435 rc_log(LOG_CRIT,
"rc_config_init: error initializing server structs");
437 if(authservers) free(authservers);
440 acct->val = acctservers;
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)
451 return sendto(sockfd, buf, len, flags, dest_addr, addrlen);
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)
460 if((connect(sockfd, dest_addr, addrlen)) != 0){
461 rc_log(LOG_ERR,
"%s: Connect Call Failed : %s", __FUNCTION__, strerror(errno));
464 return sendto(sockfd, buf, len, flags, dest_addr, addrlen);
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)
473 return recvfrom(sockfd, buf, len, flags, src_addr, addrlen);
478static void plain_close_fd(
int fd)
485static int plain_get_fd(
void *ptr,
struct sockaddr *our_sockaddr)
489 sockfd = socket(our_sockaddr->sa_family, SOCK_DGRAM, 0);
494 if (our_sockaddr->sa_family == AF_INET)
495 ((
struct sockaddr_in *)our_sockaddr)->sin_port = 0;
497 ((
struct sockaddr_in6 *)our_sockaddr)->sin6_port = 0;
499 if (bind(sockfd, SA(our_sockaddr), SA_LEN(our_sockaddr)) < 0) {
508static int plain_tcp_get_fd(
void *ptr,
struct sockaddr *our_sockaddr)
512 sockfd = socket(our_sockaddr->sa_family, SOCK_STREAM, 0);
517 if (our_sockaddr->sa_family == AF_INET)
518 ((
struct sockaddr_in *)our_sockaddr)->sin_port = 0;
520 ((
struct sockaddr_in6 *)our_sockaddr)->sin6_port = 0;
522 if (bind(sockfd, SA(our_sockaddr), SA_LEN(our_sockaddr)) < 0) {
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
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
545static int set_addr(
struct sockaddr_storage *ss,
const char *ip)
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;
553 rc_log(LOG_CRIT,
"invalid IP address for nas-ip: %s", ip);
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;
587 if (set_addr(&rh->nas_addr, txt) < 0)
589 rh->nas_addr_set = 1;
599 if (strcasecmp(txt,
"udp") == 0) {
600 memset(&rh->so, 0,
sizeof(rh->so));
602 memcpy(&rh->so, &default_socket_funcs,
sizeof(rh->so));
604 }
else if (strcasecmp(txt,
"tcp") == 0) {
605 memset(&rh->so, 0,
sizeof(rh->so));
607 memcpy(&rh->so, &default_tcp_socket_funcs,
sizeof(rh->so));
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);
616 rc_log(LOG_CRIT,
"unknown server type: %s", txt);
621 rc_log(LOG_CRIT,
"error initializing %s", txt);
679 char *buffer = NULL, *p;
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");
698 memcpy(rh->config_options, &config_options_default,
sizeof(config_options_default));
700 if ((configfd = fopen(filename,
"r")) == NULL)
702 rc_log(LOG_ERR,
"rc_read_config: can't open %s: %s", filename, strerror(errno));
708 while ((nread = getline(&buffer, &bufsize, configfd)) != -1)
712 if (nread > 0 && buffer[nread-1] ==
'\n')
713 buffer[--nread] =
'\0';
717 if ((*p ==
'#') || (*p ==
'\0'))
720 if ((pos = strcspn(p,
"\t ")) == 0) {
721 rc_log(LOG_ERR,
"%s: line %d: bogus format: %s", filename, line, p);
727 if ((option = find_option(rh, p, OT_ANY)) == NULL) {
728 rc_log(LOG_ERR,
"%s: line %d: unrecognized keyword: %s", filename, line, p);
732 if (option->status != ST_UNDEF) {
733 rc_log(LOG_ERR,
"%s: line %d: duplicate option line: %s", filename, line, p);
742 while (pos != 0 && isspace(p[pos]))
747 switch (option->type) {
749 if (set_option_str(filename, line, option, p) < 0)
753 if (set_option_int(filename, line, option, p) < 0)
757 if (set_option_srv(filename, line, option, p) < 0)
761 if (set_option_auo(filename, line, option, p) < 0)
765 rc_log(LOG_CRIT,
"rc_read_config: impossible case branch!");
778 int clientdebug = rc_conf_int_2(rh,
"clientdebug", FALSE);
779 if(clientdebug > 0) {
780 radcli_debug = clientdebug;
787 sizeof(rc_rfc_dictionary) - 1) != 0) {
788 rc_log(LOG_CRIT,
"rc_read_config: failed to load built-in RFC dictionary");
796 rc_log(LOG_CRIT,
"could not load dictionary");
821 option = find_option(rh, optname, OT_STR);
823 if (option != NULL) {
824 return (
char *)option->val;
826 rc_log(LOG_CRIT,
"rc_conf_str: unknown config option requested: %s", optname);
838static int rc_conf_int_2(rc_handle
const *rh,
char const *optname,
int complain)
842 option = find_option(rh, optname, OT_INT|OT_AUO);
844 if (option != NULL) {
846 return *((
int *)option->val);
847 }
else if(complain) {
848 rc_log(LOG_ERR,
"rc_conf_int: config option %s was not set", optname);
852 rc_log(LOG_CRIT,
"rc_conf_int: unknown config option requested: %s", optname);
866 return rc_conf_int_2(rh, optname, TRUE);
879 option = find_option(rh, optname, OT_SRV);
881 if (option != NULL) {
882 return (SERVER *)option->val;
884 rc_log(LOG_CRIT,
"rc_conf_srv: unknown config option requested: %s", optname);
900 if (!srv || !srv->max)
902 rc_log(LOG_ERR,
"%s: no authserver specified", filename);
907 if (!srv || !srv->max)
917 (strcasecmp(stype,
"tls") != 0 && strcasecmp(stype,
"dtls") != 0))
918 rc_log(LOG_DEBUG,
"%s: no acctserver specified", filename);
923 rc_log(LOG_ERR,
"%s: radius_timeout <= 0 is illegal", filename);
928 rc_log(LOG_ERR,
"%s: radius_retries <= 0 is illegal", filename);
946static int find_match (
const struct addrinfo* addr,
const struct addrinfo *hostname)
948 const struct addrinfo *ptr, *ptr2;
955 len1 = SA_GET_INLEN(ptr->ai_addr);
956 len2 = SA_GET_INLEN(ptr2->ai_addr);
960 memcmp(SA_GET_INADDR(ptr->ai_addr), SA_GET_INADDR(ptr2->ai_addr), len1) == 0) {
963 ptr2 = ptr2->ai_next;
977static int rc_ipaddr_local(
const struct sockaddr *addr)
979 int temp_sock, res, serrno;
980 struct sockaddr_storage tmpaddr;
982 memcpy(&tmpaddr, addr, SA_LEN(addr));
984 temp_sock = socket(addr->sa_family, SOCK_DGRAM, 0);
988 if (addr->sa_family == AF_INET) {
989 ((
struct sockaddr_in*)&tmpaddr)->sin_port = 0;
991 ((
struct sockaddr_in6*)&tmpaddr)->sin6_port = 0;
993 res = bind(temp_sock, SA(&tmpaddr), SS_LEN(&tmpaddr));
998 if (serrno == EADDRNOTAVAIL)
1010static int rc_is_myname(
const struct addrinfo *info)
1012 const struct addrinfo *p;
1017 res = rc_ipaddr_local(p->ai_addr);
1018 if (res == 0 || res == -1) {
1038 struct addrinfo** info,
char *secret,
rc_type type)
1044 char *buffer = NULL;
1046 char hostnm[AUTH_ID_LEN + 1];
1050 struct addrinfo *tmpinfo = NULL;
1051 const char *fservers;
1052 char const *optname;
1055 if ((*info = rc_getaddrinfo (server_name, type==
AUTH?PW_AI_AUTH:PW_AI_ACCT)) == NULL)
1060 case AUTH: optname =
"authserver";
break;
1061 case ACCT: optname =
"acctserver";
break;
1062 default: optname = NULL;
1065 if ( (optname != NULL) &&
1070 for (servernum = 0; servernum < servers->max; servernum++)
1072 if( (strcmp(server_name, servers->name[servernum]) == 0) &&
1073 (servers->secret[servernum] != NULL) )
1075 memset(secret,
'\0', MAX_SECRET_LENGTH);
1076 strlcpy(secret, servers->secret[servernum], MAX_SECRET_LENGTH);
1087 if (fservers != NULL) {
1088 if ((clientfd = fopen (fservers,
"r")) == NULL)
1090 rc_log(LOG_ERR,
"rc_find_server: couldn't open file: %s: %s", strerror(errno),
rc_conf_str(rh,
"servers"));
1094 while (getline (&buffer, &bufsize, clientfd) != -1)
1099 if ((h = strtok_r(buffer,
" \t\n", &buffer_save)) == NULL)
1102 strlcpy (hostnm, h, AUTH_ID_LEN);
1104 if ((s = strtok_r (NULL,
" \t\n", &buffer_save)) == NULL)
1107 strlcpy (secret, s, MAX_SECRET_LENGTH);
1109 if (!strchr (hostnm,
'/'))
1111 tmpinfo = rc_getaddrinfo(hostnm, 0);
1114 result = find_match (*info, tmpinfo);
1121 freeaddrinfo(tmpinfo);
1127 strtok_r(hostnm,
"/", &hostnm_save);
1128 tmpinfo = rc_getaddrinfo(hostnm, 0);
1131 if (rc_is_myname(tmpinfo) == 0)
1133 if (find_match (*info, tmpinfo) == 0)
1141 if (find_match (*info, tmpinfo) == 0)
1147 freeaddrinfo(tmpinfo);
1156 memset (secret,
'\0', MAX_SECRET_LENGTH);
1157 rc_log(LOG_ERR,
"rc_find_server: couldn't find RADIUS server %s in %s",
1166 freeaddrinfo(*info);
1171 freeaddrinfo(tmpinfo);
1192 if (rh->config_options == NULL)
1195 for (i = 0; i < NUM_OPTIONS; i++) {
1196 if (rh->config_options[i].val == NULL)
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);
1203 free(rh->config_options[i].val);
1206 free(rh->config_options);
1207 free(rh->first_dict_read);
1208 rh->config_options = NULL;
1209 rh->first_dict_read = NULL;
1212static int _initialized = 0;
1222 if (_initialized == 0) {
1223#if defined(HAVE_GNUTLS) && GNUTLS_VERSION_NUMBER < 0x030300
1225 ret = gnutls_global_init();
1228 "%s: error initializing gnutls: %s",
1229 __func__, gnutls_strerror(ret));
1233 srandom((
unsigned int)(time(NULL)+getpid()));
1237 rh = calloc(1,
sizeof(*rh));
1239 rc_log(LOG_CRIT,
"rc_new: out of memory");
1258#if defined(HAVE_GNUTLS) && GNUTLS_VERSION_NUMBER < 0x030300
1260 if (_initialized == 0) {
1261 gnutls_global_deinit();
rc_socket_type rc_get_socket_type(rc_handle *rh)
Returns the type of the socket used.
rc_handle * rc_new(void)
Initialises new Radius Client handle.
void rc_destroy(rc_handle *rh)
Destroys Radius Client handle reclaiming all memory.
int rc_read_dictionary_from_buffer(rc_handle *rh, char const *buf, size_t size)
Initialize the dictionary from Buffer.
rc_handle * rc_read_config(char const *filename)
Read the global config file.
int rc_read_dictionary(rc_handle *rh, char const *filename)
Initialize the dictionary.
int rc_conf_int(rc_handle const *rh, char const *optname)
Get the value of a config option as an integer.
char * rc_conf_str(rc_handle const *rh, char const *optname)
Get the value of a config option.
int rc_test_config(rc_handle *rh, char const *filename)
Tests the configuration the user supplied.
void rc_dict_free(rc_handle *rh)
Frees the allocated dictionary.
rc_handle * rc_config_init(rc_handle *rh)
Initialise a configuration structure for programmatic configuration.
void rc_config_free(rc_handle *rh)
Frees allocated config values.
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.
SERVER * rc_conf_srv(rc_handle const *rh, char const *optname)
Get the value of a config option.
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.
int rc_apply_config(rc_handle *rh)
Apply configuration and initialise the transport.
@ ACCT
Request for accounting server.
@ AUTH
Request for authentication server.
@ RC_SOCKET_UDP
Plain UDP socket.
@ RC_SOCKET_TCP
Plain TCP socket.
Public API of the radcli library.