several updates and fixes in auth

This commit is contained in:
Nikos Mavrogiannopoulos
2013-01-30 21:20:16 +01:00
parent 25b0617081
commit 0a8b951022
16 changed files with 528 additions and 313 deletions
+3 -2
View File
@@ -5,9 +5,10 @@ EXTRA_DIST = ocserv.1
bin_PROGRAMS = ocserv
ocserv_SOURCES = main.c worker-vpn.c worker-auth.c tlslib.c cookies.c http-parser/http_parser.c \
ocserv_SOURCES = main.c main-auth.c worker-vpn.c worker-auth.c tlslib.c \
cookies.c http-parser/http_parser.c \
vpn.h cookies.h tlslib.h http-parser/http_parser.h log.c tun.c tun.h \
config.c worker-auth.h
config.c worker-auth.h
ocserv_SOURCES += ocserv-args.def ocserv-args.c ocserv-args.h
+3 -3
View File
@@ -85,9 +85,8 @@ static void parse_cfg_file(const char* file, struct cfg_st *config)
{
tOptionValue const * pov;
const tOptionValue* val;
char tmpstr[256];
char** auth;
unsigned auth_size;
char** auth = NULL;
unsigned auth_size = 0;
unsigned j;
pov = configFileLoad(file);
@@ -127,6 +126,7 @@ unsigned j;
READ_STRING("chroot-dir", config->chroot_dir, 0);
READ_NUMERIC("cookie-validity", config->cookie_validity, 1);
READ_NUMERIC("auth-timeout", config->auth_timeout, 0);
READ_STRING("cookie-db", config->db_file, 1);
val = optionGetValue(pov, "run-as-user"); \
+7 -7
View File
@@ -38,7 +38,7 @@
/* All the functions return zero on success and a negative value on error */
int store_cookie(worker_st *server, const void* cookie, unsigned cookie_size,
int store_cookie(const struct cfg_st *config, const void* cookie, unsigned cookie_size,
const struct stored_cookie_st* sc)
{
GDBM_FILE dbf;
@@ -46,9 +46,9 @@ datum key;
datum data;
int ret;
dbf = gdbm_open((char*)server->config->db_file, 0, GDBM_WRCREAT, S_IRUSR|S_IWUSR, NULL);
dbf = gdbm_open((char*)config->db_file, 0, GDBM_WRCREAT, S_IRUSR|S_IWUSR, NULL);
if (dbf == NULL) {
oclog(server, LOG_ERR, "Cannot open cookie database: %s", server->config->db_file);
syslog(LOG_ERR, "Cannot open cookie database: %s", config->db_file);
return -1;
}
@@ -70,7 +70,7 @@ finish:
return ret;
}
int retrieve_cookie(worker_st *server, const void* cookie, unsigned cookie_size,
int retrieve_cookie(const struct cfg_st *config, const void* cookie, unsigned cookie_size,
struct stored_cookie_st* sc)
{
GDBM_FILE dbf;
@@ -78,9 +78,9 @@ datum key;
datum data;
int ret;
dbf = gdbm_open((char*)server->config->db_file, 0, GDBM_READER, 0, NULL);
dbf = gdbm_open((char*)config->db_file, 0, GDBM_READER, 0, NULL);
if (dbf == NULL) {
oclog(server, LOG_ERR, "Cannot open cookie database: %s", server->config->db_file);
syslog(LOG_ERR, "Cannot open cookie database: %s", config->db_file);
return -1;
}
@@ -104,7 +104,7 @@ finish:
return ret;
}
void expire_cookies(struct cfg_st *cfg)
void expire_cookies(const struct cfg_st *cfg)
{
GDBM_FILE dbf;
datum key;
+3 -4
View File
@@ -5,15 +5,14 @@
struct __attribute__ ((__packed__)) stored_cookie_st {
char username[MAX_USERNAME_SIZE];
char tun_name[IFNAMSIZ];
time_t expiration;
};
int store_cookie(worker_st *server, const void* cookie, unsigned cookie_size,
int store_cookie(const struct cfg_st *, const void* cookie, unsigned cookie_size,
const struct stored_cookie_st* sc);
void expire_cookies(struct cfg_st *cfg);
void expire_cookies(const struct cfg_st *cfg);
int retrieve_cookie(worker_st *server, const void* cookie, unsigned cookie_size,
int retrieve_cookie(const struct cfg_st *, const void* cookie, unsigned cookie_size,
struct stored_cookie_st* sc);
#endif
+5 -2
View File
@@ -22,6 +22,7 @@
#include <sys/socket.h>
#include <netdb.h>
#include <string.h>
#include <stdio.h>
#include <stdarg.h>
#include <vpn.h>
@@ -63,7 +64,7 @@ const char *human_addr(const struct sockaddr *sa, socklen_t salen,
return save_buf;
}
int __attribute__ ((format(printf, 3, 4)))
void __attribute__ ((format(printf, 3, 4)))
oclog(const worker_st * ws, int priority, const char *fmt, ...)
{
char buf[1024];
@@ -83,5 +84,7 @@ int __attribute__ ((format(printf, 3, 4)))
if (ip)
syslog(priority, "%s %s", ip, buf);
else
syslog(priority, "[unknown] %s", ip, buf);
syslog(priority, "[unknown] %s", buf);
return;
}
+261
View File
@@ -0,0 +1,261 @@
/*
* 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 <sys/select.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <netdb.h>
#include <signal.h>
#include <errno.h>
#include <sys/ioctl.h>
#include <gnutls/gnutls.h>
#include <gnutls/crypto.h>
#include <tlslib.h>
#include <worker-auth.h>
#include <vpn.h>
#include <cookies.h>
#include <tun.h>
#include <list.h>
static int send_auth_reply(cmd_auth_reply_t r, struct proc_list_st* proc, struct lease_st* lease)
{
struct iovec iov[4];
uint8_t cmd[2];
struct msghdr hdr;
union {
struct cmsghdr cm;
char control[CMSG_SPACE(sizeof(int))];
} control_un;
struct cmsghdr *cmptr;
memset(&control_un, 0, sizeof(control_un));
memset(&hdr, 0, sizeof(hdr));
cmd[0] = AUTH_REP;
cmd[1] = r;
iov[0].iov_base = cmd;
iov[0].iov_len = 2;
hdr.msg_iovlen++;
hdr.msg_iov = iov;
if (r == REP_AUTH_OK && lease != NULL) {
iov[1].iov_base = proc->cookie;
iov[1].iov_len = sizeof(proc->cookie);
hdr.msg_iovlen++;
iov[2].iov_base = lease->name;
iov[2].iov_len = sizeof(lease->name);
hdr.msg_iovlen++;
iov[3].iov_base = proc->username;
iov[3].iov_len = MAX_USERNAME_SIZE;
hdr.msg_iovlen++;
/* Send the tun fd */
hdr.msg_control = control_un.control;
hdr.msg_controllen = sizeof(control_un.control);
cmptr = CMSG_FIRSTHDR(&hdr);
cmptr->cmsg_len = CMSG_LEN(sizeof(int));
cmptr->cmsg_level = SOL_SOCKET;
cmptr->cmsg_type = SCM_RIGHTS;
memcpy(CMSG_DATA(cmptr), &lease->fd, sizeof(int));
}
return(sendmsg(proc->fd, &hdr, 0));
}
static int handle_auth_cookie_req(const struct cfg_st *config, struct tun_st *tun,
const struct cmd_auth_cookie_req_st * req, struct lease_st **lease,
char username[MAX_USERNAME_SIZE])
{
int ret;
struct stored_cookie_st sc;
ret = retrieve_cookie(config, req->cookie, sizeof(req->cookie), &sc);
if (ret < 0) {
return -1;
}
ret = 0; /* cookie was found and valid */
memcpy(username, sc.username, MAX_USERNAME_SIZE);
ret = open_tun(config, tun, lease);
if (ret < 0)
ret = -1; /* sorry */
return ret;
}
static
int generate_and_store_cookie(const struct cfg_st* config, uint8_t *cookie, unsigned cookie_size)
{
int ret;
struct stored_cookie_st sc;
ret = gnutls_rnd(GNUTLS_RND_RANDOM, cookie, cookie_size);
if (ret < 0)
return -2;
memset(&sc, 0, sizeof(sc));
sc.expiration = time(0) + config->cookie_validity;
ret = store_cookie(config, cookie, cookie_size, &sc);
if (ret < 0)
return -1;
return 0;
}
static int handle_auth_req(const struct cfg_st *config, struct tun_st *tun,
const struct cmd_auth_req_st * req, struct lease_st **lease,
char username[MAX_USERNAME_SIZE])
{
int ret;
#warning fix auth
if (strcmp(req->user, "test") == 0 && strcmp(req->pass, "test") == 0)
ret = 0;
else
ret = -1;
memcpy(username, req->user, MAX_USERNAME_SIZE);
if (ret == 0) { /* open tun */
ret = open_tun(config, tun, lease);
if (ret < 0)
ret = -1; /* sorry */
}
return ret;
}
int handle_commands(const struct cfg_st *config, struct tun_st *tun,
struct proc_list_st* proc)
{
struct iovec iov[2];
char buf[128];
uint8_t cmd;
struct msghdr hdr;
struct lease_st *lease;
union {
struct cmd_auth_req_st auth;
struct cmd_auth_cookie_req_st cauth;
} cmd_data;
int ret, cmd_data_len;
const char* peer_ip;
peer_ip = human_addr((void*)&proc->remote_addr, proc->remote_addr_len, buf, sizeof(buf));
memset(&cmd_data, 0, sizeof(cmd_data));
iov[0].iov_base = &cmd;
iov[0].iov_len = 1;
iov[1].iov_base = &cmd_data;
iov[1].iov_len = sizeof(cmd_data);
memset(&hdr, 0, sizeof(hdr));
hdr.msg_iov = iov;
hdr.msg_iovlen = 2;
ret = recvmsg( proc->fd, &hdr, 0);
if (ret == -1) {
syslog(LOG_ERR, "Cannot obtain data from command socket (pid: %d, peer: %s).", proc->pid, peer_ip);
return -1;
}
if (ret == 0) {
return -1;
}
cmd_data_len = ret - 1;
switch(cmd) {
case AUTH_REQ:
case AUTH_COOKIE_REQ:
if (cmd == AUTH_REQ) {
if (cmd_data_len != sizeof(cmd_data.auth)) {
syslog(LOG_ERR, "Error in received message length (pid: %d, peer: %s).", proc->pid, peer_ip);
return -2;
}
ret = handle_auth_req(config, tun, &cmd_data.auth, &lease, proc->username);
} else {
if (cmd_data_len != sizeof(cmd_data.cauth)) {
syslog(LOG_ERR, "Error in received message length (pid: %d, peer: %s).", proc->pid, peer_ip);
return -2;
}
ret = handle_auth_cookie_req(config, tun, &cmd_data.cauth, &lease, proc->username);
}
if (ret == 0) {
if (cmd == AUTH_REQ) {
/* generate and store cookie */
ret = generate_and_store_cookie(config,
proc->cookie,
COOKIE_SIZE);
if (ret < 0)
return -2;
} else { /* copy cookie */
memcpy(proc->cookie, cmd_data.cauth.cookie,
COOKIE_SIZE);
}
syslog(LOG_INFO, "User '%s' authenticated", proc->username);
ret = send_auth_reply(REP_AUTH_OK, proc, lease);
if (ret < 0) {
syslog(LOG_ERR, "Could not send reply cmd (pid: %d, peer: %s).", proc->pid, peer_ip);
return -2;
}
proc->lease = lease;
proc->lease->in_use = 1;
if (lease->fd >= 0)
close(lease->fd);
lease->fd = -1;
} else {
syslog(LOG_INFO, "Failed authentication attempt for user '%s'", proc->username);
ret = send_auth_reply( REP_AUTH_FAILED, proc, NULL);
if (ret < 0) {
syslog(LOG_ERR, "Could not send reply cmd (pid: %d, peer: %s).", proc->pid, peer_ip);
return -2;
}
}
break;
default:
syslog(LOG_ERR, "Unknown CMD 0x%x (pid: %d, peer: %s).", (unsigned)cmd, proc->pid, peer_ip);
return -2;
}
return 0;
}
+7 -176
View File
@@ -49,20 +49,6 @@ struct listen_list_st {
int fd;
};
struct proc_list_st {
struct list_head list;
int fd;
pid_t pid;
struct sockaddr_storage remote_addr; /* peer address */
socklen_t remote_addr_len;
/* the tun lease this process has */
struct lease_st* lease;
};
static int handle_commands(const struct cfg_st *config, struct tun_st *tun,
struct proc_list_st* proc);
static void tls_log_func(int level, const char *str)
{
syslog(LOG_DEBUG, "Debug[<%d>]: %s", level, str);
@@ -209,8 +195,7 @@ worker_st * ws;
static int verify_certificate_cb(gnutls_session_t session)
{
unsigned int status;
int ret, type;
gnutls_datum_t out;
int ret;
worker_st * ws;
ws = gnutls_session_get_ptr(session);
@@ -310,7 +295,7 @@ static void clear_proc_list(struct proc_list_st* clist)
int main(int argc, char** argv)
{
int fd, pid, e;
int fd, pid;
struct tls_st creds;
struct listen_list_st llist;
struct proc_list_st clist;
@@ -326,9 +311,6 @@ int main(int argc, char** argv)
struct worker_st ws;
struct cfg_st config;
struct sockaddr_storage tmp_addr;
socklen_t tmp_addr_len;
INIT_LIST_HEAD(&clist.list);
tun_st_init(&tun);
@@ -417,7 +399,7 @@ int main(int argc, char** argv)
daemon(0, 0);
alarm(config.cookie_validity + 300);
openlog("ocserv", LOG_PID, LOG_LOCAL0);
openlog("ocserv", LOG_PID|LOG_NDELAY, LOG_LOCAL0);
syslog_open = 1;
for (;;) {
@@ -500,15 +482,14 @@ int main(int argc, char** argv)
} else if (pid == -1) {
fork_failed:
close(cmd_fd[0]);
free(ctmp);
} else { /* parent */
ctmp = calloc(1, sizeof(struct proc_list_st));
if (ctmp == NULL) {
kill(pid, SIGTERM);
goto fork_failed;
}
memcpy(&ctmp->remote_addr, &tmp_addr, tmp_addr_len);
ctmp->remote_addr_len = tmp_addr_len;
memcpy(&ctmp->remote_addr, &ws.remote_addr, ws.remote_addr_len);
ctmp->remote_addr_len = ws.remote_addr_len;
ctmp->pid = pid;
ctmp->fd = cmd_fd[0];
@@ -544,17 +525,8 @@ fork_failed:
need_to_expire_cookies = 0;
pid = fork();
if (pid == 0) { /* child */
/* Drop privileges after this point */
drop_privileges(&config);
list_for_each(pos, &llist.list) {
ltmp =
list_entry(pos,
struct
listen_list_st,
list);
close(ltmp->fd);
}
clear_listen_list(&llist);
clear_proc_list(&clist);
expire_cookies(&config);
exit(0);
@@ -566,144 +538,3 @@ fork_failed:
return 0;
}
static int send_auth_reply(int fd, cmd_auth_reply_t r, struct lease_st* lease)
{
struct iovec iov[2];
uint8_t cmd[2];
struct msghdr hdr;
union {
struct cmd_auth_req_st auth;
} cmd_data;
int ret;
union {
struct cmsghdr cm;
char control[CMSG_SPACE(sizeof(int))];
} control_un;
struct cmsghdr *cmptr;
memset(&control_un, 0, sizeof(control_un));
memset(&hdr, 0, sizeof(hdr));
cmd[0] = AUTH_REP;
cmd[1] = r;
iov[0].iov_base = cmd;
iov[0].iov_len = 2;
hdr.msg_iovlen++;
hdr.msg_iov = iov;
if (r == REP_AUTH_OK && lease != NULL) {
iov[1].iov_base = lease->name;
iov[1].iov_len = sizeof(lease->name);
hdr.msg_iovlen++;
/* Send the tun fd */
hdr.msg_control = control_un.control;
hdr.msg_controllen = sizeof(control_un.control);
cmptr = CMSG_FIRSTHDR(&hdr);
cmptr->cmsg_len = CMSG_LEN(sizeof(int));
cmptr->cmsg_level = SOL_SOCKET;
cmptr->cmsg_type = SCM_RIGHTS;
*((int *) CMSG_DATA(cmptr)) = lease->fd;
}
return(sendmsg(fd, &hdr, 0));
}
static int handle_auth_req(const struct cfg_st *config, struct tun_st *tun,
const struct cmd_auth_req_st * req, struct lease_st **lease)
{
int ret;
#warning fix auth
if (strcmp(req->user, "test") == 0 && strcmp(req->pass, "test") == 0)
ret = 0;
else
ret = -1;
if (ret == 0) { /* open tun */
ret = open_tun(config, tun, lease);
if (ret < 0)
ret = -1; /* sorry */
}
return ret;
}
static int handle_commands(const struct cfg_st *config, struct tun_st *tun,
struct proc_list_st* proc)
{
struct iovec iov[2];
char buf[128];
uint8_t cmd;
struct msghdr hdr;
struct lease_st *lease;
union {
struct cmd_auth_req_st auth;
} cmd_data;
int ret, cmd_data_len;
const char* peer_ip;
peer_ip = human_addr((void*)&proc->remote_addr, proc->remote_addr_len, buf, sizeof(buf));
memset(&cmd_data, 0, sizeof(cmd_data));
iov[0].iov_base = &cmd;
iov[0].iov_len = 1;
iov[1].iov_base = &cmd_data;
iov[1].iov_len = sizeof(cmd_data);
memset(&hdr, 0, sizeof(hdr));
hdr.msg_iov = iov;
hdr.msg_iovlen = 2;
ret = recvmsg( proc->fd, &hdr, 0);
if (ret == -1) {
syslog(LOG_ERR, "Cannot obtain data from command socket (pid: %d, peer: %s).", proc->pid, peer_ip);
return -1;
}
if (ret == 0) {
return -1;
}
cmd_data_len = ret - 1;
switch(cmd) {
case AUTH_REQ:
if (cmd_data_len != sizeof(cmd_data.auth)) {
syslog(LOG_ERR, "Error in received message length (pid: %d, peer: %s).", proc->pid, peer_ip);
return -2;
}
ret = handle_auth_req(config, tun, &cmd_data.auth, &lease);
if (ret == 0) {
ret = send_auth_reply(proc->fd, REP_AUTH_OK, lease);
if (ret < 0) {
syslog(LOG_ERR, "Could not send reply cmd (pid: %d, peer: %s).", proc->pid, peer_ip);
return -2;
}
proc->lease = lease;
proc->lease->in_use = 1;
if (lease->fd >= 0)
close(lease->fd);
lease->fd = -1;
} else {
ret = send_auth_reply(proc->fd, REP_AUTH_FAILED, NULL);
if (ret < 0) {
syslog(LOG_ERR, "Could not send reply cmd (pid: %d, peer: %s).", proc->pid, peer_ip);
return -2;
}
}
break;
default:
syslog(LOG_ERR, "Unknown CMD 0x%x (pid: %d, peer: %s).", (unsigned)cmd, proc->pid, peer_ip);
return -2;
}
return 0;
}
+1 -1
View File
@@ -2,7 +2,7 @@
*
* DO NOT EDIT THIS FILE (ocserv-args.c)
*
* It has been AutoGen-ed January 30, 2013 at 05:50:16 PM by AutoGen 5.16
* It has been AutoGen-ed January 30, 2013 at 08:53:35 PM by AutoGen 5.16
* From the definitions ocserv-args.def
* and the template file options
*
+4
View File
@@ -85,6 +85,10 @@ tls-priorities = "PERFORMANCE:%SERVER_PRECEDENCE"
# The default server directory
#chroot-dir = /path/to/chroot
# The time (in seconds) that a client is allowed to stay connected prior
# to authentication
auth-timeout = 40
# Cookie validity time (in seconds)
# Once a client is authenticated he's provided a cookie with
# which he can reconnect. This option sets the maximum lifetime
+1 -1
View File
@@ -2,7 +2,7 @@
*
* DO NOT EDIT THIS FILE (ocserv-args.h)
*
* It has been AutoGen-ed January 30, 2013 at 05:50:16 PM by AutoGen 5.16
* It has been AutoGen-ed January 30, 2013 at 08:53:35 PM by AutoGen 5.16
* From the definitions ocserv-args.def
* and the template file options
*
+4
View File
@@ -6,6 +6,10 @@ auth = "pam"
# Use listen-host to limit to specific IPs or to the IPs of a provided hostname.
# listen-host = [IP|HOSTNAME]
# The time (in seconds) that a client is allowed to stay connected prior
# to authentication
auth-timeout = 40
# TCP port number
tcp-port = 3333
+6 -2
View File
@@ -112,6 +112,9 @@ static int get_avail_network_addresses(const struct cfg_st *config, const struct
memcpy(&lease->rip4, t4, lease->rip4_len);
} else if (last4 != NULL) {
t4 = (void*)&tmp;
t4->sin_family = AF_INET;
ret =
inet_pton(AF_INET, config->network.ipv4_netmask, SA_IN_P(&mask));
@@ -181,6 +184,9 @@ static int get_avail_network_addresses(const struct cfg_st *config, const struct
lease->rip6_len = sizeof(struct sockaddr_in6);
memcpy(&lease->rip6, t6, lease->rip6_len);
} else if (last6 != NULL) {
t6 = (void*)&tmp;
t6->sin6_family = AF_INET6;
ret =
inet_pton(AF_INET6, config->network.ipv6_netmask, SA_IN6_P(&mask));
@@ -227,7 +233,6 @@ static int set_network_info( const struct lease_st *lease)
{
struct ifreq ifr;
int fd, ret;
void* p;
fd = socket(AF_INET, SOCK_STREAM, 0);
if (fd == -1)
@@ -296,7 +301,6 @@ static int set_network_info( const struct lease_st *lease)
syslog(LOG_ERR, "%s: Could not bring up interface.\n", lease->name);
}
fail:
close(fd);
return ret;
}
+29 -6
View File
@@ -56,6 +56,7 @@ struct cfg_st {
const char *priorities;
const char *chroot_dir; /* where the xml files are served from */
time_t cookie_validity; /* in seconds */
unsigned auth_timeout; /* timeout of HTTP auth */
const char *db_file;
unsigned foreground;
@@ -68,6 +69,10 @@ struct cfg_st {
#include <tun.h>
#define MAX_USERNAME_SIZE 64
#define MAX_PASSWORD_SIZE 64
#define COOKIE_SIZE 32
struct tls_st {
gnutls_certificate_credentials_t xcred;
gnutls_priority_t cprio;
@@ -75,8 +80,6 @@ struct tls_st {
typedef struct worker_st {
gnutls_session_t session;
char tun_name[IFNAMSIZ];
int tun_fd;
int cmd_fd;
int conn_fd;
@@ -85,11 +88,15 @@ typedef struct worker_st {
struct sockaddr_storage remote_addr; /* peer's address */
socklen_t remote_addr_len;
/* the following are set only if authentication is complete */
char tun_name[IFNAMSIZ];
char username[MAX_USERNAME_SIZE];
uint8_t cookie[COOKIE_SIZE];
unsigned auth_ok;
int tun_fd;
} worker_st;
#define MAX_USERNAME_SIZE 64
#define MAX_PASSWORD_SIZE 64
#define COOKIE_SIZE 32
enum {
HEADER_COOKIE = 1,
@@ -110,11 +117,27 @@ void vpn_server(struct worker_st* ws, struct tls_st *creds);
const char *human_addr(const struct sockaddr *sa, socklen_t salen,
void *buf, size_t buflen);
int __attribute__ ((format(printf, 3, 4)))
void __attribute__ ((format(printf, 3, 4)))
oclog(const worker_st * server, int priority, const char *fmt, ...);
int cmd_parser (int argc, char **argv, struct cfg_st* config);
struct proc_list_st {
struct list_head list;
int fd;
pid_t pid;
struct sockaddr_storage remote_addr; /* peer address */
socklen_t remote_addr_len;
char username[MAX_USERNAME_SIZE]; /* the owner */
uint8_t cookie[COOKIE_SIZE]; /* the cookie associate with the session */
/* the tun lease this process has */
struct lease_st* lease;
};
int handle_commands(const struct cfg_st *config, struct tun_st *tun,
struct proc_list_st* proc);
/* Helper casts */
#define SA_IN_P(p) (&((struct sockaddr_in *)(p))->sin_addr)
#define SA_IN_U8_P(p) ((uint8_t*)(&((struct sockaddr_in *)(p))->sin_addr))
+109 -94
View File
@@ -55,12 +55,10 @@ const char login_msg[] = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n"
int get_auth_handler(worker_st *ws)
{
int ret;
tls_puts(ws->session, "HTTP/1.1 200 OK\r\n");
tls_puts(ws->session, "Connection: close\r\n");
tls_puts(ws->session, "Content-Type: text/xml\r\n");
tls_printf(ws->session, "Content-Length: %u\r\n", sizeof(login_msg)-1);
tls_printf(ws->session, "Content-Length: %u\r\n", (unsigned int)sizeof(login_msg)-1);
tls_puts(ws->session, "X-Transcend-Version: 1\r\n");
tls_puts(ws->session, "\r\n");
@@ -109,12 +107,6 @@ static int send_auth_req(int fd, const struct cmd_auth_req_st* r)
struct iovec iov[2];
uint8_t cmd;
struct msghdr hdr;
int ret;
union {
struct cmsghdr cm;
char control[CMSG_SPACE(sizeof(int))];
} control_un;
struct cmsghdr *cmptr;
memset(&hdr, 0, sizeof(hdr));
@@ -132,11 +124,33 @@ static int send_auth_req(int fd, const struct cmd_auth_req_st* r)
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];
uint8_t cmd;
struct msghdr hdr;
memset(&hdr, 0, sizeof(hdr));
cmd = AUTH_COOKIE_REQ;
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 recv_auth_reply(worker_st *ws)
{
struct iovec iov[3];
struct iovec iov[2];
uint8_t cmd = 0;
struct cmd_auth_resp_st resp;
struct cmd_auth_reply_st resp;
struct msghdr hdr;
int ret;
@@ -149,21 +163,19 @@ static int recv_auth_reply(worker_st *ws)
iov[0].iov_base = &cmd;
iov[0].iov_len = 1;
iov[1].iov_base = &resp.reply;
iov[1].iov_len = 1;
iov[2].iov_base = resp.vname;
iov[2].iov_len = sizeof(resp.vname);
iov[1].iov_base = &resp;
iov[1].iov_len = sizeof(resp);
memset(&hdr, 0, sizeof(hdr));
hdr.msg_iov = iov;
hdr.msg_iovlen = 3;
hdr.msg_iovlen = 2;
hdr.msg_control = control_un.control;
hdr.msg_controllen = sizeof(control_un.control);
ret = recvmsg( ws->cmd_fd, &hdr, 0);
if (ret <= 0) {
if (ret < sizeof(resp)+1) {
oclog(ws, LOG_ERR, "Received incorrect data (%d, expected %d) from main", ret, (int)sizeof(resp)+1);
return -1;
}
if (cmd != AUTH_REP)
@@ -177,8 +189,11 @@ static int recv_auth_reply(worker_st *ws)
if (cmptr->cmsg_type != SCM_RIGHTS)
return -1;
ws->tun_fd = *((int *) CMSG_DATA(cmptr));
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));
ws->auth_ok = 1;
} else
return -1;
break;
@@ -189,21 +204,9 @@ static int recv_auth_reply(worker_st *ws)
return 0;
}
/* sends an authentication request to main thread and waits for
* a reply */
static int auth_user(worker_st *ws, const struct cmd_auth_req_st* areq)
{
int ret;
ret = send_auth_req(ws->cmd_fd, areq);
if (ret < 0)
return ret;
return recv_auth_reply(ws);
}
/* grabs the username from the session certificate */
static
int get_cert_info(worker_st *ws, struct cmd_auth_req_st *areq, const char** reason)
int get_cert_info(worker_st *ws, char* user, unsigned user_size)
{
const gnutls_datum_t * cert;
unsigned int ncerts;
@@ -214,16 +217,13 @@ int ret;
cert = gnutls_certificate_get_peers (ws->session, &ncerts);
if (cert == NULL) {
*reason = "No certificate found";
return -1;
}
areq->tls_auth_ok = 1;
if (ws->config->cert_user_oid) { /* otherwise certificate username is ignored */
ret = get_cert_username(ws, cert, areq->cert_user, sizeof(areq->cert_user));
ret = get_cert_username(ws, cert, user, user_size);
if (ret < 0) {
oclog(ws, LOG_ERR, "Cannot get username (%s) from certificate", ws->config->cert_user_oid);
*reason = "No username in certificate";
return -1;
}
}
@@ -231,30 +231,75 @@ int ret;
return 0;
}
/* sends an authentication request to main thread and waits for
* a reply.
* Returns 0 on success.
*/
static int auth_user(worker_st *ws, struct cmd_auth_req_st* areq)
{
int ret;
if (ws->config->auth_types & AUTH_TYPE_CERTIFICATE) {
ret = get_cert_info(ws, areq->cert_user, sizeof(areq->cert_user));
if (ret < 0)
return -1;
areq->tls_auth_ok = 1;
}
oclog(ws, LOG_DEBUG, "Sending authentication request");
ret = send_auth_req(ws->cmd_fd, areq);
if (ret < 0)
return ret;
return recv_auth_reply(ws);
}
/* sends a cookie authentication request to main thread and waits for
* a reply.
* Returns 0 on success.
*/
int auth_cookie(worker_st *ws, void* cookie, size_t cookie_size)
{
int ret;
struct cmd_auth_cookie_req_st areq;
if (cookie_size != sizeof(areq.cookie))
return -1;
if (ws->config->auth_types & AUTH_TYPE_CERTIFICATE) {
ret = get_cert_info(ws, areq.cert_user, sizeof(areq.cert_user));
if (ret < 0)
return -1;
areq.tls_auth_ok = 1;
}
memcpy(areq.cookie, cookie, sizeof(areq.cookie));
oclog(ws, LOG_DEBUG, "Sending cookie authentication request");
ret = send_auth_cookie_req(ws->cmd_fd, &areq);
if (ret < 0)
return ret;
return recv_auth_reply(ws);
}
int post_old_auth_handler(worker_st *ws)
{
int ret;
struct req_data_st *req = ws->parser->data;
const char* reason = "Authentication failed";
unsigned char cookie[COOKIE_SIZE];
char str_cookie[2*COOKIE_SIZE+1];
char * username = NULL;
char * password = NULL;
char *p;
unsigned int i;
struct stored_cookie_st sc;
struct cmd_auth_req_st areq;
memset(&areq, 0, sizeof(areq));
if (ws->config->auth_types & AUTH_TYPE_CERTIFICATE) {
ret = get_cert_info(ws, &areq, &reason);
if (ret < 0)
goto auth_fail;
username = areq.cert_user;
}
if (ws->config->auth_types & AUTH_TYPE_USERNAME_PASS) {
/* body should be "username=test&password=test" */
username = strstr(req->body, "username=");
@@ -296,32 +341,20 @@ struct cmd_auth_req_st areq;
}
ret = auth_user(ws, &areq);
if (ret < 0)
if (ret < 0) {
if (username)
oclog(ws, LOG_INFO, "Failed authentication attempt for '%s'", username);
else
oclog(ws, LOG_INFO, "Failed authentication attempt");
goto auth_fail;
oclog(ws, LOG_INFO, "User '%s' logged in\n", username);
/* generate cookie */
ret = gnutls_rnd(GNUTLS_RND_RANDOM, cookie, sizeof(cookie));
GNUTLS_FATAL_ERR(ret);
p = str_cookie;
for (i=0;i<sizeof(cookie);i++) {
sprintf(p, "%.2x", (unsigned int)cookie[i]);
p+=2;
}
memset(&sc, 0, sizeof(sc));
sc.expiration = time(0) + ws->config->cookie_validity;
if (username)
snprintf(sc.username, sizeof(sc.username), "%s", username);
memcpy(sc.tun_name, ws->tun_name, sizeof(sc.tun_name));
oclog(ws, LOG_INFO, "User '%s' logged in\n", ws->username);
/* store cookie */
ret = store_cookie(ws, cookie, sizeof(cookie), &sc);
if (ret < 0) {
reason = "Storage issue";
goto auth_fail;
p = str_cookie;
for (i=0;i<sizeof(ws->cookie);i++) {
sprintf(p, "%.2x", (unsigned int)ws->cookie[i]);
p+=2;
}
/* reply */
@@ -355,24 +388,14 @@ struct req_data_st *req = ws->parser->data;
const char* reason = "Authentication failed";
unsigned char cookie[COOKIE_SIZE];
char str_cookie[2*COOKIE_SIZE+1];
char cert_username[MAX_USERNAME_SIZE];
char * username = NULL;
char * password = NULL;
char *p;
unsigned int i;
struct stored_cookie_st sc;
struct cmd_auth_req_st areq;
memset(&areq, 0, sizeof(areq));
if (ws->config->auth_types & AUTH_TYPE_CERTIFICATE) {
ret = get_cert_info(ws, &areq, &reason);
if (ret < 0)
goto auth_fail;
username = areq.cert_user;
}
if (ws->config->auth_types & AUTH_TYPE_USERNAME_PASS) {
/* body should contain <username>test</username><password>test</password> */
username = strstr(req->body, XMLUSER);
@@ -414,10 +437,15 @@ struct cmd_auth_req_st areq;
}
ret = auth_user(ws, &areq);
if (ret < 0)
if (ret < 0) {
if (username)
oclog(ws, LOG_INFO, "Failed authentication attempt for '%s'", username);
else
oclog(ws, LOG_INFO, "Failed authentication attempt");
goto auth_fail;
}
oclog(ws, LOG_INFO, "User '%s' logged in\n", username);
oclog(ws, LOG_INFO, "User '%s' logged in\n", ws->username);
/* generate cookie */
ret = gnutls_rnd(GNUTLS_RND_RANDOM, cookie, sizeof(cookie));
@@ -429,19 +457,6 @@ struct cmd_auth_req_st areq;
p+=2;
}
memset(&sc, 0, sizeof(sc));
sc.expiration = time(0) + ws->config->cookie_validity;
if (username)
snprintf(sc.username, sizeof(sc.username), "%s", username);
memcpy(sc.tun_name, ws->tun_name, sizeof(sc.tun_name));
/* store cookie */
ret = store_cookie(ws, cookie, sizeof(cookie), &sc);
if (ret < 0) {
reason = "Storage issue";
goto auth_fail;
}
/* reply */
tls_puts(ws->session, "HTTP/1.1 200 OK\r\n");
+54
View File
@@ -0,0 +1,54 @@
#ifndef WORKER_AUTH_H
#define WORKER_AUTH_H
#include <config.h>
#include <syslog.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <net/if.h>
#include <vpn.h>
#include <cookies.h>
typedef enum {
AUTH_REQ = 1,
AUTH_COOKIE_REQ = 2,
AUTH_REP = 3,
} cmd_request_t;
typedef enum {
REP_AUTH_OK = 0,
REP_AUTH_FAILED = 1,
} cmd_auth_reply_t;
/* AUTH_COOKIE_REQ */
struct __attribute__ ((__packed__)) cmd_auth_cookie_req_st {
uint8_t cookie[COOKIE_SIZE];
uint8_t tls_auth_ok;
char cert_user[MAX_USERNAME_SIZE];
};
/* AUTH_REQ */
struct __attribute__ ((__packed__)) cmd_auth_req_st {
uint8_t user_pass_present;
char user[MAX_USERNAME_SIZE];
char pass[MAX_PASSWORD_SIZE];
uint8_t tls_auth_ok;
char cert_user[MAX_USERNAME_SIZE];
};
/* AUTH_REP */
struct __attribute__ ((__packed__)) cmd_auth_reply_st {
uint8_t reply;
uint8_t cookie[COOKIE_SIZE];
char vname[IFNAMSIZ]; /* interface name */
char user[MAX_USERNAME_SIZE];
};
int auth_cookie(worker_st *ws, void* cookie, size_t cookie_size);
int get_auth_handler(worker_st *server);
int post_old_auth_handler(worker_st *server);
int post_new_auth_handler(worker_st *server);
#endif
+31 -15
View File
@@ -36,6 +36,7 @@
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <signal.h>
#include <vpn.h>
#include <worker-auth.h>
@@ -47,6 +48,11 @@
/* HTTP requests prior to disconnection */
#define MAX_HTTP_REQUESTS 8
static void handle_alarm(int signo)
{
exit(1);
}
static int connect_handler(worker_st *ws);
typedef int (*url_handler_fn)(worker_st*);
@@ -195,6 +201,11 @@ void vpn_server(struct worker_st* ws, struct tls_st *creds)
url_handler_fn fn;
int requests_left = MAX_HTTP_REQUESTS;
signal(SIGALRM, handle_alarm);
if (ws->config->auth_timeout)
alarm(ws->config->auth_timeout);
syslog(LOG_INFO, "Accepted connection from %s",
human_addr((void*)&ws->remote_addr, ws->remote_addr_len,
buf, sizeof(buf)));
@@ -245,7 +256,10 @@ restart:
/* parse as we go */
do {
nrecvd = tls_recv(session, buf, sizeof(buf));
GNUTLS_FATAL_ERR(nrecvd);
if (nrecvd <= 0) {
oclog(ws, LOG_INFO, "Error receiving client data");
exit(1);
}
nparsed = http_parser_execute(&parser, &settings, (void*)buf, nrecvd);
if (nparsed == 0) {
@@ -308,10 +322,10 @@ finish:
static int get_ip(struct worker_st* ws, int fd, int family, unsigned int local,
struct vpn_st* vinfo, char** buffer, size_t* buffer_size)
{
void* *ptr;
void* ptr;
const void* p;
struct ifreq ifr;
unsigned int i, flags;
unsigned int flags;
int ret, e;
memset(&ifr, 0, sizeof(ifr));
@@ -374,10 +388,8 @@ fail:
static int get_rt_vpn_info(worker_st * ws,
struct vpn_st* vinfo, char* buffer, size_t buffer_size)
{
unsigned int i;
int fd, ret;
struct ifreq ifr;
const char* p;
memset(vinfo, 0, sizeof(*vinfo));
vinfo->name = ws->tun_name;
@@ -453,7 +465,6 @@ fd_set rfds;
int l, pktlen;
int tls_fd, max;
unsigned i;
struct stored_cookie_st sc;
struct vpn_st vinfo;
char* buffer;
unsigned int buffer_size;
@@ -466,14 +477,21 @@ unsigned int buffer_size;
exit(1);
}
ret = retrieve_cookie(ws, req->cookie, sizeof(req->cookie), &sc);
if (ret < 0) {
oclog(ws, LOG_INFO, "Connect request without authentication");
tls_puts(ws->session, "HTTP/1.1 503 Service Unavailable\r\n\r\n");
tls_fatal_close(ws->session, GNUTLS_A_ACCESS_DENIED);
exit(1);
if (ws->auth_ok == 0) {
/* authentication didn't occur in this session. Use the
* cookie */
ret = auth_cookie(ws, req->cookie, sizeof(req->cookie));
if (ret < 0) {
oclog(ws, LOG_INFO, "Failed cookie authentication attempt");
tls_puts(ws->session, "HTTP/1.1 503 Service Unavailable\r\n\r\n");
tls_fatal_close(ws->session, GNUTLS_A_ACCESS_DENIED);
exit(1);
}
}
memcpy(ws->tun_name, sc.tun_name, sizeof(ws->tun_name));
/* turn of the alarm */
if (ws->config->auth_timeout)
alarm(0);
if (strcmp(req->url, "/CSCOSSLC/tunnel") != 0) {
oclog(ws, LOG_INFO, "Bad connect request: '%s'\n", req->url);
@@ -489,8 +507,6 @@ unsigned int buffer_size;
return -1;
}
oclog(ws, LOG_INFO, "User '%s' connected.\n", sc.username);
buffer_size = 2048;
buffer = malloc(buffer_size);
if (buffer == NULL) {