Allow loading additional configuration files per user or per group.

The directives currently allowed are: ipv4/6_dns and route.
This commit is contained in:
Nikos Mavrogiannopoulos
2013-10-28 11:43:05 +01:00
parent 99e7978f99
commit 00554b2f28
18 changed files with 555 additions and 60 deletions
+7
View File
@@ -1,3 +1,10 @@
* Version 0.1.8 (unreleased)
- Added configuration directives 'config-per-user' and 'config-per-group'.
They allow loading an additional configuration client per user or per
group from the setup directory.
* Version 0.1.7 (released 2013-10-25) * Version 0.1.7 (released 2013-10-25)
- Instead of suggesting different DTLS and CSTP MTU values, suggest a single - Instead of suggesting different DTLS and CSTP MTU values, suggest a single
+6
View File
@@ -169,6 +169,12 @@ output-buffer = 10
route = 192.168.1.0/255.255.255.0 route = 192.168.1.0/255.255.255.0
#route = 192.168.5.0/255.255.255.0 #route = 192.168.5.0/255.255.255.0
# Configuration files that will be applied per user connection or
# per group. Each file name on these directories must match the username
# or the groupname.
config-per-user = /etc/ocserv/config-per-user/
config-per-group = /etc/ocserv/config-per-group/
# #
# The following options are for (experimental) AnyConnect client # The following options are for (experimental) AnyConnect client
# compatibility. # compatibility.
+1
View File
@@ -16,6 +16,7 @@ CCAN_SOURCES = ccan/build_assert/build_assert.h ccan/check_type/check_type.h \
ocserv_SOURCES = main.c main-auth.c worker-vpn.c worker-auth.c tlslib.c \ ocserv_SOURCES = main.c main-auth.c worker-vpn.c worker-auth.c tlslib.c \
http-parser/http_parser.c ipc.h cookies.c worker-tun.c main-misc.c \ http-parser/http_parser.c ipc.h cookies.c worker-tun.c main-misc.c \
main-config.c \
vpn.h cookies.h tlslib.h http-parser/http_parser.h log.c tun.c tun.h \ vpn.h cookies.h tlslib.h http-parser/http_parser.h log.c tun.c tun.h \
config.c pam.c pam.h worker-resume.c worker.h main-resume.c main.h \ config.c pam.c pam.h worker-resume.c worker.h main-resume.c main.h \
worker-extras.c main-auth.h html.c html.h \ worker-extras.c main-auth.h html.c html.h \
+22
View File
@@ -42,3 +42,25 @@ const uint8_t * p = buf;
return len; return len;
} }
ssize_t force_read(int sockfd, void *buf, size_t len)
{
int left = len;
int ret;
uint8_t * p = buf;
while(left > 0) {
ret = read(sockfd, p, left);
if (ret == -1) {
if (errno != EAGAIN && errno != EINTR)
return ret;
}
if (ret > 0) {
left -= ret;
p += ret;
}
}
return len;
}
+1
View File
@@ -1,6 +1,7 @@
#ifndef COMMON_H #ifndef COMMON_H
# define COMMON_H # define COMMON_H
ssize_t force_write(int sockfd, const void *buf, size_t len); ssize_t force_write(int sockfd, const void *buf, size_t len);
ssize_t force_read(int sockfd, void *buf, size_t len);
#endif #endif
+10 -6
View File
@@ -39,10 +39,6 @@
static const char* pid_file = NULL; static const char* pid_file = NULL;
static const char* cfg_file = DEFAULT_CFG_FILE; static const char* cfg_file = DEFAULT_CFG_FILE;
#define MAX_ENTRIES 64
enum option_types { OPTION_NUMERIC, OPTION_STRING, OPTION_BOOLEAN, OPTION_MULTI_LINE };
struct cfg_options { struct cfg_options {
const char* name; const char* name;
unsigned type; unsigned type;
@@ -102,6 +98,8 @@ static struct cfg_options available_options[] = {
{ .name = "ipv6-netmask", .type = OPTION_STRING, .mandatory = 0 }, { .name = "ipv6-netmask", .type = OPTION_STRING, .mandatory = 0 },
{ .name = "ipv6-dns", .type = OPTION_STRING, .mandatory = 0 }, { .name = "ipv6-dns", .type = OPTION_STRING, .mandatory = 0 },
{ .name = "ipv6-nbns", .type = OPTION_STRING, .mandatory = 0 }, { .name = "ipv6-nbns", .type = OPTION_STRING, .mandatory = 0 },
{ .name = "config-per-user", .type = OPTION_STRING, .mandatory = 0 },
{ .name = "config-per-group", .type = OPTION_STRING, .mandatory = 0 },
}; };
static const tOptionValue* get_option(const char* name, unsigned * mand) static const tOptionValue* get_option(const char* name, unsigned * mand)
@@ -124,13 +122,13 @@ unsigned j;
if (val != NULL && val->valType == OPARG_TYPE_STRING) { \ if (val != NULL && val->valType == OPARG_TYPE_STRING) { \
if (s_name == NULL) { \ if (s_name == NULL) { \
num = 0; \ num = 0; \
s_name = malloc(sizeof(char*)*MAX_ENTRIES); \ s_name = malloc(sizeof(char*)*MAX_CONFIG_ENTRIES); \
do { \ do { \
if (val && !strcmp(val->pzName, name)==0) \ if (val && !strcmp(val->pzName, name)==0) \
continue; \ continue; \
s_name[num] = strdup(val->v.strVal); \ s_name[num] = strdup(val->v.strVal); \
num++; \ num++; \
if (num>=MAX_ENTRIES) \ if (num>=MAX_CONFIG_ENTRIES) \
break; \ break; \
} while((val = optionNextValue(pov, val)) != NULL); \ } while((val = optionNextValue(pov, val)) != NULL); \
s_name[num] = NULL; \ s_name[num] = NULL; \
@@ -354,6 +352,9 @@ unsigned auth_size = 0;
READ_STRING("ipv6-nbns", config->network.ipv6_nbns); READ_STRING("ipv6-nbns", config->network.ipv6_nbns);
READ_MULTI_LINE("route", config->network.routes, config->network.routes_size); READ_MULTI_LINE("route", config->network.routes, config->network.routes_size);
READ_STRING("config-per-user", config->per_user_dir);
READ_STRING("config-per-group", config->per_group_dir);
optionUnloadNested(pov); optionUnloadNested(pov);
} }
@@ -480,6 +481,8 @@ unsigned i;
DEL(config->xml_config_hash); DEL(config->xml_config_hash);
DEL(config->cert_hash); DEL(config->cert_hash);
#endif #endif
DEL(config->per_user_dir);
DEL(config->per_group_dir);
DEL(config->socket_file_prefix); DEL(config->socket_file_prefix);
DEL(config->default_domain); DEL(config->default_domain);
DEL(config->plain_passwd); DEL(config->plain_passwd);
@@ -514,6 +517,7 @@ unsigned i;
DEL(config->cert[i]); DEL(config->cert[i]);
DEL(config->cert); DEL(config->cert);
DEL(config->network.routes); DEL(config->network.routes);
memset(config, 0, sizeof(*config)); memset(config, 0, sizeof(*config));
parse_cfg_file(cfg_file, config); parse_cfg_file(cfg_file, config);
+57 -25
View File
@@ -39,20 +39,9 @@ typedef enum {
REP_RESUME_FAILED = 1, REP_RESUME_FAILED = 1,
} cmd_resume_reply_t; } cmd_resume_reply_t;
/* AUTH_COOKIE_REQ */ /* AUTH_INIT:
struct __attribute__ ((__packed__)) cmd_auth_cookie_req_st { * Message sent by worker to main to initialize authentication process.
uint8_t cookie[COOKIE_SIZE]; */
uint8_t tls_auth_ok;
char cert_user[MAX_USERNAME_SIZE];
char cert_group[MAX_GROUPNAME_SIZE];
};
/* AUTH_REQ */
struct __attribute__ ((__packed__)) cmd_auth_req_st {
uint8_t pass_size;
char pass[MAX_PASSWORD_SIZE];
};
struct __attribute__ ((__packed__)) cmd_auth_init_st { struct __attribute__ ((__packed__)) cmd_auth_init_st {
uint8_t user_present; uint8_t user_present;
char user[MAX_USERNAME_SIZE]; char user[MAX_USERNAME_SIZE];
@@ -62,23 +51,62 @@ struct __attribute__ ((__packed__)) cmd_auth_init_st {
char hostname[MAX_HOSTNAME_SIZE]; char hostname[MAX_HOSTNAME_SIZE];
}; };
/* AUTH_REP */ /* AUTH_COOKIE_REQ:
struct __attribute__ ((__packed__)) cmd_auth_reply_st { * Message sent by worker to main to follow up authentication (after AUTH_INIT).
uint8_t reply; * Sent if the client tried to authenticate using cookie.
*/
struct __attribute__ ((__packed__)) cmd_auth_cookie_req_st {
uint8_t cookie[COOKIE_SIZE]; uint8_t cookie[COOKIE_SIZE];
uint8_t session_id[GNUTLS_MAX_SESSION_ID]; uint8_t tls_auth_ok;
char vname[IFNAMSIZ]; /* interface name */ char cert_user[MAX_USERNAME_SIZE];
char user[MAX_USERNAME_SIZE]; char cert_group[MAX_GROUPNAME_SIZE];
char msg[MAX_MSG_SIZE]; /* in case of REP_AUTH_CONTINUE */
}; };
/* RESUME_FETCH_REQ + RESUME_DELETE_REQ */ /* AUTH_REQ:
* Message sent by worker to main to follow up authentication (after AUTH_INIT).
* Sent if the client tried to authenticate using password.
*/
struct __attribute__ ((__packed__)) cmd_auth_req_st {
uint8_t pass_size;
char pass[MAX_PASSWORD_SIZE];
};
/* AUTH_REP:
* Message sent by main to worker to follow up authentication (after AUTH_*REQ).
* Sent if the client tried to authenticate using password.
*/
struct __attribute__ ((__packed__)) cmd_auth_reply_st {
uint8_t reply; /* REP_AUTH_OK, REP_AUTH_MSG or REP_AUTH_FAILED */
/* These fields are not filled on REP_AUTH_FAILED */
union {
struct {
uint8_t cookie[COOKIE_SIZE];
uint8_t session_id[GNUTLS_MAX_SESSION_ID];
char vname[IFNAMSIZ]; /* interface name */
char user[MAX_USERNAME_SIZE];
uint8_t routes_size; /* up to MAX_ROUTES */
/* routes_size routes of cmd_auth_reply_route_st follow */
} ok;
/* in case of REP_AUTH_MSG */
char msg[MAX_MSG_SIZE];
} data;
};
/* RESUME_FETCH_REQ + RESUME_DELETE_REQ:
* Message sent by worker to main to ask for TLS resumption data, or
* to delete such data.
*/
struct __attribute__ ((__packed__)) cmd_resume_fetch_req_st { struct __attribute__ ((__packed__)) cmd_resume_fetch_req_st {
uint8_t session_id_size; uint8_t session_id_size;
uint8_t session_id[GNUTLS_MAX_SESSION_ID]; uint8_t session_id[GNUTLS_MAX_SESSION_ID];
}; };
/* RESUME_STORE_REQ */ /* RESUME_STORE_REQ:
* Message sent by worker to main to store TLS resumption data.
*/
struct __attribute__ ((__packed__)) cmd_resume_store_req_st { struct __attribute__ ((__packed__)) cmd_resume_store_req_st {
uint8_t session_id_size; uint8_t session_id_size;
uint8_t session_id[GNUTLS_MAX_SESSION_ID]; uint8_t session_id[GNUTLS_MAX_SESSION_ID];
@@ -86,14 +114,18 @@ struct __attribute__ ((__packed__)) cmd_resume_store_req_st {
uint8_t session_data[MAX_SESSION_DATA_SIZE]; uint8_t session_data[MAX_SESSION_DATA_SIZE];
}; };
/* RESUME_FETCH_REP */ /* RESUME_FETCH_REP:
* Message sent by main to worker to return stored TLS resumption data.
*/
struct __attribute__ ((__packed__)) cmd_resume_fetch_reply_st { struct __attribute__ ((__packed__)) cmd_resume_fetch_reply_st {
uint8_t reply; uint8_t reply;
uint16_t session_data_size; uint16_t session_data_size;
uint8_t session_data[MAX_SESSION_DATA_SIZE]; uint8_t session_data[MAX_SESSION_DATA_SIZE];
}; };
/* TUN_MTU */ /* TUN_MTU:
* Message sent by worker to main to alter the MTU of the TUN device.
*/
struct __attribute__ ((__packed__)) cmd_tun_mtu_st { struct __attribute__ ((__packed__)) cmd_tun_mtu_st {
uint16_t mtu; uint16_t mtu;
}; };
+72 -8
View File
@@ -43,6 +43,7 @@
#include <ccan/list/list.h> #include <ccan/list/list.h>
#include <main-auth.h> #include <main-auth.h>
#include <plain.h> #include <plain.h>
#include <common.h>
#include <pam.h> #include <pam.h>
static const struct auth_mod_st *module; static const struct auth_mod_st *module;
@@ -61,7 +62,7 @@ void main_auth_init(main_server_st *s)
} }
int send_auth_reply(main_server_st* s, struct proc_st* proc, int send_auth_reply(main_server_st* s, struct proc_st* proc,
cmd_auth_reply_t r) cmd_auth_reply_t r, struct group_cfg_st* cfg)
{ {
struct iovec iov[2]; struct iovec iov[2];
uint8_t cmd[2]; uint8_t cmd[2];
@@ -71,7 +72,14 @@ int send_auth_reply(main_server_st* s, struct proc_st* proc,
char control[CMSG_SPACE(sizeof(int))]; char control[CMSG_SPACE(sizeof(int))];
} control_un; } control_un;
struct cmd_auth_reply_st resp; struct cmd_auth_reply_st resp;
struct cmsghdr *cmptr; struct cmsghdr *cmptr;
unsigned i;
int ret;
if (cfg->routes_size > MAX_ROUTES) {
mslog(s, proc, LOG_INFO, "Note that the routes sent to the client (%d) exceed the maximum allowed (%d). Truncating.", (int)cfg->routes_size, (int)MAX_ROUTES);
cfg->routes_size = MAX_ROUTES;
}
memset(&control_un, 0, sizeof(control_un)); memset(&control_un, 0, sizeof(control_un));
memset(&hdr, 0, sizeof(hdr)); memset(&hdr, 0, sizeof(hdr));
@@ -86,15 +94,17 @@ int send_auth_reply(main_server_st* s, struct proc_st* proc,
hdr.msg_iovlen++; hdr.msg_iovlen++;
resp.reply = r; resp.reply = r;
memcpy(resp.cookie, proc->cookie, COOKIE_SIZE); memcpy(resp.data.ok.cookie, proc->cookie, COOKIE_SIZE);
memcpy(resp.session_id, proc->session_id, sizeof(resp.session_id)); memcpy(resp.data.ok.session_id, proc->session_id, sizeof(resp.data.ok.session_id));
memcpy(resp.vname, proc->lease->name, sizeof(resp.vname)); memcpy(resp.data.ok.vname, proc->lease->name, sizeof(resp.data.ok.vname));
memcpy(resp.user, proc->username, sizeof(resp.user)); memcpy(resp.data.ok.user, proc->username, sizeof(resp.data.ok.user));
iov[1].iov_base = &resp; iov[1].iov_base = &resp;
iov[1].iov_len = sizeof(resp); iov[1].iov_len = sizeof(resp);
hdr.msg_iovlen++; hdr.msg_iovlen++;
resp.data.ok.routes_size = cfg->routes_size;
/* Send the tun fd */ /* Send the tun fd */
hdr.msg_control = control_un.control; hdr.msg_control = control_un.control;
hdr.msg_controllen = sizeof(control_un.control); hdr.msg_controllen = sizeof(control_un.control);
@@ -113,7 +123,61 @@ int send_auth_reply(main_server_st* s, struct proc_st* proc,
hdr.msg_iovlen++; hdr.msg_iovlen++;
} }
return(sendmsg(proc->fd, &hdr, 0)); ret = sendmsg(proc->fd, &hdr, 0);
if (ret < 0)
return ret;
if (r == REP_AUTH_OK) {
uint8_t len;
if (cfg->ipv4_dns) {
len = strlen(cfg->ipv4_dns);
mslog(s, proc, LOG_INFO, "sending DNS '%s' with size %d", cfg->ipv4_dns, len);
ret = force_write(proc->fd, &len, 1);
if (ret < 0)
return ret;
ret = force_write(proc->fd, cfg->ipv4_dns, len);
if (ret < 0)
return ret;
} else {
len = 0;
ret = force_write(proc->fd, &len, 1);
if (ret < 0)
return ret;
}
if (cfg->ipv6_dns) {
len = strlen(cfg->ipv6_dns);
mslog(s, proc, LOG_INFO, "sending DNS '%s' with size %d", cfg->ipv6_dns, len);
ret = force_write(proc->fd, &len, 1);
if (ret < 0)
return ret;
ret = force_write(proc->fd, cfg->ipv6_dns, len);
if (ret < 0)
return ret;
} else {
len = 0;
ret = force_write(proc->fd, &len, 1);
if (ret < 0)
return ret;
}
for (i=0;i<cfg->routes_size;i++) {
len = strlen(cfg->routes[i]);
mslog(s, proc, LOG_INFO, "sending route '%s' with size %d", cfg->routes[i], len);
ret = force_write(proc->fd, &len, 1);
if (ret < 0)
return ret;
ret = force_write(proc->fd, cfg->routes[i], len);
if (ret < 0)
return ret;
}
}
return 0;
} }
int send_auth_reply_msg(main_server_st* s, struct proc_st* proc) int send_auth_reply_msg(main_server_st* s, struct proc_st* proc)
@@ -128,7 +192,7 @@ int send_auth_reply_msg(main_server_st* s, struct proc_st* proc)
return -1; return -1;
memset(&resp, 0, sizeof(resp)); memset(&resp, 0, sizeof(resp));
ret = module->auth_msg(proc->auth_ctx, resp.msg, sizeof(resp.msg)); ret = module->auth_msg(proc->auth_ctx, resp.data.msg, sizeof(resp.data.msg));
if (ret < 0) if (ret < 0)
return ret; return ret;
+122
View File
@@ -0,0 +1,122 @@
/*
* Copyright (C) 2013 Nikos Mavrogiannopoulos
*
* 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, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#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 <c-strcase.h>
#include <vpn.h>
#include <main.h>
struct cfg_options {
const char* name;
unsigned type;
};
static struct cfg_options available_options[] = {
{ .name = "route", .type = OPTION_MULTI_LINE },
{ .name = "ipv4-dns", .type = OPTION_STRING },
{ .name = "ipv6-dns", .type = OPTION_STRING },
};
#define READ_RAW_MULTI_LINE(name, s_name, num) \
val = optionGetValue(pov, name); \
if (val != NULL && val->valType == OPARG_TYPE_STRING) { \
if (s_name == NULL) { \
num = 0; \
s_name = malloc(sizeof(char*)*MAX_CONFIG_ENTRIES); \
do { \
if (val && !strcmp(val->pzName, name)==0) \
continue; \
s_name[num] = strdup(val->v.strVal); \
num++; \
if (num>=MAX_CONFIG_ENTRIES) \
break; \
} while((val = optionNextValue(pov, val)) != NULL); \
s_name[num] = NULL; \
} \
}
#undef READ_RAW_STRING
#define READ_RAW_STRING(name, s_name) \
val = optionGetValue(pov, name); \
if (val != NULL && val->valType == OPARG_TYPE_STRING) { \
s_name = strdup(val->v.strVal); \
}
static int handle_option(const tOptionValue* val)
{
unsigned j;
for (j=0;j<sizeof(available_options)/sizeof(available_options[0]);j++) {
if (strcasecmp(val->pzName, available_options[j].name) == 0) {
return 1;
}
}
return 0;
}
int parse_group_cfg_file(main_server_st* s, const char* file, struct group_cfg_st *config)
{
tOptionValue const * pov;
const tOptionValue* val, *prev;
memset(config, 0, sizeof(*config));
pov = configFileLoad(file);
if (pov == NULL) {
mslog(s, NULL, LOG_ERR, "Error loading config file %s", file);
return ERR_READ_CONFIG;
}
val = optionGetValue(pov, NULL);
if (val == NULL) {
mslog(s, NULL, LOG_ERR, "No configuration directives found in %s", file);
return ERR_READ_CONFIG;
}
do {
if (handle_option(val) == 0) {
mslog(s, NULL, LOG_ERR, "Skipping unknown option '%s' in %s", val->pzName, file);
}
prev = val;
} while((val = optionNextValue(pov, prev)) != NULL);
READ_RAW_MULTI_LINE("route", config->routes, config->routes_size);
READ_RAW_STRING("ipv4-dns", config->ipv4_dns);
READ_RAW_STRING("ipv6-dns", config->ipv6_dns);
optionUnloadNested(pov);
return 0;
}
+109 -2
View File
@@ -112,12 +112,119 @@ int send_udp_fd(main_server_st* s, struct proc_st * proc, int fd)
return(sendmsg(proc->fd, &hdr, 0)); return(sendmsg(proc->fd, &hdr, 0));
} }
static void del_additional_config(struct group_cfg_st* config)
{
unsigned i;
for(i=0;i<config->routes_size;i++) {
free(config->routes[i]);
}
free(config->routes);
free(config->ipv4_dns);
free(config->ipv6_dns);
}
static int read_additional_config(main_server_st* s, struct proc_st* proc,
struct group_cfg_st *config)
{
struct group_cfg_st u_cfg;
struct group_cfg_st g_cfg;
char file[_POSIX_PATH_MAX];
int ret;
unsigned i;
memset(config, 0, sizeof(*config));
if (s->config->per_user_dir != NULL) {
snprintf(file, sizeof(file), "%s/%s", s->config->per_user_dir, proc->username);
if (access(file, R_OK) == 0) {
mslog(s, proc, LOG_INFO, "Loading user configuration '%s'", file);
ret = parse_group_cfg_file(s, file, &u_cfg);
if (ret < 0)
return ERR_READ_CONFIG;
if (u_cfg.routes_size > 0) {
config->routes = u_cfg.routes;
config->routes_size = u_cfg.routes_size;
u_cfg.routes = NULL;
u_cfg.routes_size = 0;
}
config->ipv4_dns = u_cfg.ipv4_dns;
u_cfg.ipv4_dns = NULL;
config->ipv6_dns = u_cfg.ipv6_dns;
u_cfg.ipv6_dns = NULL;
del_additional_config(&u_cfg);
} else
mslog(s, proc, LOG_INFO, "No user configuration for '%s'", proc->username);
}
if (s->config->per_group_dir != NULL) {
snprintf(file, sizeof(file), "%s/%s", s->config->per_group_dir, proc->groupname);
if (access(file, R_OK) == 0) {
mslog(s, proc, LOG_INFO, "Loading group configuration '%s'", file);
ret = parse_group_cfg_file(s, file, &g_cfg);
if (ret < 0)
return ERR_READ_CONFIG;
if (g_cfg.routes_size > 0) {
config->routes = realloc(config->routes, (config->routes_size+g_cfg.routes_size) * sizeof(config->routes[0]));
if (config->routes == NULL)
return ERR_MEM;
for (i=0;i<g_cfg.routes_size;i++) {
config->routes[config->routes_size] = g_cfg.routes[i];
g_cfg.routes[i] = NULL;
config->routes_size++;
}
}
if (config->ipv4_dns == NULL) {
config->ipv4_dns = g_cfg.ipv4_dns;
g_cfg.ipv4_dns = NULL;
}
if (config->ipv6_dns == NULL) {
config->ipv6_dns = g_cfg.ipv6_dns;
g_cfg.ipv6_dns = NULL;
}
del_additional_config(&g_cfg);
} else
mslog(s, proc, LOG_INFO, "No group configuration for '%s'", proc->groupname);
}
return 0;
}
int handle_script_exit(main_server_st *s, struct proc_st* proc, int code) int handle_script_exit(main_server_st *s, struct proc_st* proc, int code)
{ {
int ret; int ret;
if (code == 0) { if (code == 0) {
ret = send_auth_reply(s, proc, REP_AUTH_OK); struct group_cfg_st cfg;
ret = read_additional_config(s, proc, &cfg);
if (ret < 0) {
mslog(s, proc, LOG_ERR, "error reading additional routes");
ret = ERR_READ_ROUTES;
goto fail;
}
ret = send_auth_reply(s, proc, REP_AUTH_OK, &cfg);
del_additional_config(&cfg);
if (ret < 0) { if (ret < 0) {
mslog(s, proc, LOG_ERR, "could not send reply auth cmd."); mslog(s, proc, LOG_ERR, "could not send reply auth cmd.");
ret = ERR_BAD_COMMAND; ret = ERR_BAD_COMMAND;
@@ -125,7 +232,7 @@ int ret;
} }
} else { } else {
mslog(s, proc, LOG_INFO, "failed authentication attempt for user '%s'", proc->username); mslog(s, proc, LOG_INFO, "failed authentication attempt for user '%s'", proc->username);
ret = send_auth_reply( s, proc, REP_AUTH_FAILED); ret = send_auth_reply( s, proc, REP_AUTH_FAILED, NULL);
if (ret < 0) { if (ret < 0) {
mslog(s, proc, LOG_ERR, "could not send reply auth cmd."); mslog(s, proc, LOG_ERR, "could not send reply auth cmd.");
ret = ERR_BAD_COMMAND; ret = ERR_BAD_COMMAND;
+5 -1
View File
@@ -155,8 +155,10 @@ int open_tun(main_server_st* s, struct proc_st* proc);
int set_tun_mtu(main_server_st* s, struct proc_st * proc, unsigned mtu); int set_tun_mtu(main_server_st* s, struct proc_st * proc, unsigned mtu);
int send_auth_reply_msg(main_server_st* s, struct proc_st* proc); int send_auth_reply_msg(main_server_st* s, struct proc_st* proc);
int send_auth_reply(main_server_st* s, struct proc_st* proc, int send_auth_reply(main_server_st* s, struct proc_st* proc,
cmd_auth_reply_t r); cmd_auth_reply_t r, struct group_cfg_st*);
int handle_auth_cookie_req(main_server_st* s, struct proc_st* proc, int handle_auth_cookie_req(main_server_st* s, struct proc_st* proc,
const struct cmd_auth_cookie_req_st * req); const struct cmd_auth_cookie_req_st * req);
int generate_cookie(main_server_st *s, struct proc_st* proc); int generate_cookie(main_server_st *s, struct proc_st* proc);
@@ -175,4 +177,6 @@ int handle_script_exit(main_server_st *s, struct proc_st* proc, int code);
void run_sec_mod(main_server_st * s); void run_sec_mod(main_server_st * s);
int parse_group_cfg_file(main_server_st* s, const char* file, struct group_cfg_st *config);
#endif #endif
+4 -4
View File
@@ -2,7 +2,7 @@
* *
* DO NOT EDIT THIS FILE (ocserv-args.c) * DO NOT EDIT THIS FILE (ocserv-args.c)
* *
* It has been AutoGen-ed October 20, 2013 at 05:44:06 PM by AutoGen 5.17 * It has been AutoGen-ed October 28, 2013 at 11:41:39 AM by AutoGen 5.17
* From the definitions ocserv-args.def * From the definitions ocserv-args.def
* and the template file options * and the template file options
* *
@@ -66,7 +66,7 @@ extern FILE * option_usage_fp;
* ocserv option static const strings * ocserv option static const strings
*/ */
static char const ocserv_opt_strs[1834] = static char const ocserv_opt_strs[1834] =
/* 0 */ "ocserv 0.1.6\n" /* 0 */ "ocserv 0.1.7\n"
"Copyright (C) 2013 Nikos Mavrogiannopoulos, all rights reserved.\n" "Copyright (C) 2013 Nikos Mavrogiannopoulos, all rights reserved.\n"
"This is free software. It is licensed for use, modification and\n" "This is free software. It is licensed for use, modification and\n"
"redistribution under the terms of the\n" "redistribution under the terms of the\n"
@@ -99,7 +99,7 @@ static char const ocserv_opt_strs[1834] =
/* 1129 */ "Output version information and exit\0" /* 1129 */ "Output version information and exit\0"
/* 1165 */ "version\0" /* 1165 */ "version\0"
/* 1173 */ "OCSERV\0" /* 1173 */ "OCSERV\0"
/* 1180 */ "ocserv - OpenConnect server - Ver. 0.1.6\n" /* 1180 */ "ocserv - OpenConnect server - Ver. 0.1.7\n"
"USAGE: %s [ -<flag> [<val>] | --<name>[{=| }<val>] ]...\n\0" "USAGE: %s [ -<flag> [<val>] | --<name>[{=| }<val>] ]...\n\0"
/* 1279 */ "openconnect-devel@lists.infradead.org\0" /* 1279 */ "openconnect-devel@lists.infradead.org\0"
/* 1317 */ "\n\n\0" /* 1317 */ "\n\n\0"
@@ -111,7 +111,7 @@ static char const ocserv_opt_strs[1834] =
"certificate authentication. Authenticated users are assigned an\n" "certificate authentication. Authenticated users are assigned an\n"
"unprivileged worker process and obtain a networking (tun) device and an IP\n" "unprivileged worker process and obtain a networking (tun) device and an IP\n"
"from a configurable pool of addresses.\n\0" "from a configurable pool of addresses.\n\0"
/* 1746 */ "ocserv 0.1.6\0" /* 1746 */ "ocserv 0.1.7\0"
/* 1759 */ "Usage: ocserv [options] -c [config]\n" /* 1759 */ "Usage: ocserv [options] -c [config]\n"
"ocserv --help for usage instructions.\n"; "ocserv --help for usage instructions.\n";
+7
View File
@@ -260,6 +260,13 @@ output-buffer = 10
route = 192.168.1.0/255.255.255.0 route = 192.168.1.0/255.255.255.0
route = 192.168.5.0/255.255.255.0 route = 192.168.5.0/255.255.255.0
# Configuration files that will be applied per user connection or
# per group. Each file name on these directories must match the username
# or the groupname.
# The options allow in such configuration files are ipv?-dns, and route.
#config-per-user = /etc/ocserv/config-per-user/
#config-per-group = /etc/ocserv/config-per-group/
# #
# The following options are for (experimental) AnyConnect client # The following options are for (experimental) AnyConnect client
# compatibility. # compatibility.
+3 -3
View File
@@ -2,7 +2,7 @@
* *
* DO NOT EDIT THIS FILE (ocserv-args.h) * DO NOT EDIT THIS FILE (ocserv-args.h)
* *
* It has been AutoGen-ed October 20, 2013 at 05:44:06 PM by AutoGen 5.17 * It has been AutoGen-ed October 28, 2013 at 11:41:39 AM by AutoGen 5.17
* From the definitions ocserv-args.def * From the definitions ocserv-args.def
* and the template file options * and the template file options
* *
@@ -76,8 +76,8 @@ typedef enum {
} teOptIndex; } teOptIndex;
#define OPTION_CT 7 #define OPTION_CT 7
#define OCSERV_VERSION "0.1.6" #define OCSERV_VERSION "0.1.7"
#define OCSERV_FULL_VERSION "ocserv 0.1.6" #define OCSERV_FULL_VERSION "ocserv 0.1.7"
/* /*
* Interface defines for all options. Replace "n" with the UPPER_CASED * Interface defines for all options. Replace "n" with the UPPER_CASED
+27
View File
@@ -47,6 +47,8 @@ extern int syslog_open;
#define ERR_AUTH_CONTINUE -4 #define ERR_AUTH_CONTINUE -4
#define ERR_WAIT_FOR_SCRIPT -5 #define ERR_WAIT_FOR_SCRIPT -5
#define ERR_MEM -6 #define ERR_MEM -6
#define ERR_READ_ROUTES -7
#define ERR_READ_CONFIG -8
typedef struct typedef struct
{ {
@@ -54,6 +56,14 @@ typedef struct
unsigned int entries; unsigned int entries;
} hash_db_st; } hash_db_st;
struct group_cfg_st {
char **routes;
unsigned int routes_size;
char *ipv4_dns;
char *ipv6_dns;
};
struct vpn_st { struct vpn_st {
char *name; /* device name */ char *name; /* device name */
char *ipv4_netmask; char *ipv4_netmask;
@@ -127,6 +137,10 @@ struct cfg_st {
uid_t uid; uid_t uid;
gid_t gid; gid_t gid;
/* additional configuration files */
char *per_group_dir;
char *per_user_dir;
/* the tun network */ /* the tun network */
struct vpn_st network; struct vpn_st network;
@@ -144,6 +158,10 @@ struct main_server_st;
#define MAX_GROUPNAME_SIZE MAX_USERNAME_SIZE #define MAX_GROUPNAME_SIZE MAX_USERNAME_SIZE
#define MAX_SESSION_DATA_SIZE (4*1024) #define MAX_SESSION_DATA_SIZE (4*1024)
#define MAX_CONFIG_ENTRIES 64
#define MAX_ROUTES 32
#include <tun.h> #include <tun.h>
const char *human_addr(const struct sockaddr *sa, socklen_t salen, const char *human_addr(const struct sockaddr *sa, socklen_t salen,
@@ -160,4 +178,13 @@ const char *human_addr(const struct sockaddr *sa, socklen_t salen,
#define SA_IN_P_GENERIC(addr, size) ((size==sizeof(struct sockaddr_in))?SA_IN_U8_P(addr):SA_IN6_U8_P(addr)) #define SA_IN_P_GENERIC(addr, size) ((size==sizeof(struct sockaddr_in))?SA_IN_U8_P(addr):SA_IN6_U8_P(addr))
#define SA_IN_SIZE(size) ((size==sizeof(struct sockaddr_in))?sizeof(struct in_addr):sizeof(struct in6_addr)) #define SA_IN_SIZE(size) ((size==sizeof(struct sockaddr_in))?sizeof(struct in_addr):sizeof(struct in6_addr))
/* Helper structures */
struct route_st {
uint8_t size;
char *route;
};
enum option_types { OPTION_NUMERIC, OPTION_STRING, OPTION_BOOLEAN, OPTION_MULTI_LINE };
#endif #endif
+75 -8
View File
@@ -37,6 +37,7 @@
#include "html.h" #include "html.h"
#include <worker.h> #include <worker.h>
#include <cookies.h> #include <cookies.h>
#include <common.h>
#include <tlslib.h> #include <tlslib.h>
#include <http-parser/http_parser.h> #include <http-parser/http_parser.h>
@@ -237,7 +238,7 @@ static int send_auth_cookie_req(int fd, const struct cmd_auth_cookie_req_st* r)
static int recv_auth_reply(worker_st *ws, struct cmd_auth_reply_st *resp) static int recv_auth_reply(worker_st *ws, struct cmd_auth_reply_st *resp)
{ {
struct iovec iov[2]; struct iovec iov[2];
uint8_t cmd = 0; uint8_t cmd = 0, len;
struct msghdr hdr; struct msghdr hdr;
int ret, cmdlen; int ret, cmdlen;
union { union {
@@ -245,16 +246,17 @@ static int recv_auth_reply(worker_st *ws, struct cmd_auth_reply_st *resp)
char control[CMSG_SPACE(sizeof(int))]; char control[CMSG_SPACE(sizeof(int))];
} control_un; } control_un;
struct cmsghdr *cmptr; struct cmsghdr *cmptr;
unsigned i;
iov[0].iov_base = &cmd; iov[0].iov_base = &cmd;
iov[0].iov_len = 1; iov[0].iov_len = 1;
iov[1].iov_base = resp; iov[1].iov_base = resp;
iov[1].iov_len = sizeof(*resp); iov[1].iov_len = sizeof(*resp);
memset(&hdr, 0, sizeof(hdr)); memset(&hdr, 0, sizeof(hdr));
hdr.msg_iov = iov; hdr.msg_iov = iov;
hdr.msg_iovlen = 2; hdr.msg_iovlen = 2 + MAX_ROUTES;
hdr.msg_control = control_un.control; hdr.msg_control = control_un.control;
hdr.msg_controllen = sizeof(control_un.control); hdr.msg_controllen = sizeof(control_un.control);
@@ -288,10 +290,75 @@ static int recv_auth_reply(worker_st *ws, struct cmd_auth_reply_st *resp)
return ERR_AUTH_FAIL; return ERR_AUTH_FAIL;
memcpy(&ws->tun_fd, CMSG_DATA(cmptr), sizeof(int)); memcpy(&ws->tun_fd, CMSG_DATA(cmptr), sizeof(int));
memcpy(ws->tun_name, resp->vname, sizeof(ws->tun_name)); memcpy(ws->tun_name, resp->data.ok.vname, sizeof(ws->tun_name));
memcpy(ws->username, resp->user, sizeof(ws->username)); memcpy(ws->username, resp->data.ok.user, sizeof(ws->username));
memcpy(ws->cookie, resp->cookie, sizeof(ws->cookie)); memcpy(ws->cookie, resp->data.ok.cookie, sizeof(ws->cookie));
memcpy(ws->session_id, resp->session_id, sizeof(ws->session_id)); memcpy(ws->session_id, resp->data.ok.session_id, sizeof(ws->session_id));
ws->routes_size = resp->data.ok.routes_size;
/* Read any additional data */
/* IPV4 DNS */
ret = force_read(ws->cmd_fd, &len, 1);
if (ret != 1) {
oclog(ws, LOG_ERR, "Error received route size from main (%d)", ret);
return ERR_BAD_COMMAND;
}
if (len > 0) {
ws->ipv4_dns = malloc(len+1);
if (ws->ipv4_dns == NULL)
return ERR_MEM;
ret = force_read(ws->cmd_fd, ws->ipv4_dns, len);
if (ret != len) {
oclog(ws, LOG_ERR, "Error received routes from main (%d)", ret);
return ERR_BAD_COMMAND;
}
ws->ipv4_dns[len] = 0;
}
/* IPV6 DNS */
ret = force_read(ws->cmd_fd, &len, 1);
if (ret != 1) {
oclog(ws, LOG_ERR, "Error received route size from main (%d)", ret);
return ERR_BAD_COMMAND;
}
if (len > 0) {
ws->ipv6_dns = malloc(len+1);
if (ws->ipv6_dns == NULL)
return ERR_MEM;
ret = force_read(ws->cmd_fd, ws->ipv6_dns, len);
if (ret != len) {
oclog(ws, LOG_ERR, "Error received routes from main (%d)", ret);
return ERR_BAD_COMMAND;
}
ws->ipv6_dns[len] = 0;
}
/* routes */
for (i=0;i<ws->routes_size;i++) {
ret = force_read(ws->cmd_fd, &ws->routes[i].size, 1);
if (ret != 1) {
oclog(ws, LOG_ERR, "Error received route size from main (%d)", ret);
return ERR_BAD_COMMAND;
}
ws->routes[i].route = malloc(ws->routes[i].size+1);
if (ws->routes[i].route == NULL)
return ERR_MEM;
ret = force_read(ws->cmd_fd, ws->routes[i].route, ws->routes[i].size);
if (ret != ws->routes[i].size) {
oclog(ws, LOG_ERR, "Error received routes from main (%d)", ret);
return ERR_BAD_COMMAND;
}
ws->routes[i].route[ws->routes[i].size] = 0;
}
} else } else
return ERR_AUTH_FAIL; return ERR_AUTH_FAIL;
break; break;
@@ -655,7 +722,7 @@ struct cmd_auth_reply_st resp;
ret = recv_auth_reply(ws, &resp); ret = recv_auth_reply(ws, &resp);
if (ret == ERR_AUTH_CONTINUE) { if (ret == ERR_AUTH_CONTINUE) {
ws->auth_state = S_AUTH_REQ; ws->auth_state = S_AUTH_REQ;
return get_auth_handler2(ws, http_ver, resp.msg); return get_auth_handler2(ws, http_ver, resp.data.msg);
} else if (ret < 0) } else if (ret < 0)
goto auth_fail; goto auth_fail;
+21 -2
View File
@@ -853,7 +853,11 @@ socklen_t sl;
ret = tls_printf(ws->session, "X-CSTP-Netmask: %s\r\n", vinfo.ipv4_netmask); ret = tls_printf(ws->session, "X-CSTP-Netmask: %s\r\n", vinfo.ipv4_netmask);
SEND_ERR(ret); SEND_ERR(ret);
} }
if (vinfo.ipv4_dns) {
if (ws->ipv4_dns) {
ret = tls_printf(ws->session, "X-CSTP-DNS: %s\r\n", ws->ipv4_dns);
SEND_ERR(ret);
} else if (vinfo.ipv4_dns) {
ret = tls_printf(ws->session, "X-CSTP-DNS: %s\r\n", vinfo.ipv4_dns); ret = tls_printf(ws->session, "X-CSTP-DNS: %s\r\n", vinfo.ipv4_dns);
SEND_ERR(ret); SEND_ERR(ret);
} }
@@ -872,7 +876,11 @@ socklen_t sl;
ret = tls_printf(ws->session, "X-CSTP-Netmask: %s\r\n", vinfo.ipv6_netmask); ret = tls_printf(ws->session, "X-CSTP-Netmask: %s\r\n", vinfo.ipv6_netmask);
SEND_ERR(ret); SEND_ERR(ret);
} }
if (vinfo.ipv6_dns) {
if (ws->ipv6_dns) {
ret = tls_printf(ws->session, "X-CSTP-DNS: %s\r\n", ws->ipv6_dns);
SEND_ERR(ret);
} else if (vinfo.ipv6_dns) {
ret = tls_printf(ws->session, "X-CSTP-DNS: %s\r\n", vinfo.ipv6_dns); ret = tls_printf(ws->session, "X-CSTP-DNS: %s\r\n", vinfo.ipv6_dns);
SEND_ERR(ret); SEND_ERR(ret);
} }
@@ -892,6 +900,17 @@ socklen_t sl;
"X-CSTP-Split-Include: %s\r\n", vinfo.routes[i]); "X-CSTP-Split-Include: %s\r\n", vinfo.routes[i]);
SEND_ERR(ret); SEND_ERR(ret);
} }
for (i=0;i<ws->routes_size;i++) {
if (req->no_ipv6 != 0 && strchr(ws->routes[i].route, ':') != 0)
continue;
if (req->no_ipv4 != 0 && strchr(ws->routes[i].route, '.') != 0)
continue;
oclog(ws, LOG_DEBUG, "adding route %s", ws->routes[i].route);
ret = tls_printf(ws->session,
"X-CSTP-Split-Include: %s\r\n", ws->routes[i].route);
SEND_ERR(ret);
}
ret = tls_printf(ws->session, "X-CSTP-Keepalive: %u\r\n", ws->config->keepalive); ret = tls_printf(ws->session, "X-CSTP-Keepalive: %u\r\n", ws->config->keepalive);
SEND_ERR(ret); SEND_ERR(ret);
+6 -1
View File
@@ -118,6 +118,12 @@ typedef struct worker_st {
unsigned cert_auth_ok; unsigned cert_auth_ok;
int tun_fd; int tun_fd;
/* additional data - received per user or per group */
char *ipv4_dns;
char *ipv6_dns;
unsigned routes_size;
struct route_st routes[MAX_ROUTES];
struct http_req_st req; struct http_req_st req;
} worker_st; } worker_st;
@@ -142,7 +148,6 @@ void __attribute__ ((format(printf, 3, 4)))
int get_rt_vpn_info(worker_st * ws, int get_rt_vpn_info(worker_st * ws,
struct vpn_st* vinfo, char* buffer, size_t buffer_size); struct vpn_st* vinfo, char* buffer, size_t buffer_size);
ssize_t tun_write(int sockfd, const void *buf, size_t len);
int send_tun_mtu(worker_st *ws, unsigned int mtu); int send_tun_mtu(worker_st *ws, unsigned int mtu);
int handle_worker_commands(struct worker_st *ws); int handle_worker_commands(struct worker_st *ws);