Added support for reading user configuration from radius.

This commit is contained in:
Nikos Mavrogiannopoulos
2014-12-09 13:20:11 +01:00
parent 2194e11b39
commit 766afb591a
11 changed files with 258 additions and 25 deletions

View File

@@ -76,6 +76,7 @@ ocserv_SOURCES = main.c main-auth.c worker-vpn.c worker-auth.c tlslib.c \
icmp-ping.c icmp-ping.h \
sec-mod-sup-config.c sec-mod-sup-config.h \
sup-config/file.c sup-config/file.h \
sup-config/radius.c sup-config/radius.h \
worker-bandwidth.c worker-bandwidth.h ctl.h main-ctl.h \
vasprintf.c vasprintf.h \
proc-search.c proc-search.h \

View File

@@ -33,26 +33,20 @@
#include <freeradius-client.h>
#if !defined(PW_FRAMED_IPV6_ADDRESS) && defined(PW_TYPE_IPV6ADDR)
#define PW_FRAMED_IPV6_ADDRESS 168
#define PW_DNS_SERVER_IPV6_ADDRESS 169
#endif
#define RAD_GROUP_NAME 1030
#define RAD_IPV4_DNS1 ((311<<16)|(28))
#define RAD_IPV4_DNS2 ((311<<16)|(29))
int rc_aaa(rc_handle *rh, uint32_t client_port, VALUE_PAIR *send, VALUE_PAIR **received,
char *msg, int add_nas_port, int request_type);
static rc_handle *rh = NULL;
struct radius_ctx_st {
char username[MAX_USERNAME_SIZE*2];
char groupname[MAX_GROUPNAME_SIZE];
char msg[4096];
char ipv4[MAX_IP_STR];
char ipv6[MAX_IP_STR];
const char *config; /* radius config file */
const char *pass_msg;
unsigned retries;
};
static void radius_global_init(void *pool, void *additional)
{
rh = rc_read_config(additional);
@@ -170,6 +164,7 @@ static int radius_auth_pass(void *ctx, const char *pass, unsigned pass_len)
if (ret == OK_RC) {
VALUE_PAIR *vp = recvd;
uint32_t ip;
while(vp != NULL) {
if (vp->attribute == PW_SERVICE_TYPE && vp->lvalue != PW_FRAMED) {
syslog(LOG_ERR,
@@ -177,9 +172,35 @@ static int radius_auth_pass(void *ctx, const char *pass, unsigned pass_len)
(int)vp->lvalue);
goto fail;
} else if (vp->attribute == RAD_GROUP_NAME && vp->type == PW_TYPE_STRING) {
/* Group-Name */
snprintf(pctx->groupname, sizeof(pctx->groupname), "%s", vp->strvalue);
#ifdef PW_FRAMED_IPV6_ADDRESS
} else if (vp->attribute == PW_FRAMED_IPV6_ADDRESS && vp->type == PW_TYPE_IPV6ADDR) {
/* Framed-IPv6-Address */
inet_ntop(AF_INET6, vp->strvalue, pctx->ipv6, sizeof(pctx->ipv6));
} else if (vp->attribute == PW_DNS_SERVER_IPV6_ADDRESS && vp->type == PW_TYPE_IPV6ADDR) {
/* DNS-Server-IPv6-Address */
if (pctx->ipv6_dns1[0] == 0)
inet_ntop(AF_INET6, vp->strvalue, pctx->ipv6_dns1, sizeof(pctx->ipv6_dns1));
else
inet_ntop(AF_INET6, vp->strvalue, pctx->ipv6_dns2, sizeof(pctx->ipv6_dns2));
#endif
} else if (vp->attribute == PW_FRAMED_IP_ADDRESS && vp->type == PW_TYPE_IPADDR) {
inet_ntop(AF_INET, &vp->lvalue, pctx->ipv4, sizeof(pctx->ipv4));
/* Framed-IP-Address */
ip = htonl(vp->lvalue);
inet_ntop(AF_INET, &ip, pctx->ipv4, sizeof(pctx->ipv4));
} else if (vp->attribute == PW_FRAMED_IP_NETMASK && vp->type == PW_TYPE_IPADDR) {
/* Framed-IP-Netmask */
ip = htonl(vp->lvalue);
inet_ntop(AF_INET, &ip, pctx->ipv4_mask, sizeof(pctx->ipv4_mask));
} else if (vp->attribute == RAD_IPV4_DNS1 && vp->type == PW_TYPE_IPADDR) {
/* MS-Primary-DNS-Server */
ip = htonl(vp->lvalue);
inet_ntop(AF_INET, &ip, pctx->ipv4_dns1, sizeof(pctx->ipv4_dns1));
} else if (vp->attribute == RAD_IPV4_DNS2 && vp->type == PW_TYPE_IPADDR) {
/* MS-Secondary-DNS-Server */
ip = htonl(vp->lvalue);
inet_ntop(AF_INET, &ip, pctx->ipv4_dns2, sizeof(pctx->ipv4_dns2));
} else {
syslog(LOG_DEBUG, "radius: ignoring server's value %u of type %u", (int)vp->attribute, (int)vp->type);
}

View File

@@ -23,6 +23,27 @@
#include <sec-mod-auth.h>
struct radius_ctx_st {
char username[MAX_USERNAME_SIZE*2];
char groupname[MAX_GROUPNAME_SIZE];
char msg[4096];
/* variables for configuration */
char ipv4[MAX_IP_STR];
char ipv4_mask[MAX_IP_STR];
char ipv4_dns1[MAX_IP_STR];
char ipv4_dns2[MAX_IP_STR];
char ipv6[MAX_IP_STR];
uint16_t ipv6_prefix;
char ipv6_dns1[MAX_IP_STR];
char ipv6_dns2[MAX_IP_STR];
const char *config; /* radius config file */
const char *pass_msg;
unsigned retries;
};
extern const struct auth_mod_st radius_auth_funcs;
#endif

View File

@@ -34,6 +34,7 @@
#include <auth/pam.h>
#include <auth/radius.h>
#include <auth/plain.h>
#include <sec-mod-sup-config.h>
#include <vpn.h>
#include <cookies.h>
@@ -145,7 +146,9 @@ static struct cfg_options available_options[] = {
{ .name = "default-group-config", .type = OPTION_STRING, .mandatory = 0 },
};
static char *get_brackets_string(void *pool, const char *str);
#define get_brackets_string get_brackets_string1
static char *get_brackets_string1(void *pool, const char *str);
static char *get_brackets_string2(void *pool, const char *str);
static const tOptionValue* get_option(const char* name, unsigned * mand)
{
@@ -302,7 +305,7 @@ unsigned j;
}
}
static char *get_brackets_string(void *pool, const char *str)
static char *get_brackets_string1(void *pool, const char *str)
{
char *p, *p2;
unsigned len;
@@ -315,10 +318,47 @@ static char *get_brackets_string(void *pool, const char *str)
while (c_isspace(*p))
p++;
p2 = strchr(p, ']');
p2 = strchr(p, ',');
if (p2 == NULL) {
fprintf(stderr, "error parsing %s\n", str);
exit(1);
p2 = strchr(p, ']');
if (p2 == NULL) {
fprintf(stderr, "error parsing %s\n", str);
exit(1);
}
}
len = p2 - p;
return talloc_strndup(pool, p, len);
}
static char *get_brackets_string2(void *pool, const char *str)
{
char *p, *p2;
unsigned len;
p = strchr(str, '[');
if (p == NULL) {
return NULL;
}
p++;
p = strchr(p, ',');
if (p == NULL) {
return NULL;
}
p++;
while (c_isspace(*p))
p++;
p2 = strchr(p, ',');
if (p2 == NULL) {
p2 = strchr(p, ']');
if (p2 == NULL) {
fprintf(stderr, "error parsing %s\n", str);
exit(1);
}
}
len = p2 - p;
@@ -366,6 +406,8 @@ unsigned force_cert_auth;
prev = val;
} while((val = optionNextValue(pov, prev)) != NULL);
config->sup_config_type = SUP_CONFIG_FILE;
READ_MULTI_LINE("auth", auth, auth_size);
for (j=0;j<auth_size;j++) {
if (c_strncasecmp(auth[j], "pam", 3) == 0) {
@@ -395,17 +437,27 @@ unsigned force_cert_auth;
amod = &plain_auth_funcs;
config->auth_types |= amod->type;
} else if (strncasecmp(auth[j], "radius", 6) == 0) {
const char *p;
if ((config->auth_types & AUTH_TYPE_USERNAME_PASS) != 0) {
fprintf(stderr, "You cannot mix multiple username/password authentication methods\n");
exit(1);
}
#ifdef HAVE_RADIUS
config->auth_additional = get_brackets_string(config, auth[j]+6);
config->auth_additional = get_brackets_string1(config, auth[j]+6);
if (config->auth_additional == NULL) {
fprintf(stderr, "No configuration specified; error in %s\n", auth[j]);
exit(1);
}
p = get_brackets_string2(config, auth[j]+6);
if (p != NULL) {
if (strcasecmp(p, "groupconfig") != 0) {
fprintf(stderr, "No known configuration option: %s\n", p);
exit(1);
}
config->sup_config_type = SUP_CONFIG_RADIUS;
}
amod = &radius_auth_funcs;
config->auth_types |= amod->type;
#else

View File

@@ -76,7 +76,7 @@ An example configuration file follows.
# User authentication method. Could be set multiple times and in
# that case all should succeed. To enable multiple methods use
# multiple auth directives. Available options: certificate, certificate[optional],
# plain, pam, radius[config].
# plain, pam, radius[configfile,groupconfig].
#auth = "certificate"
#auth = "pam"
@@ -97,8 +97,9 @@ An example configuration file follows.
#auth = "plain[/etc/ocserv/ocpasswd]"
# The radius option requires specifying freeradius-client configuration
# file.
#auth = "radius[/etc/radiusclient/radiusclient.conf]"
# file. If the groupconfig option is set, then config-per-user will be overriden,
# and all configuration will be read from radius.
#auth = "radius[/etc/radiusclient/radiusclient.conf,groupconfig]"
# Whether to enable seccomp worker isolation. That restricts the number of
# system calls allowed to a worker process, in order to reduce damage from a

View File

@@ -29,9 +29,14 @@
#include <vpn.h>
#include <sec-mod-sup-config.h>
#include <sup-config/file.h>
#include <sup-config/radius.h>
void sup_config_init(sec_mod_st *sec)
{
sec->config_module = &file_sup_config;
if (sec->config->sup_config_type == SUP_CONFIG_FILE) {
sec->config_module = &file_sup_config;
} else if (sec->config->sup_config_type == SUP_CONFIG_RADIUS) {
sec->config_module = &radius_sup_config;
}
}

View File

@@ -23,6 +23,9 @@
#include <sec-mod.h>
#define SUP_CONFIG_FILE 1
#define SUP_CONFIG_RADIUS 2
/* The get_sup_config() should read any additional configuration for
* proc->username/proc->groupname and save it in proc->config.
*/

100
src/sup-config/radius.c Normal file
View File

@@ -0,0 +1,100 @@
/*
* Copyright (C) 2014 Red Hat, Inc.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <config.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <pwd.h>
#include <grp.h>
#include <fcntl.h>
#include <ocserv-args.h>
#include <autoopts/options.h>
#include <limits.h>
#include <common.h>
#include <c-strcase.h>
#ifdef HAVE_RADIUS
#include <vpn.h>
#include <main.h>
#include <sec-mod-sup-config.h>
#include <auth/radius.h>
static int get_sup_config(struct cfg_st *cfg, client_entry_st *entry,
SecAuthSessionReplyMsg *msg, void *pool)
{
struct radius_ctx_st *pctx = entry->auth_ctx;
unsigned dns = 0;
if (pctx == NULL)
return 0;
if (pctx->ipv4[0] != 0) {
msg->explicit_ipv4 = talloc_strdup(pool, pctx->ipv4);
}
if (pctx->ipv4_mask[0] != 0) {
msg->ipv4_netmask = talloc_strdup(pool, pctx->ipv4_mask);
}
if (pctx->ipv4_dns1[0] != 0)
dns++;
if (pctx->ipv4_dns2[0] != 0)
dns++;
if (pctx->ipv6_dns1[0] != 0)
dns++;
if (pctx->ipv6_dns2[0] != 0)
dns++;
if (dns > 0) {
msg->dns = talloc_size(pool, dns*sizeof(char*));
if (msg->dns != NULL) {
unsigned pos = 0;
if (pctx->ipv4_dns1[0] != 0)
msg->dns[pos++] = talloc_strdup(pool, pctx->ipv4_dns1);
if (pctx->ipv4_dns2[0] != 0)
msg->dns[pos++] = talloc_strdup(pool, pctx->ipv4_dns2);
if (pctx->ipv6_dns1[0] != 0)
msg->dns[pos++] = talloc_strdup(pool, pctx->ipv6_dns1);
if (pctx->ipv6_dns2[0] != 0)
msg->dns[pos++] = talloc_strdup(pool, pctx->ipv6_dns2);
msg->n_dns = dns;
}
}
if (pctx->ipv6[0] != 0) {
msg->explicit_ipv6 = talloc_strdup(pool, pctx->ipv6);
}
if (pctx->ipv6_prefix != 0) {
msg->ipv6_prefix = pctx->ipv6_prefix;
msg->has_ipv6_prefix = 1;
}
return 0;
}
struct config_mod_st radius_sup_config = {
.get_sup_config = get_sup_config,
};
#endif

28
src/sup-config/radius.h Normal file
View File

@@ -0,0 +1,28 @@
/*
* Copyright (C) 2014 Red Hat
*
* Author: Nikos Mavrogiannopoulos
*
* This file is part of ocserv.
*
* The GnuTLS is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>
*/
#ifndef SUP_CONFIG_RADIUS_H
#define SUP_CONFIG_RADIUS_H
#include <sec-mod-sup-config.h>
extern struct config_mod_st radius_sup_config;
#endif

View File

@@ -192,6 +192,7 @@ struct cfg_st {
unsigned int udp_port;
unsigned int is_dyndns;
char* unix_conn_file;
unsigned int sup_config_type; /* one of SUP_CONFIG_ */
char *pin_file;
char *srk_pin_file;