Added GSSAPI as an additional password auth mechanism

That also adds the ability to support an OR composition of multiple
authentication methods. That is using the 'enable-auth' config option.
This commit is contained in:
Nikos Mavrogiannopoulos
2015-02-09 16:38:27 +01:00
parent 5e4763d229
commit 8bb0af61bc
21 changed files with 747 additions and 170 deletions

View File

@@ -391,6 +391,26 @@ AC_DEFINE([HAVE_LZ4], [], [LZ4 was found])
])
fi
dnl GSSAPI
AC_ARG_WITH(gssapi,
AS_HELP_STRING([--without-gssapi], [disable support for GSSAPI authentication]),
test_for_gssapi=$withval,
test_for_gssapi=yes)
enable_gssapi=no
if test "$test_for_gssapi" = yes;then
PKG_CHECK_MODULES([LIBKRB5], [krb5-gssapi], [
enable_gssapi=yes
AC_DEFINE([HAVE_GSSAPI], [], [GSSAPI was found])
],
[
AC_MSG_WARN([[
***
*** gssapi not found. Will disable compression support.
*** ]])
])
fi
dnl needed in the included PCL
AC_C_VOLATILE
AC_C_CONST
@@ -467,6 +487,7 @@ Summary of build options:
PAM auth backend: ${pam_enabled}
Radius auth backend: ${radius_enabled}
GSSAPI auth backend: ${enable_gssapi}
Anyconnect compat: ${anyconnect_enabled}
TCP wrappers: ${libwrap_enabled}
systemd: ${systemd_enabled}

View File

@@ -5,7 +5,8 @@ AM_CPPFLAGS = -I$(srcdir)/../gl/ -I$(builddir)/../gl/ \
$(LIBGNUTLS_CFLAGS) \
$(LIBPROTOBUF_C_CFLAGS) $(LIBLZ4_CFLAGS) \
$(LIBNL3_CFLAGS) $(LIBREADLINE_CFLAGS) \
$(LIBTALLOC_CFLAGS) $(LIBDBUS_CFLAGS)
$(LIBTALLOC_CFLAGS) $(LIBDBUS_CFLAGS) \
$(LIBKRB5_CFLAGS)
BUILT_SOURCES = ocpasswd-args.c ocpasswd-args.h \
ocserv-args.c ocserv-args.h ipc.pb-c.c ipc.pb-c.h \
@@ -63,7 +64,7 @@ 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/radius.c auth/radius.h \
auth/common.c auth/common.h
auth/common.c auth/common.h auth/gssapi.h auth/gssapi.c
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 \
@@ -90,7 +91,7 @@ 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) $(LIBTALLOC_LIBS) \
$(FREERADIUS_CLIENT_LIBS) $(LIBLZ4_LIBS)
$(FREERADIUS_CLIENT_LIBS) $(LIBLZ4_LIBS) $(LIBKRB5_LIBS)
if PCL

268
src/auth/gssapi.c Normal file
View File

@@ -0,0 +1,268 @@
/*
* Copyright (C) 2015 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 "gssapi.h"
#include "auth/common.h"
#include <gssapi/gssapi.h>
#include <gssapi/gssapi_ext.h>
#include <gssapi/gssapi_krb5.h>
#include <gl/base64.h>
#define MAX_MSG_SIZE 256
#ifdef HAVE_GSSAPI
static gss_cred_id_t glob_creds;
gss_OID_set glob_oids;
struct gssapi_ctx_st {
char username[MAX_USERNAME_SIZE];
gss_ctx_id_t gssctx;
gss_cred_id_t delegated_creds;
gss_buffer_desc msg;
};
static void gssapi_global_init(void *pool, void *additional)
{
int ret;
OM_uint32 time, minor;
gss_name_t name = GSS_C_NO_NAME;
if (additional && strncmp(additional, "keytab:", 7) == 0) {
gss_key_value_element_desc element;
gss_key_value_set_desc cred_store;
element.key = "keytab";
element.value = additional+7;
cred_store.count = 1;
cred_store.elements = &element;
ret = gss_acquire_cred_from(&minor, name, 0, GSS_C_NO_OID_SET, 2,
&cred_store, &glob_creds, &glob_oids, &time);
} else {
ret = gss_acquire_cred(&minor, name, 0, GSS_C_NO_OID_SET, 2,
&glob_creds, &glob_oids, &time);
}
if (ret != GSS_S_COMPLETE) {
ret = -1;
syslog(LOG_ERR, "gssapi: error in gss_acquire_cred[%s]: %d", (name==GSS_C_NO_NAME)?"default":(char*)additional, ret);
exit(1);
}
if (name != GSS_C_NO_NAME)
gss_release_name(&minor, &name);
return;
}
static void gssapi_global_deinit()
{
OM_uint32 minor;
if (glob_creds != NULL)
gss_release_cred(&minor, &glob_creds);
}
static void get_name(struct gssapi_ctx_st *pctx, gss_name_t client, gss_OID mech_type)
{
int ret;
OM_uint32 minor;
gss_buffer_desc name;
pctx->username[0] = 0;
ret = gss_display_name(&minor, client, &name, NULL);
if (GSS_ERROR(ret)) {
syslog(LOG_ERR, "gssapi: error in gss_display_name: %d", ret);
return;
}
syslog(LOG_DEBUG, "gssapi: full username %.*s", (unsigned)name.length, (char*)name.value);
gss_release_buffer(&minor, &name);
ret = gss_localname(&minor, client, mech_type, &name);
if (GSS_ERROR(ret) || name.length >= MAX_USERNAME_SIZE) {
syslog(LOG_ERR, "gssapi: error in gss_display_name: %d", ret);
return;
}
syslog(LOG_DEBUG, "gssapi: username %.*s", (unsigned)name.length, (char*)name.value);
memcpy(pctx->username, name.value, name.length);
pctx->username[name.length] = 0;
gss_release_buffer(&minor, &name);
return;
}
static int gssapi_auth_init(void **ctx, void *pool, const char *spnego, const char *ip,
void *additional)
{
struct gssapi_ctx_st *pctx;
OM_uint32 minor, flags, time;
gss_buffer_desc buf;
gss_name_t client = GSS_C_NO_NAME;
gss_OID mech_type = GSS_C_NO_OID;
int ret;
size_t raw_len;
char *raw;
if (spnego == NULL || spnego[0] == 0) {
syslog(LOG_ERR, "gssapi: error in spnego data %s", __func__);
return ERR_AUTH_FAIL;
}
pctx = talloc_zero(pool, struct gssapi_ctx_st);
if (pctx == NULL)
return ERR_AUTH_FAIL;
ret = base64_decode_alloc(spnego, strlen(spnego), &raw, &raw_len);
if (ret == 0) {
syslog(LOG_ERR, "gssapi: error in base64 decoding %s", __func__);
return ERR_AUTH_FAIL;
}
buf.value = raw;
buf.length = raw_len;
ret = gss_accept_sec_context(&minor, &pctx->gssctx, glob_creds, &buf,
GSS_C_NO_CHANNEL_BINDINGS, &client, &mech_type, &pctx->msg,
&flags, &time, &pctx->delegated_creds);
free(raw);
if (ret == GSS_S_CONTINUE_NEEDED) {
gss_release_name(&minor, &client);
ret = ERR_AUTH_CONTINUE;
} else if (ret == GSS_S_COMPLETE) {
get_name(pctx, client, mech_type);
gss_release_name(&minor, &client);
ret = 0;
} else {
syslog(LOG_ERR, "gssapi: error in gss_accept_sec_context: %d", ret);
return ERR_AUTH_FAIL;
}
*ctx = pctx;
return ret;
}
static int gssapi_auth_group(void *ctx, const char *suggested, char *groupname, int groupname_size)
{
groupname[0] = 0;
return 0;
}
static int gssapi_auth_user(void *ctx, char *username, int username_size)
{
struct gssapi_ctx_st *pctx = ctx;
strlcpy(username, pctx->username, username_size);
return -1;
}
/* Returns 0 if the user is successfully authenticated, and sets the appropriate group name.
*/
static int gssapi_auth_pass(void *ctx, const char *spnego, unsigned spnego_len)
{
struct gssapi_ctx_st *pctx = ctx;
OM_uint32 minor, flags, time;
gss_buffer_desc buf;
gss_name_t client = GSS_C_NO_NAME;
gss_OID mech_type = GSS_C_NO_OID;
size_t raw_len;
char *raw;
int ret;
/* nothing to be done */
ret = base64_decode_alloc(spnego, spnego_len, &raw, &raw_len);
if (ret == 0) {
syslog(LOG_ERR, "gssapi: error in base64 decoding %s", __func__);
return ERR_AUTH_FAIL;
}
buf.value = raw;
buf.length = raw_len;
ret = gss_accept_sec_context(&minor, &pctx->gssctx, glob_creds, &buf,
GSS_C_NO_CHANNEL_BINDINGS, &client, &mech_type, &pctx->msg,
&flags, &time, &pctx->delegated_creds);
free(raw);
if (ret == GSS_S_CONTINUE_NEEDED) {
gss_release_name(&minor, &client);
return ERR_AUTH_CONTINUE;
} else if (ret == GSS_S_COMPLETE) {
get_name(pctx, client, mech_type);
gss_release_name(&minor, &client);
return 0;
} else {
syslog(LOG_ERR, "gssapi: error in gss_accept_sec_context: %d", ret);
return ERR_AUTH_FAIL;
}
}
static int gssapi_auth_msg(void *ctx, char *msg, size_t msg_size)
{
struct gssapi_ctx_st *pctx = ctx;
OM_uint32 min;
/* our msg is our SPNEGO reply */
if (pctx->msg.value != NULL) {
base64_encode((char *)pctx->msg.value, pctx->msg.length, (char *)msg, msg_size);
gss_release_buffer(&min, &pctx->msg);
pctx->msg.value = NULL;
} else {
msg[0] = 0;
}
return 0;
}
static void gssapi_auth_deinit(void *ctx)
{
struct gssapi_ctx_st *pctx = ctx;
OM_uint32 min;
gss_delete_sec_context(&min, &pctx->gssctx, GSS_C_NO_BUFFER);
gss_release_cred(&min, &pctx->delegated_creds);
gss_release_buffer(&min, &pctx->msg);
talloc_free(ctx);
}
const struct auth_mod_st gssapi_auth_funcs = {
.type = AUTH_TYPE_GSSAPI,
.auth_init = gssapi_auth_init,
.auth_deinit = gssapi_auth_deinit,
.auth_msg = gssapi_auth_msg,
.auth_pass = gssapi_auth_pass,
.auth_user = gssapi_auth_user,
.auth_group = gssapi_auth_group,
.global_init = gssapi_global_init,
.global_deinit = gssapi_global_deinit,
};
#endif

28
src/auth/gssapi.h Normal file
View File

@@ -0,0 +1,28 @@
/*
* Copyright (C) 2015 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 GSSAPI_H
#define GSSAPI_H
#include <sec-mod-auth.h>
extern const struct auth_mod_st gssapi_auth_funcs;
#endif

View File

@@ -160,8 +160,11 @@ static int pam_auth_init(void** ctx, void *pool, const char* user, const char* i
int pret;
struct pam_ctx_st * pctx;
if (user == NULL)
return -1;
if (user == NULL || user[0] == 0) {
syslog(LOG_AUTH,
"pam-auth: no username present");
return ERR_AUTH_FAIL;
}
pctx = talloc_zero(pool, struct pam_ctx_st);
if (pctx == NULL)
@@ -188,7 +191,7 @@ struct pam_ctx_st * pctx;
*ctx = pctx;
return 0;
return ERR_AUTH_CONTINUE;
fail2:
pam_end(pctx->ph, pret);

View File

@@ -167,6 +167,12 @@ static int plain_auth_init(void **ctx, void *pool, const char *username, const c
struct plain_ctx_st *pctx;
int ret;
if (username == NULL || username[0] == 0) {
syslog(LOG_AUTH,
"plain-auth: no username present");
return ERR_AUTH_FAIL;
}
pctx = talloc_zero(pool, struct plain_ctx_st);
if (pctx == NULL)
return ERR_AUTH_FAIL;
@@ -183,7 +189,7 @@ static int plain_auth_init(void **ctx, void *pool, const char *username, const c
*ctx = pctx;
return 0;
return ERR_AUTH_CONTINUE;
}
static int plain_auth_group(void *ctx, const char *suggested, char *groupname, int groupname_size)

View File

@@ -67,6 +67,12 @@ static int radius_auth_init(void **ctx, void *pool, const char *username, const
struct radius_ctx_st *pctx;
char *default_realm;
if (username == NULL || username[0] == 0) {
syslog(LOG_AUTH,
"radius-auth: no username present");
return ERR_AUTH_FAIL;
}
pctx = talloc_zero(pool, struct radius_ctx_st);
if (pctx == NULL)
return ERR_AUTH_FAIL;
@@ -88,7 +94,7 @@ static int radius_auth_init(void **ctx, void *pool, const char *username, const
*ctx = pctx;
return 0;
return ERR_AUTH_CONTINUE;
}
static int radius_auth_group(void *ctx, const char *suggested, char *groupname, int groupname_size)

View File

@@ -34,6 +34,7 @@
#include <auth/pam.h>
#include <auth/radius.h>
#include <auth/plain.h>
#include <auth/gssapi.h>
#include <sec-mod-sup-config.h>
#include <vpn.h>
@@ -47,7 +48,6 @@
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;
@@ -58,6 +58,7 @@ struct cfg_options {
static struct cfg_options available_options[] = {
{ .name = "auth", .type = OPTION_MULTI_LINE, .mandatory = 1 },
{ .name = "enable-auth", .type = OPTION_MULTI_LINE, .mandatory = 0 },
{ .name = "route", .type = OPTION_MULTI_LINE, .mandatory = 0 },
{ .name = "no-route", .type = OPTION_MULTI_LINE, .mandatory = 0 },
{ .name = "select-group", .type = OPTION_MULTI_LINE, .mandatory = 0 },
@@ -152,10 +153,10 @@ static struct cfg_options available_options[] = {
};
#define get_brackets_string get_brackets_string1
static char *get_brackets_string1(void *pool, const char *str);
static char *get_brackets_string1(struct cfg_st *config, const char *str);
#ifdef HAVE_RADIUS
static char *get_brackets_string2(void *pool, const char *str)
static char *get_brackets_string2(struct cfg_st *config, const char *str)
{
char *p, *p2;
unsigned len;
@@ -186,7 +187,28 @@ static char *get_brackets_string2(void *pool, const char *str)
len = p2 - p;
return talloc_strndup(pool, p, len);
return talloc_strndup(config, p, len);
}
static char *radius_get_brackets_string(struct cfg_st *config, const char *str)
{
char *ret, *p;
ret = get_brackets_string1(config, str+6);
if (ret == NULL) {
fprintf(stderr, "No radius configuration specified\n");
exit(1);
}
p = get_brackets_string2(config, str+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;
}
return ret;
}
#endif
@@ -219,7 +241,7 @@ unsigned j;
do { \
if (val && !strcmp(val->pzName, name)==0) \
continue; \
s_name[num] = talloc_strdup(config, val->v.strVal); \
s_name[num] = talloc_strdup(s_name, val->v.strVal); \
num++; \
if (num>=MAX_CONFIG_ENTRIES) \
break; \
@@ -345,7 +367,7 @@ unsigned j;
}
}
static char *get_brackets_string1(void *pool, const char *str)
static char *get_brackets_string1(struct cfg_st *config, const char *str)
{
char *p, *p2;
unsigned len;
@@ -369,10 +391,9 @@ static char *get_brackets_string1(void *pool, const char *str)
len = p2 - p;
return talloc_strndup(pool, p, len);
return talloc_strndup(config, p, len);
}
/* Parses the string ::1/prefix, to return prefix
* and modify the string to contain the network only.
*/
@@ -395,9 +416,107 @@ unsigned extract_prefix(char *network)
return prefix;
}
const struct auth_mod_st *get_auth_mod(void)
typedef struct auth_types_st {
const char *name;
unsigned name_size;
const struct auth_mod_st *mod;
unsigned type;
char *(*get_brackets_string)(struct cfg_st *config, const char *);
} auth_types_st;
#define NAME(x) (x),(sizeof(x)-1)
static auth_types_st avail_auth_types[] =
{
return amod;
#ifdef HAVE_PAM
{NAME("pam"), &pam_auth_funcs, AUTH_TYPE_PAM, get_brackets_string},
#endif
#ifdef HAVE_GSSAPI
{NAME("gssapi"), &gssapi_auth_funcs, AUTH_TYPE_GSSAPI, get_brackets_string},
#endif
#ifdef HAVE_RADIUS
{NAME("radius"), &radius_auth_funcs, AUTH_TYPE_RADIUS, radius_get_brackets_string},
#endif
{NAME("plain"), &plain_auth_funcs, AUTH_TYPE_PLAIN, get_brackets_string},
{NAME("certificate[optional]"), NULL, AUTH_TYPE_CERTIFICATE_OPT, NULL},
{NAME("certificate"), NULL, AUTH_TYPE_CERTIFICATE, NULL},
};
static void figure_auth_funcs(struct cfg_st *config, char **auth, unsigned auth_size,
unsigned primary)
{
unsigned j, i;
unsigned found;
if (primary != 0) {
/* Set the primary authentication methods */
for (j=0;j<auth_size;j++) {
found = 0;
for (i=0;i<sizeof(avail_auth_types)/sizeof(avail_auth_types[0]);i++) {
if (c_strncasecmp(auth[j], avail_auth_types[i].name, avail_auth_types[i].name_size) == 0) {
if (avail_auth_types[i].get_brackets_string)
config->auth[0].additional = avail_auth_types[i].get_brackets_string(config, auth[j]+avail_auth_types[i].name_size);
if (config->auth[0].amod != NULL && avail_auth_types[i].mod != NULL) {
fprintf(stderr, "%s: You cannot mix multiple authentication methods of this type\n", auth[j]);
exit(1);
}
if (config->auth[0].amod == NULL)
config->auth[0].amod = avail_auth_types[i].mod;
config->auth[0].type |= avail_auth_types[i].type;
if (config->auth[0].name == NULL)
config->auth[0].name = avail_auth_types[i].name;
fprintf(stderr, "Setting '%s' as primary authentication method\n", avail_auth_types[i].name);
config->auth[0].enabled = 1;
config->auth_methods = 1;
found = 1;
break;
}
}
if (found == 0) {
fprintf(stderr, "Unknown or unsupported auth method: %s\n", auth[j]);
exit(1);
}
talloc_free(auth[j]);
}
} else {
unsigned x = config->auth_methods;
/* Append authentication methods (alternative options) */
for (j=0;j<auth_size;j++) {
found = 0;
for (i=0;i<sizeof(avail_auth_types)/sizeof(avail_auth_types[0]);i++) {
if (c_strncasecmp(auth[j], avail_auth_types[i].name, avail_auth_types[i].name_size) == 0) {
if (avail_auth_types[i].get_brackets_string)
config->auth[x].additional = avail_auth_types[i].get_brackets_string(config, auth[j]+avail_auth_types[i].name_size);
if (config->auth[x].name == NULL)
config->auth[x].name = avail_auth_types[i].name;
fprintf(stderr, "Enabling '%s' as authentication method\n", avail_auth_types[i].name);
config->auth[x].amod = avail_auth_types[i].mod;
config->auth[x].type |= avail_auth_types[i].type;
config->auth[x].enabled = 1;
found = 1;
x++;
if (x >= MAX_AUTH_METHODS) {
fprintf(stderr, "You cannot enable more than %d authentication methods\n", x);
exit(1);
}
break;
}
}
if (found == 0) {
fprintf(stderr, "Unknown or unsupported auth method: %s\n", auth[j]);
exit(1);
}
talloc_free(auth[j]);
}
config->auth_methods = x;
}
talloc_free(auth);
}
static void parse_cfg_file(const char* file, struct cfg_st *config, unsigned reload)
@@ -439,81 +558,26 @@ unsigned force_cert_auth;
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) {
config->auth_additional = get_brackets_string(config, auth[j]+3);
if ((config->auth_types & AUTH_TYPE_USERNAME_PASS) != 0) {
fprintf(stderr, "You cannot mix multiple username/password authentication methods\n");
exit(1);
}
#ifdef HAVE_PAM
amod = &pam_auth_funcs;
config->auth_types |= amod->type;
#else
fprintf(stderr, "PAM support is disabled\n");
exit(1);
#endif
} else if (strncasecmp(auth[j], "plain", 5) == 0) {
if ((config->auth_types & AUTH_TYPE_USERNAME_PASS) != 0) {
fprintf(stderr, "You cannot mix multiple username/password authentication methods\n");
exit(1);
}
figure_auth_funcs(config, auth, auth_size, 1);
auth = NULL;
auth_size = 0;
config->auth_additional = get_brackets_string(config, auth[j]+5);
if (config->auth_additional == NULL) {
fprintf(stderr, "Format error in %s\n", auth[j]);
exit(1);
}
amod = &plain_auth_funcs;
config->auth_types |= amod->type;
} else if (strncasecmp(auth[j], "radius", 6) == 0) {
if ((config->auth_types & AUTH_TYPE_USERNAME_PASS) != 0) {
fprintf(stderr, "You cannot mix multiple username/password authentication methods\n");
exit(1);
} else {
READ_MULTI_LINE("enable-auth", auth, auth_size);
figure_auth_funcs(config, auth, auth_size, 0);
auth = NULL;
auth_size = 0;
#ifdef HAVE_RADIUS
const char *p;
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) {
config->auth_types |= AUTH_TYPE_CERTIFICATE_OPT;
fprintf(stderr, "The authentication option certificate[optional] is experimental and may be removed in the future\n");
} else {
fprintf(stderr, "Unknown auth method: %s\n", auth[j]);
exit(1);
}
talloc_free(auth[j]);
if (config->auth[0].enabled == 0) {
fprintf(stderr, "No authentication method was specified!\n");
exit(1);
}
talloc_free(auth);
/* When adding allocated data, remember to modify
* reload_cfg_file();
*/
READ_STRING("listen-host", config->name);
READ_TF("listen-host-is-dyndns", config->is_dyndns, 0);
READ_STRING("listen-clear-file", config->unix_conn_file);
READ_NUMERIC("tcp-port", config->port);
READ_NUMERIC("udp-port", config->udp_port);
@@ -550,11 +614,6 @@ unsigned force_cert_auth;
if (reload == 0 && pid_file[0] == 0)
READ_STATIC_STRING("pid-file", pid_file);
READ_STRING("listen-clear-file", config->unix_conn_file);
if (config->unix_conn_file != NULL && (config->auth_types & AUTH_TYPE_CERTIFICATE)) {
fprintf(stderr, "The option 'listen-clear-file' cannot be combined with 'auth=certificate'\n");
exit(1);
}
READ_STRING("socket-file", config->socket_file_prefix);
READ_STRING("occtl-socket-file", config->occtl_socket_file);
@@ -729,8 +788,9 @@ unsigned force_cert_auth;
READ_STRING("default-select-group", config->default_select_group);
READ_TF("auto-select-group", auto_select_group, 0);
if (auto_select_group != 0 && amod != NULL && amod->group_list != NULL) {
amod->group_list(config, config->auth_additional, &config->group_list, &config->group_list_size);
if (auto_select_group != 0 && config->auth[0].amod != NULL && config->auth[0].amod->group_list != NULL) {
config->auth[0].amod->group_list(config, config->auth[0].additional, &config->group_list, &config->group_list_size);
} else {
READ_MULTI_BRACKET_LINE("select-group",
config->group_list,
@@ -799,18 +859,29 @@ static void check_cfg(struct cfg_st *config)
exit(1);
}
if (config->auth_types & AUTH_TYPE_CERTIFICATE) {
if (config->cisco_client_compat == 0 && ((config->auth_types & AUTH_TYPE_CERTIFICATE_OPT) != AUTH_TYPE_CERTIFICATE_OPT))
if (config->auth[0].type & AUTH_TYPE_CERTIFICATE) {
if (config->cisco_client_compat == 0 && ((config->auth[0].type & AUTH_TYPE_CERTIFICATE_OPT) != AUTH_TYPE_CERTIFICATE_OPT))
config->cert_req = GNUTLS_CERT_REQUIRE;
else
config->cert_req = GNUTLS_CERT_REQUEST;
} else {
unsigned i;
for (i=1;i<config->auth_methods;i++) {
if (config->auth[i].type & AUTH_TYPE_CERTIFICATE) {
config->cert_req = GNUTLS_CERT_REQUEST;
break;
}
}
}
if (config->auth_additional != NULL && (config->auth_types & AUTH_TYPE_PLAIN) == AUTH_TYPE_PLAIN) {
if (access(config->auth_additional, R_OK) != 0) {
fprintf(stderr, "cannot access password file '%s'\n", config->auth_additional);
exit(1);
}
if (config->cert_req != 0 && config->cert_user_oid == NULL) {
fprintf(stderr, "A certificate is requested by the option 'cert-user-oid' is not set\n");
exit(1);
}
if (config->unix_conn_file != NULL && (config->cert_req != 0)) {
fprintf(stderr, "The option 'listen-clear-file' cannot be combined with 'auth=certificate'\n");
exit(1);
}
#ifdef ANYCONNECT_CLIENT_COMPAT
@@ -897,7 +968,7 @@ unsigned i;
DEL(config->per_group_dir);
DEL(config->socket_file_prefix);
DEL(config->default_domain);
DEL(config->auth_additional);
DEL(config->ocsp_response);
DEL(config->banner);
DEL(config->dh_params_file);
@@ -969,6 +1040,9 @@ void print_version(tOptions *opts, tOptDesc *desc)
#ifdef HAVE_RADIUS
fprintf(stderr, "radius, ");
#endif
#ifdef HAVE_GSSAPI
fprintf(stderr, "gssapi, ");
#endif
#ifdef HAVE_PAM
fprintf(stderr, "PAM, ");
#endif
@@ -990,14 +1064,31 @@ void print_version(tOptions *opts, tOptDesc *desc)
exit(0);
}
void reload_cfg_file(void *pool, struct cfg_st* config)
{
auth_struct_st bak[MAX_AUTH_METHODS];
unsigned bak_size, i;
/* authentication methods can't change on reload */
memcpy(bak, config->auth, sizeof(config->auth));
memset(config->auth, 0, sizeof(config->auth));
bak_size = config->auth_methods;
clear_cfg_file(config);
memset(config, 0, sizeof(*config));
parse_cfg_file(cfg_file, config, 1);
/* reset the auth methods */
for (i=0;i<config->auth_methods;i++) {
if (config->auth[i].enabled)
DEL(config->auth[i].additional);
}
memcpy(config->auth, bak, sizeof(config->auth));
config->auth_methods = bak_size;
check_cfg(config);
return;

View File

@@ -17,3 +17,5 @@ X-CSTP-Address-Type, HEADER_CSTP_ATYPE
X-CSTP-Hostname, HEADER_HOSTNAME
X-CSTP-Full-IPv6-Capability, HEADER_FULL_IPV6
X-AnyConnect-Identifier-DeviceType, HEADER_DEVICE_TYPE
X-Need-SPNEGO, HEADER_NEED_SPNEGO
Authorization, HEADER_AUTHORIZATION

View File

@@ -166,6 +166,7 @@ message sec_auth_init_msg
repeated string cert_group_names = 6;
optional string hostname = 7;
required string ip = 8;
required uint32 auth_type = 9 [default = 0];
}
/* SEC_AUTH_CONT */

View File

@@ -293,5 +293,6 @@ void request_reload(int signo);
void request_stop(int signo);
const struct auth_mod_st *get_auth_mod(void);
const struct auth_mod_st *get_backup_auth_mod(void);
#endif

View File

@@ -105,6 +105,7 @@ An example configuration file follows.
#auth = "pam[gid-min=1000]"
#auth = "plain[/etc/ocserv/ocpasswd]"
#auth = "radius[/etc/radiusclient/radiusclient.conf,groupconfig]"
#backup-auth = "gssapi[/etc/gssapi/config]"
# Whether to enable seccomp/Linux namespaces worker isolation. That restricts the number of
# system calls allowed to a worker process, in order to reduce damage from a

View File

@@ -51,24 +51,18 @@
#include <vpn.h>
#include <sec-mod-sup-config.h>
static const struct auth_mod_st *module = NULL;
#ifdef HAVE_GSSAPI
# include <gssapi/gssapi.h>
# include <gssapi/gssapi_ext.h>
#endif
void sec_auth_init(sec_mod_st * sec, struct cfg_st *config)
{
module = get_auth_mod();
unsigned i;
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);
}
for (i=0;i<config->auth_methods;i++) {
if (config->auth[i].enabled && config->auth[i].amod && config->auth[i].amod->global_init)
config->auth[i].amod->global_init(sec, config->auth[i].additional);
}
}
@@ -165,18 +159,9 @@ static
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] = "";
int ret;
if (module == NULL || e->auth_ctx == NULL)
return -1;
ret = module->auth_msg(e->auth_ctx, tmp, sizeof(tmp));
if (ret < 0)
return ret;
msg.msg = tmp;
msg.msg = e->msg_str;
msg.reply = AUTH__REP__MSG;
msg.has_sid = 1;
@@ -202,8 +187,8 @@ static int check_user_group_status(sec_mod_st * sec, client_entry_st * e,
unsigned need_cert = 1;
if (sec->config->auth_types & AUTH_TYPE_CERTIFICATE) {
if ((sec->config->auth_types & AUTH_TYPE_CERTIFICATE_OPT) == AUTH_TYPE_CERTIFICATE_OPT) {
if (e->auth_type & AUTH_TYPE_CERTIFICATE) {
if ((e->auth_type & AUTH_TYPE_CERTIFICATE_OPT) == AUTH_TYPE_CERTIFICATE_OPT) {
need_cert = 0;
}
@@ -307,7 +292,7 @@ int handle_sec_auth_res(int cfd, sec_mod_st * sec, client_entry_st * e, int resu
/* opens or closes a session.
*/
int handle_sec_auth_session_cmd(int cfd, sec_mod_st * sec, const SecAuthSessionMsg * req,
int handle_sec_auth_session_cmd(int cfd, sec_mod_st *sec, const SecAuthSessionMsg *req,
unsigned cmd)
{
client_entry_st *e;
@@ -340,8 +325,8 @@ int handle_sec_auth_session_cmd(int cfd, sec_mod_st * sec, const SecAuthSessionM
return -1;
}
if (module != NULL && module->open_session != NULL) {
ret = module->open_session(e->auth_ctx, req->sid.data, req->sid.len);
if (e->module != NULL && e->module->open_session != NULL) {
ret = e->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.");
@@ -428,10 +413,10 @@ int handle_sec_auth_stats_cmd(sec_mod_st * sec, const CliStatsMsg * req)
if (req->uptime > e->stats.uptime)
e->stats.uptime = req->uptime;
if (module == NULL || module->session_stats == NULL)
if (e->module == NULL || e->module->session_stats == NULL)
return 0;
module->session_stats(e->auth_ctx, &e->stats);
e->module->session_stats(e->auth_ctx, &e->stats);
return 0;
}
@@ -473,8 +458,14 @@ int handle_sec_auth_cont(int cfd, sec_mod_st * sec, const SecAuthContMsg * req)
goto cleanup;
}
if (e->module == NULL) {
seclog(sec, LOG_ERR, "no module available!");
ret = -1;
goto cleanup;
}
ret =
module->auth_pass(e->auth_ctx, req->password,
e->module->auth_pass(e->auth_ctx, req->password,
strlen(req->password));
if (ret < 0) {
seclog(sec, LOG_DEBUG,
@@ -486,10 +477,30 @@ int handle_sec_auth_cont(int cfd, sec_mod_st * sec, const SecAuthContMsg * req)
return handle_sec_auth_res(cfd, sec, e, ret);
}
static
int set_module(sec_mod_st * sec, client_entry_st *e, unsigned auth_type)
{
unsigned i;
for (i=0;i<sec->config->auth_methods;i++) {
if (sec->config->auth[i].enabled && (sec->config->auth[i].type & auth_type) == auth_type) {
e->module = sec->config->auth[i].amod;
e->auth_type = sec->config->auth[i].type;
e->auth_additional = sec->config->auth[i].additional;
seclog(sec, LOG_INFO, "using '%s' authentication to authenticate user (%x)", sec->config->auth[i].name, auth_type);
return 0;
}
}
return -1;
}
int handle_sec_auth_init(int cfd, sec_mod_st * sec, const SecAuthInitMsg * req)
{
int ret = -1;
client_entry_st *e;
unsigned need_continue = 0;
if (check_if_banned(sec, req->ip) != 0) {
seclog(sec, LOG_INFO,
@@ -497,34 +508,34 @@ int handle_sec_auth_init(int cfd, sec_mod_st * sec, const SecAuthInitMsg * req)
return -1;
}
if ((req->user_name == NULL || req->user_name[0] == 0)
&& (sec->config->auth_types & AUTH_TYPE_USERNAME_PASS)) {
seclog(sec, LOG_DEBUG,
"auth init from '%s' with no username present", req->ip);
return -1;
}
e = new_client_entry(sec, req->ip);
if (e == NULL) {
seclog(sec, LOG_ERR, "cannot initialize memory");
return -1;
}
ret = set_module(sec, e, req->auth_type);
if (ret < 0) {
seclog(sec, LOG_ERR, "no module found for auth type %u", (unsigned)req->auth_type);
goto cleanup;
}
if (req->hostname != NULL) {
strlcpy(e->hostname, req->hostname, sizeof(e->hostname));
}
if (sec->config->auth_types & AUTH_TYPE_USERNAME_PASS) {
/* req->username is non-null at this point */
if (e->module) {
ret =
module->auth_init(&e->auth_ctx, e, req->user_name, req->ip,
sec->config->auth_additional);
if (ret < 0) {
e->module->auth_init(&e->auth_ctx, e, req->user_name, req->ip,
e->auth_additional);
if (ret == ERR_AUTH_CONTINUE) {
need_continue = 1;
} else if (ret < 0) {
goto cleanup;
}
ret =
module->auth_group(e->auth_ctx, req->group_name, e->groupname,
e->module->auth_group(e->auth_ctx, req->group_name, e->groupname,
sizeof(e->groupname));
if (ret != 0) {
ret = -1;
@@ -534,14 +545,20 @@ int handle_sec_auth_init(int cfd, sec_mod_st * sec, const SecAuthInitMsg * req)
/* a module is allowed to change the name of the user */
ret =
module->auth_user(e->auth_ctx, e->username,
e->module->auth_user(e->auth_ctx, e->username,
sizeof(e->username));
if (ret != 0 && req->user_name != NULL) {
strlcpy(e->username, req->user_name, sizeof(e->username));
}
ret = e->module->auth_msg(e->auth_ctx, e->msg_str, sizeof(e->msg_str));
if (ret < 0) {
ret = -1;
goto cleanup;
}
}
if (sec->config->auth_types & AUTH_TYPE_CERTIFICATE) {
if (e->auth_type & AUTH_TYPE_CERTIFICATE) {
if (e->groupname[0] == 0 && req->group_name != NULL && sec->config->cert_group_oid != NULL) {
unsigned i, found = 0;
@@ -575,7 +592,7 @@ int handle_sec_auth_init(int cfd, sec_mod_st * sec, const SecAuthInitMsg * req)
req->tls_auth_ok?"(with cert) ":"",
e->username, e->groupname, req->ip);
if (sec->config->auth_types & AUTH_TYPE_USERNAME_PASS) {
if (need_continue != 0) {
ret = ERR_AUTH_CONTINUE;
goto cleanup;
}
@@ -587,15 +604,15 @@ int handle_sec_auth_init(int cfd, sec_mod_st * sec, const SecAuthInitMsg * req)
void sec_auth_user_deinit(sec_mod_st * sec, client_entry_st * e)
{
if (module == NULL)
if (e->module == NULL)
return;
seclog(sec, LOG_DEBUG, "auth deinit for user '%s'", e->username);
if (e->auth_ctx != NULL) {
if (e->have_session) {
module->close_session(e->auth_ctx, &e->stats);
e->module->close_session(e->auth_ctx, &e->stats);
}
module->auth_deinit(e->auth_ctx);
e->module->auth_deinit(e->auth_ctx);
e->auth_ctx = NULL;
e->have_session = 0;
}

View File

@@ -358,7 +358,6 @@ 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;
}

View File

@@ -56,6 +56,8 @@ typedef struct client_entry_st {
unsigned in_use; /* counter of users of this structure */
unsigned tls_auth_ok;
char msg_str[MAX_MSG_SIZE];
stats_st stats;
unsigned status; /* PS_AUTH_ */
@@ -71,6 +73,12 @@ typedef struct client_entry_st {
/* The time this client entry was last modified (created or closed) */
time_t time;
/* the auth type associated with the user */
unsigned auth_type;
/* the module this entry is using */
const struct auth_mod_st *module;
void *auth_additional; /* input to auth_init */
} client_entry_st;
void *sec_mod_client_db_init(sec_mod_st *sec);
@@ -98,7 +106,6 @@ void seclog_hex(const struct sec_mod_st* sec, int priority,
const char *prefix, uint8_t* bin, unsigned bin_size, unsigned b64);
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(int cfd, sec_mod_st *sec, const SecAuthInitMsg * req);
int handle_sec_auth_cont(int cfd, sec_mod_st *sec, const SecAuthContMsg * req);

View File

@@ -398,10 +398,10 @@ static int verify_certificate_cb(gnutls_session_t session)
fail:
/* In cisco client compatibility we don't hangup immediately, we
* simply use the flag (ws->cert_auth_ok). */
if (ws->config->cisco_client_compat == 0)
return GNUTLS_E_CERTIFICATE_ERROR;
else
if (ws->config->cisco_client_compat != 0 || ws->config->cert_req != GNUTLS_CERT_REQUIRE)
return 0;
else
return GNUTLS_E_CERTIFICATE_ERROR;
}

View File

@@ -86,6 +86,7 @@ extern int syslog_open;
#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 AUTH_TYPE_GSSAPI (1<<6)
#define ERR_SUCCESS 0
#define ERR_BAD_COMMAND -2
@@ -209,6 +210,16 @@ struct vpn_st {
unsigned int nbns_size;
};
#define MAX_AUTH_METHODS 4
typedef struct auth_struct_st {
const char *name;
char *additional;
unsigned type;
const struct auth_mod_st *amod;
bool enabled;
} auth_struct_st;
struct cfg_st {
char *name; /* server name */
unsigned int port;
@@ -230,8 +241,10 @@ struct cfg_st {
char *dh_params_file;
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 */
char *auth_additional; /* the additional string specified in the auth methode */
auth_struct_st auth[MAX_AUTH_METHODS];
unsigned auth_methods;
gnutls_certificate_request_t cert_req;
char *priorities;
unsigned enable_compression;

View File

@@ -88,6 +88,22 @@ static const char ocv3_login_msg_end[] =
static int get_cert_info(worker_st * ws);
int ws_switch_auth_to(struct worker_st *ws, unsigned auth)
{
unsigned i;
if (ws->selected_auth && ws->selected_auth->type & auth)
return 1;
for (i=1;i<ws->config->auth_methods;i++) {
if ((ws->config->auth[i].type & auth) != 0) {
ws->selected_auth = &ws->config->auth[i];
return 1;
}
}
return 0;
}
static int append_group_idx(worker_st * ws, str_st *str, unsigned i)
{
char temp[128];
@@ -215,7 +231,7 @@ int get_auth_handler2(worker_st * ws, unsigned http_ver, const char *pmsg)
goto cleanup;
}
if (ws->config->auth_types & AUTH_TYPE_USERNAME_PASS) {
if (ws->selected_auth->type & AUTH_TYPE_USERNAME_PASS) {
ret = str_append_str(&str, login_msg_user);
if (ret < 0) {
ret = -1;
@@ -223,7 +239,7 @@ int get_auth_handler2(worker_st * ws, unsigned http_ver, const char *pmsg)
}
}
if (ws->config->auth_types & AUTH_TYPE_CERTIFICATE && ws->cert_auth_ok != 0) {
if (ws->selected_auth->type & AUTH_TYPE_CERTIFICATE && ws->cert_auth_ok != 0) {
ret = get_cert_info(ws);
if (ret < 0) {
ret = -1;
@@ -262,7 +278,7 @@ int get_auth_handler2(worker_st * ws, unsigned http_ver, const char *pmsg)
}
/* append any groups available in the certificate */
if (ws->config->auth_types & AUTH_TYPE_CERTIFICATE && ws->cert_auth_ok != 0) {
if (ws->selected_auth->type & AUTH_TYPE_CERTIFICATE && ws->cert_auth_ok != 0) {
unsigned dup;
for (i=0;i<ws->cert_groups_size;i++) {
@@ -794,9 +810,9 @@ int auth_cookie(worker_st * ws, void *cookie, size_t cookie_size)
int ret;
AuthCookieRequestMsg msg = AUTH_COOKIE_REQUEST_MSG__INIT;
if ((ws->config->auth_types & AUTH_TYPE_CERTIFICATE)
if ((ws->selected_auth->type & AUTH_TYPE_CERTIFICATE)
&& ws->config->cisco_client_compat == 0) {
if (((ws->config->auth_types & AUTH_TYPE_CERTIFICATE_OPT) != AUTH_TYPE_CERTIFICATE_OPT && ws->cert_auth_ok == 0)) {
if (((ws->selected_auth->type & AUTH_TYPE_CERTIFICATE_OPT) != AUTH_TYPE_CERTIFICATE_OPT && ws->cert_auth_ok == 0)) {
oclog(ws, LOG_INFO,
"no certificate provided for cookie authentication");
return -1;
@@ -833,7 +849,7 @@ int auth_cookie(worker_st * ws, void *cookie, size_t cookie_size)
return 0;
}
int post_common_handler(worker_st * ws, unsigned http_ver)
int post_common_handler(worker_st * ws, unsigned http_ver, const char *imsg)
{
int ret, size;
char str_cookie[BASE64_LENGTH(ws->cookie_size)+1];
@@ -870,6 +886,12 @@ int post_common_handler(worker_st * ws, unsigned http_ver)
if (ret < 0)
return -1;
if (ws->selected_auth->type & AUTH_TYPE_GSSAPI && imsg != NULL) {
ret = cstp_printf(ws, "WWW-Authenticate: Negotiate %s\r\n", imsg);
if (ret < 0)
return -1;
}
ret = cstp_puts(ws, "Content-Type: text/xml\r\n");
if (ret < 0)
return -1;
@@ -966,6 +988,9 @@ int parse_reply(worker_st * ws, char *body, unsigned body_length,
unsigned temp2_len, temp1_len;
unsigned len, xml = 0;
if (body == NULL || body_length == 0)
return -1;
if (memmem(body, body_length, "<?xml", 5) != 0) {
xml = 1;
if (xml_field) {
@@ -1045,6 +1070,42 @@ int parse_reply(worker_st * ws, char *body, unsigned body_length,
return 0;
}
static
int basic_auth_handler(worker_st * ws, unsigned http_ver, const char *msg)
{
int ret;
cstp_cork(ws);
ret = cstp_printf(ws, "HTTP/1.%u 401 Unauthorized\r\n", http_ver);
if (ret < 0)
return -1;
if (msg == NULL) {
ret = cstp_puts(ws, "WWW-Authenticate: Negotiate\r\n");
} else {
ret = cstp_printf(ws, "WWW-Authenticate: Negotiate %s\r\n", msg);
}
if (ret < 0)
return -1;
ret = cstp_puts(ws, "\r\n");
if (ret < 0) {
ret = -1;
goto cleanup;
}
ret = cstp_uncork(ws);
if (ret < 0) {
ret = -1;
goto cleanup;
}
ret = 0;
cleanup:
return ret;
}
#define USERNAME_FIELD "username"
#define PASSWORD_FIELD "password"
#define GROUPNAME_FIELD "group%5flist"
@@ -1101,7 +1162,20 @@ int post_auth_handler(worker_st * ws, unsigned http_ver)
}
talloc_free(groupname);
if (ws->config->auth_types & AUTH_TYPE_USERNAME_PASS) {
if (ws->selected_auth->type & AUTH_TYPE_GSSAPI) {
if (req->authorization == NULL || req->authorization_size == 0)
return basic_auth_handler(ws, http_ver, NULL);
if (req->authorization_size > 10) {
ireq.user_name = req->authorization + 10;
ireq.auth_type |= AUTH_TYPE_GSSAPI;
} else {
oclog(ws, LOG_HTTP_DEBUG, "Invalid authorization data: %.*s", req->authorization_size, req->authorization);
goto auth_fail;
}
}
if (ws->selected_auth->type & AUTH_TYPE_USERNAME_PASS) {
ret = parse_reply(ws, req->body, req->body_length,
USERNAME_FIELD, sizeof(USERNAME_FIELD)-1,
@@ -1115,10 +1189,11 @@ int post_auth_handler(worker_st * ws, unsigned http_ver)
strlcpy(ws->username, username, sizeof(ws->username));
talloc_free(username);
ireq.user_name = ws->username;
ireq.auth_type |= AUTH_TYPE_USERNAME_PASS;
}
if (ws->config->auth_types & AUTH_TYPE_CERTIFICATE) {
if ((ws->config->auth_types & AUTH_TYPE_CERTIFICATE_OPT) != AUTH_TYPE_CERTIFICATE_OPT && ws->cert_auth_ok == 0) {
if (ws->selected_auth->type & AUTH_TYPE_CERTIFICATE) {
if ((ws->selected_auth->type & AUTH_TYPE_CERTIFICATE_OPT) != AUTH_TYPE_CERTIFICATE_OPT && ws->cert_auth_ok == 0) {
reason = MSG_NO_CERT_ERROR;
oclog(ws, LOG_INFO,
"no certificate provided for authentication");
@@ -1144,6 +1219,7 @@ int post_auth_handler(worker_st * ws, unsigned http_ver)
ireq.cert_user_name = ws->cert_username;
ireq.cert_group_names = ws->cert_groups;
ireq.n_cert_group_names = ws->cert_groups_size;
ireq.auth_type |= AUTH_TYPE_CERTIFICATE;
}
ireq.hostname = req->hostname;
@@ -1174,7 +1250,16 @@ int post_auth_handler(worker_st * ws, unsigned http_ver)
|| ws->auth_state == S_AUTH_REQ) {
SecAuthContMsg areq = SEC_AUTH_CONT_MSG__INIT;
if (ws->config->auth_types & AUTH_TYPE_USERNAME_PASS) {
if (ws->selected_auth->type & AUTH_TYPE_GSSAPI) {
if (req->authorization == NULL || req->authorization_size <= 10) {
if (req->authorization != NULL)
oclog(ws, LOG_HTTP_DEBUG, "Invalid authorization data: %.*s", req->authorization_size, req->authorization);
goto auth_fail;
}
areq.password = req->authorization + 10;
}
if (areq.password == NULL && ws->selected_auth->type & AUTH_TYPE_USERNAME_PASS) {
ret = parse_reply(ws, req->body, req->body_length,
PASSWORD_FIELD, sizeof(PASSWORD_FIELD)-1,
NULL, 0,
@@ -1186,6 +1271,9 @@ int post_auth_handler(worker_st * ws, unsigned http_ver)
}
areq.password = password;
}
if (areq.password != NULL) {
if (ws->sid_set != 0) {
areq.sid.data = ws->sid;
areq.sid.len = sizeof(ws->sid);
@@ -1234,7 +1322,10 @@ int post_auth_handler(worker_st * ws, unsigned http_ver)
ws->username);
ws->auth_state = S_AUTH_REQ;
return get_auth_handler2(ws, http_ver, msg);
if (ws->selected_auth->type & AUTH_TYPE_GSSAPI)
return basic_auth_handler(ws, http_ver, msg);
else
return get_auth_handler2(ws, http_ver, msg);
} else if (ret < 0) {
oclog(ws, LOG_ERR, "failed authentication for '%s'",
ws->username);
@@ -1244,7 +1335,7 @@ int post_auth_handler(worker_st * ws, unsigned http_ver)
oclog(ws, LOG_HTTP_DEBUG, "user '%s' obtained cookie", ws->username);
ws->auth_state = S_AUTH_COOKIE;
return post_common_handler(ws, http_ver);
return post_common_handler(ws, http_ver, msg);
ask_auth:

View File

@@ -204,6 +204,16 @@ void header_value_check(struct worker_st *ws, struct http_req_st *req)
case HEADER_DEVICE_TYPE:
req->is_mobile = 1;
break;
case HEADER_NEED_SPNEGO:
ws_switch_auth_to(ws, AUTH_TYPE_GSSAPI);
break;
case HEADER_AUTHORIZATION:
if (req->authorization != NULL)
talloc_free(req->authorization);
req->authorization = value;
req->authorization_size = value_length;
value = NULL;
break;
case HEADER_USER_AGENT:
if (value_length + 1 > MAX_AGENT_NAME) {
memcpy(req->user_agent, value, MAX_AGENT_NAME-1);

View File

@@ -355,6 +355,10 @@ void vpn_server(struct worker_st *ws)
memset(&settings, 0, sizeof(settings));
ws->selected_auth = &ws->config->auth[0];
if (ws->cert_auth_ok)
ws_switch_auth_to(ws, AUTH_TYPE_CERTIFICATE);
settings.on_url = http_url_cb;
settings.on_header_field = http_header_field_cb;
settings.on_header_value = http_header_value_cb;

View File

@@ -58,7 +58,9 @@ enum {
HEADER_FULL_IPV6,
HEADER_USER_AGENT,
HEADER_CSTP_ENCODING,
HEADER_DTLS_ENCODING
HEADER_DTLS_ENCODING,
HEADER_NEED_SPNEGO,
HEADER_AUTHORIZATION
};
enum {
@@ -130,6 +132,9 @@ struct http_req_st {
unsigned no_ipv4;
unsigned no_ipv6;
char *authorization;
unsigned authorization_size;
};
typedef struct dtls_transport_ptr {
@@ -143,6 +148,7 @@ typedef struct worker_st {
gnutls_session_t session;
gnutls_session_t dtls_session;
auth_struct_st *selected_auth;
const compression_method_st *dtls_selected_comp;
const compression_method_st *cstp_selected_comp;
@@ -309,6 +315,7 @@ int send_tun_mtu(worker_st *ws, unsigned int mtu);
int handle_worker_commands(struct worker_st *ws);
int disable_system_calls(struct worker_st *ws);
void ocsigaltstack(struct worker_st *ws);
int ws_switch_auth_to(struct worker_st *ws, unsigned auth);
int connect_to_secmod(worker_st * ws);
inline static