diff --git a/src/ipc.proto b/src/ipc.proto index 1073732d..c2cbf0d7 100644 --- a/src/ipc.proto +++ b/src/ipc.proto @@ -21,13 +21,13 @@ * == Auth with legacy client == * * main worker - * <------ AUTH_INIT (username, sid) + * <------ AUTH_INIT (username) * AUTH_REP(MSG) ------> * * (worker terminates as client disconnects) * - * <------ AUTH_REINIT (password, sid) - * AUTH_REP(ΟΚ) ------> + * <------ AUTH_REINIT (password, sid) + * AUTH_REP(ΟΚ,newsid) ------> * */ @@ -40,7 +40,6 @@ message auth_init_msg optional string cert_user_name = 4; optional string cert_group_name = 5; optional string hostname = 6; - optional bytes sid = 7; } /* AUTH_REINIT - used in cisco compatible clients, to @@ -98,6 +97,12 @@ message auth_reply_msg repeated string routes = 21; repeated string dns = 22; repeated string nbns = 23; + + /* The sid is used when this message is a reply + * to an AUTH_REINIT, to let the worker know of + * any change in the sid. + */ + optional bytes sid = 24; } /* RESUME_FETCH_REQ + RESUME_DELETE_REQ */ diff --git a/src/main-auth.c b/src/main-auth.c index f45ca5cd..486b6cb6 100644 --- a/src/main-auth.c +++ b/src/main-auth.c @@ -63,7 +63,7 @@ void main_auth_init(main_server_st *s) } int send_auth_reply(main_server_st* s, struct proc_st* proc, - AuthReplyMsg__AUTHREP r) + AuthReplyMsg__AUTHREP r, unsigned need_sid) { AuthReplyMsg msg = AUTH_REPLY_MSG__INIT; unsigned i; @@ -143,6 +143,12 @@ int send_auth_reply(main_server_st* s, struct proc_st* proc, msg.routes = proc->config.routes; } + if (need_sid) { + msg.has_sid = 1; + msg.sid.data = proc->sid; + msg.sid.len = sizeof(proc->sid); + } + ret = send_socket_msg_to_worker(s, proc, AUTH_REP, proc->tun_lease.fd, &msg, (pack_size_func)auth_reply_msg__get_packed_size, @@ -165,7 +171,7 @@ int send_auth_reply(main_server_st* s, struct proc_st* proc, return 0; } -int send_auth_reply_msg(main_server_st* s, struct proc_st* proc) +int send_auth_reply_msg(main_server_st* s, struct proc_st* proc, unsigned need_sid) { AuthReplyMsg msg = AUTH_REPLY_MSG__INIT; char tmp[MAX_MSG_SIZE] = ""; @@ -182,6 +188,12 @@ int send_auth_reply_msg(main_server_st* s, struct proc_st* proc) msg.msg = tmp; msg.reply = AUTH_REPLY_MSG__AUTH__REP__MSG; + if (need_sid) { + msg.has_sid = 1; + msg.sid.data = proc->sid; + msg.sid.len = sizeof(proc->sid); + } + ret = send_msg_to_worker(s, proc, AUTH_REP, &msg, (pack_size_func)auth_reply_msg__get_packed_size, (pack_func)auth_reply_msg__pack); @@ -281,32 +293,6 @@ const char* ip; snprintf(proc->hostname, sizeof(proc->hostname), "%s", req->hostname); } - if (req->has_sid != 0 && req->sid.len == sizeof(proc->sid)) { - unsigned unique = 1; - struct proc_st *ctmp = NULL; - - /* the client has requested changing its SID. We must first make sure it is - * unique. - */ - list_for_each(&s->proc_list.head, ctmp, list) { - if (ctmp->sid_size > 0 && ctmp->sid_size == req->sid.len) { - if (memcmp(req->sid.data, ctmp->sid, ctmp->sid_size) == 0) { - /* it is not */ - unique = 0; - break; - } - } - } - - if (unique != 0) { - memcpy(proc->sid, req->sid.data, sizeof(proc->sid)); - proc->sid_size = sizeof(proc->sid); - mslog_hex(s, proc, LOG_DEBUG, "auth init set SID to", req->sid.data, req->sid.len, 1); - } else { - mslog_hex(s, proc, LOG_DEBUG, "auth init asks to set SID but it is not unique", req->sid.data, req->sid.len, 1); - } - } - if (req->user_name != NULL && s->config->auth_types & AUTH_TYPE_USERNAME_PASS) { ret = module->auth_init(&proc->auth_ctx, req->user_name, ip, s->auth_extra); if (ret < 0) @@ -349,7 +335,7 @@ unsigned found = 0; ip = human_addr((void*)&proc->remote_addr, proc->remote_addr_len, ipbuf, sizeof(ipbuf)); - if (req->sid.len == 0) { + if (req->sid.len != SID_SIZE) { mslog(s, proc, LOG_DEBUG, "auth reinit from '%s' with no SID present", ip); return -1; } @@ -361,8 +347,8 @@ unsigned found = 0; /* search all procs for a matching SID */ list_for_each(&s->proc_list.head, ctmp, list) { - if (ctmp->status == PS_AUTH_ZOMBIE && ctmp->sid_size > 0 && ctmp->sid_size == req->sid.len) { - if (memcmp(req->sid.data, ctmp->sid, ctmp->sid_size) == 0) { + if (ctmp->status == PS_AUTH_ZOMBIE) { + if (memcmp(req->sid.data, ctmp->sid, SID_SIZE) == 0) { /* replace sessions */ ctmp->pid = proc->pid; ctmp->fd = proc->fd; @@ -370,8 +356,7 @@ unsigned found = 0; proc->pid = -1; proc->fd = -1; - proc->sid_size = 0; - proc->status = PS_AUTH_ZOMBIE; + proc->status = PS_AUTH_DEAD; *_proc = proc = ctmp; found = 1; break; diff --git a/src/main-ctl-handler.c b/src/main-ctl-handler.c index 23b58063..43489b54 100644 --- a/src/main-ctl-handler.c +++ b/src/main-ctl-handler.c @@ -508,6 +508,8 @@ static int append_user_info(DBusMessageIter * subs, struct proc_st *ctmp) strtmp = "auth"; else if (ctmp->status == PS_AUTH_ZOMBIE) strtmp = "zombie"; + else if (ctmp->status == PS_AUTH_DEAD) + strtmp = "dead"; else if (ctmp->status == PS_AUTH_INACTIVE) strtmp = "pre-auth"; else if (ctmp->status == PS_AUTH_FAILED) diff --git a/src/main-misc.c b/src/main-misc.c index bf4ae8e7..4cf38c05 100644 --- a/src/main-misc.c +++ b/src/main-misc.c @@ -86,14 +86,14 @@ int set_tun_mtu(main_server_st * s, struct proc_st *proc, unsigned mtu) return ret; } -int handle_script_exit(main_server_st * s, struct proc_st *proc, int code) +int handle_script_exit(main_server_st * s, struct proc_st *proc, int code, unsigned need_sid) { int ret; if (code == 0) { proc->status = PS_AUTH_COMPLETED; - ret = send_auth_reply(s, proc, AUTH_REPLY_MSG__AUTH__REP__OK); + ret = send_auth_reply(s, proc, AUTH_REPLY_MSG__AUTH__REP__OK, need_sid); if (ret < 0) { mslog(s, proc, LOG_ERR, "could not send auth reply cmd."); @@ -107,7 +107,7 @@ int handle_script_exit(main_server_st * s, struct proc_st *proc, int code) "failed authentication attempt for user '%s'", proc->username); ret = - send_auth_reply(s, proc, AUTH_REPLY_MSG__AUTH__REP__FAILED); + send_auth_reply(s, proc, AUTH_REPLY_MSG__AUTH__REP__FAILED, need_sid); if (ret < 0) { mslog(s, proc, LOG_ERR, "could not send reply auth cmd."); @@ -314,7 +314,7 @@ void proc_to_zombie(main_server_st * s, struct proc_st *proc) { proc->status = PS_AUTH_ZOMBIE; - mslog(s, proc, LOG_INFO, "client disconnected, became zombie"); + mslog_hex(s, proc, LOG_INFO, "client disconnected, became zombie", proc->sid, sizeof(proc->sid), 1); /* close the intercomm fd */ if (proc->fd >= 0) @@ -389,12 +389,12 @@ static int accept_user(main_server_st * s, struct proc_st *proc, unsigned cmd) } static int handle_auth_res(main_server_st * s, struct proc_st *proc, - unsigned cmd, int result, unsigned cont) + unsigned cmd, int result, unsigned cont, unsigned need_sid) { int ret; if (cont != 0 && result == ERR_AUTH_CONTINUE) { - ret = send_auth_reply_msg(s, proc); + ret = send_auth_reply_msg(s, proc, need_sid); if (ret < 0) { proc->status = PS_AUTH_FAILED; mslog(s, proc, LOG_ERR, @@ -425,7 +425,7 @@ static int handle_auth_res(main_server_st * s, struct proc_st *proc, ret = 0; else { /* no script was called. Handle it as a successful script call. */ - ret = handle_script_exit(s, proc, ret); + ret = handle_script_exit(s, proc, ret, need_sid); if (ret < 0) proc->status = PS_AUTH_FAILED; } @@ -657,7 +657,7 @@ int handle_commands(main_server_st * s, struct proc_st *proc) proc->status = PS_AUTH_INIT; - ret = handle_auth_res(s, proc, cmd, ret, 1); + ret = handle_auth_res(s, proc, cmd, ret, 1, 0); if (ret < 0) { goto cleanup; } @@ -687,13 +687,13 @@ int handle_commands(main_server_st * s, struct proc_st *proc) proc->status = PS_AUTH_INIT; - ret = handle_auth_res(s, proc, cmd, ret, 1); + ret = handle_auth_res(s, proc, cmd, ret, 1, 1); if (ret < 0) { goto cleanup; } /* handle_auth_reinit() has succeeded so the current proc - * is in zombie state and unused. Terminate it. + * is in dead state and unused. Terminate it. */ ret = ERR_WORKER_TERMINATED; goto cleanup; @@ -727,7 +727,7 @@ int handle_commands(main_server_st * s, struct proc_st *proc) proc->status = PS_AUTH_INIT; - ret = handle_auth_res(s, proc, cmd, ret, 1); + ret = handle_auth_res(s, proc, cmd, ret, 1, 0); if (ret < 0) { goto cleanup; } @@ -755,7 +755,7 @@ int handle_commands(main_server_st * s, struct proc_st *proc) auth_cookie_request_msg__free_unpacked(auth_cookie_req, NULL); - ret = handle_auth_res(s, proc, cmd, ret, 0); + ret = handle_auth_res(s, proc, cmd, ret, 0, 0); if (ret < 0) { goto cleanup; } @@ -849,8 +849,11 @@ void expire_zombies(main_server_st * s) if (s->config->cisco_client_compat == 0) return; + /* In CISCO compatibility mode we could have proc_st in + * mode INACTIVE or ZOMBIE that need to be cleaned up. + */ list_for_each_safe(&s->proc_list.head, ctmp, cpos, list) { - if (ctmp->status == PS_AUTH_ZOMBIE && + if ((ctmp->status == PS_AUTH_ZOMBIE || ctmp->status == PS_AUTH_DEAD) && now - ctmp->conn_time > MAX_ZOMBIE_SECS) { remove_proc(s, ctmp, 0); } diff --git a/src/main.c b/src/main.c index cf6abcf8..fd9a4ec1 100644 --- a/src/main.c +++ b/src/main.c @@ -423,7 +423,7 @@ struct script_wait_st *stmp = NULL, *spos; if (stmp->pid == pid) { mslog(s, stmp->proc, LOG_DEBUG, "%s-script exit status: %u", stmp->up?"connect":"disconnect", estatus); list_del(&stmp->list); - ret = handle_script_exit(s, stmp->proc, estatus); + ret = handle_script_exit(s, stmp->proc, estatus, 0); if (ret < 0) remove_proc(s, stmp->proc, 1); free(stmp); @@ -959,6 +959,13 @@ int main(int argc, char** argv) } set_cloexec_flag (fd, 1); + ret = gnutls_rnd(GNUTLS_RND_NONCE, ws.sid, sizeof(ws.sid)); + if (ret < 0) { + close(fd); + mslog(&s, NULL, LOG_ERR, "Error generating SID"); + break; + } + /* Check if the client is on the banned list */ ret = check_if_banned(&s, &ws.remote_addr, ws.remote_addr_len); if (ret < 0) { @@ -1024,6 +1031,7 @@ fork_failed: } memcpy(&ctmp->remote_addr, &ws.remote_addr, ws.remote_addr_len); ctmp->remote_addr_len = ws.remote_addr_len; + memcpy(&ctmp->sid, &ws.sid, sizeof(ws.sid)); ctmp->pid = pid; ctmp->conn_time = time(0); diff --git a/src/main.h b/src/main.h index 008fc29d..8065e1b3 100644 --- a/src/main.h +++ b/src/main.h @@ -69,6 +69,7 @@ enum { PS_AUTH_FAILED, /* no tried authenticated but failed */ PS_AUTH_INIT, /* worker has sent an auth init msg */ PS_AUTH_ZOMBIE, /* in INIT state but worker has disconnected! - only present when cisco-client-compat is set */ + PS_AUTH_DEAD, /* it was created but subsequently the client revived a zombie proc. - only present when cisco-client-compat is set */ PS_AUTH_COMPLETED, /* successful authentication */ }; @@ -96,7 +97,6 @@ struct proc_st { * sessions. */ uint8_t sid[SID_SIZE]; - unsigned sid_size; /* acts as a flag if sid is set */ /* The DTLS session ID associated with the TLS session * it is either generated or restored from a cookie. @@ -239,10 +239,10 @@ void mslog_hex(const main_server_st * s, const struct proc_st* proc, int open_tun(main_server_st* s, struct proc_st* proc); 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_msg(main_server_st* s, struct proc_st* proc, unsigned need_sid); int send_auth_reply(main_server_st* s, struct proc_st* proc, - AuthReplyMsg__AUTHREP r); + AuthReplyMsg__AUTHREP r, unsigned need_sid); int handle_auth_cookie_req(main_server_st* s, struct proc_st* proc, const AuthCookieRequestMsg * req); @@ -260,7 +260,7 @@ 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); +int handle_script_exit(main_server_st *s, struct proc_st* proc, int code, unsigned need_sid); void run_sec_mod(main_server_st * s); diff --git a/src/worker-auth.c b/src/worker-auth.c index 00c5c11f..1b63a48c 100644 --- a/src/worker-auth.c +++ b/src/worker-auth.c @@ -80,6 +80,7 @@ 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)]; + char context[BASE64_LENGTH(SID_SIZE)+1]; struct http_req_st *req = &ws->req; unsigned int lsize; @@ -92,11 +93,8 @@ int get_auth_handler2(worker_st * ws, unsigned http_ver, const char *pmsg) if (ret < 0) return -1; - if (req->sid_cookie_set == 0) { - char context[BASE64_LENGTH(SID_SIZE)+1]; - size_t csize = sizeof(context); - - base64_encode((char*)ws->sid, sizeof(ws->sid), (char*)context, csize); + if (req->sid_cookie_set == 0 || memcmp(req->sid_cookie, ws->sid, SID_SIZE) != 0) { + base64_encode((char*)ws->sid, sizeof(ws->sid), (char*)context, sizeof(context)); ret = tls_printf(ws->session, "Set-Cookie: webvpncontext=%s; Max-Age=%u; Secure\r\n", @@ -114,7 +112,7 @@ int get_auth_handler2(worker_st * ws, unsigned http_ver, const char *pmsg) if (ws->auth_state == S_AUTH_REQ) { /* only ask password */ if (pmsg == NULL) - pmsg = "Please enter password"; + pmsg = "Please enter your password."; lsize = snprintf(login_msg, sizeof(login_msg), login_msg_no_user, pmsg); @@ -239,6 +237,10 @@ static int recv_auth_reply(worker_st * ws, char *txt, size_t max_txt_size) } snprintf(txt, max_txt_size, "%s", msg->msg); + if (msg->has_sid && msg->sid.len == sizeof(ws->sid)) { + /* update our sid */ + memcpy(ws->sid, msg->sid.data, sizeof(ws->sid)); + } ret = ERR_AUTH_CONTINUE; goto cleanup; @@ -256,8 +258,15 @@ static int recv_auth_reply(worker_st * ws, char *txt, size_t max_txt_size) snprintf(ws->username, sizeof(ws->username), "%s", msg->user_name); - if (msg->cookie.len != sizeof(ws->cookie) || - msg->session_id.len != sizeof(ws->session_id)) { + if (msg->has_sid && msg->sid.len == sizeof(ws->sid)) { + /* update our sid */ + memcpy(ws->sid, msg->sid.data, sizeof(ws->sid)); + } + + if (msg->has_cookie == 0 || + msg->cookie.len != sizeof(ws->cookie) || + msg->session_id.len != sizeof(ws->session_id)) { + ret = ERR_AUTH_FAIL; goto cleanup; } @@ -720,8 +729,11 @@ int post_auth_handler(worker_st * ws, unsigned http_ver) rreq.tls_auth_ok = ws->cert_auth_ok; rreq.password = password; - rreq.sid.data = ws->sid; - rreq.sid.len = sizeof(ws->sid); + + if (req->sid_cookie_set != 0) { + rreq.sid.data = req->sid_cookie; + rreq.sid.len = sizeof(req->sid_cookie); + } ret = send_msg_to_main(ws, AUTH_REINIT, &rreq, (pack_size_func)auth_reinit_msg__get_packed_size, @@ -768,12 +780,6 @@ int post_auth_handler(worker_st * ws, unsigned http_ver) } ireq.hostname = req->hostname; - if (req->sid_cookie_set != 0) { - oclog(ws, LOG_INFO, "updating SID"); - ireq.sid.data = ws->sid; - ireq.sid.len = sizeof(ws->sid); - ireq.has_sid = 1; - } ret = send_msg_to_main(ws, AUTH_INIT, &ireq, diff --git a/src/worker-vpn.c b/src/worker-vpn.c index 469a5e3f..88cfb013 100644 --- a/src/worker-vpn.c +++ b/src/worker-vpn.c @@ -370,9 +370,9 @@ static void value_check(struct worker_st *ws, struct http_req_st *req) tmplen--; } - nlen = sizeof(ws->sid); - ret = base64_decode((char*)p, tmplen, (char*)ws->sid, &nlen); - if (ret == 0 || nlen != sizeof(ws->sid)) { + nlen = sizeof(req->sid_cookie); + ret = base64_decode((char*)p, tmplen, (char*)req->sid_cookie, &nlen); + if (ret == 0 || nlen != sizeof(req->sid_cookie)) { oclog(ws, LOG_DEBUG, "could not decode sid: %.*s", tmplen, p); req->sid_cookie_set = 0; } else { @@ -666,12 +666,6 @@ void vpn_server(struct worker_st *ws) else ws->proto = AF_INET6; - ret = gnutls_rnd(GNUTLS_RND_NONCE, ws->sid, sizeof(ws->sid)); - if (ret < 0) { - oclog(ws, LOG_ERR, "Error generating SID"); - exit_worker(ws); - } - /* initialize the session */ ret = gnutls_init(&session, GNUTLS_SERVER); GNUTLS_FATAL_ERR(ret); @@ -728,7 +722,8 @@ void vpn_server(struct worker_st *ws) if (nrecvd <= 0) { if (nrecvd == 0) goto finish; - oclog(ws, LOG_INFO, "error receiving client data"); + if (nrecvd != GNUTLS_E_PREMATURE_TERMINATION) + oclog(ws, LOG_ERR, "error receiving client data"); exit_worker(ws); } diff --git a/src/worker.h b/src/worker.h index ace73bf5..d7b1e852 100644 --- a/src/worker.h +++ b/src/worker.h @@ -86,9 +86,12 @@ struct http_req_st { char hostname[MAX_HOSTNAME_SIZE]; char user_agent[MAX_AGENT_NAME]; + unsigned int next_header; unsigned char cookie[COOKIE_SIZE]; unsigned int cookie_set; + + uint8_t sid_cookie[SID_SIZE]; unsigned int sid_cookie_set; unsigned char master_secret[TLS_MASTER_SIZE];