Advanced auth implemented

This commit is contained in:
Nikos Mavrogiannopoulos
2013-06-24 11:15:09 +02:00
parent cbcdbd2fb2
commit e5def94e6a
16 changed files with 831 additions and 297 deletions

View File

@@ -112,6 +112,22 @@ if [ test "$anyconnect_enabled" = "yes" ];then
AC_DEFINE([ANYCONNECT_CLIENT_COMPAT], [], [Enable Anyconnect compatibility])
fi
pcl_enabled=no
LIBS="$oldlibs -lpcl"
AC_MSG_CHECKING([for pcl library])
AC_LINK_IFELSE([AC_LANG_PROGRAM([
#include <pcl.h>],[
co_create(0, 0, 0, 0);])],
[AC_MSG_RESULT(yes)
AC_SUBST([PCL_LIBS], [-lpcl])
AC_SUBST([PCL_CFLAGS], [])
pcl_enabled=yes],
[AC_MSG_RESULT(no)
AC_MSG_ERROR([[
***
*** libpcl (portable co-routines) was not found.
*** ]])])
LIBS="$oldlibs"
enable_local_libopts=yes
NEED_LIBOPTS_DIR=true

View File

@@ -16,7 +16,7 @@ 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 \
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 \
worker-extras.c \
worker-extras.c main-auth.h \
main-user.c cookies-gdbm.c cookies-hash.c worker-misc.c setproctitle.h \
setproctitle.c worker-privs.c plain.c plain.h common.h common.c \
sec-mod.c sec-mod.h script-list.h system.c system.h icmp-ping.c icmp-ping.h \
@@ -26,7 +26,7 @@ ocserv_SOURCES += ocserv-args.def ocserv-args.c ocserv-args.h
ocserv_LDADD = ../gl/libgnu.a ../libopts/libopts.a
ocserv_LDADD += $(LIBGNUTLS_LIBS) $(GDBM_LIBS) $(PAM_LIBS) $(LIBUTIL) \
$(LIBSECCOMP) $(LIBWRAP) $(LIBCRYPT)
$(LIBSECCOMP) $(LIBWRAP) $(LIBCRYPT) $(PCL_LIBS)
ocserv-args.c ocserv-args.h: $(srcdir)/ocserv-args.def
@AUTOGEN@ $<

View File

@@ -10,10 +10,14 @@
#include <vpn.h>
#include <tlslib.h>
#define MAX_MSG_SIZE 256
typedef enum {
AUTH_REQ = 1,
AUTH_COOKIE_REQ,
AUTH_INIT=1,
AUTH_REP,
AUTH_REQ,
AUTH_COOKIE_REQ,
AUTH_MSG,
RESUME_STORE_REQ,
RESUME_DELETE_REQ,
RESUME_FETCH_REQ,
@@ -24,8 +28,9 @@ typedef enum {
} cmd_request_t;
typedef enum {
REP_AUTH_OK = 0,
REP_AUTH_FAILED = 1,
REP_AUTH_OK = 1,
REP_AUTH_MSG = 2,
REP_AUTH_FAILED = 3,
} cmd_auth_reply_t;
typedef enum {
@@ -43,9 +48,13 @@ struct __attribute__ ((__packed__)) cmd_auth_cookie_req_st {
/* AUTH_REQ */
struct __attribute__ ((__packed__)) cmd_auth_req_st {
uint8_t user_pass_present;
char user[MAX_USERNAME_SIZE];
uint8_t pass_present;
char pass[MAX_PASSWORD_SIZE];
};
struct __attribute__ ((__packed__)) cmd_auth_init_st {
uint8_t user_present;
char user[MAX_USERNAME_SIZE];
uint8_t tls_auth_ok;
char cert_user[MAX_USERNAME_SIZE];
char cert_group[MAX_GROUPNAME_SIZE];
@@ -59,6 +68,7 @@ struct __attribute__ ((__packed__)) cmd_auth_reply_st {
uint8_t session_id[GNUTLS_MAX_SESSION_ID];
char vname[IFNAMSIZ]; /* interface name */
char user[MAX_USERNAME_SIZE];
char msg[MAX_MSG_SIZE]; /* in case of REP_AUTH_CONTINUE */
};
/* RESUME_FETCH_REQ + RESUME_DELETE_REQ */

View File

@@ -41,8 +41,24 @@
#include <tun.h>
#include <main.h>
#include <ccan/list/list.h>
#include "pam.h"
#include "plain.h"
#include <main-auth.h>
#include <plain.h>
#include <pam.h>
static const struct auth_mod_st *module;
void main_auth_init(main_server_st *s)
{
#ifdef HAVE_PAM
if ((s->config->auth_types & pam_auth_funcs.type) == pam_auth_funcs.type)
module = &pam_auth_funcs;
else
#endif
if ((s->config->auth_types & plain_auth_funcs.type) == plain_auth_funcs.type) {
module = &plain_auth_funcs;
s->auth_extra = s->config->plain_passwd;
}
}
int send_auth_reply(main_server_st* s, struct proc_st* proc,
cmd_auth_reply_t r)
@@ -100,6 +116,41 @@ int send_auth_reply(main_server_st* s, struct proc_st* proc,
return(sendmsg(proc->fd, &hdr, 0));
}
int send_auth_reply_msg(main_server_st* s, struct proc_st* proc)
{
struct iovec iov[2];
uint8_t cmd[1];
struct msghdr hdr;
struct cmd_auth_reply_st resp;
int ret;
if (proc->auth_ctx == NULL)
return -1;
memset(&resp, 0, sizeof(resp));
ret = module->auth_msg(proc->auth_ctx, resp.msg, sizeof(resp.msg));
if (ret < 0)
return ret;
memset(&hdr, 0, sizeof(hdr));
hdr.msg_iov = iov;
cmd[0] = AUTH_REP;
resp.reply = REP_AUTH_MSG;
iov[0].iov_base = cmd;
iov[0].iov_len = 1;
hdr.msg_iovlen++;
iov[1].iov_base = &resp;
iov[1].iov_len = sizeof(resp);
hdr.msg_iovlen++;
return(sendmsg(proc->fd, &hdr, 0));
}
int handle_auth_cookie_req(main_server_st* s, struct proc_st* proc,
const struct cmd_auth_cookie_req_st * req)
{
@@ -145,12 +196,6 @@ time_t now = time(0);
goto cleanup;
}
}
ret = open_tun(s, &proc->lease);
if (ret < 0) {
ret = -1; /* sorry */
goto cleanup;
}
/* ok auth ok. Renew the cookie. */
sc->expiration = time(0) + s->config->cookie_validity;
@@ -201,36 +246,38 @@ struct stored_cookie_st *sc;
return 0;
}
int handle_auth_req(main_server_st *s, struct proc_st* proc,
const struct cmd_auth_req_st * req)
int handle_auth_init(main_server_st *s, struct proc_st* proc,
const struct cmd_auth_init_st * req)
{
int ret = -1;
char ipbuf[128];
const char* ip;
unsigned username_set = 0;
ip = human_addr((void*)&proc->remote_addr, proc->remote_addr_len,
ipbuf, sizeof(ipbuf));
ipbuf, sizeof(ipbuf));
if (req->user_pass_present != 0) {
#ifdef HAVE_PAM
if ((s->config->auth_types & AUTH_TYPE_PAM) == AUTH_TYPE_PAM) {
ret = pam_auth_user(req->user, req->pass, proc->groupname, sizeof(proc->groupname), ip);
if (ret != 0)
ret = -1;
if (req->user_present == 0 && s->config->auth_types & AUTH_TYPE_USERNAME_PASS) {
mslog(s, proc, LOG_DEBUG, "auth init from '%s' with no username present", ip);
return -1;
}
memcpy(proc->username, req->user, MAX_USERNAME_SIZE);
username_set = 1;
}
#endif
if ((s->config->auth_types & AUTH_TYPE_PLAIN) == AUTH_TYPE_PLAIN) {
ret = plain_auth_user(s->config->plain_passwd, req->user, req->pass, proc->groupname, sizeof(proc->groupname));
if (ret != 0)
ret = -1;
if (req->hostname[0] != 0) {
memcpy(proc->hostname, req->hostname, MAX_HOSTNAME_SIZE);
proc->hostname[sizeof(proc->hostname)-1] = 0;
}
memcpy(proc->username, req->user, MAX_USERNAME_SIZE);
username_set = 1;
}
if (req->user_present != 0 && s->config->auth_types & AUTH_TYPE_USERNAME_PASS) {
ret = module->auth_init(&proc->auth_ctx, req->user, ip, s->auth_extra);
if (ret < 0)
return ret;
ret = module->auth_group(proc->auth_ctx, proc->groupname, sizeof(proc->groupname));
if (ret != 0)
return -1;
proc->groupname[sizeof(proc->groupname)-1] = 0;
memcpy(proc->username, req->user, MAX_USERNAME_SIZE);
proc->username[sizeof(proc->username)-1] = 0;
}
if (s->config->auth_types & AUTH_TYPE_CERTIFICATE) {
@@ -238,35 +285,42 @@ unsigned username_set = 0;
ret = 0;
}
if (username_set == 0) {
if (proc->username[0] == 0) {
memcpy(proc->username, req->cert_user, sizeof(proc->username));
memcpy(proc->groupname, req->cert_group, sizeof(proc->groupname));
proc->username[sizeof(proc->username)-1] = 0;
proc->groupname[sizeof(proc->groupname)-1] = 0;
} else {
if (strcmp(proc->username, req->cert_user) != 0) {
mslog(s, proc, LOG_INFO, "user '%s' presented a certificate from user '%s'", proc->username, req->cert_user);
ret = -1;
return -1;
}
if (strcmp(proc->groupname, req->cert_group) != 0) {
mslog(s, proc, LOG_INFO, "user '%s' presented a certificate from group '%s' but he is member of '%s'", proc->username, req->cert_group, proc->groupname);
ret = -1;
return -1;
}
}
}
if (ret == 0) { /* open tun */
if (req->hostname[0] != 0)
memcpy(proc->hostname, req->hostname, MAX_HOSTNAME_SIZE);
mslog(s, proc, LOG_DEBUG, "auth init for user '%s' from '%s'", proc->username, ip);
proc->username[sizeof(proc->username)-1] = 0;
proc->groupname[sizeof(proc->groupname)-1] = 0;
proc->hostname[sizeof(proc->hostname)-1] = 0;
ret = open_tun(s, &proc->lease);
if (ret < 0)
ret = -1; /* sorry */
if (s->config->auth_types & AUTH_TYPE_USERNAME_PASS) {
return ERR_AUTH_CONTINUE;
}
return ret;
return 0;
}
int handle_auth_req(main_server_st *s, struct proc_st* proc,
const struct cmd_auth_req_st * req)
{
if (proc->auth_ctx == NULL) {
mslog(s, proc, LOG_ERR, "auth req but with no context!");
return -1;
}
mslog(s, proc, LOG_DEBUG, "auth req for user '%s'", proc->username);
return module->auth_pass(proc->auth_ctx, req->pass);
}
int check_multiple_users(main_server_st *s, struct proc_st* proc)
@@ -292,3 +346,11 @@ unsigned int entries = 1; /* that one */
return 0;
}
void proc_auth_deinit(main_server_st* s, struct proc_st* proc)
{
mslog(s, proc, LOG_DEBUG, "auth deinit for user '%s'", proc->username);
if (proc->auth_ctx != NULL) {
module->auth_deinit(proc->auth_ctx);
proc->auth_ctx = NULL;
}
}

18
src/main-auth.h Normal file
View File

@@ -0,0 +1,18 @@
#ifndef AUTH_H
# define AUTH_H
#include <main.h>
struct auth_mod_st {
unsigned int type;
int (*auth_init)(void** ctx, 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);
int (*auth_group)(void* ctx, char *groupname, int groupname_size);
void (*auth_deinit)(void* ctx);
};
void main_auth_init(main_server_st *s);
void proc_auth_deinit(main_server_st* s, struct proc_st* proc);
#endif

View File

@@ -147,6 +147,54 @@ fail:
return ret;
}
static int accept_user(main_server_st *s, struct proc_st* proc, unsigned cmd)
{
int ret;
const char* group;
mslog(s, proc, LOG_DEBUG, "accepting user '%s'", proc->username);
proc_auth_deinit(s, proc);
ret = open_tun(s, &proc->lease);
if (ret < 0) {
return -1;
}
/* check for multiple connections */
ret = check_multiple_users(s, proc);
if (ret < 0) {
mslog(s, proc, LOG_INFO, "user '%s' tried to connect more than %u times", proc->username, s->config->max_same_clients);
return ret;
}
if (proc->groupname[0] == 0)
group = "[unknown]";
else
group = proc->groupname;
if (cmd == AUTH_REQ || cmd == AUTH_INIT) {
/* generate and store cookie */
ret = generate_and_store_vals(s, proc);
if (ret < 0) {
return ERR_BAD_COMMAND;
}
mslog(s, proc, LOG_INFO, "user '%s' of group '%s' authenticated", proc->username, group);
} else {
mslog(s, proc, LOG_INFO, "user '%s' of group '%s' re-authenticated (using cookie)", proc->username, group);
}
/* do scripts and utmp */
ret = user_connected(s, proc);
if (ret == ERR_WAIT_FOR_SCRIPT) {
return 0;
}
if (ret < 0) {
mslog(s, proc, LOG_INFO, "user '%s' disconnected due to script", proc->username);
}
return 0;
}
int handle_commands(main_server_st *s, struct proc_st* proc)
{
@@ -159,9 +207,9 @@ int handle_commands(main_server_st *s, struct proc_st* proc)
struct cmd_resume_store_req_st sresume;
struct cmd_resume_fetch_req_st fresume;
struct cmd_tun_mtu_st tmtu;
struct cmd_auth_init_st auth_init;
} cmd_data;
int ret, cmd_data_len, e;
const char* group;
memset(&cmd_data, 0, sizeof(cmd_data));
@@ -187,7 +235,12 @@ int handle_commands(main_server_st *s, struct proc_st* proc)
}
cmd_data_len = ret - 1;
if (proc->auth_status == PS_AUTH_INIT && cmd != AUTH_REQ) {
mslog(s, proc, LOG_ERR, "received message %u when expecting auth req.", (unsigned)cmd);
return ERR_BAD_COMMAND;
}
switch(cmd) {
case CMD_TUN_MTU:
if (cmd_data_len != sizeof(cmd_data.tmtu)) {
@@ -242,64 +295,83 @@ int handle_commands(main_server_st *s, struct proc_st* proc)
break;
case AUTH_REQ:
case AUTH_COOKIE_REQ:
if (cmd == AUTH_REQ) {
if (cmd_data_len != sizeof(cmd_data.auth)) {
mslog(s, proc, LOG_ERR, "error in received message (%u) length.", (unsigned)cmd);
return ERR_BAD_COMMAND;
}
ret = handle_auth_req(s, proc, &cmd_data.auth);
} else {
if (cmd_data_len != sizeof(cmd_data.cauth)) {
mslog(s, proc, LOG_ERR, "error in received message (%u) length.", (unsigned)cmd);
return ERR_BAD_COMMAND;
}
ret = handle_auth_cookie_req(s, proc, &cmd_data.cauth);
case AUTH_INIT:
if (cmd_data_len != sizeof(cmd_data.auth_init)) {
mslog(s, proc, LOG_ERR, "error in received message (%u) length.", (unsigned)cmd);
return ERR_BAD_COMMAND;
}
if (ret == 0) {
/* check for multiple connections */
ret = check_multiple_users(s, proc);
if (proc->auth_status != PS_AUTH_INACTIVE) {
mslog(s, proc, LOG_ERR, "received authentication init when complete.");
return ERR_BAD_COMMAND;
}
ret = handle_auth_init(s, proc, &cmd_data.auth_init);
if (ret == ERR_AUTH_CONTINUE) {
proc->auth_status = PS_AUTH_INIT;
ret = send_auth_reply_msg(s, proc);
if (ret < 0) {
mslog(s, proc, LOG_INFO, "user '%s' tried to connect more than %u times", proc->username, s->config->max_same_clients);
mslog(s, proc, LOG_ERR, "could not send reply auth cmd.");
return ret;
}
if (ret == 0) {
if (proc->groupname[0] == 0)
group = "[unknown]";
else
group = proc->groupname;
if (cmd == AUTH_REQ) {
/* generate and store cookie */
ret = generate_and_store_vals(s, proc);
if (ret < 0) {
ret = ERR_BAD_COMMAND;
goto cleanup;
}
mslog(s, proc, LOG_INFO, "user '%s' of group '%s' authenticated", proc->username, group);
} else {
mslog(s, proc, LOG_INFO, "user '%s' of group '%s' re-authenticated (using cookie)", proc->username, group);
}
}
/* do scripts and utmp */
if (ret == 0) {
ret = user_connected(s, proc);
if (ret == ERR_WAIT_FOR_SCRIPT) {
return 0;
}
if (ret < 0) {
mslog(s, proc, LOG_INFO, "user '%s' disconnected due to script", proc->username);
}
}
} else {
break; /* wait for another command */
} else if (ret < 0) {
add_to_ip_ban_list(s, &proc->remote_addr, proc->remote_addr_len);
return ret;
}
break;
case AUTH_REQ:
if (proc->auth_status != PS_AUTH_INIT) {
mslog(s, proc, LOG_ERR, "received authentication request when not initialized.");
return ERR_BAD_COMMAND;
}
if (cmd_data_len != sizeof(cmd_data.auth)) {
mslog(s, proc, LOG_ERR, "error in received message (%u) length.", (unsigned)cmd);
return ERR_BAD_COMMAND;
}
ret = handle_auth_req(s, proc, &cmd_data.auth);
if (ret == ERR_AUTH_CONTINUE) {
ret = send_auth_reply_msg(s, proc);
if (ret < 0) {
mslog(s, proc, LOG_ERR, "could not send reply auth cmd.");
return ret;
}
break; /* wait for another command */
} else if (ret < 0) {
add_to_ip_ban_list(s, &proc->remote_addr, proc->remote_addr_len);
return ret;
}
ret = accept_user(s, proc, cmd);
if (ret < 0) {
goto cleanup;
}
proc->auth_status = PS_AUTH_COMPLETED;
goto cleanup;
case AUTH_COOKIE_REQ:
if (cmd_data_len != sizeof(cmd_data.cauth)) {
mslog(s, proc, LOG_ERR, "error in received message (%u) length.", (unsigned)cmd);
return ERR_BAD_COMMAND;
}
ret = handle_auth_cookie_req(s, proc, &cmd_data.cauth);
if (ret < 0) {
add_to_ip_ban_list(s, &proc->remote_addr, proc->remote_addr_len);
return ret;
}
ret = accept_user(s, proc, cmd);
if (ret < 0) {
goto cleanup;
}
proc->auth_status = PS_AUTH_COMPLETED;
cleanup:
/* no script was called. Handle it as a successful script call. */

View File

@@ -44,6 +44,7 @@
#endif
#include <main.h>
#include <main-auth.h>
#include <worker.h>
#include <cookies.h>
#include <tun.h>
@@ -299,6 +300,9 @@ static void remove_proc(main_server_st* s, struct proc_st *proc, unsigned k)
close(proc->fd);
proc->fd = -1;
proc->pid = -1;
if (proc->auth_ctx != NULL)
proc_auth_deinit(s, proc);
if (proc->lease)
proc->lease->in_use = 0;
@@ -669,6 +673,8 @@ int main(int argc, char** argv)
s.config = &config;
s.tun = &tun;
main_auth_init(&s);
ret = cookie_db_init(&s);
if (ret < 0) {
fprintf(stderr, "Could not initialize cookie database.\n");
@@ -861,6 +867,7 @@ fork_failed:
if (FD_ISSET(ctmp->fd, &rd)) {
ret = handle_commands(&s, ctmp);
if (ret < 0) {
fprintf(stderr, "error in command deleting\n");
remove_from_script_list(&s, ctmp);
remove_proc(&s, ctmp, (ret==ERR_BAD_COMMAND)?1:0);
}

View File

@@ -9,10 +9,6 @@
#include <tlslib.h>
#include "ipc.h"
#define ERR_WAIT_FOR_SCRIPT -5
#define ERR_BAD_COMMAND -2
#define ERR_MEM -6
int cmd_parser (int argc, char **argv, struct cfg_st* config);
void reload_cfg_file(struct cfg_st* config);
void write_pid_file(void);
@@ -45,6 +41,12 @@ struct script_wait_st {
struct proc_st* proc;
};
enum {
PS_AUTH_INACTIVE,
PS_AUTH_INIT,
PS_AUTH_COMPLETED,
};
struct proc_st {
struct list_node list;
int fd;
@@ -68,6 +70,9 @@ struct proc_st {
char groupname[MAX_GROUPNAME_SIZE]; /* the owner's group */
char hostname[MAX_HOSTNAME_SIZE]; /* the requested hostname */
uint8_t cookie[COOKIE_SIZE]; /* the cookie associated with the session */
void * auth_ctx; /* the context of authentication */
unsigned auth_status; /* PS_AUTH_ */
};
struct proc_list_st {
@@ -108,6 +113,8 @@ typedef struct main_server_st {
pid_t sec_mod_pid;
unsigned active_clients;
void * auth_extra;
} main_server_st;
void clear_lists(main_server_st *s);
@@ -144,13 +151,16 @@ void mslog_hex(const main_server_st * s, const struct proc_st* proc,
int open_tun(main_server_st* s, struct lease_st** l);
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(main_server_st* s, struct proc_st* proc,
cmd_auth_reply_t r);
int handle_auth_cookie_req(main_server_st* s, struct proc_st* proc,
const struct cmd_auth_cookie_req_st * req);
int generate_and_store_vals(main_server_st *s, struct proc_st* proc);
int handle_auth_init(main_server_st *s, struct proc_st* proc,
const struct cmd_auth_init_st * req);
int handle_auth_req(main_server_st *s, struct proc_st* proc,
const struct cmd_auth_req_st * req);
const struct cmd_auth_req_st * req);
int check_multiple_users(main_server_st *s, struct proc_st* proc);

252
src/pam.c
View File

@@ -21,6 +21,8 @@
#include <stdlib.h>
#include <string.h>
#include <syslog.h>
#include <vpn.h>
#include <main-auth.h>
#ifdef HAVE_PAM
@@ -28,89 +30,245 @@
#include <sys/types.h>
#include <pwd.h>
#include <grp.h>
#include <pcl.h>
#define APP_NAME PACKAGE
#define MAX_REPLIES 2
struct local_st {
const char* password;
const char* username;
enum {
PAM_S_INIT,
PAM_S_WAIT_FOR_PASS,
PAM_S_COMPLETE,
};
int dummy_conv(int msg_size, const struct pam_message **msg,
struct pam_ctx_st {
char password[MAX_PASSWORD_SIZE];
char username[MAX_USERNAME_SIZE];
pam_handle_t * ph;
struct pam_conv dc;
coroutine_t cr;
int cr_ret;
const char* cr_msg;
unsigned sent_msg;
struct pam_response *replies; /* for safety */
unsigned state; /* PAM_S_ */
};
static int dummy_conv(int msg_size, const struct pam_message **msg,
struct pam_response **resp, void *uptr)
{
struct local_st * l = uptr;
struct pam_ctx_st * pctx = uptr;
unsigned i;
struct pam_response *replies;
if (msg_size == 0)
return PAM_SUCCESS;
replies = calloc(1, msg_size*sizeof(*replies));
if (replies == NULL)
pctx->replies = calloc(1, msg_size*sizeof(*pctx->replies));
if (pctx->replies == NULL)
return PAM_BUF_ERR;
for (i=0;i<msg_size;i++) {
/*syslog(LOG_DEBUG, "PAM message: %s\n", msg[i]->msg);*/
/*if (msg[i]->msg_style == PAM_PROMPT_ECHO_OFF)*/
replies[i].resp = strdup(l->password);
switch (msg[i]->msg_style) {
case PAM_ERROR_MSG:
case PAM_TEXT_INFO:
fprintf(stderr, "msg: %s\n", msg[i]->msg);
if (pctx->sent_msg == 0) {
pctx->state = PAM_S_WAIT_FOR_PASS;
pctx->cr_msg = msg[i]->msg;
pctx->cr_ret = PAM_SUCCESS;
pctx->sent_msg = 1;
co_resume();
pctx->state = PAM_S_INIT;
}
break;
}
switch (msg[i]->msg_style) {
case PAM_PROMPT_ECHO_OFF:
case PAM_PROMPT_ECHO_ON:
if (pctx->sent_msg == 0) {
/* no message, just asking for password */
pctx->state = PAM_S_WAIT_FOR_PASS;
pctx->cr_msg = NULL;
pctx->cr_ret = PAM_SUCCESS;
pctx->sent_msg = 1;
co_resume();
pctx->state = PAM_S_INIT;
}
pctx->replies[i].resp = strdup(pctx->password);
pctx->sent_msg = 0;
break;
}
}
*resp = replies;
*resp = pctx->replies;
pctx->replies = NULL;
return PAM_SUCCESS;
}
static void co_auth_user(void* data)
{
struct pam_ctx_st * pctx = data;
int pret;
pctx->state = PAM_S_INIT;
pret = pam_authenticate(pctx->ph, 0);
if (pret != PAM_SUCCESS) {
pctx->cr_ret = pret;
return;
}
pret = pam_acct_mgmt(pctx->ph, PAM_SILENT);
if (pret != PAM_SUCCESS) {
pctx->cr_ret = pret;
return;
}
pctx->state = PAM_S_COMPLETE;
pctx->cr_ret = PAM_SUCCESS;
co_resume();
}
static int pam_auth_init(void** ctx, const char* user, const char* ip, void* additional)
{
int pret;
struct pam_ctx_st * pctx;
if (user == NULL)
return -1;
pctx = calloc(1, sizeof(*pctx));
if (pctx == NULL)
return -1;
pctx->cr = co_create(co_auth_user, pctx, NULL, 128*1024);
if (pctx->cr == NULL)
goto fail;
pctx->dc.conv = dummy_conv;
pctx->dc.appdata_ptr = pctx;
snprintf(pctx->username, sizeof(pctx->username), "%s", user);
pret = pam_start(APP_NAME, user, &pctx->dc, &pctx->ph);
if (pret != PAM_SUCCESS) {
syslog(LOG_AUTH, "Error in PAM authentication initialization: %s", pam_strerror(pctx->ph, pret));
goto fail;
}
if (ip != NULL)
pam_set_item(pctx->ph, PAM_RHOST, ip);
*ctx = pctx;
return 0;
fail:
free(pctx);
return -1;
}
static int pam_auth_msg(void* ctx, char* msg, size_t msg_size)
{
struct pam_ctx_st * pctx = ctx;
if (pctx->state != PAM_S_INIT && pctx->state != PAM_S_WAIT_FOR_PASS) {
syslog(LOG_AUTH, "PAM conversation in wrong state (%d)", pctx->state);
return ERR_AUTH_FAIL;
}
if (pctx->state == PAM_S_INIT) {
/* get the prompt */
pctx->cr_ret = PAM_CONV_ERR;
co_call(pctx->cr);
}
if (pctx->cr_ret != PAM_SUCCESS) {
syslog(LOG_AUTH, "Error in PAM authentication: %s", pam_strerror(pctx->ph, pctx->cr_ret));
return ERR_AUTH_FAIL;
}
if (msg != NULL) {
if (pctx->cr_msg == NULL)
snprintf(msg, msg_size, "Please enter your password");
else
snprintf(msg, msg_size, "%s", pctx->cr_msg);
}
return 0;
}
/* Returns 0 if the user is successfully authenticated
*/
int pam_auth_user(const char* user, const char* pass, char *groupname, int groupname_size, const char* ip)
static int pam_auth_pass(void* ctx, const char* pass)
{
pam_handle_t * ph;
int ret, pret;
struct local_st local;
const struct pam_conv dc = { dummy_conv, &local };
struct passwd * pwd;
struct pam_ctx_st * pctx = ctx;
local.username = user;
local.password = pass;
pret = pam_start(APP_NAME, user, &dc, &ph);
if (pret != PAM_SUCCESS) {
syslog(LOG_AUTH, "Error in PAM authentication initialization: %s", pam_strerror(ph, pret));
if (pass == NULL)
return -1;
if (pctx->state != PAM_S_WAIT_FOR_PASS) {
syslog(LOG_AUTH, "PAM conversation in wrong state (%d/expecting %d)", pctx->state, PAM_S_WAIT_FOR_PASS);
return ERR_AUTH_FAIL;
}
snprintf(pctx->password, sizeof(pctx->password), "%s", pass);
pctx->cr_ret = PAM_CONV_ERR;
co_call(pctx->cr);
if (pctx->cr_ret != PAM_SUCCESS) {
syslog(LOG_AUTH, "Error in PAM authentication: %s", pam_strerror(pctx->ph, pctx->cr_ret));
return ERR_AUTH_FAIL;
}
if (ip != NULL)
pam_set_item(ph, PAM_RHOST, ip);
pret = pam_authenticate(ph, PAM_SILENT);
if (pret != PAM_SUCCESS) {
syslog(LOG_AUTH, "Error in PAM authentication: %s", pam_strerror(ph, pret));
ret = -1;
goto fail;
}
pret = pam_acct_mgmt(ph, PAM_SILENT);
if (pret != PAM_SUCCESS) {
syslog(LOG_AUTH, "Error in PAM account management: %s", pam_strerror(ph, pret));
ret = -1;
goto fail;
}
if (pctx->state != PAM_S_COMPLETE)
return ERR_AUTH_CONTINUE;
return 0;
}
/* Returns 0 if the user is successfully authenticated
*/
static int pam_auth_group(void* ctx, char *groupname, int groupname_size)
{
struct passwd * pwd;
struct pam_ctx_st * pctx = ctx;
groupname[0] = 0;
pwd = getpwnam(user);
pwd = getpwnam(pctx->username);
if (pwd != NULL) {
struct group* grp = getgrgid(pwd->pw_gid);
if (grp != NULL)
snprintf(groupname, groupname_size, "%s", grp->gr_name);
}
ret = 0;
fail:
pam_end(ph, pret);
return ret;
return 0;
}
static void pam_auth_deinit(void* ctx)
{
struct pam_ctx_st * pctx = ctx;
pam_end(pctx->ph, pctx->cr_ret);
free(pctx->replies);
co_delete(pctx->cr);
free(pctx);
}
const struct auth_mod_st pam_auth_funcs = {
.type = AUTH_TYPE_PAM | AUTH_TYPE_USERNAME_PASS,
.auth_init = pam_auth_init,
.auth_deinit = pam_auth_deinit,
.auth_msg = pam_auth_msg,
.auth_pass = pam_auth_pass,
.auth_group = pam_auth_group
};
#endif

View File

@@ -1,6 +1,8 @@
#ifndef PAM_H
#define PAM_H
int pam_auth_user(const char* user, const char* pass, char *groupname, int groupname_size, const char* ip);
#include <main-auth.h>
extern const struct auth_mod_st pam_auth_funcs;
#endif

View File

@@ -22,12 +22,47 @@
#include <string.h>
#include <syslog.h>
#include <unistd.h>
#include <vpn.h>
#include <plain.h>
struct plain_ctx_st {
char username[MAX_USERNAME_SIZE];
char groupname[MAX_GROUPNAME_SIZE];
const char* passwd;
};
static int plain_auth_init(void** ctx, const char* username, const char* ip, void* additional)
{
struct plain_ctx_st* pctx;
pctx = malloc(sizeof(*pctx));
if (pctx == NULL)
return ERR_AUTH_FAIL;
snprintf(pctx->username, sizeof(pctx->username), "%s", username);
pctx->passwd = additional;
*ctx = pctx;
return 0;
}
static int plain_auth_group(void* ctx, char *groupname, int groupname_size)
{
struct plain_ctx_st* pctx = ctx;
snprintf(groupname, groupname_size, "%s", pctx->groupname);
return 0;
}
/* Returns 0 if the user is successfully authenticated, and sets the appropriate group name.
*/
int plain_auth_user(const char* passwd, const char* user, const char* pass, char *groupname, int groupname_size)
static int plain_auth_pass(void* ctx, const char* pass)
{
struct plain_ctx_st* pctx = ctx;
unsigned groupname_size;
FILE* fp;
char * line = NULL;
size_t len;
@@ -35,9 +70,9 @@ ssize_t ll;
char* p;
int ret;
fp = fopen(passwd, "r");
fp = fopen(pctx->passwd, "r");
if (fp == NULL) {
syslog(LOG_AUTH, "error in plain authentication; cannot open: %s", passwd);
syslog(LOG_AUTH, "error in plain authentication; cannot open: %s", pctx->passwd);
return -1;
}
@@ -52,12 +87,13 @@ int ret;
p = strtok(line, ":");
if (p != NULL && strcmp(user, p) == 0) {
if (p != NULL && strcmp(pctx->username, p) == 0) {
p = strtok(NULL, ":");
if (p != NULL) {
groupname_size = snprintf(groupname, groupname_size, "%s", p);
groupname_size = sizeof(pctx->groupname);
groupname_size = snprintf(pctx->groupname, groupname_size, "%s", p);
if (groupname_size == 1) /* values like '*' or 'x' indicate empty group */
groupname[0] = 0;
pctx->groupname[0] = 0;
p = strtok(NULL, ":");
if (p != NULL && strcmp(crypt(pass, p), p) == 0) {
@@ -69,10 +105,29 @@ int ret;
}
ret = -1;
syslog(LOG_AUTH, "error in plain authentication; error in user '%s'", user);
syslog(LOG_AUTH, "error in plain authentication; error in user '%s'", pctx->username);
exit:
fclose(fp);
free(line);
return ret;
}
static int plain_auth_msg(void* ctx, char* msg, size_t msg_size)
{
snprintf(msg, msg_size, "%s", "Please enter your password");
return 0;
}
static void plain_auth_deinit(void* ctx)
{
free(ctx);
}
const struct auth_mod_st plain_auth_funcs = {
.type = AUTH_TYPE_PLAIN | AUTH_TYPE_USERNAME_PASS,
.auth_init = plain_auth_init,
.auth_deinit = plain_auth_deinit,
.auth_msg = plain_auth_msg,
.auth_pass = plain_auth_pass,
.auth_group = plain_auth_group
};

View File

@@ -1,6 +1,8 @@
#ifndef PLAIN_H
#define PLAIN_H
int plain_auth_user(const char* passwd, const char* user, const char* pass, char *groupname, int groupname_size);
#include <main-auth.h>
extern const struct auth_mod_st plain_auth_funcs;
#endif

View File

@@ -41,13 +41,19 @@ extern int syslog_open;
#define AUTH_TYPE_CERTIFICATE (1<<2)
#define AUTH_TYPE_PLAIN (1<<3 | AUTH_TYPE_USERNAME_PASS)
#define ERR_SUCCESS 0
#define ERR_BAD_COMMAND -2
#define ERR_AUTH_FAIL -3
#define ERR_AUTH_CONTINUE -4
#define ERR_WAIT_FOR_SCRIPT -5
#define ERR_MEM -6
typedef struct
{
struct htable ht;
unsigned int entries;
} hash_db_st;
struct vpn_st {
char *name; /* device name */
char *ipv4_netmask;

View File

@@ -46,17 +46,25 @@
#define SUCCESS_MSG_FOOT "</auth>\n"
const char login_msg[] = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
static const char login_msg_user[] = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
"<auth id=\"main\">\n"
"<message>Please enter your username and password.</message>\n"
"<message>Please enter your username</message>\n"
"<form method=\"post\" action=\"/auth\">\n"
"<input type=\"text\" name=\"username\" label=\"Username:\" />\n"
"</form></auth>\n";
static const char login_msg_no_user[] = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
"<auth id=\"main\">\n"
"<message>%s</message>\n"
"<form method=\"post\" action=\"/auth\">\n"
"<input type=\"password\" name=\"password\" label=\"Password:\" />\n"
"</form></auth>\n";
int get_auth_handler(worker_st *ws, unsigned http_ver)
int get_auth_handler2(worker_st *ws, unsigned http_ver, const char* pmsg)
{
int ret;
char login_msg[MAX_MSG_SIZE+sizeof(login_msg_user)];
unsigned int lsize;
tls_cork(ws->session);
ret = tls_printf(ws->session, "HTTP/1.%u 200 OK\r\n", http_ver);
@@ -70,8 +78,18 @@ int ret;
ret = tls_puts(ws->session, "Content-Type: text/xml\r\n");
if (ret < 0)
return -1;
if (ws->auth_state == S_AUTH_REQ) {
/* only ask password */
if (pmsg == NULL)
pmsg = "Please enter password";
lsize = snprintf(login_msg, sizeof(login_msg), login_msg_no_user, pmsg);
} else {
/* ask for username only */
lsize = snprintf(login_msg, sizeof(login_msg), login_msg_user);
}
ret = tls_printf(ws->session, "Content-Length: %u\r\n", (unsigned int)sizeof(login_msg)-1);
ret = tls_printf(ws->session, "Content-Length: %u\r\n", (unsigned int)lsize);
if (ret < 0)
return -1;
@@ -83,7 +101,7 @@ int ret;
if (ret < 0)
return -1;
ret = tls_send(ws->session, login_msg, sizeof(login_msg)-1);
ret = tls_send(ws->session, login_msg, lsize);
if (ret < 0)
return -1;
@@ -94,6 +112,11 @@ int ret;
return 0;
}
int get_auth_handler(worker_st *ws, unsigned http_ver)
{
return get_auth_handler2(ws, http_ver, NULL);
}
static
int get_cert_names(worker_st *ws, const gnutls_datum_t* raw,
char* username, size_t username_size,
@@ -166,6 +189,28 @@ static int send_auth_req(int fd, const struct cmd_auth_req_st* r)
return(sendmsg(fd, &hdr, 0));
}
static int send_auth_init(int fd, const struct cmd_auth_init_st* r)
{
struct iovec iov[2];
uint8_t cmd;
struct msghdr hdr;
memset(&hdr, 0, sizeof(hdr));
cmd = AUTH_INIT;
iov[0].iov_base = &cmd;
iov[0].iov_len = 1;
iov[1].iov_base = (void*)r;
iov[1].iov_len = sizeof(*r);
hdr.msg_iov = iov;
hdr.msg_iovlen = 2;
return(sendmsg(fd, &hdr, 0));
}
static int send_auth_cookie_req(int fd, const struct cmd_auth_cookie_req_st* r)
{
struct iovec iov[2];
@@ -188,11 +233,10 @@ static int send_auth_cookie_req(int fd, const struct cmd_auth_cookie_req_st* r)
return(sendmsg(fd, &hdr, 0));
}
static int recv_auth_reply(worker_st *ws)
static int recv_auth_reply(worker_st *ws, struct cmd_auth_reply_st *resp)
{
struct iovec iov[2];
uint8_t cmd = 0;
struct cmd_auth_reply_st resp;
struct msghdr hdr;
int ret, cmdlen;
union {
@@ -204,8 +248,8 @@ static int recv_auth_reply(worker_st *ws)
iov[0].iov_base = &cmd;
iov[0].iov_len = 1;
iov[1].iov_base = &resp;
iov[1].iov_len = sizeof(resp);
iov[1].iov_base = resp;
iov[1].iov_len = sizeof(*resp);
memset(&hdr, 0, sizeof(hdr));
hdr.msg_iov = iov;
@@ -213,44 +257,46 @@ static int recv_auth_reply(worker_st *ws)
hdr.msg_control = control_un.control;
hdr.msg_controllen = sizeof(control_un.control);
ret = recvmsg( ws->cmd_fd, &hdr, 0);
cmdlen = ret;
if (cmdlen < 2) {
oclog(ws, LOG_ERR, "Received incorrect data (%d, expected %d) from main", cmdlen, (int)2);
return -1;
return ERR_AUTH_FAIL;
}
if (cmd != AUTH_REP)
return -1;
return ERR_AUTH_FAIL;
cmdlen--;
switch(resp.reply) {
switch(resp->reply) {
case REP_AUTH_MSG:
return ERR_AUTH_CONTINUE;
case REP_AUTH_OK:
if (cmdlen < sizeof(resp)) {
oclog(ws, LOG_ERR, "Received incorrect data (%d, expected %d) from main", ret, (int)sizeof(resp)+1);
return -1;
if (cmdlen < sizeof(*resp)) {
oclog(ws, LOG_ERR, "Received incorrect data (%d, expected %d) from main", ret, (int)sizeof(*resp)+1);
return ERR_AUTH_FAIL;
}
if ( (cmptr = CMSG_FIRSTHDR(&hdr)) != NULL && cmptr->cmsg_len == CMSG_LEN(sizeof(int))) {
if (cmptr->cmsg_level != SOL_SOCKET)
return -1;
if (cmptr->cmsg_type != SCM_RIGHTS)
return -1;
return ERR_AUTH_FAIL;
memcpy(&ws->tun_fd, CMSG_DATA(cmptr), sizeof(int));
memcpy(ws->tun_name, resp.vname, sizeof(ws->tun_name));
memcpy(ws->username, resp.user, sizeof(ws->username));
memcpy(ws->cookie, resp.cookie, sizeof(ws->cookie));
memcpy(ws->session_id, resp.session_id, sizeof(ws->session_id));
memcpy(ws->tun_name, resp->vname, sizeof(ws->tun_name));
memcpy(ws->username, resp->user, sizeof(ws->username));
memcpy(ws->cookie, resp->cookie, sizeof(ws->cookie));
memcpy(ws->session_id, resp->session_id, sizeof(ws->session_id));
ws->auth_ok = 1;
} else
return -1;
return ERR_AUTH_FAIL;
break;
default:
return -1;
return ERR_AUTH_FAIL;
}
return 0;
@@ -283,33 +329,21 @@ int ret;
}
/* sends an authentication request to main thread and waits for
* a reply.
* Returns 0 on success.
* a reply.
* Returns 0 on success, AUTH_ERR_CONTINUE on partial success (must
* be called again in that case) and a negative error code on other errors.
*/
static int auth_user(worker_st *ws, struct cmd_auth_req_st* areq)
static int auth_user_pass(worker_st *ws, struct cmd_auth_req_st* areq)
{
int ret;
if (ws->config->auth_types & AUTH_TYPE_CERTIFICATE) {
if (ws->cert_auth_ok == 0) {
oclog(ws, LOG_INFO, "no certificate provided for authentication");
return -1;
}
ret = get_cert_info(ws, areq->cert_user, sizeof(areq->cert_user),
areq->cert_group, sizeof(areq->cert_group));
if (ret < 0)
return -1;
areq->tls_auth_ok = 1;
}
oclog(ws, LOG_DEBUG, "sending authentication request");
oclog(ws, LOG_DEBUG, "sending auth request");
ret = send_auth_req(ws->cmd_fd, areq);
if (ret < 0)
return ret;
return recv_auth_reply(ws);
return 0;
}
/* sends a cookie authentication request to main thread and waits for
@@ -320,6 +354,7 @@ int auth_cookie(worker_st *ws, void* cookie, size_t cookie_size)
{
int ret;
struct cmd_auth_cookie_req_st areq;
struct cmd_auth_reply_st resp;
memset(&areq, 0, sizeof(areq));
@@ -347,7 +382,7 @@ struct cmd_auth_cookie_req_st areq;
if (ret < 0)
return ret;
return recv_auth_reply(ws);
return recv_auth_reply(ws, &resp);
}
int post_common_handler(worker_st *ws, unsigned http_ver)
@@ -437,39 +472,34 @@ char msg[MAX_BANNER_SIZE+32];
#define XMLUSER_END "</username>"
#define XMLPASS_END "</password>"
int post_auth_handler(worker_st *ws, unsigned http_ver)
static
int read_user_pass(worker_st *ws, char* body, unsigned body_length, char** username, char** password)
{
int ret;
struct http_req_st *req = &ws->req;
const char* reason = "Authentication failed";
char * username = NULL;
char * password = NULL;
char *p;
struct cmd_auth_req_st areq;
memset(&areq, 0, sizeof(areq));
if (ws->config->auth_types & AUTH_TYPE_USERNAME_PASS) {
if (memmem(req->body, req->body_length, "<?xml", 5) != 0) {
oclog(ws, LOG_DEBUG, "POST body: '%.*s'", req->body_length, req->body);
char *p;
if (memmem(body, body_length, "<?xml", 5) != 0) {
oclog(ws, LOG_DEBUG, "POST body: '%.*s'", body_length, body);
if (username != NULL) {
/* body should contain <username>test</username><password>test</password> */
username = memmem(req->body, req->body_length, XMLUSER, sizeof(XMLUSER)-1);
if (username == NULL) {
reason = "No username";
goto ask_auth;
*username = memmem(body, body_length, XMLUSER, sizeof(XMLUSER)-1);
if (*username == NULL) {
return -1;
}
username += sizeof(XMLUSER)-1;
*username += sizeof(XMLUSER)-1;
}
password = memmem(req->body, req->body_length, XMLPASS, sizeof(XMLPASS)-1);
if (password == NULL) {
reason = "No password";
goto auth_fail;
}
password += sizeof(XMLPASS)-1;
/* modify body */
p = username;
if (password != NULL) {
*password = memmem(body, body_length, XMLPASS, sizeof(XMLPASS)-1);
if (*password == NULL) {
return -1;
}
*password += sizeof(XMLPASS)-1;
}
/* modify body */
if (username != NULL) {
p = *username;
while(*p != 0) {
if (*p == '<' && (strncmp(p, XMLUSER_END, sizeof(XMLUSER_END)-1) == 0)) {
*p = 0;
@@ -477,72 +507,141 @@ struct cmd_auth_req_st areq;
}
p++;
}
p = password;
while(*p != 0) {
if (*p == '<' && (strncmp(p, XMLPASS_END, sizeof(XMLPASS_END)-1) == 0)) {
*p = 0;
break;
}
p++;
}
areq.user_pass_present = 1;
snprintf(areq.user, sizeof(areq.user), "%s", username);
snprintf(areq.pass, sizeof(areq.pass), "%s", password);
} else { /* non-xml version */
/* body should be "username=test&password=test" */
username = memmem(req->body, req->body_length, "username=", sizeof("username=")-1);
if (username == NULL) {
reason = "No username";
goto auth_fail;
}
username += sizeof("username=")-1;
password = memmem(req->body, req->body_length, "password=", sizeof("password=")-1);
if (password == NULL) {
reason = "No password";
goto auth_fail;
}
password += sizeof("password=")-1;
/* modify body */
p = username;
while(*p != 0) {
if (*p == '&') {
*p = 0;
break;
}
p++;
}
p = password;
while(*p != 0) {
if (*p == '&') {
*p = 0;
break;
}
p++;
}
areq.user_pass_present = 1;
snprintf(areq.user, sizeof(areq.user), "%s", username);
snprintf(areq.pass, sizeof(areq.pass), "%s", password);
}
}
if (password != NULL) {
p = *password;
while(*p != 0) {
if (*p == '<' && (strncmp(p, XMLPASS_END, sizeof(XMLPASS_END)-1) == 0)) {
*p = 0;
break;
}
p++;
}
}
if (req->hostname[0] != 0) {
memcpy(areq.hostname, req->hostname, sizeof(areq.hostname));
} else { /* non-xml version */
/* body should be "username=test&password=test" */
if (username != NULL) {
*username = memmem(body, body_length, "username=", sizeof("username=")-1);
if (*username == NULL) {
return -1;
}
*username += sizeof("username=")-1;
}
if (password != NULL) {
*password = memmem(body, body_length, "password=", sizeof("password=")-1);
if (*password == NULL) {
return -1;
}
*password += sizeof("password=")-1;
}
/* modify body */
if (username != NULL) {
p = *username;
while(*p != 0) {
if (*p == '&') {
*p = 0;
break;
}
p++;
}
}
if (password != NULL) {
p = *password;
while(*p != 0) {
if (*p == '&') {
*p = 0;
break;
}
p++;
}
}
}
return 0;
}
int post_auth_handler(worker_st *ws, unsigned http_ver)
{
int ret;
struct http_req_st *req = &ws->req;
const char* reason = "Authentication failed";
char * username = NULL;
char * password = NULL;
struct cmd_auth_reply_st resp;
if (ws->auth_state == S_AUTH_INACTIVE) {
struct cmd_auth_init_st areq;
memset(&areq, 0, sizeof(areq));
if (ws->config->auth_types & AUTH_TYPE_USERNAME_PASS) {
ret = read_user_pass(ws, req->body, req->body_length, &username, NULL);
if (ret < 0)
goto ask_auth;
snprintf(areq.user, sizeof(areq.user), "%s", username);
areq.user_present = 1;
}
if (ws->config->auth_types & AUTH_TYPE_CERTIFICATE) {
if (ws->cert_auth_ok == 0) {
oclog(ws, LOG_INFO, "no certificate provided for authentication");
return -1;
}
ret = get_cert_info(ws, areq.cert_user, sizeof(areq.cert_user),
areq.cert_group, sizeof(areq.cert_group));
if (ret < 0)
return -1;
areq.tls_auth_ok = 1;
}
if (req->hostname[0] != 0) {
memcpy(areq.hostname, req->hostname, sizeof(areq.hostname));
}
ret = send_auth_init(ws->cmd_fd, &areq);
if (ret < 0)
goto auth_fail;
ws->auth_state = S_AUTH_INIT;
} else {
struct cmd_auth_req_st areq;
if (ws->config->auth_types & AUTH_TYPE_USERNAME_PASS) {
memset(&areq, 0, sizeof(areq));
ret = read_user_pass(ws, req->body, req->body_length, NULL, &password);
if (ret < 0)
goto ask_auth;
snprintf(areq.pass, sizeof(areq.pass), "%s", password);
ret = auth_user_pass(ws, &areq);
if (ret < 0)
goto auth_fail;
ws->auth_state = S_AUTH_REQ;
} else
goto auth_fail;
}
ret = auth_user(ws, &areq);
if (ret < 0) {
ret = recv_auth_reply(ws, &resp);
if (ret == ERR_AUTH_CONTINUE) {
ws->auth_state = S_AUTH_REQ;
return get_auth_handler2(ws, http_ver, resp.msg);
} else if (ret < 0)
goto auth_fail;
}
oclog(ws, LOG_INFO, "User '%s' logged in", ws->username);
ws->auth_state = S_AUTH_COMPLETE;
return post_common_handler(ws, http_ver);;
return post_common_handler(ws, http_ver);
ask_auth:
return get_auth_handler(ws, http_ver);

View File

@@ -752,6 +752,13 @@ time_t udp_recv_time = 0, now;
unsigned mtu_overhead = 0;
socklen_t sl;
if (ws->auth_state != S_AUTH_COMPLETE) {
oclog(ws, LOG_INFO, "authentication was not completed");
tls_puts(ws->session, "HTTP/1.1 503 Service Unavailable\r\n\r\n");
tls_close(ws->session);
exit_worker(ws);
}
ws->buffer_size = 16*1024;
ws->buffer = malloc(ws->buffer_size);
if (ws->buffer == NULL) {

View File

@@ -37,6 +37,13 @@ enum {
HTTP_HEADER_VALUE_RECV
};
enum {
S_AUTH_INACTIVE = 0,
S_AUTH_INIT,
S_AUTH_REQ,
S_AUTH_COMPLETE
};
struct http_req_st {
char url[256];
@@ -52,12 +59,13 @@ struct http_req_st {
unsigned int master_secret_set;
char *body;
unsigned int body_length;
char *gnutls_ciphersuite; /* static string */
char *selected_ciphersuite; /* static string */
int gnutls_cipher;
int gnutls_mac;
unsigned int body_length;
unsigned int headers_complete;
unsigned int message_complete;
unsigned dtls_mtu;
@@ -76,6 +84,7 @@ typedef struct worker_st {
http_parser *parser;
struct cfg_st *config;
unsigned int auth_state; /* S_AUTH */
struct sockaddr_storage remote_addr; /* peer's address */
socklen_t remote_addr_len;
@@ -116,6 +125,7 @@ typedef struct worker_st {
void vpn_server(struct worker_st* ws);
int auth_cookie(worker_st *ws, void* cookie, size_t cookie_size);
int auth_user_deinit(worker_st *ws);
int get_auth_handler(worker_st *server, unsigned http_ver);
int post_auth_handler(worker_st *server, unsigned http_ver);