From 61ae5a9c06d19cec7a2b9c443c2fedc039205469 Mon Sep 17 00:00:00 2001 From: Nikos Mavrogiannopoulos Date: Mon, 4 Feb 2013 20:43:28 +0100 Subject: [PATCH] Added connect and disconnect scripts --- src/Makefile.am | 2 +- src/config.c | 3 + src/main-auth.c | 8 +++ src/main-script.c | 138 ++++++++++++++++++++++++++++++++++++++++++++ src/main.c | 15 ++++- src/main.h | 6 +- src/ocserv-args.c | 2 +- src/ocserv-args.def | 8 +++ src/ocserv-args.h | 2 +- src/sample.config | 10 +++- src/vpn.h | 3 + 11 files changed, 191 insertions(+), 6 deletions(-) create mode 100644 src/main-script.c diff --git a/src/Makefile.am b/src/Makefile.am index 9bf9e767..3dd58ba9 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -9,7 +9,7 @@ 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 pam.c pam.h worker-resume.c worker.h hash.h \ - hashtable.h main-resume.c main.h + hashtable.h main-resume.c main.h main-script.c ocserv_SOURCES += ocserv-args.def ocserv-args.c ocserv-args.h diff --git a/src/config.c b/src/config.c index 0ba4c29d..b334cb0c 100644 --- a/src/config.c +++ b/src/config.c @@ -122,6 +122,9 @@ unsigned j; READ_STRING("crl", config->crl, 0); READ_STRING("cert-user-oid", config->cert_user_oid, 0); + READ_STRING("connect-script", config->connect_script, 0); + READ_STRING("disconnect-script", config->disconnect_script, 0); + READ_STRING("tls-priorities", config->priorities, 0); READ_STRING("chroot-dir", config->chroot_dir, 0); diff --git a/src/main-auth.c b/src/main-auth.c index 41188966..8a684dd3 100644 --- a/src/main-auth.c +++ b/src/main-auth.c @@ -296,6 +296,13 @@ int handle_commands(main_server_st *s, struct proc_list_st* proc) ret = handle_auth_cookie_req(s, proc, &cmd_data.cauth, &lease); } + if (ret == 0) { + ret = call_connect_script(s, proc); + if (ret < 0) { + syslog(LOG_INFO, "User '%s' disconnected due to script", proc->username); + } + } + if (ret == 0) { if (cmd == AUTH_REQ) { /* generate and store cookie */ @@ -303,6 +310,7 @@ int handle_commands(main_server_st *s, struct proc_list_st* proc) if (ret < 0) return -2; } + syslog(LOG_INFO, "User '%s' authenticated", proc->username); ret = send_auth_reply(s, proc, REP_AUTH_OK, lease); diff --git a/src/main-script.c b/src/main-script.c new file mode 100644 index 00000000..b7d200e2 --- /dev/null +++ b/src/main-script.c @@ -0,0 +1,138 @@ +/* + * 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 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +void call_disconnect_script(main_server_st *s, struct proc_list_st* proc) +{ +pid_t pid; +int ret; + + if (s->config->disconnect_script == NULL) + return; + + /* XXX: close fds */ + pid = fork(); + if (pid == 0) { + char real[64]; + char local[64]; + char remote[64]; + + if (getnameinfo((void*)&proc->remote_addr, proc->remote_addr_len, real, sizeof(real), NULL, 0, NI_NUMERICHOST) != 0) + exit(1); + + if (proc->lease->lip4_len > 0) { + if (getnameinfo((void*)&proc->lease->lip4, proc->lease->lip4_len, local, sizeof(local), NULL, 0, NI_NUMERICHOST) != 0) + exit(1); + } else { + if (getnameinfo((void*)&proc->lease->lip6, proc->lease->lip6_len, local, sizeof(local), NULL, 0, NI_NUMERICHOST) != 0) + exit(1); + } + + if (proc->lease->rip4_len > 0) { + if (getnameinfo((void*)&proc->lease->rip4, proc->lease->rip4_len, remote, sizeof(remote), NULL, 0, NI_NUMERICHOST) != 0) + exit(1); + } else { + if (getnameinfo((void*)&proc->lease->rip6, proc->lease->rip6_len, remote, sizeof(remote), NULL, 0, NI_NUMERICHOST) != 0) + exit(1); + } + + ret = execlp(s->config->disconnect_script, s->config->disconnect_script, + proc->username, proc->lease->name, real, local, remote, NULL); + if (ret == -1) + exit(1); + + exit(0); + } else if (pid == -1) { + syslog(LOG_ERR, "Could not fork()"); + } +} + +int call_connect_script(main_server_st *s, struct proc_list_st* proc) +{ +pid_t pid; +int ret, status; + + if (s->config->connect_script == NULL) + return 0; + + /* XXX: close fds */ + pid = fork(); + if (pid == 0) { + char real[64]; + char local[64]; + char remote[64]; + + if (getnameinfo((void*)&proc->remote_addr, proc->remote_addr_len, real, sizeof(real), NULL, 0, NI_NUMERICHOST) != 0) + exit(1); + + if (proc->lease->lip4_len > 0) { + if (getnameinfo((void*)&proc->lease->lip4, proc->lease->lip4_len, local, sizeof(local), NULL, 0, NI_NUMERICHOST) != 0) + exit(1); + } else { + if (getnameinfo((void*)&proc->lease->lip6, proc->lease->lip6_len, local, sizeof(local), NULL, 0, NI_NUMERICHOST) != 0) + exit(1); + } + + if (proc->lease->rip4_len > 0) { + if (getnameinfo((void*)&proc->lease->rip4, proc->lease->rip4_len, remote, sizeof(remote), NULL, 0, NI_NUMERICHOST) != 0) + exit(1); + } else { + if (getnameinfo((void*)&proc->lease->rip6, proc->lease->rip6_len, remote, sizeof(remote), NULL, 0, NI_NUMERICHOST) != 0) + exit(1); + } + + ret = execlp(s->config->connect_script, s->config->connect_script, + proc->username, proc->lease->name, real, local, remote, NULL); + if (ret == -1) + exit(1); + + exit(0); + } else if (pid == -1) { + syslog(LOG_ERR, "Could not fork()"); + return -1; + } + + ret = waitpid(pid, &status, 0); + if (WEXITSTATUS(status) == 0) + return 0; + return -1; +} diff --git a/src/main.c b/src/main.c index b24df060..a944b215 100644 --- a/src/main.c +++ b/src/main.c @@ -45,6 +45,7 @@ int syslog_open = 0; static unsigned int terminate = 0; static unsigned int need_maintainance = 0; +static unsigned int need_children_cleanup = 0; struct listen_list_st { struct list_head list; @@ -159,7 +160,7 @@ listen_ports(struct cfg_st* config, struct listen_list_st *list, const char *nod return 0; } -static void handle_children(int signo) +static void cleanup_children(main_server_st *s) { int status; pid_t pid; @@ -174,6 +175,12 @@ pid_t pid; } else syslog(LOG_DEBUG, "Child %u died peacefully\n", (unsigned)pid); } + need_children_cleanup = 0; +} + +static void handle_children(int signo) +{ + need_children_cleanup = 1; } static void handle_alarm(int signo) @@ -579,6 +586,7 @@ fork_failed: /* received a bad command from worker */ kill(ctmp->pid, SIGTERM); } + call_disconnect_script(&s, ctmp); remove_proc(ctmp); active_clients--; } @@ -601,6 +609,11 @@ fork_failed: } alarm(MAINTAINANCE_TIME); } + + if (need_children_cleanup != 0) { + cleanup_children(&s); + } + } return 0; diff --git a/src/main.h b/src/main.h index c1ffb3df..c74afd0d 100644 --- a/src/main.h +++ b/src/main.h @@ -7,6 +7,7 @@ #include #include #include +#include "ipc.h" int cmd_parser (int argc, char **argv, struct cfg_st* config); @@ -17,7 +18,7 @@ struct proc_list_st { 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 */ + uint8_t cookie[COOKIE_SIZE]; /* the cookie associated with the session */ uint8_t session_id[GNUTLS_MAX_SESSION_ID]; /* the tun lease this process has */ @@ -32,6 +33,9 @@ typedef struct main_server_st { int handle_commands(main_server_st *s, struct proc_list_st* cur); +int call_connect_script(main_server_st *s, struct proc_list_st* cur); +void call_disconnect_script(main_server_st *s, struct proc_list_st* cur); + void expire_tls_sessions(main_server_st *s); int send_resume_fetch_reply(main_server_st* s, struct proc_list_st* proc, diff --git a/src/ocserv-args.c b/src/ocserv-args.c index 97d4f519..b0c0aeb0 100644 --- a/src/ocserv-args.c +++ b/src/ocserv-args.c @@ -2,7 +2,7 @@ * * DO NOT EDIT THIS FILE (ocserv-args.c) * - * It has been AutoGen-ed January 31, 2013 at 12:25:38 AM by AutoGen 5.16 + * It has been AutoGen-ed February 4, 2013 at 08:41:20 PM by AutoGen 5.16 * From the definitions ocserv-args.def * and the template file options * diff --git a/src/ocserv-args.def b/src/ocserv-args.def index 55826ab6..ef6b35a4 100644 --- a/src/ocserv-args.def +++ b/src/ocserv-args.def @@ -92,6 +92,14 @@ auth-timeout = 40 # of that cookie. cookie-validity = 14400 +# Script to call when a client connects and obtains an IP +# Parameters: username device IP-REAL IP-LOCAL IP-REMOTE +# IP-REAL is the remote IP of the client, +# IP-LOCAL is the local IP in the P-t-P connection and IP-REMOTE +# is the VPN client IP. +connect-script = /bin/echo +disconnect-script = /bin/echo + # Cookie database file. Where to store the cookies. cookie-db = /path/to/db diff --git a/src/ocserv-args.h b/src/ocserv-args.h index 718d8b84..1258f0ec 100644 --- a/src/ocserv-args.h +++ b/src/ocserv-args.h @@ -2,7 +2,7 @@ * * DO NOT EDIT THIS FILE (ocserv-args.h) * - * It has been AutoGen-ed January 31, 2013 at 12:25:38 AM by AutoGen 5.16 + * It has been AutoGen-ed February 4, 2013 at 08:41:20 PM by AutoGen 5.16 * From the definitions ocserv-args.def * and the template file options * diff --git a/src/sample.config b/src/sample.config index ebf605f1..5d14b0df 100644 --- a/src/sample.config +++ b/src/sample.config @@ -46,7 +46,7 @@ tls-priorities = "PERFORMANCE:%SERVER_PRECEDENCE:%COMPAT" # Once a client is authenticated he's provided a cookie with # which he can reconnect. This option sets the maximum lifetime # of that cookie. -cookie-validity = 30 +cookie-validity = 14400 # Cookie database file. Where to store the cookies. cookie-db = /var/tmp/ocserv-cookie.db @@ -58,6 +58,14 @@ run-as-group = nogroup device = vpns +# Script to call when a client connects and obtains an IP +# Parameters: username device IP-REAL IP-LOCAL IP-REMOTE +# IP-REAL is the remote IP of the client, +# IP-LOCAL is the local IP in the P-t-P connection and IP-REMOTE +# is the VPN client IP. +connect-script = /bin/echo +disconnect-script = /bin/echo + # The pool from which the VPN user IPs will be drawn from. ipv4-network = 192.168.1.0 ipv4-netmask = 255.255.255.0 diff --git a/src/vpn.h b/src/vpn.h index 239ca936..70168a03 100644 --- a/src/vpn.h +++ b/src/vpn.h @@ -61,6 +61,9 @@ struct cfg_st { unsigned foreground; unsigned max_clients; + const char *connect_script; + const char *disconnect_script; + uid_t uid; gid_t gid;