Merge branch 'radius'

That merges all the changes needed for radius support.
This commit is contained in:
Nikos Mavrogiannopoulos
2014-12-10 19:59:30 +01:00
36 changed files with 1338 additions and 326 deletions

3
README
View File

@@ -30,6 +30,9 @@ libopts25-dev / autogen-libopts-devel
autogen / autogen
For radius support the freeradius-client library is required. Currently
(2014-12-10) the best would be to use the version from the git repository
at: https://github.com/FreeRADIUS/freeradius-client
=== Build instructions ===

5
TODO
View File

@@ -1,8 +1,7 @@
Short term items:
* Enhance the current accounting modules to allow, native radius support
with real-time accounting (e.g., sending periodically the transferred
bytes). Use radius for testing it.
* Use the UDP address to report the client's IP when sniproxy or haproxy
are being used.
* When a user (IP) gets into the BAN list multiple times, disable it for
longer time (or should we drop this functionality altogether and rely

View File

@@ -188,6 +188,32 @@ AC_LINK_IFELSE([AC_LANG_PROGRAM([
LIBS="$oldlibs"
fi
AC_ARG_WITH(radius,
AS_HELP_STRING([--without-radius], [do not include Radius support]),
test_for_radius=$withval,
test_for_radius=yes)
radius_enabled=no
if test "$test_for_radius" = yes;then
LIBS="$oldlibs -lfreeradius-client"
AC_MSG_CHECKING([for freeradius client library])
AC_LINK_IFELSE([AC_LANG_PROGRAM([
#include <freeradius-client.h>],[
rc_read_config(0);])],
[AC_MSG_RESULT(yes)
AC_SUBST([FREERADIUS_CLIENT_LIBS], [-lfreeradius-client])
AC_SUBST([FREERADIUS_CLIENT_CFLAGS], [])
radius_enabled=yes
AC_DEFINE([HAVE_RADIUS], 1, [Enable the Radius library])],
[AC_MSG_RESULT(no)
AC_MSG_WARN([[
***
*** libfreeradius-client was not found. Radius support will be disabled.
*** ]])])
LIBS="$oldlibs"
fi
gl_INIT
AC_LIB_HAVE_LINKFLAGS(crypt,, [#define _XOPEN_SOURCE
@@ -381,6 +407,7 @@ Summary of build options:
CFlags: ${CFLAGS}
PAM auth backend: ${pam_enabled}
Radius auth backend: ${radius_enabled}
TCP wrappers: ${libwrap_enabled}
systemd: ${systemd_enabled}
(socket activation)

View File

@@ -22,6 +22,14 @@ auth = "plain[./sample.passwd]"
# to generate password entries.
#auth = "plain[/etc/ocserv/ocpasswd]"
# The radius option requires specifying freeradius-client configuration
# file. If the groupconfig option is set, then config-per-user will be overriden,
# and all configuration will be read from radius. The supported atributes for
# radius configuration are:
# Group-Name, Framed-IPv6-Address, DNS-Server-IPv6-Address, Framed-IP-Address,
# Framed-IP-Netmask, MS-Primary-DNS-Server, MS-Secondary-DNS-Server
#auth = "radius[/usr/local/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
# bug in the worker process. It is available on Linux systems at a performance cost.
@@ -56,6 +64,12 @@ max-same-clients = 2
# reconnects.
#listen-host-is-dyndns = true
# Stats report time. The number of seconds after which each
# worker process will report its usage statistics (number of
# bytes transferred etc). This is useful when accounting like
# radius is in use.
#stats-report-time = 360
# TCP and UDP port number
tcp-port = 443
udp-port = 443

View File

@@ -62,7 +62,8 @@ endif
COMMON_SOURCES=common.c common.h system.c system.h setproctitle.c setproctitle.h
# Authentication module sources
AUTH_SOURCES=auth/pam.c auth/pam.h auth/plain.c auth/plain.h
AUTH_SOURCES=auth/pam.c auth/pam.h auth/plain.c auth/plain.h auth/radius.c auth/radius.h \
auth/common.c auth/common.h
ocserv_SOURCES = main.c main-auth.c worker-vpn.c worker-auth.c tlslib.c \
cookies.c main-misc.c ip-lease.c ip-lease.h \
@@ -73,8 +74,9 @@ ocserv_SOURCES = main.c main-auth.c worker-vpn.c worker-auth.c tlslib.c \
sec-mod.c sec-mod-db.c sec-mod-auth.c sec-mod-auth.h sec-mod.h sec-mod-ban.c \
script-list.h $(COMMON_SOURCES) $(AUTH_SOURCES) \
icmp-ping.c icmp-ping.h \
main-sup-config.c main-sup-config.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 \
@@ -87,7 +89,8 @@ ocserv_SOURCES += ipc.pb-c.h ipc.pb-c.c ctl.pb-c.c ctl.pb-c.h
ocserv_LDADD = ../gl/libgnu.a $(NEEDED_LIBOPTS) libcmd-ocserv.a
ocserv_LDADD += $(LIBGNUTLS_LIBS) $(PAM_LIBS) $(LIBUTIL) \
$(LIBSECCOMP) $(LIBWRAP) $(LIBCRYPT) $(NEEDED_HTTP_PARSER_LIBS) \
$(LIBPROTOBUF_C_LIBS) $(LIBSYSTEMD_DAEMON) $(LIBTALLOC_LIBS)
$(LIBPROTOBUF_C_LIBS) $(LIBSYSTEMD_DAEMON) $(LIBTALLOC_LIBS) \
$(FREERADIUS_CLIENT_LIBS)
if PCL

26
src/auth/common.c Normal file
View File

@@ -0,0 +1,26 @@
/*
* Copyright (C) 2014 Red Hat, Inc.
*
* This file is part of ocserv.
*
* ocserv 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.
*
* ocserv 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 <auth/common.h>
const char* pass_msg_first = "Please enter your password.";
const char* pass_msg_second = "Please enter your challenge password.";
const char* pass_msg_failed = "Login failed.\nPlease enter your password.";

10
src/auth/common.h Normal file
View File

@@ -0,0 +1,10 @@
#ifndef AUTH_COMMON_H
# define AUTH_COMMON_H
#define MAX_TRIES 3
extern const char* pass_msg_first;
extern const char* pass_msg_second;
extern const char* pass_msg_failed;
#endif

View File

@@ -348,7 +348,7 @@ struct pam_ctx_st * pctx = ctx;
talloc_free(pctx);
}
static int pam_auth_open_session(void* ctx)
static int pam_auth_open_session(void* ctx, const void *sid, unsigned sid_size)
{
struct pam_ctx_st * pctx = ctx;
int pret;

View File

@@ -29,14 +29,11 @@
#include <vpn.h>
#include <c-ctype.h>
#include "plain.h"
#include "auth/common.h"
#include <ccan/htable/htable.h>
#include <ccan/hash/hash.h>
#define MAX_CPASS_SIZE 128
#define MAX_TRIES 3
const char* pass_msg_first = "Please enter your password.";
const char* pass_msg_failed = "Login failed.\nPlease enter your password.";
struct plain_ctx_st {
char username[MAX_USERNAME_SIZE];

425
src/auth/radius.c Normal file
View File

@@ -0,0 +1,425 @@
/*
* Copyright (C) 2014 Red Hat, Inc.
*
* This file is part of ocserv.
*
* ocserv 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.
*
* ocserv 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 <syslog.h>
#include <unistd.h>
#include <vpn.h>
#include <c-ctype.h>
#include <arpa/inet.h> /* inet_ntop */
#include "radius.h"
#include "auth/common.h"
#ifdef HAVE_RADIUS
#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;
static void radius_global_init(void *pool, void *additional)
{
rh = rc_read_config(additional);
if (rh == NULL) {
fprintf(stderr, "radius initialization error\n");
exit(1);
}
if (rc_read_dictionary(rh, rc_conf_str(rh, "dictionary")) != 0) {
fprintf(stderr, "error reading the radius dictionary\n");
exit(1);
}
return;
}
static void radius_global_deinit()
{
if (rh != NULL)
rc_destroy(rh);
}
static int radius_auth_init(void **ctx, void *pool, const char *username, const char *ip,
void *additional)
{
struct radius_ctx_st *pctx;
char *default_realm;
pctx = talloc_zero(pool, struct radius_ctx_st);
if (pctx == NULL)
return ERR_AUTH_FAIL;
snprintf(pctx->username, sizeof(pctx->username), "%s", username);
pctx->config = additional;
pctx->pass_msg = pass_msg_first;
default_realm = rc_conf_str(rh, "default_realm");
if ((strchr(username, '@') == NULL) && default_realm &&
default_realm[0] != 0) {
snprintf(pctx->username, sizeof(pctx->username), "%s@%s", username, default_realm);
} else {
strcpy(pctx->username, username);
}
*ctx = pctx;
return 0;
}
static int radius_auth_group(void *ctx, const char *suggested, char *groupname, int groupname_size)
{
struct radius_ctx_st *pctx = ctx;
groupname[0] = 0;
if (suggested != NULL) {
if (strcmp(suggested, pctx->groupname) == 0) {
snprintf(groupname, groupname_size, "%s", pctx->groupname);
return 0;
}
syslog(LOG_AUTH,
"user '%s' requested group '%s' but is not a member",
pctx->username, suggested);
return -1;
}
if (pctx->groupname[0] != 0 && groupname[0] == 0) {
snprintf(groupname, groupname_size, "%s", pctx->groupname);
}
return 0;
}
static int radius_auth_user(void *ctx, char *username, int username_size)
{
/* do not update username */
return -1;
}
/* Returns 0 if the user is successfully authenticated, and sets the appropriate group name.
*/
static int radius_auth_pass(void *ctx, const char *pass, unsigned pass_len)
{
struct radius_ctx_st *pctx = ctx;
VALUE_PAIR *send = NULL, *recvd = NULL;
uint32_t service;
int ret;
syslog(LOG_DEBUG, "communicating username (%s) and password to radius", pctx->username);
if (rc_avpair_add(rh, &send, PW_USER_NAME, pctx->username, -1, 0) == NULL) {
syslog(LOG_ERR,
"%s:%u: user '%s' auth error", __func__, __LINE__,
pctx->username);
return ERR_AUTH_FAIL;
}
if (rc_avpair_add(rh, &send, PW_USER_PASSWORD, (char*)pass, -1, 0) == NULL) {
syslog(LOG_ERR,
"%s:%u: user '%s' auth error", __func__, __LINE__,
pctx->username);
ret = ERR_AUTH_FAIL;
goto cleanup;
}
service = PW_AUTHENTICATE_ONLY;
if (rc_avpair_add(rh, &send, PW_SERVICE_TYPE, &service, -1, 0) == NULL) {
syslog(LOG_ERR,
"%s:%u: user '%s' auth error", __func__, __LINE__,
pctx->username);
ret = ERR_AUTH_FAIL;
goto cleanup;
}
ret = rc_aaa(rh, 0, send, &recvd, pctx->msg, 1, PW_ACCESS_REQUEST);
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,
"%s:%u: unknown radius service type '%d'", __func__, __LINE__,
(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) {
/* 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);
}
vp = vp->next;
}
ret = 0;
cleanup:
rc_avpair_free(send);
if (recvd != NULL)
rc_avpair_free(recvd);
return ret;
} else {
fail:
if (send != NULL)
rc_avpair_free(send);
if (recvd != NULL)
rc_avpair_free(recvd);
if (ret == PW_ACCESS_CHALLENGE) {
pctx->pass_msg = pass_msg_second;
return ERR_AUTH_CONTINUE;
} else if (pctx->retries++ < MAX_TRIES) {
pctx->pass_msg = pass_msg_failed;
return ERR_AUTH_CONTINUE;
} else {
syslog(LOG_AUTH,
"radius-auth: error authenticating user '%s'",
pctx->username);
return ERR_AUTH_FAIL;
}
}
}
static int radius_auth_msg(void *ctx, char *msg, size_t msg_size)
{
struct radius_ctx_st *pctx = ctx;
snprintf(msg, msg_size, "%s", pctx->pass_msg);
return 0;
}
static void radius_auth_deinit(void *ctx)
{
struct radius_ctx_st *pctx = ctx;
talloc_free(pctx);
}
static void radius_auth_session_stats(void* ctx, uint64_t bytes_in, uint64_t bytes_out)
{
struct radius_ctx_st * pctx = ctx;
int ret;
uint32_t status_type;
VALUE_PAIR *send = NULL, *recvd = NULL;
uint32_t uin, uout;
status_type = PW_STATUS_ALIVE;
syslog(LOG_DEBUG, "sending radius session interim update");
if (rc_avpair_add(rh, &send, PW_ACCT_STATUS_TYPE, &status_type, -1, 0) == NULL) {
ret = -1;
goto cleanup;
}
if (rc_avpair_add(rh, &send, PW_USER_NAME, pctx->username, -1, 0) == NULL) {
ret = -1;
goto cleanup;
}
if (rc_avpair_add(rh, &send, PW_ACCT_SESSION_ID, pctx->sid, -1, 0) == NULL) {
ret = -1;
goto cleanup;
}
uin = bytes_in;
uout = bytes_out;
if (rc_avpair_add(rh, &send, PW_ACCT_INPUT_OCTETS, &uin, -1, 0) == NULL) {
ret = -1;
goto cleanup;
}
if (rc_avpair_add(rh, &send, PW_ACCT_OUTPUT_OCTETS, &uout, -1, 0) == NULL) {
ret = -1;
goto cleanup;
}
uin = bytes_in / 4294967296;
if (rc_avpair_add(rh, &send, PW_ACCT_INPUT_GIGAWORDS, &uin, -1, 0) == NULL) {
ret = -1;
goto cleanup;
}
uout = bytes_in / 4294967296;
if (rc_avpair_add(rh, &send, PW_ACCT_OUTPUT_GIGAWORDS, &uout, -1, 0) == NULL) {
ret = -1;
goto cleanup;
}
ret = rc_aaa(rh, 0, send, &recvd, pctx->msg, 1, PW_ACCOUNTING_REQUEST);
if (recvd != NULL)
rc_avpair_free(recvd);
if (ret != OK_RC) {
syslog(LOG_AUTH, "radius-auth: radius_open_session: %d", ret);
goto cleanup;
}
cleanup:
rc_avpair_free(send);
return;
}
static int radius_auth_open_session(void* ctx, const void *sid, unsigned sid_size)
{
struct radius_ctx_st * pctx = ctx;
int ret;
uint32_t status_type;
VALUE_PAIR *send = NULL, *recvd = NULL;
status_type = PW_STATUS_START;
if (sid_size != SID_SIZE) {
syslog(LOG_DEBUG, "incorrect sid size");
return -1;
}
base64_encode((char *)sid, sid_size, (char *)pctx->sid, sizeof(pctx->sid));
syslog(LOG_DEBUG, "opening session %s with radius", pctx->sid);
if (rc_avpair_add(rh, &send, PW_USER_NAME, pctx->username, -1, 0) == NULL) {
ret = -1;
goto cleanup;
}
if (rc_avpair_add(rh, &send, PW_ACCT_SESSION_ID, pctx->sid, -1, 0) == NULL) {
ret = -1;
goto cleanup;
}
if (rc_avpair_add(rh, &send, PW_ACCT_STATUS_TYPE, &status_type, -1, 0) == NULL) {
ret = -1;
goto cleanup;
}
ret = rc_aaa(rh, 0, send, &recvd, pctx->msg, 1, PW_ACCOUNTING_REQUEST);
if (recvd != NULL)
rc_avpair_free(recvd);
if (ret != OK_RC) {
syslog(LOG_AUTH, "radius-auth: radius_open_session: %d", ret);
ret = -1;
goto cleanup;
}
ret = 0;
cleanup:
rc_avpair_free(send);
return ret;
}
static void radius_auth_close_session(void* ctx)
{
struct radius_ctx_st * pctx = ctx;
int ret;
uint32_t status_type;
VALUE_PAIR *send = NULL, *recvd = NULL;
status_type = PW_STATUS_STOP;
syslog(LOG_DEBUG, "closing session with radius");
if (rc_avpair_add(rh, &send, PW_ACCT_STATUS_TYPE, &status_type, -1, 0) == NULL)
return;
if (rc_avpair_add(rh, &send, PW_USER_NAME, pctx->username, -1, 0) == NULL) {
goto cleanup;
}
if (rc_avpair_add(rh, &send, PW_ACCT_SESSION_ID, pctx->sid, -1, 0) == NULL) {
goto cleanup;
}
ret = rc_aaa(rh, 0, send, &recvd, pctx->msg, 1, PW_ACCOUNTING_REQUEST);
if (recvd != NULL)
rc_avpair_free(recvd);
if (ret != OK_RC) {
syslog(LOG_INFO, "radius-auth: radius_close_session: %d", ret);
goto cleanup;
}
cleanup:
rc_avpair_free(send);
return;
}
const struct auth_mod_st radius_auth_funcs = {
.type = AUTH_TYPE_RADIUS | AUTH_TYPE_USERNAME_PASS,
.global_init = radius_global_init,
.global_deinit = radius_global_deinit,
.auth_init = radius_auth_init,
.auth_deinit = radius_auth_deinit,
.auth_msg = radius_auth_msg,
.auth_pass = radius_auth_pass,
.auth_user = radius_auth_user,
.auth_group = radius_auth_group,
.open_session = radius_auth_open_session,
.close_session = radius_auth_close_session,
.session_stats = radius_auth_session_stats,
.group_list = NULL
};
#endif

52
src/auth/radius.h Normal file
View File

@@ -0,0 +1,52 @@
/*
* Copyright (C) 2014 Red Hat, Inc.
*
* 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 RADIUS_H
#define RADIUS_H
#include <sec-mod-auth.h>
#include <base64.h>
struct radius_ctx_st {
char username[MAX_USERNAME_SIZE*2];
char groupname[MAX_GROUPNAME_SIZE];
char sid[BASE64_LENGTH(SID_SIZE) + 1];
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

@@ -56,6 +56,8 @@ static char tmp[32];
case CMD_CLI_STATS:
return "cli stats";
case SM_CMD_CLI_STATS:
return "sm: cli stats";
case SM_CMD_AUTH_INIT:
return "sm: auth init";
case SM_CMD_AUTH_CONT:

View File

@@ -1,5 +1,6 @@
/*
* Copyright (C) 2013 Nikos Mavrogiannopoulos
* Copyright (C) 2013, 2014 Nikos Mavrogiannopoulos
* Copyright (C) 2014 Red Hat, Inc.
*
* Author: Nikos Mavrogiannopoulos
*
@@ -42,6 +43,22 @@ ssize_t force_read_timeout(int sockfd, void *buf, size_t len, unsigned sec);
ssize_t recv_timeout(int sockfd, void *buf, size_t len, unsigned sec);
int ip_cmp(const struct sockaddr_storage *s1, const struct sockaddr_storage *s2, size_t n);
char* ipv6_prefix_to_mask(void *pool, unsigned prefix);
inline static int valid_ipv6_prefix(unsigned prefix)
{
switch (prefix) {
case 16:
case 32:
case 48:
case 64:
case 80:
case 96:
case 112:
case 128:
return 1;
default:
return 0;
}
}
typedef size_t (*pack_func)(const void*, uint8_t *);
typedef size_t (*pack_size_func)(const void*);

View File

@@ -32,7 +32,9 @@
#include <c-strcase.h>
#include <c-ctype.h>
#include <auth/pam.h>
#include <auth/radius.h>
#include <auth/plain.h>
#include <sec-mod-sup-config.h>
#include <vpn.h>
#include <cookies.h>
@@ -45,6 +47,7 @@
static char pid_file[_POSIX_PATH_MAX] = "";
static const char* cfg_file = DEFAULT_CFG_FILE;
static const struct auth_mod_st *amod = NULL;
struct cfg_options {
const char* name;
@@ -106,6 +109,7 @@ static struct cfg_options available_options[] = {
{ .name = "net-priority", .type = OPTION_STRING, .mandatory = 0 },
{ .name = "output-buffer", .type = OPTION_NUMERIC, .mandatory = 0 },
{ .name = "cookie-timeout", .type = OPTION_NUMERIC, .mandatory = 0 },
{ .name = "stats-report-time", .type = OPTION_NUMERIC, .mandatory = 0 },
{ .name = "rekey-time", .type = OPTION_NUMERIC, .mandatory = 0 },
{ .name = "rekey-method", .type = OPTION_STRING, .mandatory = 0 },
{ .name = "auth-timeout", .type = OPTION_NUMERIC, .mandatory = 0 },
@@ -143,7 +147,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)
{
@@ -300,7 +306,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;
@@ -313,10 +319,13 @@ 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;
@@ -324,6 +333,45 @@ static char *get_brackets_string(void *pool, const char *str)
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;
return talloc_strndup(pool, p, len);
}
const struct auth_mod_st *get_auth_mod(void)
{
return amod;
}
static void parse_cfg_file(const char* file, struct cfg_st *config, unsigned reload)
{
tOptionValue const * pov;
@@ -332,7 +380,6 @@ unsigned j, i, mand;
char** auth = NULL;
unsigned auth_size = 0;
unsigned prefix = 0, auto_select_group = 0;
const struct auth_mod_st *amod = NULL;
char *tmp;
unsigned force_cert_auth;
@@ -360,6 +407,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) {
@@ -369,7 +418,7 @@ unsigned force_cert_auth;
exit(1);
}
#ifdef HAVE_PAM
config->auth_types |= AUTH_TYPE_PAM;
config->auth_types |= amod->type;
amod = &pam_auth_funcs;
#else
fprintf(stderr, "PAM support is disabled\n");
@@ -387,7 +436,35 @@ unsigned force_cert_auth;
exit(1);
}
amod = &plain_auth_funcs;
config->auth_types |= AUTH_TYPE_PLAIN;
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_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
fprintf(stderr, "Radius support is disabled\n");
exit(1);
#endif
} else if (c_strcasecmp(auth[j], "certificate") == 0) {
config->auth_types |= AUTH_TYPE_CERTIFICATE;
} else if (c_strcasecmp(auth[j], "certificate[optional]") == 0) {
@@ -452,8 +529,9 @@ unsigned force_cert_auth;
if (config->occtl_socket_file == NULL)
config->occtl_socket_file = talloc_strdup(config, OCCTL_UNIX_SOCKET);
if (config->auth_types & AUTH_TYPE_USERNAME_PASS) {
READ_TF("session-control", config->session_control, 0);
val = get_option("session-control", NULL);
if (val != NULL) {
fprintf(stderr, "The option 'session-control' is deprecated\n");
}
READ_STRING("banner", config->banner);
@@ -496,6 +574,8 @@ unsigned force_cert_auth;
READ_TF("deny-roaming", config->deny_roaming, 0);
READ_NUMERIC("stats-report-time", config->stats_report_time);
config->rekey_time = -1;
READ_NUMERIC("rekey-time", config->rekey_time);
if (config->rekey_time == -1) {
@@ -561,10 +641,9 @@ unsigned force_cert_auth;
READ_NUMERIC("ipv6-prefix", prefix);
if (prefix > 0) {
config->network.ipv6_netmask = ipv6_prefix_to_mask(config, prefix);
config->network.ipv6_prefix = prefix;
if (config->network.ipv6_netmask == NULL) {
if (valid_ipv6_prefix(prefix) == 0) {
fprintf(stderr, "invalid IPv6 prefix: %u\n", prefix);
exit(1);
}
@@ -642,8 +721,8 @@ static void check_cfg(struct cfg_st *config)
exit(1);
}
if (config->network.ipv6 != NULL && config->network.ipv6_netmask == NULL) {
fprintf(stderr, "No mask found for IPv6 network.\n");
if (config->network.ipv6 != NULL && config->network.ipv6_prefix == 0) {
fprintf(stderr, "No prefix found for IPv6 network.\n");
exit(1);
}
@@ -775,7 +854,6 @@ unsigned i;
DEL(config->network.ipv4);
DEL(config->network.ipv4_netmask);
DEL(config->network.ipv6);
DEL(config->network.ipv6_netmask);
for (i=0;i<config->network.routes_size;i++)
DEL(config->network.routes[i]);
DEL(config->network.routes);
@@ -822,6 +900,9 @@ void print_version(tOptions *opts, tOptDesc *desc)
#ifdef HAVE_LIBWRAP
fprintf(stderr, "tcp-wrappers, ");
#endif
#ifdef HAVE_RADIUS
fprintf(stderr, "radius, ");
#endif
#ifdef HAVE_PAM
fprintf(stderr, "PAM, ");
#endif
@@ -846,6 +927,7 @@ void print_version(tOptions *opts, tOptDesc *desc)
void reload_cfg_file(void *pool, struct cfg_st* config)
{
clear_cfg_file(config);
memset(config, 0, sizeof(*config));
parse_cfg_file(cfg_file, config, 1);

View File

@@ -141,7 +141,34 @@ int get_ipv4_lease(main_server_st* s, struct proc_st* proc)
int ret;
const char* c_network, *c_netmask;
char buf[64];
if (proc->config.explicit_ipv4) {
/* if an explicit IP is given for that client, then
* don't do any IP accounting */
ret =
inet_pton(AF_INET, proc->config.explicit_ipv4, SA_IN_P(&network));
if (ret != 1) {
mslog(s, NULL, LOG_ERR, "error reading explicit IP: %s", proc->config.explicit_ipv4);
return -1;
}
proc->ipv4 = talloc_zero(proc, struct ip_lease_st);
if (proc->ipv4 == NULL)
return ERR_MEM;
((struct sockaddr_in*)&network)->sin_family = AF_INET;
((struct sockaddr_in*)&network)->sin_port = 0;
memcpy(&proc->ipv4->lip, &network, sizeof(struct sockaddr_in));
proc->ipv4->lip_len = sizeof(struct sockaddr_in);
memcpy(&proc->ipv4->rip, &network, sizeof(struct sockaddr_in));
proc->ipv4->rip_len = sizeof(struct sockaddr_in);
return 0;
}
/* Our IP accounting */
if (proc->config.ipv4_network && proc->config.ipv4_netmask) {
c_network = proc->config.ipv4_network;
c_netmask = proc->config.ipv4_netmask;
@@ -273,15 +300,42 @@ int get_ipv6_lease(main_server_st* s, struct proc_st* proc)
struct sockaddr_storage tmp, mask, network, rnd;
unsigned i, max_loops = MAX_IP_TRIES;
int ret;
const char* c_network, *c_netmask;
const char* c_network;
char *c_netmask = NULL;
char buf[64];
if (proc->config.ipv6_network && proc->config.ipv6_netmask) {
if (proc->config.explicit_ipv6) {
/* if an explicit IP is given for that client, then
* don't do any IP accounting */
ret =
inet_pton(AF_INET6, proc->config.explicit_ipv6, SA_IN6_P(&network));
if (ret != 1) {
mslog(s, NULL, LOG_ERR, "error reading explicit IP: %s", proc->config.explicit_ipv6);
return -1;
}
proc->ipv6 = talloc_zero(proc, struct ip_lease_st);
if (proc->ipv6 == NULL)
return ERR_MEM;
((struct sockaddr_in6*)&network)->sin6_family = AF_INET6;
((struct sockaddr_in6*)&network)->sin6_port = 0;
memcpy(&proc->ipv6->lip, &network, sizeof(struct sockaddr_in6));
proc->ipv6->lip_len = sizeof(struct sockaddr_in6);
memcpy(&proc->ipv6->rip, &network, sizeof(struct sockaddr_in6));
proc->ipv6->rip_len = sizeof(struct sockaddr_in6);
return 0;
}
if (proc->config.ipv6_network && proc->config.ipv6_prefix) {
c_network = proc->config.ipv6_network;
c_netmask = proc->config.ipv6_netmask;
c_netmask = ipv6_prefix_to_mask(proc, proc->config.ipv6_prefix);
} else {
c_network = s->config->network.ipv6;
c_netmask = s->config->network.ipv6_netmask;
c_netmask = ipv6_prefix_to_mask(proc, proc->config.ipv6_prefix);
}
if (c_network && c_netmask) {
@@ -392,6 +446,7 @@ int get_ipv6_lease(main_server_st* s, struct proc_st* proc)
return 0;
fail:
talloc_free(proc->ipv6);
talloc_free(c_netmask);
proc->ipv6 = NULL;
return ret;
@@ -399,7 +454,7 @@ fail:
}
static
int unref_ip_lease(struct ip_lease_st * lease)
int unref_ip_lease(struct ip_lease_st *lease)
{
if (lease->db) {
htable_del(&lease->db->ht, rehash(lease, NULL), lease);
@@ -407,7 +462,7 @@ int unref_ip_lease(struct ip_lease_st * lease)
return 0;
}
int get_ip_leases(main_server_st* s, struct proc_st* proc)
int get_ip_leases(main_server_st *s, struct proc_st *proc)
{
int ret;
char buf[128];
@@ -417,7 +472,7 @@ char buf[128];
if (ret < 0)
return ret;
if (proc->ipv4) {
if (proc->ipv4 && proc->ipv4->db) {
if (htable_add(&s->ip_leases.ht, rehash(proc->ipv4, NULL), proc->ipv4) == 0) {
mslog(s, proc, LOG_ERR, "could not add IPv4 lease to hash table.");
return -1;
@@ -431,7 +486,7 @@ char buf[128];
if (ret < 0)
return ret;
if (proc->ipv6) {
if (proc->ipv6 && proc->ipv4->db) {
if (htable_add(&s->ip_leases.ht, rehash(proc->ipv6, NULL), proc->ipv6) == 0) {
mslog(s, proc, LOG_ERR, "could not add IPv6 lease to hash table.");
return -1;

View File

@@ -86,6 +86,7 @@ message cli_stats_msg
{
required uint64 bytes_in = 1;
required uint64 bytes_out = 2;
optional bytes sid = 3; /* only required by sec-mod */
}
/* UDP_FD */
@@ -192,4 +193,24 @@ message sec_auth_session_msg
message sec_auth_session_reply_msg
{
required AUTH_REP reply = 1;
/* sup - config */
optional bool no_udp = 10;
optional bool deny_roaming = 11;
optional bool require_cert = 12;
repeated string routes = 13;
repeated string iroutes = 14;
repeated string dns = 15;
repeated string nbns = 16;
optional string ipv4_net = 17;
optional string ipv4_netmask = 18;
optional string ipv6_net = 19;
optional uint32 ipv6_prefix = 20;
optional string cgroup = 21;
optional string xml_config_file = 22;
optional uint32 rx_per_sec = 23;
optional uint32 tx_per_sec = 24;
optional uint32 net_priority = 25;
optional string explicit_ipv4 = 26;
optional string explicit_ipv6 = 27;
}

View File

@@ -36,7 +36,6 @@
#include <script-list.h>
#include <ip-lease.h>
#include <proc-search.h>
#include <main-sup-config.h>
#include "str.h"
#include <vpn.h>
@@ -85,7 +84,6 @@ int send_cookie_auth_reply(main_server_st* s, struct proc_st* proc,
}
msg.ipv4_netmask = proc->config.ipv4_netmask;
msg.ipv6_netmask = proc->config.ipv6_netmask;
msg.ipv4_network = proc->config.ipv4_network;
msg.ipv6_network = proc->config.ipv6_network;
@@ -210,17 +208,16 @@ struct cookie_entry_st *old;
memset(&proc->config, 0, sizeof(proc->config));
apply_default_sup_config(s->config, proc);
if (s->config_module) {
ret = s->config_module->get_sup_config(s->config, proc);
if (ret < 0) {
mslog(s, proc, LOG_ERR,
"error reading additional configuration");
return ERR_READ_CONFIG;
}
/* loads sup config */
ret = session_open(s, proc);
if (ret < 0) {
mslog(s, proc, LOG_INFO, "could not open session");
return -1;
}
if (proc->config.cgroup != NULL) {
put_into_cgroup(s, proc->config.cgroup, proc->pid);
}
/* Put into right cgroup */
if (proc->config.cgroup != NULL) {
put_into_cgroup(s, proc->config.cgroup, proc->pid);
}
/* check whether the cookie IP matches */
@@ -284,12 +281,6 @@ struct cookie_entry_st *old;
memcpy(proc->ipv4_seed, &cmsg->ipv4_seed, sizeof(proc->ipv4_seed));
ret = session_open(s, proc);
if (ret < 0) {
mslog(s, proc, LOG_INFO, "could not open session");
return -1;
}
/* add the links to proc hash */
proc_table_add(s, proc);

View File

@@ -46,7 +46,6 @@
#include <proc-search.h>
#include <ipc.pb-c.h>
#include <script-list.h>
#include <main-sup-config.h>
#ifdef HAVE_MALLOC_TRIM
# include <malloc.h>
@@ -168,10 +167,8 @@ int session_cmd(main_server_st * s, struct proc_st *proc, unsigned open)
int sd, ret, e;
SecAuthSessionMsg ireq = SEC_AUTH_SESSION_MSG__INIT;
SecAuthSessionReplyMsg *msg = NULL;
unsigned type;
if (s->config->session_control == 0)
return 0;
unsigned type, i;
PROTOBUF_ALLOCATOR(pa, proc);
if (open)
type = SM_CMD_AUTH_SESSION_OPEN;
@@ -227,6 +224,86 @@ int session_cmd(main_server_st * s, struct proc_st *proc, unsigned open)
mslog(s, proc, LOG_INFO, "could not initiate session for '%s'", proc->username);
return -1;
}
/* fill in group_cfg_st */
if (msg->has_no_udp)
proc->config.no_udp = msg->no_udp;
if (msg->has_deny_roaming)
proc->config.deny_roaming = msg->deny_roaming;
if (msg->has_require_cert)
proc->config.require_cert = msg->require_cert;
if (msg->has_ipv6_prefix)
proc->config.ipv6_prefix = msg->ipv6_prefix;
if (msg->rx_per_sec)
proc->config.rx_per_sec = msg->rx_per_sec;
if (msg->tx_per_sec)
proc->config.tx_per_sec = msg->tx_per_sec;
if (msg->net_priority)
proc->config.net_priority = msg->net_priority;
if (msg->ipv4_net) {
proc->config.ipv4_network = talloc_strdup(proc, msg->ipv4_net);
}
if (msg->ipv4_netmask) {
proc->config.ipv4_netmask = talloc_strdup(proc, msg->ipv4_netmask);
}
if (msg->ipv6_net) {
proc->config.ipv6_network = talloc_strdup(proc, msg->ipv6_net);
}
if (msg->cgroup) {
proc->config.cgroup = talloc_strdup(proc, msg->cgroup);
}
if (msg->xml_config_file) {
proc->config.xml_config_file = talloc_strdup(proc, msg->xml_config_file);
}
if (msg->explicit_ipv4) {
proc->config.explicit_ipv4 = talloc_strdup(proc, msg->explicit_ipv4);
}
if (msg->explicit_ipv6) {
proc->config.explicit_ipv6 = talloc_strdup(proc, msg->explicit_ipv6);
}
if (msg->n_routes > 0) {
proc->config.routes = talloc_size(proc, sizeof(char*)*msg->n_routes);
for (i=0;i<msg->n_routes;i++) {
proc->config.routes[i] = talloc_strdup(proc, msg->routes[i]);
}
proc->config.routes_size = msg->n_routes;
}
if (msg->n_iroutes > 0) {
proc->config.iroutes = talloc_size(proc, sizeof(char*)*msg->n_iroutes);
for (i=0;i<msg->n_iroutes;i++) {
proc->config.iroutes[i] = talloc_strdup(proc, msg->iroutes[i]);
}
proc->config.iroutes_size = msg->n_iroutes;
}
if (msg->n_dns > 0) {
proc->config.dns = talloc_size(proc, sizeof(char*)*msg->n_dns);
for (i=0;i<msg->n_dns;i++) {
proc->config.dns[i] = talloc_strdup(proc, msg->dns[i]);
}
proc->config.dns_size = msg->n_dns;
}
if (msg->n_nbns > 0) {
proc->config.nbns = talloc_size(proc, sizeof(char*)*msg->n_nbns);
for (i=0;i<msg->n_nbns;i++) {
proc->config.nbns[i] = talloc_strdup(proc, msg->nbns[i]);
}
proc->config.nbns_size = msg->n_nbns;
}
sec_auth_session_reply_msg__free_unpacked(msg, &pa);
} else {
close(sd);
}
@@ -262,7 +339,7 @@ void remove_proc(main_server_st * s, struct proc_st *proc, unsigned k)
}
/* close any pending sessions */
if (s->config->session_control != 0 && proc->active_sid) {
if (proc->active_sid) {
session_close(s, proc);
}
@@ -273,26 +350,17 @@ void remove_proc(main_server_st * s, struct proc_st *proc, unsigned k)
proc->pid = -1;
remove_iroutes(s, proc);
if (s->config_module) {
s->config_module->clear_sup_config(&proc->config);
}
if (proc->ipv4 || proc->ipv6)
remove_ip_leases(s, proc);
/* expire any available cookies */
if (proc->cookie_ptr) {
unsigned timeout = s->config->cookie_timeout;
proc->cookie_ptr->proc = NULL;
if (s->config->session_control != 0) {
/* if we use session control and we closed the session we
* need to invalidate the cookie, so that a new session is
* used on the next connection */
proc->cookie_ptr->expiration = 1;
} else {
proc->cookie_ptr->expiration = time(0) + timeout;
}
/* if we use session control and we closed the session we
* need to invalidate the cookie, so that a new session is
* used on the next connection */
proc->cookie_ptr->expiration = 1;
}
close_tun(s, proc);

View File

@@ -51,7 +51,6 @@
# include <systemd/sd-daemon.h>
#endif
#include <main.h>
#include <main-sup-config.h>
#include <main-ctl.h>
#include <route-add.h>
#include <worker.h>
@@ -987,8 +986,6 @@ int main(int argc, char** argv)
run_sec_mod(s);
sup_config_init(s);
ret = ctl_handler_init(s);
if (ret < 0) {
fprintf(stderr, "Cannot create command handler\n");

View File

@@ -213,7 +213,6 @@ typedef struct main_server_st {
time_t start_time;
void * auth_extra;
struct config_mod_st *config_module;
#ifdef HAVE_DBUS
void * ctl_ctx;
@@ -305,4 +304,6 @@ int send_socket_msg_to_worker(main_server_st* s, struct proc_st* proc, uint8_t c
void request_reload(int signo);
void request_stop(int signo);
const struct auth_mod_st *get_auth_mod(void);
#endif

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.
# plain, pam, radius[configfile,groupconfig].
#auth = "certificate"
#auth = "pam"
@@ -96,11 +96,13 @@ An example configuration file follows.
# to generate password entries.
#auth = "plain[/etc/ocserv/ocpasswd]"
# Whether to enable the authentication method's session control (i.e., PAM).
# That requires more resources on the server, and makes cookies one-time-use;
# thus don't enable unless you need it. That should be used when you have an
# accounting system in place with the PAM modules.
#session-control = true
# The radius option requires specifying freeradius-client configuration
# file. If the groupconfig option is set, then config-per-user will be overriden,
# and all configuration will be read from radius. The supported atributes for
# radius configuration are:
# Group-Name, Framed-IPv6-Address, DNS-Server-IPv6-Address, Framed-IP-Address,
# Framed-IP-Netmask, MS-Primary-DNS-Server, MS-Secondary-DNS-Server
#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
@@ -141,6 +143,12 @@ udp-port = 3333
# combined with certificate authentication.
#listen-clear-file = /var/run/ocserv-conn.socket
# Stats report time. The number of seconds after which each
# worker process will report its usage statistics (number of
# bytes transferred etc). This is useful when accounting like
# radius is in use.
#stats-report-time = 360
# Keepalive in seconds
keepalive = 32400

View File

@@ -49,19 +49,26 @@
#include <auth/pam.h>
#include <sec-mod.h>
#include <vpn.h>
#include <sec-mod-sup-config.h>
static const struct auth_mod_st *module = NULL;
void sec_auth_init(struct cfg_st *config)
void sec_auth_init(sec_mod_st * sec, struct cfg_st *config)
{
#ifdef HAVE_PAM
if ((config->auth_types & pam_auth_funcs.type) == pam_auth_funcs.type)
module = &pam_auth_funcs;
else
#endif
if ((config->auth_types & plain_auth_funcs.type) ==
plain_auth_funcs.type) {
module = &plain_auth_funcs;
module = get_auth_mod();
if (module && module->global_init) {
module->global_init(sec, config->auth_additional);
}
}
void sec_auth_reinit(sec_mod_st * sec, struct cfg_st *config)
{
if (module) {
if (module != get_auth_mod()) {
seclog(sec, LOG_ERR, "Cannot change authentication method on reload");
exit(1);
}
}
}
@@ -102,7 +109,7 @@ static int generate_cookie(sec_mod_st * sec, client_entry_st * entry)
}
static
int send_sec_auth_reply(sec_mod_st * sec, client_entry_st * entry, AUTHREP r)
int send_sec_auth_reply(int cfd, sec_mod_st * sec, client_entry_st * entry, AUTHREP r)
{
SecAuthReplyMsg msg = SEC_AUTH_REPLY_MSG__INIT;
int ret;
@@ -130,7 +137,7 @@ int send_sec_auth_reply(sec_mod_st * sec, client_entry_st * entry, AUTHREP r)
msg.dtls_session_id.data = entry->dtls_session_id;
msg.dtls_session_id.len = sizeof(entry->dtls_session_id);
ret = send_msg(entry, sec->fd, SM_CMD_AUTH_REP,
ret = send_msg(entry, cfd, SM_CMD_AUTH_REP,
&msg,
(pack_size_func)
sec_auth_reply_msg__get_packed_size,
@@ -138,7 +145,7 @@ int send_sec_auth_reply(sec_mod_st * sec, client_entry_st * entry, AUTHREP r)
} else {
msg.reply = AUTH__REP__FAILED;
ret = send_msg(entry, sec->fd, SM_CMD_AUTH_REP,
ret = send_msg(entry, cfd, SM_CMD_AUTH_REP,
&msg,
(pack_size_func)
sec_auth_reply_msg__get_packed_size,
@@ -155,7 +162,7 @@ int send_sec_auth_reply(sec_mod_st * sec, client_entry_st * entry, AUTHREP r)
}
static
int send_sec_auth_reply_msg(sec_mod_st * sec, client_entry_st * e)
int send_sec_auth_reply_msg(int cfd, sec_mod_st * sec, client_entry_st * e)
{
SecAuthReplyMsg msg = SEC_AUTH_REPLY_MSG__INIT;
char tmp[MAX_MSG_SIZE] = "";
@@ -176,7 +183,7 @@ int send_sec_auth_reply_msg(sec_mod_st * sec, client_entry_st * e)
msg.sid.data = e->sid;
msg.sid.len = sizeof(e->sid);
ret = send_msg(e, sec->fd, SM_CMD_AUTH_REP, &msg,
ret = send_msg(e, cfd, SM_CMD_AUTH_REP, &msg,
(pack_size_func) sec_auth_reply_msg__get_packed_size,
(pack_func) sec_auth_reply_msg__pack);
if (ret < 0) {
@@ -256,12 +263,12 @@ static int check_user_group_status(sec_mod_st * sec, client_entry_st * e,
* @result: the auth result
*/
static
int handle_sec_auth_res(sec_mod_st * sec, client_entry_st * e, int result)
int handle_sec_auth_res(int cfd, sec_mod_st * sec, client_entry_st * e, int result)
{
int ret;
if (result == ERR_AUTH_CONTINUE) {
ret = send_sec_auth_reply_msg(sec, e);
ret = send_sec_auth_reply_msg(cfd, sec, e);
if (ret < 0) {
e->status = PS_AUTH_FAILED;
seclog(sec, LOG_ERR, "could not send reply auth cmd.");
@@ -271,7 +278,7 @@ int handle_sec_auth_res(sec_mod_st * sec, client_entry_st * e, int result)
} else if (result == 0) {
e->status = PS_AUTH_COMPLETED;
ret = send_sec_auth_reply(sec, e, AUTH__REP__OK);
ret = send_sec_auth_reply(cfd, sec, e, AUTH__REP__OK);
if (ret < 0) {
e->status = PS_AUTH_FAILED;
seclog(sec, LOG_ERR, "could not send reply auth cmd.");
@@ -279,14 +286,11 @@ int handle_sec_auth_res(sec_mod_st * sec, client_entry_st * e, int result)
}
ret = 0;
if (module != NULL && (sec->config->session_control == 0 || module->open_session == NULL)) {
del_client_entry(sec, e);
} /* else do nothing, and wait for session close/open messages */
} else {
e->status = PS_AUTH_FAILED;
add_ip_to_ban_list(sec, e->ip, time(0) + sec->config->min_reauth_time);
ret = send_sec_auth_reply(sec, e, AUTH__REP__FAILED);
ret = send_sec_auth_reply(cfd, sec, e, AUTH__REP__FAILED);
if (ret < 0) {
seclog(sec, LOG_ERR, "could not send reply auth cmd.");
return ret;
@@ -305,19 +309,13 @@ int handle_sec_auth_res(sec_mod_st * sec, client_entry_st * e, int result)
/* opens or closes a session.
*/
int handle_sec_auth_session_cmd(sec_mod_st * sec, const SecAuthSessionMsg * req, unsigned cmd)
int handle_sec_auth_session_cmd(int cfd, sec_mod_st * sec, const SecAuthSessionMsg * req,
unsigned cmd)
{
client_entry_st *e;
void *lpool;
int ret;
if (module == NULL || module->open_session == NULL)
return 0;
if (sec->config->session_control == 0) {
seclog(sec, LOG_ERR, "auth session open/close but session control is disabled!");
return 0;
}
if (req->sid.len != SID_SIZE) {
seclog(sec, LOG_ERR, "auth session open/close but with illegal sid size (%d)!",
(int)req->sid.len);
@@ -331,14 +329,44 @@ int handle_sec_auth_session_cmd(sec_mod_st * sec, const SecAuthSessionMsg * req,
}
if (cmd == SM_CMD_AUTH_SESSION_OPEN) {
ret = module->open_session(e->auth_ctx);
if (ret < 0) {
e->status = PS_AUTH_FAILED;
seclog(sec, LOG_ERR, "could not open session.");
del_client_entry(sec, e);
return ret;
SecAuthSessionReplyMsg rep = SEC_AUTH_SESSION_REPLY_MSG__INIT;
if (module != NULL && module->open_session != NULL) {
ret = module->open_session(e->auth_ctx, req->sid.data, req->sid.len);
if (ret < 0) {
e->status = PS_AUTH_FAILED;
seclog(sec, LOG_ERR, "could not open session.");
del_client_entry(sec, e);
rep.reply = AUTH__REP__FAILED;
} else {
e->have_session = 1;
rep.reply = AUTH__REP__OK;
}
} else {
rep.reply = AUTH__REP__OK;
}
e->have_session = 1;
lpool = talloc_new(e);
if (lpool == NULL) {
return ERR_MEM;
}
if (sec->config_module && sec->config_module->get_sup_config) {
ret = sec->config_module->get_sup_config(sec->config, e, &rep, lpool);
if (ret < 0) {
seclog(sec, LOG_ERR, "error reading additional configuration for '%s'", e->username);
talloc_free(lpool);
return ERR_READ_CONFIG;
}
}
ret = send_msg(lpool, cfd, SM_CMD_AUTH_SESSION_REPLY, &rep,
(pack_size_func) sec_auth_session_reply_msg__get_packed_size,
(pack_func) sec_auth_session_reply_msg__pack);
if (ret < 0) {
seclog(sec, LOG_WARNING, "sec-mod error in sending session reply");
}
talloc_free(lpool);
} else {
del_client_entry(sec, e);
}
@@ -346,7 +374,38 @@ int handle_sec_auth_session_cmd(sec_mod_st * sec, const SecAuthSessionMsg * req,
return 0;
}
int handle_sec_auth_cont(sec_mod_st * sec, const SecAuthContMsg * req)
int handle_sec_auth_stats_cmd(sec_mod_st * sec, const CliStatsMsg * req)
{
client_entry_st *e;
if (req->sid.len != SID_SIZE) {
seclog(sec, LOG_ERR, "auth session open/close but with illegal sid size (%d)!",
(int)req->sid.len);
return -1;
}
e = find_client_entry(sec, req->sid.data);
if (e == NULL) {
seclog(sec, LOG_INFO, "session open/close but with non-existing sid!");
return -1;
}
if (e->status != PS_AUTH_COMPLETED) {
seclog(sec, LOG_ERR, "session stats received in unauthenticated client!");
return -1;
}
e->bytes_in = req->bytes_in;
e->bytes_out = req->bytes_out;
if (module == NULL || module->session_stats == NULL)
return 0;
module->session_stats(e->auth_ctx, e->bytes_in, e->bytes_out);
return 0;
}
int handle_sec_auth_cont(int cfd, sec_mod_st * sec, const SecAuthContMsg * req)
{
client_entry_st *e;
int ret;
@@ -391,10 +450,10 @@ int handle_sec_auth_cont(sec_mod_st * sec, const SecAuthContMsg * req)
e->username);
}
return handle_sec_auth_res(sec, e, ret);
return handle_sec_auth_res(cfd, sec, e, ret);
}
int handle_sec_auth_init(sec_mod_st * sec, const SecAuthInitMsg * req)
int handle_sec_auth_init(int cfd, sec_mod_st * sec, const SecAuthInitMsg * req)
{
int ret = -1;
client_entry_st *e;
@@ -488,7 +547,7 @@ int handle_sec_auth_init(sec_mod_st * sec, const SecAuthInitMsg * req)
ret = 0;
cleanup:
return handle_sec_auth_res(sec, e, ret);
return handle_sec_auth_res(cfd, sec, e, ret);
}
void sec_auth_user_deinit(sec_mod_st * sec, client_entry_st * e)

View File

@@ -28,13 +28,16 @@
struct auth_mod_st {
unsigned int type;
void (*global_init)(void *pool, void* additional);
void (*global_deinit)(void);
int (*auth_init)(void** ctx, void *pool, const char* username, const char* ip, void* additional);
int (*auth_msg)(void* ctx, char* msg, size_t msg_size);
int (*auth_pass)(void* ctx, const char* pass, unsigned pass_len);
int (*auth_group)(void* ctx, const char *suggested, char *groupname, int groupname_size);
int (*auth_user)(void* ctx, char *groupname, int groupname_size);
int (*open_session)(void *ctx); /* optional, may be null */
int (*open_session)(void *ctx, const void *sid, unsigned sid_size); /* optional, may be null */
void (*session_stats)(void *ctx, uint64_t bytes_in, uint64_t bytes_out); /* optional, may be null */
void (*close_session)(void *ctx); /* optional */
void (*auth_deinit)(void* ctx);

View File

@@ -27,11 +27,16 @@
#include <main.h>
#include <common.h>
#include <vpn.h>
#include <main-sup-config.h>
#include <sec-mod-sup-config.h>
#include <sup-config/file.h>
#include <sup-config/radius.h>
void sup_config_init(main_server_st *s)
void sup_config_init(sec_mod_st *sec)
{
s->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

@@ -21,16 +21,19 @@
#ifndef SUP_CONFIG_H
# define SUP_CONFIG_H
#include <main.h>
#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.
*/
struct config_mod_st {
int (*get_sup_config)(struct cfg_st *global_config, struct proc_st *proc);
void (*clear_sup_config)(struct group_cfg_st *out);
int (*get_sup_config)(struct cfg_st *global_config, client_entry_st *entry,
SecAuthSessionReplyMsg *msg, void *pool);
};
void sup_config_init(main_server_st *s);
void sup_config_init(sec_mod_st *sec);
#endif

View File

@@ -40,6 +40,7 @@
#include <sec-mod.h>
#include <tlslib.h>
#include <ipc.pb-c.h>
#include <sec-mod-sup-config.h>
#include <gnutls/gnutls.h>
#include <gnutls/abstract.h>
@@ -166,7 +167,7 @@ int load_pins(struct cfg_st *config, struct pin_st *s)
return 0;
}
static int handle_op(void *pool, sec_mod_st * sec, uint8_t type, uint8_t * rep,
static int handle_op(void *pool, int cfd, sec_mod_st * sec, uint8_t type, uint8_t * rep,
size_t rep_size)
{
SecOpMsg msg = SEC_OP_MSG__INIT;
@@ -175,7 +176,7 @@ static int handle_op(void *pool, sec_mod_st * sec, uint8_t type, uint8_t * rep,
msg.data.data = rep;
msg.data.len = rep_size;
ret = send_msg(pool, sec->fd, type, &msg,
ret = send_msg(pool, cfd, type, &msg,
(pack_size_func) sec_op_msg__get_packed_size,
(pack_func) sec_op_msg__pack);
if (ret < 0) {
@@ -186,7 +187,7 @@ static int handle_op(void *pool, sec_mod_st * sec, uint8_t type, uint8_t * rep,
}
static
int process_packet(void *pool, sec_mod_st * sec, cmd_request_t cmd,
int process_packet(void *pool, int cfd, sec_mod_st * sec, cmd_request_t cmd,
uid_t uid, uint8_t * buffer, size_t buffer_size)
{
unsigned i;
@@ -243,11 +244,27 @@ int process_packet(void *pool, sec_mod_st * sec, cmd_request_t cmd,
return -1;
}
ret = handle_op(pool, sec, cmd, out.data, out.size);
ret = handle_op(pool, cfd, sec, cmd, out.data, out.size);
gnutls_free(out.data);
return ret;
case SM_CMD_CLI_STATS:{
CliStatsMsg *tmsg;
tmsg = cli_stats_msg__unpack(&pa, data.size, data.data);
if (tmsg == NULL) {
seclog(sec, LOG_ERR, "error unpacking data");
ret = ERR_BAD_COMMAND;
return -1;
}
ret = handle_sec_auth_stats_cmd(sec, tmsg);
cli_stats_msg__free_unpacked(tmsg, &pa);
return ret;
}
break;
case SM_CMD_AUTH_INIT:{
SecAuthInitMsg *auth_init;
@@ -259,7 +276,7 @@ int process_packet(void *pool, sec_mod_st * sec, cmd_request_t cmd,
return -1;
}
ret = handle_sec_auth_init(sec, auth_init);
ret = handle_sec_auth_init(cfd, sec, auth_init);
sec_auth_init_msg__free_unpacked(auth_init, &pa);
return ret;
}
@@ -274,14 +291,13 @@ int process_packet(void *pool, sec_mod_st * sec, cmd_request_t cmd,
return -1;
}
ret = handle_sec_auth_cont(sec, auth_cont);
ret = handle_sec_auth_cont(cfd, sec, auth_cont);
sec_auth_cont_msg__free_unpacked(auth_cont, &pa);
return ret;
}
case SM_CMD_AUTH_SESSION_OPEN:
case SM_CMD_AUTH_SESSION_CLOSE:{
SecAuthSessionMsg *msg;
SecAuthSessionReplyMsg rep = SEC_AUTH_SESSION_REPLY_MSG__INIT;
if (uid != 0) {
seclog(sec, LOG_INFO, "received session open/close from unauthorized uid (%u)\n", (unsigned)uid);
@@ -296,23 +312,9 @@ int process_packet(void *pool, sec_mod_st * sec, cmd_request_t cmd,
return -1;
}
ret = handle_sec_auth_session_cmd(sec, msg, cmd);
ret = handle_sec_auth_session_cmd(cfd, sec, msg, cmd);
sec_auth_session_msg__free_unpacked(msg, &pa);
if (cmd == SM_CMD_AUTH_SESSION_OPEN) {
if (ret < 0)
rep.reply = AUTH__REP__FAILED;
else
rep.reply = AUTH__REP__OK;
ret = send_msg(pool, sec->fd, SM_CMD_AUTH_SESSION_REPLY, &rep,
(pack_size_func) sec_auth_session_reply_msg__get_packed_size,
(pack_func) sec_auth_session_reply_msg__pack);
if (ret < 0) {
seclog(sec, LOG_WARNING, "sec-mod error in sending session reply");
}
}
return ret;
}
default:
@@ -356,6 +358,7 @@ static void check_other_work(sec_mod_st *sec)
if (need_reload) {
seclog(sec, LOG_DEBUG, "reloading configuration");
reload_cfg_file(sec, sec->config);
sec_auth_reinit(sec, sec->config);
need_reload = 0;
}
@@ -371,6 +374,54 @@ static void check_other_work(sec_mod_st *sec)
}
}
static
void serve_request(sec_mod_st *sec, uid_t uid, int cfd, uint8_t *buffer, unsigned buffer_size)
{
int ret, e;
unsigned cmd, length;
uint16_t l16;
void *pool = buffer;
/* read request */
ret = force_read_timeout(cfd, buffer, 3, MAX_WAIT_SECS);
if (ret == 0)
goto leave;
else if (ret < 3) {
e = errno;
seclog(sec, LOG_INFO, "error receiving msg head: %s",
strerror(e));
goto leave;
}
cmd = buffer[0];
memcpy(&l16, &buffer[1], 2);
length = l16;
if (length > buffer_size - 4) {
seclog(sec, LOG_INFO, "too big message (%d)", length);
goto leave;
}
/* read the body */
ret = force_read_timeout(cfd, buffer, length, MAX_WAIT_SECS);
if (ret < 0) {
e = errno;
seclog(sec, LOG_INFO, "error receiving msg body: %s",
strerror(e));
goto leave;
}
ret = process_packet(pool, cfd, sec, cmd, uid, buffer, ret);
if (ret < 0) {
seclog(sec, LOG_INFO, "error processing data for '%s' command (%d)", cmd_request_to_str(cmd), ret);
}
leave:
talloc_free(pool);
close(cfd);
return;
}
/* sec_mod_server:
* @config: server configuration
* @socket_file: the name of the socket
@@ -404,11 +455,9 @@ void sec_mod_server(void *main_pool, struct cfg_st *config, const char *socket_f
struct sockaddr_un sa;
socklen_t sa_len;
int cfd, ret, e;
unsigned cmd, length;
unsigned i, buffer_size;
uid_t uid;
uint8_t *buffer, *tpool;
uint16_t l16;
uint8_t *buffer;
struct pin_st pins;
int sd;
sec_mod_st *sec;
@@ -435,6 +484,8 @@ void sec_mod_server(void *main_pool, struct cfg_st *config, const char *socket_f
sec->dcookie_key.size = COOKIE_KEY_SIZE;
sec->config = talloc_steal(sec, config);
sup_config_init(sec);
memset(&sa, 0, sizeof(sa));
sa.sun_family = AF_UNIX;
snprintf(sa.sun_path, sizeof(sa.sun_path), "%s", socket_file);
@@ -452,7 +503,7 @@ void sec_mod_server(void *main_pool, struct cfg_st *config, const char *socket_f
alarm(MAINTAINANCE_TIME);
sec_auth_init(config);
sec_auth_init(sec, config);
#ifdef HAVE_PKCS11
ret = gnutls_pkcs11_reinit();
@@ -470,13 +521,6 @@ void sec_mod_server(void *main_pool, struct cfg_st *config, const char *socket_f
if (config->min_reauth_time > 0)
sec_mod_ban_db_init(sec);
buffer_size = 8 * 1024;
buffer = talloc_size(sec, buffer_size);
if (buffer == NULL) {
seclog(sec, LOG_ERR, "error in memory allocation");
exit(1);
}
sd = socket(AF_UNIX, SOCK_STREAM, 0);
if (sd == -1) {
@@ -578,50 +622,18 @@ void sec_mod_server(void *main_pool, struct cfg_st *config, const char *socket_f
ret = check_upeer_id("sec-mod", cfd, config->uid, config->gid, &uid);
if (ret < 0) {
seclog(sec, LOG_INFO, "rejected unauthorized connection");
goto cont;
} else {
buffer_size = 8 * 1024;
buffer = talloc_size(sec, buffer_size);
if (buffer == NULL) {
seclog(sec, LOG_ERR, "error in memory allocation");
close(cfd);
} else {
serve_request(sec, uid, cfd, buffer, buffer_size);
}
}
/* read request */
ret = force_read_timeout(cfd, buffer, 3, MAX_WAIT_SECS);
if (ret == 0)
goto cont;
else if (ret < 3) {
e = errno;
seclog(sec, LOG_INFO, "error receiving msg head: %s",
strerror(e));
goto cont;
}
cmd = buffer[0];
memcpy(&l16, &buffer[1], 2);
length = l16;
if (length > buffer_size - 4) {
seclog(sec, LOG_INFO, "too big message (%d)", length);
goto cont;
}
/* read the body */
ret = force_read_timeout(cfd, buffer, length, MAX_WAIT_SECS);
if (ret < 0) {
e = errno;
seclog(sec, LOG_INFO, "error receiving msg body: %s",
strerror(e));
goto cont;
}
tpool = talloc_new(sec);
sec->fd = cfd;
ret = process_packet(tpool, sec, cmd, uid, buffer, ret);
if (ret < 0) {
seclog(sec, LOG_INFO, "error processing data for '%s' command (%d)", cmd_request_to_str(cmd), ret);
}
talloc_free(tpool);
#ifdef DEBUG_LEAKS
talloc_report_full(sec, stderr);
#endif
cont:
close(cfd);
}
}

View File

@@ -19,6 +19,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>
*/
#ifndef SEC_MOD_H
# define SEC_MOD_H
#include <cookies.h>
#include <gnutls/abstract.h>
@@ -34,7 +35,7 @@ typedef struct sec_mod_st {
struct htable *client_db;
struct htable *ban_db;
int fd;
struct config_mod_st *config_module;
} sec_mod_st;
@@ -49,6 +50,11 @@ typedef struct client_entry_st {
unsigned have_session; /* whether an auth session is initialized */
unsigned tls_auth_ok;
/* these are filled in after the worker process dies, using the
* Cli stats message. */
uint64_t bytes_in;
uint64_t bytes_out;
unsigned status; /* PS_AUTH_ */
char ip[MAX_IP_STR]; /* the user's IP */
@@ -83,11 +89,13 @@ void cleanup_client_entries(sec_mod_st *sec);
}
#endif
void sec_auth_init(struct cfg_st *config);
void sec_auth_init(sec_mod_st *sec, struct cfg_st *config);
void sec_auth_reinit(sec_mod_st *sec, struct cfg_st *config);
int handle_sec_auth_init(sec_mod_st *sec, const SecAuthInitMsg * req);
int handle_sec_auth_cont(sec_mod_st *sec, const SecAuthContMsg * req);
int handle_sec_auth_session_cmd(sec_mod_st * sec, const SecAuthSessionMsg * req, unsigned cmd);
int handle_sec_auth_init(int cfd, sec_mod_st *sec, const SecAuthInitMsg * req);
int handle_sec_auth_cont(int cfd, sec_mod_st *sec, const SecAuthContMsg * req);
int handle_sec_auth_session_cmd(int cfd, sec_mod_st *sec, const SecAuthSessionMsg *req, unsigned cmd);
int handle_sec_auth_stats_cmd(sec_mod_st * sec, const CliStatsMsg * req);
void sec_auth_user_deinit(sec_mod_st * sec, client_entry_st * e);
void sec_mod_server(void *main_pool, struct cfg_st *config, const char *socket_file,

View File

@@ -1,5 +1,6 @@
/*
* Copyright (C) 2013 Nikos Mavrogiannopoulos
* 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
@@ -33,7 +34,7 @@
#include <vpn.h>
#include <main.h>
#include <main-sup-config.h>
#include <sec-mod-sup-config.h>
struct cfg_options {
const char* name;
@@ -68,14 +69,14 @@ static struct cfg_options available_options[] = {
if (val != NULL && val->valType == OPARG_TYPE_STRING) { \
if (s_name == NULL) { \
num = 0; \
s_name = talloc_size(proc, sizeof(char*)*MAX_CONFIG_ENTRIES); \
s_name = talloc_size(pool, sizeof(char*)*MAX_CONFIG_ENTRIES); \
} \
do { \
if (num >= MAX_CONFIG_ENTRIES) \
break; \
if (val && !strcmp(val->pzName, name)==0) \
continue; \
s_name[num] = talloc_strdup(proc, val->v.strVal); \
s_name[num] = talloc_strdup(pool, val->v.strVal); \
num++; \
} while((val = optionNextValue(pov, val)) != NULL); \
s_name[num] = NULL; \
@@ -86,28 +87,33 @@ static struct cfg_options available_options[] = {
if (val != NULL && val->valType == OPARG_TYPE_STRING) { \
if (s_name != NULL) \
talloc_free(s_name); \
s_name = talloc_strdup(proc, val->v.strVal); \
s_name = talloc_strdup(pool, val->v.strVal); \
}}
#define READ_RAW_NUMERIC(name, s_name) { \
#define READ_RAW_NUMERIC(name, s_name, def) { \
val = optionGetValue(pov, name); \
if (val != NULL) { \
if (val->valType == OPARG_TYPE_NUMERIC) \
if (val->valType == OPARG_TYPE_NUMERIC) {\
s_name = val->v.longVal; \
else if (val->valType == OPARG_TYPE_STRING) \
def = 1; \
} else if (val->valType == OPARG_TYPE_STRING) {\
s_name = atoi(val->v.strVal); \
def = 1; \
} \
}}
#define READ_RAW_PRIO_TOS(name, s_name) { \
#define READ_RAW_PRIO_TOS(name, s_name, def) { \
val = optionGetValue(pov, name); \
if (val != NULL) { \
if (val->valType == OPARG_TYPE_STRING) { \
if (strncmp(val->v.strVal, "0x", 2) == 0) { \
s_name = strtol(val->v.strVal, NULL, 16); \
s_name = TOS_PACK(s_name); \
def = 1; \
} else { \
s_name = atoi(val->v.strVal); \
s_name++; \
def = 1; \
} \
} \
}}
@@ -115,12 +121,13 @@ static struct cfg_options available_options[] = {
#define READ_TF(name, s_name, def) { \
{ char* tmp_tf = NULL; \
READ_RAW_STRING(name, tmp_tf); \
if (tmp_tf == NULL) s_name = def; \
else { \
if (tmp_tf == NULL) { def = 0; \
} else { \
if (c_strcasecmp(tmp_tf, "true") == 0 || c_strcasecmp(tmp_tf, "yes") == 0) \
s_name = 1; \
else \
s_name = 0; \
def = 1; \
} \
talloc_free(tmp_tf); \
}}
@@ -143,13 +150,13 @@ unsigned j;
* already allocated using this function.
*/
static
int parse_group_cfg_file(struct cfg_st *global_config, struct proc_st *proc,
int parse_group_cfg_file(struct cfg_st *global_config,
SecAuthSessionReplyMsg *msg, void *pool,
const char* file)
{
tOptionValue const * pov;
const tOptionValue* val, *prev;
unsigned prefix = 0;
struct group_cfg_st *sconfig = &proc->config;
pov = configFileLoad(file);
if (pov == NULL) {
@@ -171,60 +178,58 @@ struct group_cfg_st *sconfig = &proc->config;
prev = val;
} while((val = optionNextValue(pov, prev)) != NULL);
READ_TF("no-udp", sconfig->no_udp, (global_config->udp_port!=0)?0:1);
READ_TF("deny-roaming", sconfig->deny_roaming, global_config->deny_roaming);
READ_TF("require-cert", sconfig->require_cert, 0);
READ_TF("no-udp", msg->no_udp, msg->has_no_udp);
READ_TF("deny-roaming", msg->deny_roaming, msg->has_deny_roaming);
READ_TF("require-cert", msg->require_cert, msg->has_require_cert);
READ_RAW_MULTI_LINE("route", sconfig->routes, sconfig->routes_size);
READ_RAW_MULTI_LINE("iroute", sconfig->iroutes, sconfig->iroutes_size);
READ_RAW_MULTI_LINE("route", msg->routes, msg->n_routes);
READ_RAW_MULTI_LINE("iroute", msg->iroutes, msg->n_iroutes);
READ_RAW_MULTI_LINE("dns", sconfig->dns, sconfig->dns_size);
if (sconfig->dns_size == 0) {
READ_RAW_MULTI_LINE("dns", msg->dns, msg->n_dns);
if (msg->n_dns == 0) {
/* try aliases */
READ_RAW_MULTI_LINE("ipv6-dns", sconfig->dns, sconfig->dns_size);
READ_RAW_MULTI_LINE("ipv4-dns", sconfig->dns, sconfig->dns_size);
READ_RAW_MULTI_LINE("ipv6-dns", msg->dns, msg->n_dns);
READ_RAW_MULTI_LINE("ipv4-dns", msg->dns, msg->n_dns);
}
READ_RAW_MULTI_LINE("nbns", sconfig->nbns, sconfig->nbns_size);
if (sconfig->nbns_size == 0) {
READ_RAW_MULTI_LINE("nbns", msg->nbns, msg->n_nbns);
if (msg->n_nbns == 0) {
/* try aliases */
READ_RAW_MULTI_LINE("ipv6-nbns", sconfig->nbns, sconfig->nbns_size);
READ_RAW_MULTI_LINE("ipv4-nbns", sconfig->nbns, sconfig->nbns_size);
READ_RAW_MULTI_LINE("ipv6-nbns", msg->nbns, msg->n_nbns);
READ_RAW_MULTI_LINE("ipv4-nbns", msg->nbns, msg->n_nbns);
}
READ_RAW_STRING("cgroup", sconfig->cgroup);
READ_RAW_STRING("ipv4-network", sconfig->ipv4_network);
READ_RAW_STRING("ipv6-network", sconfig->ipv6_network);
READ_RAW_STRING("ipv4-netmask", sconfig->ipv4_netmask);
READ_RAW_STRING("cgroup", msg->cgroup);
READ_RAW_STRING("ipv4-network", msg->ipv4_net);
READ_RAW_STRING("ipv6-network", msg->ipv6_net);
READ_RAW_STRING("ipv4-netmask", msg->ipv4_netmask);
READ_RAW_NUMERIC("ipv6-prefix", prefix);
if (prefix > 0) {
sconfig->ipv6_netmask = ipv6_prefix_to_mask(proc, prefix);
sconfig->ipv6_prefix = prefix;
if (sconfig->ipv6_netmask == NULL) {
READ_RAW_NUMERIC("ipv6-prefix", msg->ipv6_prefix, msg->has_ipv6_prefix);
if (msg->has_ipv6_prefix != 0) {
if (valid_ipv6_prefix(msg->ipv6_prefix) == 0) {
syslog(LOG_ERR, "unknown ipv6-prefix '%u' in %s", prefix, file);
}
}
READ_RAW_NUMERIC("rx-data-per-sec", sconfig->rx_per_sec);
READ_RAW_NUMERIC("tx-data-per-sec", sconfig->tx_per_sec);
sconfig->rx_per_sec /= 1000; /* in kb */
sconfig->tx_per_sec /= 1000; /* in kb */
READ_RAW_NUMERIC("rx-data-per-sec", msg->rx_per_sec, msg->has_rx_per_sec);
READ_RAW_NUMERIC("tx-data-per-sec", msg->tx_per_sec, msg->has_tx_per_sec);
msg->rx_per_sec /= 1000; /* in kb */
msg->tx_per_sec /= 1000; /* in kb */
/* net-priority will contain the actual priority + 1,
* to allow having zero as uninitialized. */
READ_RAW_PRIO_TOS("net-priority", sconfig->net_priority);
READ_RAW_PRIO_TOS("net-priority", msg->net_priority, msg->has_net_priority);
READ_RAW_STRING("user-profile", sconfig->xml_config_file);
READ_RAW_STRING("user-profile", msg->xml_config_file);
optionUnloadNested(pov);
return 0;
}
static int read_sup_config_file(struct cfg_st *global_config, struct proc_st *proc,
const char *file, const char *fallback, const char *type)
static int read_sup_config_file(struct cfg_st *global_config,
SecAuthSessionReplyMsg *msg, void *pool,
const char *file, const char *fallback, const char *type)
{
int ret;
@@ -232,44 +237,41 @@ static int read_sup_config_file(struct cfg_st *global_config, struct proc_st *pr
syslog(LOG_DEBUG, "Loading %s configuration '%s'", type,
file);
ret = parse_group_cfg_file(global_config, proc, file);
ret = parse_group_cfg_file(global_config, msg, pool, file);
if (ret < 0)
return ERR_READ_CONFIG;
} else {
if (fallback != NULL) {
syslog(LOG_DEBUG, "Loading default %s configuration '%s'", type, fallback);
ret = parse_group_cfg_file(global_config, proc, fallback);
ret = parse_group_cfg_file(global_config, msg, pool, fallback);
if (ret < 0)
return ERR_READ_CONFIG;
} else {
syslog(LOG_DEBUG, "No %s configuration for '%s'", type,
proc->username);
}
}
return 0;
}
static int get_sup_config(struct cfg_st *global_config, struct proc_st *proc)
static int get_sup_config(struct cfg_st *cfg, client_entry_st *entry,
SecAuthSessionReplyMsg *msg, void *pool)
{
char file[_POSIX_PATH_MAX];
int ret;
if (global_config->per_group_dir != NULL && proc->groupname[0] != 0) {
snprintf(file, sizeof(file), "%s/%s", global_config->per_group_dir,
proc->groupname);
if (cfg->per_group_dir != NULL && entry->groupname[0] != 0) {
snprintf(file, sizeof(file), "%s/%s", cfg->per_group_dir,
entry->groupname);
ret = read_sup_config_file(global_config, proc, file, global_config->default_group_conf, "group");
ret = read_sup_config_file(cfg, msg, pool, file, cfg->default_group_conf, "group");
if (ret < 0)
return ret;
}
if (global_config->per_user_dir != NULL) {
snprintf(file, sizeof(file), "%s/%s", global_config->per_user_dir,
proc->username);
ret = read_sup_config_file(global_config, proc, file, global_config->default_user_conf, "user");
if (cfg->per_user_dir != NULL) {
snprintf(file, sizeof(file), "%s/%s", cfg->per_user_dir,
entry->username);
ret = read_sup_config_file(cfg, msg, pool, file, cfg->default_user_conf, "user");
if (ret < 0)
return ret;
}
@@ -277,41 +279,6 @@ static int get_sup_config(struct cfg_st *global_config, struct proc_st *proc)
return 0;
}
static
void clear_sup_config(struct group_cfg_st* config)
{
unsigned i;
for(i=0;i<config->routes_size;i++) {
talloc_free(config->routes[i]);
}
talloc_free(config->routes);
for(i=0;i<config->iroutes_size;i++) {
talloc_free(config->iroutes[i]);
}
talloc_free(config->iroutes);
for(i=0;i<config->dns_size;i++) {
talloc_free(config->dns[i]);
}
talloc_free(config->dns);
for(i=0;i<config->nbns_size;i++) {
talloc_free(config->nbns[i]);
}
talloc_free(config->nbns);
talloc_free(config->cgroup);
talloc_free(config->ipv4_network);
talloc_free(config->ipv6_network);
talloc_free(config->ipv4_netmask);
talloc_free(config->ipv6_netmask);
safe_memset(config, 0, sizeof(*config));
}
struct config_mod_st file_sup_config = {
.get_sup_config = get_sup_config,
.clear_sup_config = clear_sup_config,
};

View File

@@ -21,7 +21,7 @@
#ifndef SUP_CONFIG_FILE_H
#define SUP_CONFIG_FILE_H
#include <main-sup-config.h>
#include <sec-mod-sup-config.h>
extern struct config_mod_st file_sup_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

@@ -76,6 +76,7 @@ extern int syslog_open;
#define AUTH_TYPE_PLAIN (1<<2 | AUTH_TYPE_USERNAME_PASS)
#define AUTH_TYPE_CERTIFICATE (1<<3)
#define AUTH_TYPE_CERTIFICATE_OPT (1<<4|AUTH_TYPE_CERTIFICATE)
#define AUTH_TYPE_RADIUS (1<<5 | AUTH_TYPE_USERNAME_PASS)
#define ERR_SUCCESS 0
#define ERR_BAD_COMMAND -2
@@ -122,6 +123,7 @@ typedef enum {
SM_CMD_AUTH_SESSION_OPEN,
SM_CMD_AUTH_SESSION_CLOSE,
SM_CMD_AUTH_SESSION_REPLY,
SM_CMD_CLI_STATS,
} cmd_request_t;
#define MAX_IP_STR 46
@@ -145,8 +147,10 @@ struct group_cfg_st {
char *ipv6_network;
unsigned ipv6_prefix;
char *ipv4_netmask;
char *ipv6_netmask;
char *explicit_ipv4;
char *explicit_ipv6;
char *cgroup;
char *xml_config_file;
@@ -166,7 +170,6 @@ struct vpn_st {
char *ipv4_network;
char *ipv4;
char *ipv4_local; /* local IPv4 address */
char *ipv6_netmask;
char *ipv6_network;
unsigned ipv6_prefix;
@@ -190,6 +193,8 @@ struct cfg_st {
unsigned int udp_port;
unsigned int is_dyndns;
char* unix_conn_file;
unsigned int sup_config_type; /* one of SUP_CONFIG_ */
unsigned int stats_report_time;
char *pin_file;
char *srk_pin_file;
@@ -204,7 +209,6 @@ struct cfg_st {
char *cert_user_oid; /* The OID that will be used to extract the username */
char *cert_group_oid; /* The OID that will be used to extract the groupname */
unsigned int auth_types; /* or'ed sequence of AUTH_TYPE */
unsigned session_control; /* whether to use the session control part of authentication (PAM) */
char *auth_additional; /* the additional string specified in the auth methode */
gnutls_certificate_request_t cert_req;
char *priorities;

View File

@@ -548,12 +548,6 @@ static int recv_cookie_auth_reply(worker_st * ws)
talloc_strdup(ws, msg->ipv4_netmask);
}
if (msg->ipv6_netmask != NULL) {
talloc_free(ws->config->network.ipv6_netmask);
ws->config->network.ipv6_netmask =
talloc_strdup(ws, msg->ipv6_netmask);
}
if (msg->ipv4_network != NULL) {
talloc_free(ws->config->network.ipv4_network);
ws->config->network.ipv4_network =
@@ -647,7 +641,7 @@ static int recv_cookie_auth_reply(worker_st * ws)
}
/* returns the fd */
static int connect_to_secmod(worker_st * ws)
int connect_to_secmod(worker_st * ws)
{
int sd, ret, e;
@@ -673,16 +667,6 @@ static int connect_to_secmod(worker_st * ws)
return sd;
}
static
int send_msg_to_secmod(worker_st * ws, int sd, uint8_t cmd,
const void *msg, pack_size_func get_size, pack_func pack)
{
oclog(ws, LOG_DEBUG, "sending message '%s' to secmod",
cmd_request_to_str(cmd));
return send_msg(ws, sd, cmd, msg, get_size, pack);
}
static int recv_auth_reply(worker_st * ws, int sd, char *txt,
size_t max_txt_size)
{

View File

@@ -227,7 +227,6 @@ int complete_vpn_info(worker_st * ws, struct vpn_st *vinfo)
vinfo->ipv6_network = ws->config->network.ipv6_network;
vinfo->ipv4_netmask = ws->config->network.ipv4_netmask;
vinfo->ipv6_netmask = ws->config->network.ipv6_netmask;
vinfo->ipv6_prefix = ws->config->network.ipv6_prefix;
if (ws->config->network.mtu != 0) {

View File

@@ -992,6 +992,34 @@ int periodic_check(worker_st * ws, unsigned mtu_overhead, time_t now,
}
if (ws->config->stats_report_time > 0 &&
now - ws->last_stats_msg >= ws->config->stats_report_time &&
ws->sid_set) {
CliStatsMsg msg = CLI_STATS_MSG__INIT;
int sd;
ws->last_stats_msg = now;
sd = connect_to_secmod(ws);
if (sd >= 0) {
msg.bytes_in = ws->tun_bytes_in;
msg.bytes_out = ws->tun_bytes_out;
msg.sid.len = sizeof(ws->sid);
msg.sid.data = ws->sid;
msg.has_sid = 1;
send_msg_to_secmod(ws, sd, SM_CMD_CLI_STATS, &msg,
(pack_size_func)cli_stats_msg__get_packed_size,
(pack_func) cli_stats_msg__pack);
close(sd);
oclog(ws, LOG_DEBUG,
"sending periodic stats (in: %lu, out: %lu) to sec-mod",
(unsigned long)msg.bytes_in,
(unsigned long)msg.bytes_out);
}
}
/* check DPD. Otherwise exit */
if (ws->udp_state == UP_ACTIVE &&
now - ws->last_msg_udp > DPD_TRIES * dpd && dpd > 0) {

View File

@@ -172,6 +172,9 @@ typedef struct worker_st {
time_t last_tls_rehandshake;
time_t last_dtls_rehandshake;
/* the time the last stats message was sent */
time_t last_stats_msg;
/* for mtu trials */
unsigned last_good_mtu;
unsigned last_bad_mtu;
@@ -274,6 +277,17 @@ int handle_worker_commands(struct worker_st *ws);
int disable_system_calls(struct worker_st *ws);
void ocsigaltstack(struct worker_st *ws);
int connect_to_secmod(worker_st * ws);
inline static
int send_msg_to_secmod(worker_st * ws, int sd, uint8_t cmd,
const void *msg, pack_size_func get_size, pack_func pack)
{
oclog(ws, LOG_DEBUG, "sending message '%s' to secmod",
cmd_request_to_str(cmd));
return send_msg(ws, sd, cmd, msg, get_size, pack);
}
inline static
int send_msg_to_main(worker_st *ws, uint8_t cmd,
const void* msg, pack_size_func get_size, pack_func pack)