From b552f27ddbf2a8bb46c2e1d07ba059f78c8e0d50 Mon Sep 17 00:00:00 2001 From: Nikos Mavrogiannopoulos Date: Wed, 13 Mar 2013 18:45:48 +0100 Subject: [PATCH] Do not let scripts block the server operation. --- src/config.c | 7 +++ src/log.c | 21 +++++++ src/main-auth.c | 18 +++--- src/main-misc.c | 138 +++++++++++++++++++++++--------------------- src/main-user.c | 51 ++++++++-------- src/main.c | 95 ++++++++++++++++++------------ src/main.h | 32 ++++++++-- src/ocserv-args.c | 2 +- src/ocserv-args.def | 5 +- src/ocserv-args.h | 2 +- src/script-list.h | 35 +++++++++++ src/tun.c | 1 + src/worker-auth.c | 4 -- 13 files changed, 260 insertions(+), 151 deletions(-) create mode 100644 src/script-list.h diff --git a/src/config.c b/src/config.c index e0d3d291..d56f1fb0 100644 --- a/src/config.c +++ b/src/config.c @@ -266,6 +266,13 @@ static void check_cfg( struct cfg_st *config) else config->cert_req = GNUTLS_CERT_REQUEST; } + + if (config->plain_passwd != NULL) { + if (access(config->plain_passwd, R_OK) != 0) { + fprintf(stderr, "cannot access password file %s\n", config->plain_passwd); + exit(1); + } + } #ifdef ANYCONNECT_CLIENT_COMPAT if (config->cert) { diff --git a/src/log.c b/src/log.c index abeb520a..9bc025b0 100644 --- a/src/log.c +++ b/src/log.c @@ -122,3 +122,24 @@ void __attribute__ ((format(printf, 4, 5))) return; } + +void mslog_hex(const main_server_st * s, const struct proc_st* proc, + int priority, const char *prefix, uint8_t* bin, unsigned bin_size) +{ + char buf[512]; + int ret; + size_t buf_size; + gnutls_datum_t data = {bin, bin_size}; + + if (priority == LOG_DEBUG && s->config->debug == 0) + return; + + buf_size = sizeof(buf); + ret = gnutls_hex_encode(&data, buf, &buf_size); + if (ret < 0) + return; + + mslog(s, proc, priority, "%s %s", prefix, buf); + + return; +} diff --git a/src/main-auth.c b/src/main-auth.c index b05b8725..aaceb64e 100644 --- a/src/main-auth.c +++ b/src/main-auth.c @@ -45,7 +45,7 @@ #include "plain.h" int send_auth_reply(main_server_st* s, struct proc_st* proc, - cmd_auth_reply_t r, struct lease_st* lease) + cmd_auth_reply_t r) { struct iovec iov[2]; uint8_t cmd[2]; @@ -62,7 +62,7 @@ int send_auth_reply(main_server_st* s, struct proc_st* proc, hdr.msg_iov = iov; - if (r == REP_AUTH_OK && lease != NULL) { + if (r == REP_AUTH_OK && proc->lease != NULL) { cmd[0] = AUTH_REP; iov[0].iov_base = cmd; @@ -72,7 +72,7 @@ int send_auth_reply(main_server_st* s, struct proc_st* proc, resp.reply = r; memcpy(resp.cookie, proc->cookie, COOKIE_SIZE); memcpy(resp.session_id, proc->session_id, sizeof(resp.session_id)); - memcpy(resp.vname, lease->name, sizeof(resp.vname)); + memcpy(resp.vname, proc->lease->name, sizeof(resp.vname)); memcpy(resp.user, proc->username, sizeof(resp.user)); iov[1].iov_base = &resp; @@ -87,7 +87,7 @@ int send_auth_reply(main_server_st* s, struct proc_st* proc, 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)); + memcpy(CMSG_DATA(cmptr), &proc->lease->fd, sizeof(int)); } else { cmd[0] = AUTH_REP; cmd[1] = REP_AUTH_FAILED; @@ -101,7 +101,7 @@ int send_auth_reply(main_server_st* s, struct proc_st* proc, } int handle_auth_cookie_req(main_server_st* s, struct proc_st* proc, - const struct cmd_auth_cookie_req_st * req, struct lease_st **lease) + const struct cmd_auth_cookie_req_st * req) { int ret; struct stored_cookie_st *sc; @@ -146,7 +146,7 @@ time_t now = time(0); } } - ret = open_tun(s, lease); + ret = open_tun(s, &proc->lease); if (ret < 0) { ret = -1; /* sorry */ goto cleanup; @@ -177,7 +177,7 @@ struct stored_cookie_st *sc; ret = gnutls_rnd(GNUTLS_RND_NONCE, proc->session_id, sizeof(proc->session_id)); if (ret < 0) return -2; - proc->session_id_size = sizeof( proc->session_id); + proc->session_id_size = sizeof(proc->session_id); sc = calloc(1, sizeof(*sc)); if (sc == NULL) @@ -202,7 +202,7 @@ struct stored_cookie_st *sc; } int handle_auth_req(main_server_st *s, struct proc_st* proc, - const struct cmd_auth_req_st * req, struct lease_st **lease) + const struct cmd_auth_req_st * req) { int ret = -1; unsigned username_set = 0; @@ -256,7 +256,7 @@ unsigned username_set = 0; proc->groupname[sizeof(proc->groupname)-1] = 0; proc->hostname[sizeof(proc->hostname)-1] = 0; - ret = open_tun(s, lease); + ret = open_tun(s, &proc->lease); if (ret < 0) ret = -1; /* sorry */ } diff --git a/src/main-misc.c b/src/main-misc.c index fac6cd5b..5b29e869 100644 --- a/src/main-misc.c +++ b/src/main-misc.c @@ -108,12 +108,47 @@ int send_udp_fd(main_server_st* s, struct proc_st * proc, int fd) return(sendmsg(proc->fd, &hdr, 0)); } +int handle_script_exit(main_server_st *s, struct proc_st* proc, int code) +{ +int ret; + + if (code == 0) { + ret = send_auth_reply(s, proc, REP_AUTH_OK); + if (ret < 0) { + mslog(s, proc, LOG_ERR, "could not send reply auth cmd."); + ret = ERR_BAD_COMMAND; + goto fail; + } + } else { + mslog(s, proc, LOG_INFO, "failed authentication attempt for user '%s'", proc->username); + ret = send_auth_reply( s, proc, REP_AUTH_FAILED); + if (ret < 0) { + mslog(s, proc, LOG_ERR, "could not send reply auth cmd."); + ret = ERR_BAD_COMMAND; + goto fail; + } + } + ret = 0; + +fail: + /* we close the lease tun fd both on success and failure. + * The parent doesn't need to keep the tunfd. + */ + if (proc->lease) { + if (proc->lease->fd >= 0) + close(proc->lease->fd); + proc->lease->fd = -1; + } + + return ret; +} + + int handle_commands(main_server_st *s, struct proc_st* proc) { struct iovec iov[2]; uint8_t cmd; struct msghdr hdr; - struct lease_st *lease; union { struct cmd_auth_req_st auth; struct cmd_auth_cookie_req_st cauth; @@ -153,16 +188,15 @@ int handle_commands(main_server_st *s, struct proc_st* proc) case CMD_TUN_MTU: if (cmd_data_len != sizeof(cmd_data.tmtu)) { mslog(s, proc, LOG_ERR, "error in received message (cmd %u) length.", (unsigned)cmd); - return -2; + return ERR_BAD_COMMAND; } set_tun_mtu(s, proc, cmd_data.tmtu.mtu); break; - case RESUME_STORE_REQ: if (cmd_data_len <= sizeof(cmd_data.sresume)-MAX_SESSION_DATA_SIZE) { mslog(s, proc, LOG_ERR, "error in received message (cmd %u) length.", (unsigned)cmd); - return -2; + return ERR_BAD_COMMAND; } ret = handle_resume_store_req(s, proc, &cmd_data.sresume); if (ret < 0) { @@ -174,7 +208,7 @@ int handle_commands(main_server_st *s, struct proc_st* proc) case RESUME_DELETE_REQ: if (cmd_data_len != sizeof(cmd_data.fresume)) { mslog(s, proc, LOG_ERR, "error in received message (cmd %u) length.", (unsigned)cmd); - return -2; + return ERR_BAD_COMMAND; } ret = handle_resume_delete_req(s, proc, &cmd_data.fresume); if (ret < 0) { @@ -187,7 +221,7 @@ int handle_commands(main_server_st *s, struct proc_st* proc) if (cmd_data_len != sizeof(cmd_data.fresume)) { mslog(s, proc, LOG_ERR, "error in received message (%u) length.", (unsigned)cmd); - return -2; + return ERR_BAD_COMMAND; } ret = handle_resume_fetch_req(s, proc, &cmd_data.fresume, &reply); if (ret < 0) { @@ -199,29 +233,27 @@ int handle_commands(main_server_st *s, struct proc_st* proc) if (ret < 0) { mslog(s, proc, LOG_ERR, "could not send reply cmd %d.", (unsigned) cmd); - return -2; + return ERR_BAD_COMMAND; } break; case AUTH_REQ: case AUTH_COOKIE_REQ: - lease = NULL; - 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 -2; + return ERR_BAD_COMMAND; } - ret = handle_auth_req(s, proc, &cmd_data.auth, &lease); + 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 -2; + return ERR_BAD_COMMAND; } - ret = handle_auth_cookie_req(s, proc, &cmd_data.cauth, &lease); + ret = handle_auth_cookie_req(s, proc, &cmd_data.cauth); } if (ret == 0) { @@ -231,9 +263,32 @@ int handle_commands(main_server_st *s, struct proc_st* proc) mslog(s, proc, LOG_INFO, "user '%s' tried to connect more than %u times", proc->username, s->config->max_same_clients); } + 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, lease); + 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); } @@ -242,60 +297,13 @@ int handle_commands(main_server_st *s, struct proc_st* proc) add_to_ip_ban_list(s, &proc->remote_addr, proc->remote_addr_len); } - if (ret == 0) { - if (proc->groupname[0] == 0) - group = "[unknown]"; - else - group = proc->groupname; +cleanup: + /* no script was called. Handle it as a successful script call. */ + return handle_script_exit(s, proc, ret); - if (cmd == AUTH_REQ) { - /* generate and store cookie */ - ret = generate_and_store_vals(s, proc); - if (ret < 0) { - ret = -2; - goto lease_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); - } - - ret = send_auth_reply(s, proc, REP_AUTH_OK, lease); - if (ret < 0) { - mslog(s, proc, LOG_ERR, "could not send reply cmd %d.", (unsigned)cmd); - ret = -2; - goto lease_cleanup; - } - - proc->lease = lease; - proc->lease->in_use = 1; - ret = 0; - } else { - mslog(s, proc, LOG_INFO, "failed authentication attempt for user '%s'", proc->username); - ret = send_auth_reply( s, proc, REP_AUTH_FAILED, NULL); - if (ret < 0) { - mslog(s, proc, LOG_ERR, "could not send reply cmd."); - ret = -2; - goto lease_cleanup; - } - ret = 0; - } - -lease_cleanup: - /* we close the lease tun fd both on success and failure. - * The parent doesn't need to know the tunfd. - */ - if (lease) { - if (lease->fd >= 0) - close(lease->fd); - lease->fd = -1; - } - return ret; - - break; default: mslog(s, proc, LOG_ERR, "unknown CMD 0x%x.", (unsigned)cmd); - return -2; + return ERR_BAD_COMMAND; } return 0; diff --git a/src/main-user.c b/src/main-user.c index 99f47540..d321f06b 100644 --- a/src/main-user.c +++ b/src/main-user.c @@ -43,14 +43,14 @@ #include #include #include +#include #include static -int call_script(main_server_st *s, struct proc_st* proc, struct lease_st* lease, unsigned up) +int call_script(main_server_st *s, struct proc_st* proc, unsigned up) { pid_t pid; -int ret, status; -unsigned estatus; +int ret; const char* script; if (up != 0) @@ -67,34 +67,36 @@ const char* script; char local[64]; char remote[64]; - /* Note we don't use proc->lease and accept lease directly - * because we are called before proc population is completed */ if (getnameinfo((void*)&proc->remote_addr, proc->remote_addr_len, real, sizeof(real), NULL, 0, NI_NUMERICHOST) != 0) exit(1); - if (lease->lip4_len > 0) { - if (getnameinfo((void*)&lease->lip4, lease->lip4_len, local, sizeof(local), NULL, 0, NI_NUMERICHOST) != 0) + 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*)&lease->lip6, lease->lip6_len, local, sizeof(local), NULL, 0, NI_NUMERICHOST) != 0) + if (getnameinfo((void*)&proc->lease->lip6, proc->lease->lip6_len, local, sizeof(local), NULL, 0, NI_NUMERICHOST) != 0) exit(1); } - if (lease->rip4_len > 0) { - if (getnameinfo((void*)&lease->rip4, lease->rip4_len, remote, sizeof(remote), NULL, 0, NI_NUMERICHOST) != 0) + 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*)&lease->rip6, lease->rip6_len, remote, sizeof(remote), NULL, 0, NI_NUMERICHOST) != 0) + if (getnameinfo((void*)&proc->lease->rip6, proc->lease->rip6_len, remote, sizeof(remote), NULL, 0, NI_NUMERICHOST) != 0) exit(1); } setenv("USERNAME", proc->username, 1); setenv("GROUPNAME", proc->groupname, 1); setenv("HOSTNAME", proc->hostname, 1); - setenv("DEVICE", lease->name, 1); + setenv("DEVICE", proc->lease->name, 1); setenv("IP_REAL", real, 1); setenv("IP_LOCAL", local, 1); setenv("IP_REMOTE", remote, 1); + if (up) + setenv("REASON", "connect", 1); + else + setenv("REASON", "disconnect", 1); mslog(s, proc, LOG_DEBUG, "executing script %s", script); ret = execl(script, script, NULL); @@ -109,21 +111,16 @@ const char* script; return -1; } - ret = waitpid(pid, &status, 0); - estatus = WEXITSTATUS(status); - mslog(s, proc, LOG_DEBUG, "%s-script exit status: %u", (up!=0)?"connect":"disconnect", estatus); - - if (estatus == 0) { - return 0; + if (up) { + add_to_script_list(s, pid, up, proc); + return ERR_WAIT_FOR_SCRIPT; } else { - if (WIFSIGNALED(status)) - mslog(s, proc, LOG_DEBUG, "%s-script exit due to signal", (up!=0)?"connect":"disconnect"); - return -1; + return 0; } } static void -add_utmp_entry(main_server_st *s, struct proc_st* proc, struct lease_st* lease) +add_utmp_entry(main_server_st *s, struct proc_st* proc) { #ifdef HAVE_LIBUTIL struct utmpx entry; @@ -135,7 +132,7 @@ add_utmp_entry(main_server_st *s, struct proc_st* proc, struct lease_st* lease) memset(&entry, 0, sizeof(entry)); entry.ut_type = USER_PROCESS; entry.ut_pid = proc->pid; - snprintf(entry.ut_line, sizeof(entry.ut_line), "%s", lease->name); + snprintf(entry.ut_line, sizeof(entry.ut_line), "%s", proc->lease->name); snprintf(entry.ut_user, sizeof(entry.ut_user), "%s", proc->username); if (proc->remote_addr_len == sizeof(struct sockaddr_in)) memcpy(entry.ut_addr_v6, SA_IN_P(&proc->remote_addr), sizeof(struct in_addr)); @@ -188,13 +185,13 @@ static void remove_utmp_entry(main_server_st *s, struct proc_st* proc) #endif } -int user_connected(main_server_st *s, struct proc_st* proc, struct lease_st* lease) +int user_connected(main_server_st *s, struct proc_st* proc) { int ret; - add_utmp_entry(s, proc, lease); + add_utmp_entry(s, proc); - ret = call_script(s, proc, lease, 1); + ret = call_script(s, proc, 1); if (ret < 0) return ret; @@ -204,6 +201,6 @@ int ret; void user_disconnected(main_server_st *s, struct proc_st* proc) { remove_utmp_entry(s, proc); - call_script(s, proc, proc->lease, 0); + call_script(s, proc, 0); } diff --git a/src/main.c b/src/main.c index cf104cb6..ed31c134 100644 --- a/src/main.c +++ b/src/main.c @@ -32,6 +32,7 @@ #include #include #include +#include #include #include @@ -285,14 +286,48 @@ int s, y, e; return 0; } +static void remove_proc(main_server_st* s, struct proc_st *proc, unsigned k) +{ + if (k) + kill(proc->pid, SIGTERM); + + user_disconnected(s, proc); + + /* close the intercomm fd */ + if (proc->fd >= 0) + close(proc->fd); + proc->fd = -1; + proc->pid = -1; + + if (proc->lease) + proc->lease->in_use = 0; + list_del(&proc->list); + free(proc); +} static void cleanup_children(main_server_st *s) { -int status; +int status, estatus, ret; pid_t pid; +struct script_wait_st *stmp, *spos; while ((pid = waitpid(-1, &status, WNOHANG)) > 0) { - if (WEXITSTATUS(status) != 0 || + estatus = WEXITSTATUS(status); + + /* check if someone was waiting for that pid */ + list_for_each_safe(&s->script_list.head, stmp, spos, list) { + if (stmp->pid == pid) { + mslog(s, stmp->proc, LOG_DEBUG, "%s-script exit status: %u", stmp->up?"connect":"disconnect", estatus); + ret = handle_script_exit(s, stmp->proc, estatus); + if (ret < 0) + remove_proc(s, stmp->proc, 0); + list_del(&stmp->list); + free(stmp); + break; + } + } + + if (estatus != 0 || (WIFSIGNALED(status) && WTERMSIG(status) == SIGSEGV)) { if (WIFSIGNALED(status)) mslog(s, NULL, LOG_ERR, "Child %u died with sigsegv\n", (unsigned)pid); @@ -311,8 +346,6 @@ static void handle_alarm(int signo) need_maintainance = 1; } - - static void drop_privileges(main_server_st* s) { int ret, e; @@ -357,6 +390,7 @@ void clear_lists(main_server_st *s) { struct listener_st *ltmp, *lpos; struct proc_st *ctmp, *cpos; + struct script_wait_st *script_tmp, *script_pos; struct banned_st *btmp, *bpos; list_for_each_safe(&s->llist.head, ltmp, lpos, list) { @@ -379,6 +413,11 @@ void clear_lists(main_server_st *s) free(btmp); } + list_for_each_safe(&s->script_list.head, script_tmp, script_pos, list) { + list_del(&script_tmp->list); + free(script_tmp); + } + tls_cache_deinit(s->tls_db); } @@ -394,20 +433,6 @@ static void kill_children(main_server_st* s) } } -static void remove_proc(struct proc_st *ctmp) -{ - /* close the intercomm fd */ - if (ctmp->fd >= 0) - close(ctmp->fd); - ctmp->fd = -1; - ctmp->pid = -1; - - if (ctmp->lease) - ctmp->lease->in_use = 0; - list_del(&ctmp->list); - free(ctmp); -} - static void handle_term(int signo) { /* kill all children */ @@ -438,7 +463,7 @@ int connected = 0; cli_addr_size = sizeof(cli_addr); ret = recvfrom(listener->fd, buffer, sizeof(buffer), MSG_PEEK, (void*)&cli_addr, &cli_addr_size); if (ret < 0) { - mslog(s, NULL, LOG_INFO, "Error receiving in UDP socket"); + mslog(s, NULL, LOG_INFO, "error receiving in UDP socket"); return -1; } @@ -453,11 +478,11 @@ int connected = 0; mslog(s, NULL, LOG_DEBUG, "DTLS hello version: %u.%u", (unsigned int)buffer[RECORD_PAYLOAD_POS], (unsigned int)buffer[RECORD_PAYLOAD_POS+1]); if (buffer[1] != 254 && (buffer[1] != 1 && buffer[2] != 0) && buffer[RECORD_PAYLOAD_POS] != 254 && (buffer[RECORD_PAYLOAD_POS] != 0 && buffer[RECORD_PAYLOAD_POS+1] != 0)) { - mslog(s, NULL, LOG_INFO, "Unknown DTLS version: %u.%u", (unsigned)buffer[1], (unsigned)buffer[2]); + mslog(s, NULL, LOG_INFO, "unknown DTLS version: %u.%u", (unsigned)buffer[1], (unsigned)buffer[2]); goto fail; } if (buffer[0] != 22) { - mslog(s, NULL, LOG_INFO, "Unexpected DTLS content type: %u", (unsigned int)buffer[0]); + mslog(s, NULL, LOG_INFO, "unexpected DTLS content type: %u", (unsigned int)buffer[0]); goto fail; } @@ -466,8 +491,8 @@ int connected = 0; session_id = &buffer[RECORD_PAYLOAD_POS+HANDSHAKE_SESSION_ID_POS+1]; /* search for the IP and the session ID in all procs */ - list_for_each(&s->clist.head, ctmp, list) { + list_for_each(&s->clist.head, ctmp, list) { if (session_id_size == ctmp->session_id_size && memcmp(session_id, ctmp->session_id, session_id_size) == 0) { @@ -480,15 +505,14 @@ int connected = 0; ret = send_udp_fd(s, ctmp, listener->fd); if (ret < 0) { - mslog(s, ctmp, LOG_ERR, "Error passing UDP socket"); + mslog(s, ctmp, LOG_ERR, "error passing UDP socket"); return -1; } - mslog(s, ctmp, LOG_DEBUG, "Passed UDP socket"); + mslog(s, ctmp, LOG_DEBUG, "passed UDP socket"); ctmp->udp_fd_received = 1; connected = 1; reopen_udp_port(listener); - break; } } @@ -569,13 +593,14 @@ int main(int argc, char** argv) int cmd_fd[2]; struct worker_st ws; struct cfg_st config; - unsigned active_clients = 0, set; + unsigned set; main_server_st s; memset(&s, 0, sizeof(s)); list_head_init(&s.clist.head); list_head_init(&s.ban_list.head); + list_head_init(&s.script_list.head); tun_st_init(&tun); tls_cache_init(&s.tls_db); @@ -711,9 +736,9 @@ int main(int argc, char** argv) break; } - if (config.max_clients > 0 && active_clients >= config.max_clients) { + if (config.max_clients > 0 && s.active_clients >= config.max_clients) { close(fd); - mslog(&s, NULL, LOG_INFO, "Reached maximum client limit (active: %u)", active_clients); + mslog(&s, NULL, LOG_INFO, "Reached maximum client limit (active: %u)", s.active_clients); break; } @@ -762,6 +787,7 @@ int main(int argc, char** argv) fork_failed: close(cmd_fd[0]); } else { /* parent */ + /* add_proc */ ctmp = calloc(1, sizeof(struct proc_st)); if (ctmp == NULL) { kill(pid, SIGTERM); @@ -775,7 +801,7 @@ fork_failed: set_cloexec_flag (cmd_fd[0], 1); list_add(&s.clist.head, &(ctmp->list)); - active_clients++; + s.active_clients++; } close(cmd_fd[1]); close(fd); @@ -786,7 +812,7 @@ fork_failed: /* connection on UDP port */ ret = forward_udp_to_owner(&s, ltmp); if (ret < 0) { - mslog(&s, NULL, LOG_INFO, "Could not determine the owner of received UDP packet"); + mslog(&s, NULL, LOG_INFO, "could not determine the owner of received UDP packet"); } if (config.rate_limit_ms > 0) @@ -799,13 +825,8 @@ fork_failed: if (FD_ISSET(ctmp->fd, &rd)) { ret = handle_commands(&s, ctmp); if (ret < 0) { - if (ret == -2) { - /* received a bad command from worker */ - kill(ctmp->pid, SIGTERM); - } - user_disconnected(&s, ctmp); - remove_proc(ctmp); - active_clients--; + remove_from_script_list(&s, ctmp); + remove_proc(&s, ctmp, (ret==ERR_BAD_COMMAND)?1:0); } } } diff --git a/src/main.h b/src/main.h index 9c39adff..6e6c3a5f 100644 --- a/src/main.h +++ b/src/main.h @@ -9,6 +9,9 @@ #include #include "ipc.h" +#define ERR_WAIT_FOR_SCRIPT -5 +#define ERR_BAD_COMMAND -2 + int cmd_parser (int argc, char **argv, struct cfg_st* config); void reload_cfg_file(struct cfg_st* config); void write_pid_file(void); @@ -32,12 +35,20 @@ struct listen_list_st { unsigned int total; }; +struct script_wait_st { + struct list_node list; + + pid_t pid; + unsigned int up; /* connect or disconnect script */ + struct proc_st* proc; +}; + struct proc_st { struct list_node list; int fd; pid_t pid; unsigned udp_fd_received; /* if the corresponding process has received a UDP fd */ - + /* the tun lease this process has */ struct lease_st* lease; @@ -62,6 +73,10 @@ struct proc_list_st { unsigned int total; }; +struct script_list_st { + struct list_head head; +}; + struct banned_st { struct list_node list; time_t failed_time; /* The time authentication failed */ @@ -84,14 +99,17 @@ typedef struct main_server_st { struct listen_list_st llist; struct proc_list_st clist; + struct script_list_st script_list; struct ban_list_st ban_list; + + unsigned active_clients; } main_server_st; void clear_lists(main_server_st *s); int handle_commands(main_server_st *s, struct proc_st* cur); -int user_connected(main_server_st *s, struct proc_st* cur, struct lease_st*); +int user_connected(main_server_st *s, struct proc_st* cur); void user_disconnected(main_server_st *s, struct proc_st* cur); void expire_tls_sessions(main_server_st *s); @@ -115,17 +133,19 @@ void __attribute__ ((format(printf, 4, 5))) mslog(const main_server_st * s, const struct proc_st* proc, int priority, const char *fmt, ...); +void mslog_hex(const main_server_st * s, const struct proc_st* proc, + int priority, const char *prefix, uint8_t* bin, unsigned bin_size); 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(main_server_st* s, struct proc_st* proc, - cmd_auth_reply_t r, struct lease_st* lease); + 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, struct lease_st **lease); + const struct cmd_auth_cookie_req_st * req); int generate_and_store_vals(main_server_st *s, struct proc_st* proc); int handle_auth_req(main_server_st *s, struct proc_st* proc, - const struct cmd_auth_req_st * req, struct lease_st **lease); + const struct cmd_auth_req_st * req); int check_multiple_users(main_server_st *s, struct proc_st* proc); @@ -133,4 +153,6 @@ void add_to_ip_ban_list(main_server_st* s, struct sockaddr_storage *addr, sockle void expire_banned(main_server_st* s); int check_if_banned(main_server_st* s, struct sockaddr_storage *addr, socklen_t addr_len); +int handle_script_exit(main_server_st *s, struct proc_st* proc, int code); + #endif diff --git a/src/ocserv-args.c b/src/ocserv-args.c index 2750319a..8327ad6c 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 March 12, 2013 at 11:39:41 PM by AutoGen 5.16 + * It has been AutoGen-ed March 13, 2013 at 06:29:47 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 b026ed93..98460794 100644 --- a/src/ocserv-args.def +++ b/src/ocserv-args.def @@ -191,9 +191,10 @@ cookie-validity = 43200 # Script to call when a client connects and obtains an IP # Parameters are passed on the environment. -# USERNAME, GROUPNAME, HOSTNAME (the hostname selected by client), +# REASON, USERNAME, GROUPNAME, HOSTNAME (the hostname selected by client), # DEVICE, IP_REAL (the real IP of the client), IP_LOCAL (the local IP -# in the P-t-P connection), IP_REMOTE (the VPN IP of the client). +# in the P-t-P connection), IP_REMOTE (the VPN IP of the client). REASON +# may be "connect" or "disconnect". #connect-script = /usr/bin/myscript #disconnect-script = /usr/bin/myscript diff --git a/src/ocserv-args.h b/src/ocserv-args.h index 5ec11279..64b556a9 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 March 12, 2013 at 11:39:41 PM by AutoGen 5.16 + * It has been AutoGen-ed March 13, 2013 at 06:29:46 PM by AutoGen 5.16 * From the definitions ocserv-args.def * and the template file options * diff --git a/src/script-list.h b/src/script-list.h new file mode 100644 index 00000000..4d2f9fd7 --- /dev/null +++ b/src/script-list.h @@ -0,0 +1,35 @@ +#ifndef SCRIPT_LIST_H +# define SCRIPT_LIST_H + +#include + +inline static +void add_to_script_list(main_server_st* s, pid_t pid, unsigned up, struct proc_st* proc) +{ +struct script_wait_st *stmp; + + stmp = malloc(sizeof(*stmp)); + if (stmp == NULL) + return; + + stmp->proc = proc; + stmp->pid = pid; + stmp->up = up; + + list_add(&s->script_list.head, &(stmp->list)); +} + +inline static void remove_from_script_list(main_server_st* s, struct proc_st* proc) +{ +struct script_wait_st *stmp, *spos; + + list_for_each_safe(&s->script_list.head, stmp, spos, list) { + if (stmp->proc == proc) { + list_del(&stmp->list); + free(stmp); + break; + } + } +} + +#endif diff --git a/src/tun.c b/src/tun.c index d5d0a33e..d282a397 100644 --- a/src/tun.c +++ b/src/tun.c @@ -406,6 +406,7 @@ int open_tun(main_server_st* s, struct lease_st** l) goto fail; } + lease->in_use = 1; lease->fd = tunfd; *l = lease; diff --git a/src/worker-auth.c b/src/worker-auth.c index d8cfa2f7..4a98f226 100644 --- a/src/worker-auth.c +++ b/src/worker-auth.c @@ -527,10 +527,6 @@ struct cmd_auth_req_st areq; ret = auth_user(ws, &areq); 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; }