diff --git a/doc/sample.config b/doc/sample.config index ecd7b2a2..d3866770 100644 --- a/doc/sample.config +++ b/doc/sample.config @@ -228,5 +228,5 @@ route-del-cmd = "ip route delete %R dev %D" # certificate even if they are authenticating via a previously granted # cookie. Legacy CISCO clients do not do that, and thus this option # should be set for them. -#always-require-cert = false +cisco-client-compat = true diff --git a/src/common.c b/src/common.c index 4364b6a9..5c503aee 100644 --- a/src/common.c +++ b/src/common.c @@ -31,6 +31,8 @@ cmd_request_t cmd = _cmd; switch(cmd) { case AUTH_INIT: return "auth init"; + case AUTH_REINIT: + return "auth reinit"; case AUTH_REP: return "auth reply"; case AUTH_REQ: diff --git a/src/cookies.c b/src/cookies.c index 29240b75..54dba1f2 100644 --- a/src/cookies.c +++ b/src/cookies.c @@ -129,16 +129,16 @@ int generate_cookie(main_server_st *s, struct proc_st* proc) int ret; struct stored_cookie_st sc; - ret = gnutls_rnd(GNUTLS_RND_NONCE, proc->session_id, sizeof(proc->session_id)); + ret = gnutls_rnd(GNUTLS_RND_NONCE, proc->dtls_session_id, sizeof(proc->dtls_session_id)); if (ret < 0) return -1; - proc->session_id_size = sizeof(proc->session_id); + proc->dtls_session_id_size = sizeof(proc->dtls_session_id); memcpy(sc.username, proc->username, sizeof(proc->username)); memcpy(sc.groupname, proc->groupname, sizeof(proc->groupname)); memcpy(sc.hostname, proc->hostname, sizeof(proc->hostname)); - memcpy(sc.session_id, proc->session_id, sizeof(proc->session_id)); + memcpy(sc.session_id, proc->dtls_session_id, sizeof(proc->dtls_session_id)); sc.expiration = time(0) + s->config->cookie_validity; diff --git a/src/ipc.proto b/src/ipc.proto index 20375c6b..406bac81 100644 --- a/src/ipc.proto +++ b/src/ipc.proto @@ -7,6 +7,16 @@ message auth_init_msg optional string cert_user_name = 4; optional string cert_group_name = 5; optional string hostname = 6; + required bytes session_id = 7; +} + +/* AUTH_REINIT - used in cisco compatible clients, to + * revive open authentication in zombie mode. */ +message auth_reinit_msg +{ + required bool tls_auth_ok = 1 [default = false]; + required string password = 2; + required bytes session_id = 3; } /* AUTH_COOKIE_REQ */ diff --git a/src/main-auth.c b/src/main-auth.c index ccb1b74e..85e45f78 100644 --- a/src/main-auth.c +++ b/src/main-auth.c @@ -80,14 +80,14 @@ int send_auth_reply(main_server_st* s, struct proc_st* proc, msg.has_cookie = 1; msg.cookie.data = proc->cookie; msg.cookie.len = COOKIE_SIZE; - + msg.has_session_id = 1; - msg.session_id.data = proc->session_id; - msg.session_id.len = sizeof(proc->session_id); - + msg.session_id.data = proc->dtls_session_id; + msg.session_id.len = sizeof(proc->dtls_session_id); + msg.vname = proc->tun_lease.name; msg.user_name = proc->username; - + msg.ipv4_dns = proc->config.ipv4_dns; msg.ipv6_dns = proc->config.ipv6_dns; msg.ipv4_nbns = proc->config.ipv4_nbns; @@ -108,13 +108,13 @@ int send_auth_reply(main_server_st* s, struct proc_st* proc, msg.has_net_priority = 1; msg.net_priority = proc->config.net_priority; } - + msg.n_routes = proc->config.routes_size; for (i=0;iconfig.routes_size;i++) { mslog(s, proc, LOG_DEBUG, "sending route '%s'", proc->config.routes[i]); msg.routes = proc->config.routes; } - + ret = send_socket_msg_to_worker(s, proc, AUTH_REP, proc->tun_lease.fd, &msg, (pack_size_func)auth_reply_msg__get_packed_size, @@ -127,7 +127,7 @@ int send_auth_reply(main_server_st* s, struct proc_st* proc, (pack_size_func)auth_reply_msg__get_packed_size, (pack_func)auth_reply_msg__pack); } - + if (ret < 0) { int e = errno; mslog(s, proc, LOG_ERR, "send_msg: %s", strerror(e)); @@ -141,7 +141,7 @@ int send_auth_reply_msg(main_server_st* s, struct proc_st* proc) { AuthReplyMsg msg = AUTH_REPLY_MSG__INIT; char tmp[MAX_MSG_SIZE] = ""; - + int ret; if (proc->auth_ctx == NULL) @@ -172,7 +172,7 @@ static int check_user_group_status(main_server_st *s, struct proc_st* proc, mslog(s, proc, LOG_INFO, "user '%s' presented no certificate", proc->username); return -1; } - + if (tls_auth_ok != 0) { if (proc->username[0] == 0) { memcpy(proc->username, cert_user, sizeof(proc->username)); @@ -192,7 +192,7 @@ static int check_user_group_status(main_server_st *s, struct proc_st* proc, } } } - + return 0; } @@ -212,18 +212,18 @@ time_t now = time(0); if (sc.expiration < now) return -1; - + memcpy(proc->cookie, req->cookie.data, req->cookie.len); memcpy(proc->username, sc.username, sizeof(proc->username)); memcpy(proc->groupname, sc.groupname, sizeof(proc->groupname)); memcpy(proc->hostname, sc.hostname, sizeof(proc->hostname)); - memcpy(proc->session_id, sc.session_id, sizeof(proc->session_id)); - proc->session_id_size = sizeof(proc->session_id); - + memcpy(proc->dtls_session_id, sc.session_id, sizeof(proc->dtls_session_id)); + proc->dtls_session_id_size = sizeof(proc->dtls_session_id); + proc->username[sizeof(proc->username)-1] = 0; proc->groupname[sizeof(proc->groupname)-1] = 0; proc->hostname[sizeof(proc->hostname)-1] = 0; - + memcpy(proc->ipv4_seed, sc.ipv4_seed, sizeof(proc->ipv4_seed)); proc->seeds_are_set = 1; @@ -245,7 +245,12 @@ const char* ip; ipbuf, sizeof(ipbuf)); if (req->user_name == NULL && s->config->auth_types & AUTH_TYPE_USERNAME_PASS) { - mslog(s, proc, LOG_DEBUG, "auth init from '%s' with no username present", ip); + mslog(s, proc, LOG_DEBUG, "auth init from '%s' with no username present", ip); + return -1; + } + + if (req->session_id.len == 0 || req->session_id.len > sizeof(proc->tls_session_id)) { + mslog(s, proc, LOG_DEBUG, "auth init from '%s' with no session ID present", ip); return -1; } @@ -271,20 +276,73 @@ const char* ip; } } + memcpy(proc->tls_session_id, req->session_id.data, req->session_id.len); + proc->tls_session_id_size = req->session_id.len; + ret = check_user_group_status(s, proc, req->tls_auth_ok, req->cert_user_name, req->cert_group_name); if (ret < 0) return ret; - mslog(s, proc, LOG_DEBUG, "auth init for user '%s' from '%s'", proc->username, ip); if (s->config->auth_types & AUTH_TYPE_USERNAME_PASS) { return ERR_AUTH_CONTINUE; } - + return 0; } +int handle_auth_reinit(main_server_st *s, struct proc_st** _proc, + const AuthReinitMsg * req) +{ +char ipbuf[128]; +const char* ip; +struct proc_st *ctmp = NULL; +struct proc_st *proc = *_proc; +unsigned found = 0; + + ip = human_addr((void*)&proc->remote_addr, proc->remote_addr_len, + ipbuf, sizeof(ipbuf)); + + if (req->session_id.len == 0) { + mslog(s, proc, LOG_DEBUG, "auth reinit from '%s' with no session ID present", ip); + return -1; + } + + if (req->password == NULL && s->config->auth_types & AUTH_TYPE_USERNAME_PASS) { + mslog(s, proc, LOG_DEBUG, "auth reinit from '%s' with no password present", ip); + return -1; + } + + /* search all procs for a matching session ID */ + + list_for_each(&s->proc_list.head, ctmp, list) { + if (ctmp->status == PS_AUTH_ZOMBIE && ctmp->tls_session_id_size == req->session_id.len) { + if (memcmp(req->session_id.data, ctmp->tls_session_id, ctmp->tls_session_id_size) == 0) { + /* replace sessions */ + ctmp->pid = proc->pid; + ctmp->fd = proc->fd; + memcpy(&ctmp->remote_addr, &proc->remote_addr, proc->remote_addr_len); + + proc->pid = -1; + proc->fd = -1; + *_proc = proc = ctmp; + found = 1; + break; + } + } + } + + if (found == 0) { + mslog(s, proc, LOG_DEBUG, "auth reinit received from '%s', but does not match any session", ip); + return -1; + } + + mslog(s, proc, LOG_DEBUG, "auth reinit for user '%s' from '%s'", proc->username, ip); + + return module->auth_pass(proc->auth_ctx, req->password, strlen(req->password)); +} + int handle_auth_req(main_server_st *s, struct proc_st* proc, const AuthRequestMsg * req) { @@ -293,7 +351,7 @@ int handle_auth_req(main_server_st *s, struct proc_st* proc, return -1; } mslog(s, proc, LOG_DEBUG, "auth req for user '%s'", proc->username); - + if (req->password == NULL) return -1; @@ -315,7 +373,7 @@ struct proc_st *ctmp = NULL, *cpos; unsigned int entries = 1; /* that one */ list_for_each_safe(&s->proc_list.head, ctmp, cpos, list) { - if (ctmp != proc) { + if (ctmp != proc && ctmp->pid != -1) { if (memcmp(proc->cookie, ctmp->cookie, sizeof(proc->cookie)) == 0) { mslog(s, ctmp, LOG_DEBUG, "disconnecting '%s' due to new cookie connection", ctmp->username); @@ -330,10 +388,10 @@ unsigned int entries = 1; /* that one */ } } } - + if (s->config->max_same_clients && entries > s->config->max_same_clients) return -1; - + return 0; } diff --git a/src/main-ctl-handler.c b/src/main-ctl-handler.c index 5aecfd74..297ca147 100644 --- a/src/main-ctl-handler.c +++ b/src/main-ctl-handler.c @@ -502,12 +502,16 @@ static int append_user_info(DBusMessageIter * subs, struct proc_st *ctmp) return -1; } - if (ctmp->auth_status == PS_AUTH_COMPLETED) + if (ctmp->status == PS_AUTH_COMPLETED) strtmp = "connected"; - else if (ctmp->auth_status == PS_AUTH_INIT) + else if (ctmp->status == PS_AUTH_INIT) strtmp = "auth"; - else + else if (ctmp->status == PS_AUTH_ZOMBIE) + strtmp = "zombie"; + else if (ctmp->status == PS_AUTH_INACTIVE) strtmp = "pre-auth"; + else + strtmp = "unknown"; if (dbus_message_iter_append_basic (subs, DBUS_TYPE_STRING, &strtmp) == 0) { return -1; diff --git a/src/main-misc.c b/src/main-misc.c index f01bac64..580f5941 100644 --- a/src/main-misc.c +++ b/src/main-misc.c @@ -51,11 +51,11 @@ #include #include "pam.h" -int set_tun_mtu(main_server_st* s, struct proc_st * proc, unsigned mtu) +int set_tun_mtu(main_server_st * s, struct proc_st *proc, unsigned mtu) { -int fd, ret, e; -struct ifreq ifr; -const char* name; + int fd, ret, e; + struct ifreq ifr; + const char *name; if (proc->tun_lease.name[0] == 0) return -1; @@ -74,44 +74,50 @@ const char* name; ret = ioctl(fd, SIOCSIFMTU, &ifr); if (ret != 0) { e = errno; - mslog(s, proc, LOG_INFO, "ioctl SIOCSIFMTU error: %s", strerror(e)); + mslog(s, proc, LOG_INFO, "ioctl SIOCSIFMTU error: %s", + strerror(e)); ret = -1; goto fail; } ret = 0; -fail: + fail: close(fd); 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) { -int ret; + int ret; if (code == 0) { - proc->auth_status = PS_AUTH_COMPLETED; + proc->status = PS_AUTH_COMPLETED; ret = send_auth_reply(s, proc, AUTH_REPLY_MSG__AUTH__REP__OK); if (ret < 0) { - mslog(s, proc, LOG_ERR, "could not send auth reply cmd."); + mslog(s, proc, LOG_ERR, + "could not send auth reply cmd."); ret = ERR_BAD_COMMAND; goto fail; } apply_iroutes(s, proc); } else { - mslog(s, proc, LOG_INFO, "failed authentication attempt for user '%s'", proc->username); - ret = send_auth_reply( s, proc, AUTH_REPLY_MSG__AUTH__REP__FAILED); + mslog(s, proc, LOG_INFO, + "failed authentication attempt for user '%s'", + proc->username); + ret = + send_auth_reply(s, proc, AUTH_REPLY_MSG__AUTH__REP__FAILED); if (ret < 0) { - mslog(s, proc, LOG_ERR, "could not send reply auth cmd."); + mslog(s, proc, LOG_ERR, + "could not send reply auth cmd."); ret = ERR_BAD_COMMAND; goto fail; } } ret = 0; -fail: + fail: /* we close the lease tun fd both on success and failure. * The parent doesn't need to keep the tunfd. */ @@ -124,14 +130,16 @@ fail: return ret; } -static int read_additional_config_file(main_server_st* s, struct proc_st* proc, const char* file, const char* type) +static int read_additional_config_file(main_server_st * s, struct proc_st *proc, + const char *file, const char *type) { -struct group_cfg_st cfg; -int ret; -unsigned i; + struct group_cfg_st cfg; + int ret; + unsigned i; if (access(file, R_OK) == 0) { - mslog(s, proc, LOG_DEBUG, "Loading %s configuration '%s'", type, file); + mslog(s, proc, LOG_DEBUG, "Loading %s configuration '%s'", type, + file); ret = parse_group_cfg_file(s, file, &cfg); if (ret < 0) @@ -145,12 +153,19 @@ unsigned i; cfg.routes = NULL; cfg.routes_size = 0; } else { - proc->config.routes = safe_realloc(proc->config.routes, (proc->config.routes_size + cfg.routes_size) * sizeof(proc->config.routes[0])); + proc->config.routes = + safe_realloc(proc->config.routes, + (proc->config.routes_size + + cfg.routes_size) * + sizeof(proc->config. + routes[0])); if (proc->config.routes == NULL) return ERR_MEM; - for (i=0;iconfig.routes[proc->config.routes_size] = cfg.routes[i]; + for (i = 0; i < cfg.routes_size; i++) { + proc->config.routes[proc->config. + routes_size] = + cfg.routes[i]; cfg.routes[i] = NULL; proc->config.routes_size++; } @@ -225,21 +240,23 @@ unsigned i; del_additional_config(&cfg); } else - mslog(s, proc, LOG_DEBUG, "No %s configuration for '%s'", type, proc->username); + mslog(s, proc, LOG_DEBUG, "No %s configuration for '%s'", type, + proc->username); return 0; } - -static int read_additional_config(struct main_server_st* s, struct proc_st* proc) +static int read_additional_config(struct main_server_st *s, + struct proc_st *proc) { -char file[_POSIX_PATH_MAX]; -int ret; + char file[_POSIX_PATH_MAX]; + int ret; memset(&proc->config, 0, sizeof(proc->config)); if (s->config->per_user_dir != NULL) { - snprintf(file, sizeof(file), "%s/%s", s->config->per_user_dir, proc->username); + snprintf(file, sizeof(file), "%s/%s", s->config->per_user_dir, + proc->username); ret = read_additional_config_file(s, proc, file, "user"); if (ret < 0) @@ -247,7 +264,8 @@ int ret; } if (s->config->per_group_dir != NULL && proc->groupname[0] != 0) { - snprintf(file, sizeof(file), "%s/%s", s->config->per_group_dir, proc->groupname); + snprintf(file, sizeof(file), "%s/%s", s->config->per_group_dir, + proc->groupname); ret = read_additional_config_file(s, proc, file, "group"); if (ret < 0) @@ -263,12 +281,12 @@ int ret; /* k: whether to kill the process */ -void remove_proc(main_server_st* s, struct proc_st *proc, unsigned k) +void remove_proc(main_server_st * s, struct proc_st *proc, unsigned k) { list_del(&proc->list); s->active_clients--; - if (k) + if (k && proc->pid != -1) kill(proc->pid, SIGTERM); remove_from_script_list(s, proc); @@ -292,12 +310,24 @@ void remove_proc(main_server_st* s, struct proc_st *proc, unsigned k) free(proc); } +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"); + + /* close the intercomm fd */ + if (proc->fd >= 0) + close(proc->fd); + proc->fd = -1; + proc->pid = -1; +} /* This is the function after which proc is populated */ -static int accept_user(main_server_st *s, struct proc_st* proc, unsigned cmd) +static int accept_user(main_server_st * s, struct proc_st *proc, unsigned cmd) { -int ret; -const char* group; + int ret; + const char *group; mslog(s, proc, LOG_DEBUG, "accepting user '%s'", proc->username); proc_auth_deinit(s, proc); @@ -305,13 +335,16 @@ const char* group; /* 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); + mslog(s, proc, LOG_INFO, + "user '%s' tried to connect more than %u times", + proc->username, s->config->max_same_clients); return ret; } ret = read_additional_config(s, proc); if (ret < 0) { - mslog(s, proc, LOG_ERR, "error reading additional configuration"); + mslog(s, proc, LOG_ERR, + "error reading additional configuration"); return ERR_READ_CONFIG; } @@ -325,34 +358,85 @@ const char* group; else group = proc->groupname; - if (cmd == AUTH_REQ || cmd == AUTH_INIT) { + if (cmd == AUTH_REQ || cmd == AUTH_INIT || cmd == AUTH_REINIT) { /* generate cookie */ ret = generate_cookie(s, proc); if (ret < 0) { - return ERR_BAD_COMMAND; + return ret; } - mslog(s, proc, LOG_INFO, "user '%s' of group '%s' authenticated", proc->username, group); + mslog(s, proc, LOG_INFO, + "user '%s' of group '%s' authenticated", proc->username, + group); + } else if (cmd == AUTH_COOKIE_REQ) { + mslog(s, proc, LOG_INFO, + "user '%s' of group '%s' re-authenticated (using cookie)", + proc->username, group); } else { - mslog(s, proc, LOG_INFO, "user '%s' of group '%s' re-authenticated (using cookie)", proc->username, group); + mslog(s, proc, LOG_INFO, + "user '%s' of group '%s' authenticated but from unknown state!", + proc->username, group); + return ERR_BAD_COMMAND; } /* do scripts and utmp */ ret = user_connected(s, proc); if (ret < 0 && ret != ERR_WAIT_FOR_SCRIPT) { - mslog(s, proc, LOG_INFO, "user '%s' disconnected due to script", proc->username); + mslog(s, proc, LOG_INFO, "user '%s' disconnected due to script", + proc->username); } return ret; } -int handle_commands(main_server_st *s, struct proc_st* proc) +static int handle_auth_res(main_server_st * s, struct proc_st *proc, + unsigned cmd, int result, unsigned cont) +{ + int ret; + + if (cont != 0 && result == 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; + } + return 0; /* wait for another command */ + } else if (result == 0) { + ret = accept_user(s, proc, cmd); + if (ret < 0) { + goto auth_ok; + } + proc->status = PS_AUTH_COMPLETED; + goto auth_ok; + } else if (result < 0) { + add_to_ip_ban_list(s, &proc->remote_addr, + proc->remote_addr_len); + return result; + } else { + mslog(s, proc, LOG_ERR, "unexpected auth result: %d\n", result); + return ERR_BAD_COMMAND; + } + + auth_ok: + if (ret == ERR_WAIT_FOR_SCRIPT) + ret = 0; + else { + /* no script was called. Handle it as a successful script call. */ + ret = handle_script_exit(s, proc, ret); + } + + return ret; +} + +int handle_commands(main_server_st * s, struct proc_st *proc) { struct iovec iov[3]; uint8_t cmd; struct msghdr hdr; - AuthInitMsg * auth_init; - AuthCookieRequestMsg * auth_cookie_req; - AuthRequestMsg * auth_req; + AuthInitMsg *auth_init; + AuthReinitMsg *auth_reinit; + AuthCookieRequestMsg *auth_cookie_req; + AuthRequestMsg *auth_req; uint16_t length; uint8_t *raw; int ret, raw_len, e; @@ -367,10 +451,12 @@ int handle_commands(main_server_st *s, struct proc_st* proc) hdr.msg_iov = iov; hdr.msg_iovlen = 2; - ret = recvmsg( proc->fd, &hdr, 0); + ret = recvmsg(proc->fd, &hdr, 0); if (ret == -1) { e = errno; - mslog(s, proc, LOG_ERR, "cannot obtain metadata from command socket: %s", strerror(e)); + mslog(s, proc, LOG_ERR, + "cannot obtain metadata from command socket: %s", + strerror(e)); return ERR_BAD_COMMAND; } @@ -384,8 +470,8 @@ int handle_commands(main_server_st *s, struct proc_st* proc) return ERR_BAD_COMMAND; } - mslog(s, proc, LOG_DEBUG, "main received message '%s' of %u bytes\n", - cmd_request_to_str(cmd), (unsigned)length); + mslog(s, proc, LOG_DEBUG, "main received message '%s' of %u bytes\n", + cmd_request_to_str(cmd), (unsigned)length); raw = malloc(length); if (raw == NULL) { @@ -393,16 +479,18 @@ int handle_commands(main_server_st *s, struct proc_st* proc) return ERR_MEM; } - raw_len = force_read_timeout( proc->fd, raw, length, 2); + raw_len = force_read_timeout(proc->fd, raw, length, 2); if (raw_len != length) { e = errno; - mslog(s, proc, LOG_ERR, "cannot obtain data from command socket: %s", strerror(e)); + mslog(s, proc, LOG_ERR, + "cannot obtain data from command socket: %s", + strerror(e)); ret = ERR_BAD_COMMAND; goto cleanup; } - switch(cmd) { - case CMD_TUN_MTU: { + switch (cmd) { + case CMD_TUN_MTU:{ TunMtuMsg *tmsg; tmsg = tun_mtu_msg__unpack(NULL, raw_len, raw); @@ -416,10 +504,10 @@ int handle_commands(main_server_st *s, struct proc_st* proc) tun_mtu_msg__free_unpacked(tmsg, NULL); - } + } - break; - case CMD_SESSION_INFO: { + break; + case CMD_SESSION_INFO:{ SessionInfoMsg *tmsg; tmsg = session_info_msg__unpack(NULL, raw_len, raw); @@ -430,21 +518,29 @@ int handle_commands(main_server_st *s, struct proc_st* proc) } if (tmsg->tls_ciphersuite) - snprintf(proc->tls_ciphersuite, sizeof(proc->tls_ciphersuite), "%s", tmsg->tls_ciphersuite); + snprintf(proc->tls_ciphersuite, + sizeof(proc->tls_ciphersuite), "%s", + tmsg->tls_ciphersuite); if (tmsg->dtls_ciphersuite) - snprintf(proc->dtls_ciphersuite, sizeof(proc->dtls_ciphersuite), "%s", tmsg->dtls_ciphersuite); + snprintf(proc->dtls_ciphersuite, + sizeof(proc->dtls_ciphersuite), "%s", + tmsg->dtls_ciphersuite); if (tmsg->user_agent) - snprintf(proc->user_agent, sizeof(proc->user_agent), "%s", tmsg->user_agent); + snprintf(proc->user_agent, + sizeof(proc->user_agent), "%s", + tmsg->user_agent); session_info_msg__free_unpacked(tmsg, NULL); - } + } - break; - case RESUME_STORE_REQ: { - SessionResumeStoreReqMsg* smsg; + break; + case RESUME_STORE_REQ:{ + SessionResumeStoreReqMsg *smsg; - smsg = session_resume_store_req_msg__unpack(NULL, raw_len, raw); + smsg = + session_resume_store_req_msg__unpack(NULL, raw_len, + raw); if (smsg == NULL) { mslog(s, proc, LOG_ERR, "error unpacking data"); ret = ERR_BAD_COMMAND; @@ -456,17 +552,20 @@ int handle_commands(main_server_st *s, struct proc_st* proc) session_resume_store_req_msg__free_unpacked(smsg, NULL); if (ret < 0) { - mslog(s, proc, LOG_DEBUG, "could not store resumption data"); + mslog(s, proc, LOG_DEBUG, + "could not store resumption data"); } - } + } - break; + break; - case RESUME_DELETE_REQ: { - SessionResumeFetchMsg* fmsg; + case RESUME_DELETE_REQ:{ + SessionResumeFetchMsg *fmsg; - fmsg = session_resume_fetch_msg__unpack(NULL, raw_len, raw); + fmsg = + session_resume_fetch_msg__unpack(NULL, raw_len, + raw); if (fmsg == NULL) { mslog(s, proc, LOG_ERR, "error unpacking data"); ret = ERR_BAD_COMMAND; @@ -478,17 +577,21 @@ int handle_commands(main_server_st *s, struct proc_st* proc) session_resume_fetch_msg__free_unpacked(fmsg, NULL); if (ret < 0) { - mslog(s, proc, LOG_DEBUG, "could not delete resumption data."); + mslog(s, proc, LOG_DEBUG, + "could not delete resumption data."); } - } + } - break; - case RESUME_FETCH_REQ: { - SessionResumeReplyMsg msg = SESSION_RESUME_REPLY_MSG__INIT; - SessionResumeFetchMsg* fmsg; + break; + case RESUME_FETCH_REQ:{ + SessionResumeReplyMsg msg = + SESSION_RESUME_REPLY_MSG__INIT; + SessionResumeFetchMsg *fmsg; - fmsg = session_resume_fetch_msg__unpack(NULL, raw_len, raw); + fmsg = + session_resume_fetch_msg__unpack(NULL, raw_len, + raw); if (fmsg == NULL) { mslog(s, proc, LOG_ERR, "error unpacking data"); ret = ERR_BAD_COMMAND; @@ -500,183 +603,187 @@ int handle_commands(main_server_st *s, struct proc_st* proc) session_resume_fetch_msg__free_unpacked(fmsg, NULL); if (ret < 0) { - msg.reply = SESSION_RESUME_REPLY_MSG__RESUME__REP__FAILED; - mslog(s, proc, LOG_DEBUG, "could not fetch resumption data."); + msg.reply = + SESSION_RESUME_REPLY_MSG__RESUME__REP__FAILED; + mslog(s, proc, LOG_DEBUG, + "could not fetch resumption data."); } else { - msg.reply = SESSION_RESUME_REPLY_MSG__RESUME__REP__OK; + msg.reply = + SESSION_RESUME_REPLY_MSG__RESUME__REP__OK; } - ret = send_msg_to_worker(s, proc, RESUME_FETCH_REP, &msg, - (pack_size_func)session_resume_reply_msg__get_packed_size, - (pack_func)session_resume_reply_msg__pack); + ret = + send_msg_to_worker(s, proc, RESUME_FETCH_REP, &msg, + (pack_size_func) + session_resume_reply_msg__get_packed_size, + (pack_func) + session_resume_reply_msg__pack); if (ret < 0) { - mslog(s, proc, LOG_ERR, "could not send reply cmd %d.", (unsigned) cmd); + mslog(s, proc, LOG_ERR, + "could not send reply cmd %d.", + (unsigned)cmd); ret = ERR_BAD_COMMAND; goto cleanup; } - } + } - break; + break; - case AUTH_INIT: - - if (proc->auth_status != PS_AUTH_INACTIVE) { - mslog(s, proc, LOG_ERR, "received authentication init when complete."); - ret = ERR_BAD_COMMAND; - goto cleanup; - } - - auth_init = auth_init_msg__unpack(NULL, raw_len, raw); - if (auth_init == NULL) { - mslog(s, proc, LOG_ERR, "error unpacking data"); - ret = ERR_BAD_COMMAND; - goto cleanup; - } - - ret = handle_auth_init(s, proc, auth_init); - - auth_init_msg__free_unpacked(auth_init, NULL); - - 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_ERR, "could not send reply auth cmd."); - goto cleanup; - } - break; /* wait for another command */ - } else if (ret == 0) { - ret = accept_user(s, proc, cmd); - if (ret < 0) { - goto cleanup_auth; - } - proc->auth_status = PS_AUTH_COMPLETED; - goto cleanup; - } else if (ret < 0) { - add_to_ip_ban_list(s, &proc->remote_addr, proc->remote_addr_len); - goto cleanup; - } - - break; - - case AUTH_REQ: - if (proc->auth_status != PS_AUTH_INIT) { - mslog(s, proc, LOG_ERR, "received authentication request when not initialized."); - ret = ERR_BAD_COMMAND; - goto cleanup_auth; - } - - proc->auth_reqs++; - if (proc->auth_reqs > MAX_AUTH_REQS) { - mslog(s, proc, LOG_ERR, "received too many authentication requests."); - ret = ERR_BAD_COMMAND; - goto cleanup_auth; - } - - auth_req = auth_request_msg__unpack(NULL, raw_len, raw); - if (auth_req == NULL) { - mslog(s, proc, LOG_ERR, "error unpacking data"); - ret = ERR_BAD_COMMAND; - goto cleanup_auth; - } - - ret = handle_auth_req(s, proc, auth_req); - - auth_request_msg__free_unpacked(auth_req, NULL); - - 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."); - goto cleanup_auth; - } - break; /* wait for another command */ - } else if (ret < 0) { - add_to_ip_ban_list(s, &proc->remote_addr, proc->remote_addr_len); - goto cleanup_auth; - } - - ret = accept_user(s, proc, cmd); - if (ret < 0) { - goto cleanup_auth; - } - proc->auth_status = PS_AUTH_COMPLETED; - goto cleanup_auth; - - case AUTH_COOKIE_REQ: - - if (proc->auth_status != PS_AUTH_INACTIVE) { - mslog(s, proc, LOG_ERR, "received unexpected cookie authentication."); - ret = ERR_BAD_COMMAND; - goto cleanup_auth; - } - - auth_cookie_req = auth_cookie_request_msg__unpack(NULL, raw_len, raw); - if (auth_cookie_req == NULL) { - mslog(s, proc, LOG_ERR, "error unpacking data"); - ret = ERR_BAD_COMMAND; - goto cleanup_auth; - } - - ret = handle_auth_cookie_req(s, proc, auth_cookie_req); - - auth_cookie_request_msg__free_unpacked(auth_cookie_req, NULL); - - if (ret < 0) { - add_to_ip_ban_list(s, &proc->remote_addr, proc->remote_addr_len); - goto cleanup_auth; - } - - ret = accept_user(s, proc, cmd); - if (ret < 0) { - goto cleanup_auth; - } - - proc->auth_status = PS_AUTH_COMPLETED; - -cleanup_auth: - if (ret == ERR_WAIT_FOR_SCRIPT) - ret = 0; - else { - /* no script was called. Handle it as a successful script call. */ - ret = handle_script_exit(s, proc, ret); - } - goto cleanup; - - default: - mslog(s, proc, LOG_ERR, "unknown CMD 0x%x.", (unsigned)cmd); + case AUTH_INIT: + if (proc->status != PS_AUTH_INACTIVE) { + mslog(s, proc, LOG_ERR, + "received authentication init when complete."); ret = ERR_BAD_COMMAND; goto cleanup; + } + + auth_init = auth_init_msg__unpack(NULL, raw_len, raw); + if (auth_init == NULL) { + mslog(s, proc, LOG_ERR, "error unpacking data"); + ret = ERR_BAD_COMMAND; + goto cleanup; + } + + ret = handle_auth_init(s, proc, auth_init); + + auth_init_msg__free_unpacked(auth_init, NULL); + + proc->status = PS_AUTH_INIT; + + ret = handle_auth_res(s, proc, cmd, ret, 1); + if (ret < 0) { + goto cleanup; + } + + break; + + case AUTH_REINIT: + if (proc->status != PS_AUTH_INACTIVE + || s->config->cisco_client_compat == 0) { + mslog(s, proc, LOG_ERR, + "received authentication reinit when complete."); + ret = ERR_BAD_COMMAND; + goto cleanup; + } + + auth_reinit = auth_reinit_msg__unpack(NULL, raw_len, raw); + if (auth_reinit == NULL) { + mslog(s, proc, LOG_ERR, "error unpacking data"); + ret = ERR_BAD_COMMAND; + goto cleanup; + } + + /* note that it may replace proc on success */ + ret = handle_auth_reinit(s, &proc, auth_reinit); + + auth_reinit_msg__free_unpacked(auth_reinit, NULL); + + proc->status = PS_AUTH_INIT; + + ret = handle_auth_res(s, proc, cmd, ret, 1); + if (ret < 0) { + goto cleanup; + } + + case AUTH_REQ: + if (proc->status != PS_AUTH_INIT) { + mslog(s, proc, LOG_ERR, + "received authentication request when not initialized."); + ret = ERR_BAD_COMMAND; + goto cleanup; + } + + proc->auth_reqs++; + if (proc->auth_reqs > MAX_AUTH_REQS) { + mslog(s, proc, LOG_ERR, + "received too many authentication requests."); + ret = ERR_BAD_COMMAND; + goto cleanup; + } + + auth_req = auth_request_msg__unpack(NULL, raw_len, raw); + if (auth_req == NULL) { + mslog(s, proc, LOG_ERR, "error unpacking data"); + ret = ERR_BAD_COMMAND; + goto cleanup; + } + + ret = handle_auth_req(s, proc, auth_req); + + auth_request_msg__free_unpacked(auth_req, NULL); + + proc->status = PS_AUTH_INIT; + + ret = handle_auth_res(s, proc, cmd, ret, 1); + if (ret < 0) { + goto cleanup; + } + + break; + + case AUTH_COOKIE_REQ: + + if (proc->status != PS_AUTH_INACTIVE) { + mslog(s, proc, LOG_ERR, + "received unexpected cookie authentication."); + ret = ERR_BAD_COMMAND; + goto cleanup; + } + + auth_cookie_req = + auth_cookie_request_msg__unpack(NULL, raw_len, raw); + if (auth_cookie_req == NULL) { + mslog(s, proc, LOG_ERR, "error unpacking data"); + ret = ERR_BAD_COMMAND; + goto cleanup; + } + + ret = handle_auth_cookie_req(s, proc, auth_cookie_req); + + auth_cookie_request_msg__free_unpacked(auth_cookie_req, NULL); + + ret = handle_auth_res(s, proc, cmd, ret, 0); + if (ret < 0) { + goto cleanup; + } + + break; + + default: + mslog(s, proc, LOG_ERR, "unknown CMD 0x%x.", (unsigned)cmd); + ret = ERR_BAD_COMMAND; + goto cleanup; } ret = 0; -cleanup: + cleanup: free(raw); return ret; } -int check_if_banned(main_server_st* s, struct sockaddr_storage *addr, socklen_t addr_len) +int check_if_banned(main_server_st * s, struct sockaddr_storage *addr, + socklen_t addr_len) { -time_t now = time(0); -struct banned_st *btmp, *bpos; + time_t now = time(0); + struct banned_st *btmp, *bpos; if (s->config->min_reauth_time == 0) return 0; list_for_each_safe(&s->ban_list.head, btmp, bpos, list) { - if (now-btmp->failed_time > s->config->min_reauth_time) { + if (now - btmp->failed_time > s->config->min_reauth_time) { /* invalid entry. Clean it up */ list_del(&btmp->list); free(btmp); } else { - if (SA_IN_SIZE(btmp->addr_len) == SA_IN_SIZE(addr_len) && - memcmp(SA_IN_P_GENERIC(&btmp->addr, btmp->addr_len), - SA_IN_P_GENERIC(addr, addr_len), - SA_IN_SIZE(btmp->addr_len)) == 0) { + if (SA_IN_SIZE(btmp->addr_len) == SA_IN_SIZE(addr_len) + && + memcmp(SA_IN_P_GENERIC(&btmp->addr, btmp->addr_len), + SA_IN_P_GENERIC(addr, addr_len), + SA_IN_SIZE(btmp->addr_len)) == 0) { return -1; } } @@ -685,17 +792,16 @@ struct banned_st *btmp, *bpos; return 0; } - -void expire_banned(main_server_st* s) +void expire_banned(main_server_st * s) { -time_t now = time(0); -struct banned_st *btmp = NULL, *bpos; + time_t now = time(0); + struct banned_st *btmp = NULL, *bpos; if (s->config->min_reauth_time == 0) return; list_for_each_safe(&s->ban_list.head, btmp, bpos, list) { - if (now-btmp->failed_time > s->config->min_reauth_time) { + if (now - btmp->failed_time > s->config->min_reauth_time) { /* invalid entry. Clean it up */ list_del(&btmp->list); free(btmp); @@ -705,9 +811,10 @@ struct banned_st *btmp = NULL, *bpos; return; } -void add_to_ip_ban_list(main_server_st* s, struct sockaddr_storage *addr, socklen_t addr_len) +void add_to_ip_ban_list(main_server_st * s, struct sockaddr_storage *addr, + socklen_t addr_len) { -struct banned_st *btmp; + struct banned_st *btmp; if (s->config->min_reauth_time == 0) return; @@ -723,31 +830,51 @@ struct banned_st *btmp; list_add(&s->ban_list.head, &(btmp->list)); } +void expire_zombies(main_server_st * s) +{ + time_t now = time(0); + struct proc_st *ctmp = NULL, *cpos; + + if (s->config->cisco_client_compat == 0) + return; + + list_for_each_safe(&s->proc_list.head, ctmp, cpos, list) { + if (ctmp->status == PS_AUTH_ZOMBIE && + now - ctmp->conn_time > MAX_ZOMBIE_SECS) { + remove_proc(s, ctmp, 0); + } + } + + return; +} + void run_sec_mod(main_server_st * s) { -int e; -pid_t pid; -char file[_POSIX_PATH_MAX]; -const char *p; + int e; + pid_t pid; + char file[_POSIX_PATH_MAX]; + const char *p; /* make socket name */ - snprintf(s->socket_file, sizeof(s->socket_file), "%s.%u", s->config->socket_file_prefix, (unsigned)getpid()); + snprintf(s->socket_file, sizeof(s->socket_file), "%s.%u", + s->config->socket_file_prefix, (unsigned)getpid()); p = s->socket_file; if (s->config->chroot_dir != NULL) { - snprintf(file, sizeof(file), "%s/%s.%u", - s->config->chroot_dir, s->config->socket_file_prefix, (unsigned)getpid()); + snprintf(file, sizeof(file), "%s/%s.%u", + s->config->chroot_dir, s->config->socket_file_prefix, + (unsigned)getpid()); p = file; } pid = fork(); - if (pid == 0) { /* child */ + if (pid == 0) { /* child */ clear_lists(s); kill_on_parent_kill(SIGTERM); - setproctitle(PACKAGE_NAME"-secmod"); + setproctitle(PACKAGE_NAME "-secmod"); sec_mod_server(s->config, p); exit(0); - } else if (pid > 0) { /* parent */ + } else if (pid > 0) { /* parent */ s->sec_mod_pid = pid; } else { e = errno; @@ -757,36 +884,40 @@ const char *p; } /* Puts the provided PIN into the config's cgroup */ -void put_into_cgroup(main_server_st * s, const char* _cgroup, pid_t pid) +void put_into_cgroup(main_server_st * s, const char *_cgroup, pid_t pid) { -char* name, *p, *savep; -char cgroup[128]; -char file[_POSIX_PATH_MAX]; -FILE* fd; + char *name, *p, *savep; + char cgroup[128]; + char file[_POSIX_PATH_MAX]; + FILE *fd; if (_cgroup == NULL) return; #ifdef __linux__ - /* format: cpu,memory:cgroup-name */ - snprintf(cgroup, sizeof(cgroup), "%s", _cgroup); - - name = strchr(cgroup, ':'); - if (name == NULL) { - mslog(s, NULL, LOG_ERR, "error parsing cgroup name: %s", cgroup); + /* format: cpu,memory:cgroup-name */ + snprintf(cgroup, sizeof(cgroup), "%s", _cgroup); + + name = strchr(cgroup, ':'); + if (name == NULL) { + mslog(s, NULL, LOG_ERR, "error parsing cgroup name: %s", + cgroup); return; - } - name[0] = 0; - name++; - - p = strtok_r(cgroup, ",", &savep); - while (p != NULL) { - mslog(s, NULL, LOG_DEBUG, "putting process %u to cgroup '%s:%s'", (unsigned)pid, p, name); + } + name[0] = 0; + name++; - snprintf(file, sizeof(file), "/sys/fs/cgroup/%s/%s/tasks", p, name); + p = strtok_r(cgroup, ",", &savep); + while (p != NULL) { + mslog(s, NULL, LOG_DEBUG, + "putting process %u to cgroup '%s:%s'", (unsigned)pid, p, + name); - fd = fopen(file, "w"); - if (fd == NULL) { + snprintf(file, sizeof(file), "/sys/fs/cgroup/%s/%s/tasks", p, + name); + + fd = fopen(file, "w"); + if (fd == NULL) { mslog(s, NULL, LOG_ERR, "cannot open: %s", file); return; } @@ -796,10 +927,11 @@ FILE* fd; } fclose(fd); p = strtok_r(NULL, ",", &savep); - } - - return; + } + + return; #else - mslog(s, NULL, LOG_DEBUG, "Ignoring cgroup option as it is not supported on this system"); + mslog(s, NULL, LOG_DEBUG, + "Ignoring cgroup option as it is not supported on this system"); #endif } diff --git a/src/main-resume.c b/src/main-resume.c index 92ae8ae6..2306cb90 100644 --- a/src/main-resume.c +++ b/src/main-resume.c @@ -38,138 +38,156 @@ #include #include -int handle_resume_delete_req(main_server_st* s, struct proc_st * proc, - const SessionResumeFetchMsg * req) +int handle_resume_delete_req(main_server_st * s, struct proc_st *proc, + const SessionResumeFetchMsg * req) { -tls_cache_st* cache; -struct htable_iter iter; -size_t key; + tls_cache_st *cache; + struct htable_iter iter; + size_t key; key = hash_any(req->session_id.data, req->session_id.len, 0); cache = htable_firstval(&s->tls_db->ht, &iter, key); - while(cache != NULL) { + while (cache != NULL) { if (req->session_id.len == cache->session_id_size && - memcmp (req->session_id.data, cache->session_id, req->session_id.len) == 0) { + memcmp(req->session_id.data, cache->session_id, + req->session_id.len) == 0) { - cache->session_data_size = 0; - cache->session_id_size = 0; - - htable_delval(&s->tls_db->ht, &iter); - free(cache); + cache->session_data_size = 0; + cache->session_id_size = 0; + + htable_delval(&s->tls_db->ht, &iter); + free(cache); s->tls_db->entries--; - return 0; + return 0; } - - cache = htable_nextval(&s->tls_db->ht, &iter, key); - } - return 0; + cache = htable_nextval(&s->tls_db->ht, &iter, key); + } + + return 0; } -int handle_resume_fetch_req(main_server_st* s, struct proc_st * proc, - const SessionResumeFetchMsg * req, - SessionResumeReplyMsg* rep) +int handle_resume_fetch_req(main_server_st * s, struct proc_st *proc, + const SessionResumeFetchMsg * req, + SessionResumeReplyMsg * rep) { -tls_cache_st* cache; -struct htable_iter iter; -size_t key; + tls_cache_st *cache; + struct htable_iter iter; + size_t key; rep->reply = SESSION_RESUME_REPLY_MSG__RESUME__REP__FAILED; key = hash_any(req->session_id.data, req->session_id.len, 0); cache = htable_firstval(&s->tls_db->ht, &iter, key); - while(cache != NULL) { + while (cache != NULL) { if (req->session_id.len == cache->session_id_size && - memcmp (req->session_id.data, cache->session_id, req->session_id.len) == 0) { + memcmp(req->session_id.data, cache->session_id, + req->session_id.len) == 0) { - if (proc->remote_addr_len == cache->remote_addr_len && - ip_cmp(&proc->remote_addr, &cache->remote_addr, proc->remote_addr_len) == 0) { + if (proc->remote_addr_len == cache->remote_addr_len && + ip_cmp(&proc->remote_addr, &cache->remote_addr, + proc->remote_addr_len) == 0) { - rep->reply = SESSION_RESUME_REPLY_MSG__RESUME__REP__OK; - - rep->has_session_data = 1; - rep->session_data.data = (void*)cache->session_data; - rep->session_data.len = cache->session_data_size; + rep->reply = + SESSION_RESUME_REPLY_MSG__RESUME__REP__OK; - return 0; + rep->has_session_data = 1; + + rep->session_data.data = + (void *)cache->session_data; + rep->session_data.len = + cache->session_data_size; + + mslog_hex(s, proc, LOG_DEBUG, "TLS session DB resuming", + req->session_id.data, + req->session_id.len); + + return 0; } } - cache = htable_nextval(&s->tls_db->ht, &iter, key); - } + cache = htable_nextval(&s->tls_db->ht, &iter, key); + } - return 0; + return 0; } -int handle_resume_store_req(main_server_st* s, struct proc_st * proc, - const SessionResumeStoreReqMsg * req) +int handle_resume_store_req(main_server_st * s, struct proc_st *proc, + const SessionResumeStoreReqMsg * req) { -tls_cache_st* cache; -size_t key; -unsigned int max; + tls_cache_st *cache; + size_t key; + unsigned int max; if (req->session_id.len > GNUTLS_MAX_SESSION_ID) return -1; if (req->session_data.len > MAX_SESSION_DATA_SIZE) return -1; - max = MAX(2*s->config->max_clients, DEFAULT_MAX_CACHED_TLS_SESSIONS); + max = MAX(2 * s->config->max_clients, DEFAULT_MAX_CACHED_TLS_SESSIONS); if (s->tls_db->entries >= max) { - mslog(s, NULL, LOG_INFO, "maximum number of stored TLS sessions reached (%u)", max); + mslog(s, NULL, LOG_INFO, + "maximum number of stored TLS sessions reached (%u)", + max); need_maintenance = 1; return -1; } key = hash_any(req->session_id.data, req->session_id.len, 0); - + cache = malloc(sizeof(*cache)); if (cache == NULL) return -1; - + cache->session_id_size = req->session_id.len; cache->session_data_size = req->session_data.len; cache->remote_addr_len = proc->remote_addr_len; memcpy(cache->session_id, req->session_id.data, req->session_id.len); - memcpy(cache->session_data, req->session_data.data, req->session_data.len); + memcpy(cache->session_data, req->session_data.data, + req->session_data.len); memcpy(&cache->remote_addr, &proc->remote_addr, proc->remote_addr_len); - + htable_add(&s->tls_db->ht, key, cache); s->tls_db->entries++; + mslog_hex(s, proc, LOG_DEBUG, "TLS session DB storing", + req->session_id.data, + req->session_id.len); + return 0; } -void expire_tls_sessions(main_server_st *s) +void expire_tls_sessions(main_server_st * s) { -tls_cache_st* cache; -struct htable_iter iter; -time_t now, exp; + tls_cache_st *cache; + struct htable_iter iter; + time_t now, exp; now = time(0); cache = htable_first(&s->tls_db->ht, &iter); - while(cache != NULL) { + while (cache != NULL) { gnutls_datum_t d; - d.data = (void*)cache->session_data; + d.data = (void *)cache->session_data; d.size = cache->session_data_size; exp = gnutls_db_check_entry_time(&d); - if (now-exp > TLS_SESSION_EXPIRATION_TIME) { - cache->session_data_size = 0; - cache->session_id_size = 0; + if (now - exp > TLS_SESSION_EXPIRATION_TIME) { + cache->session_data_size = 0; + cache->session_id_size = 0; - htable_delval(&s->tls_db->ht, &iter); - free(cache); + htable_delval(&s->tls_db->ht, &iter); + free(cache); s->tls_db->entries--; } - cache = htable_next(&s->tls_db->ht, &iter); - } + cache = htable_next(&s->tls_db->ht, &iter); + } - return; + return; } diff --git a/src/main.c b/src/main.c index 44e7ba6b..667bef06 100644 --- a/src/main.c +++ b/src/main.c @@ -657,8 +657,8 @@ time_t now; now = time(0); list_for_each(&s->proc_list.head, ctmp, list) { - if (session_id_size == ctmp->session_id_size && - memcmp(session_id, ctmp->session_id, session_id_size) == 0 && + if (session_id_size == ctmp->dtls_session_id_size && + memcmp(session_id, ctmp->dtls_session_id, session_id_size) == 0 && (now - ctmp->udp_fd_receive_time > UDP_FD_RESEND_TIME)) { UdpFdMsg msg = UDP_FD_MSG__INIT; @@ -744,6 +744,7 @@ unsigned total = 10; need_maintenance = 0; mslog(s, NULL, LOG_INFO, "Performing maintenance"); expire_tls_sessions(s); + expire_zombies(s); expire_banned(s); alarm(MAINTAINANCE_TIME(s)); } @@ -900,8 +901,10 @@ int main(int argc, char** argv) } list_for_each(&s.proc_list.head, ctmp, list) { - FD_SET(ctmp->fd, &rd_set); - n = MAX(n, ctmp->fd); + if (ctmp->fd > 0) { + FD_SET(ctmp->fd, &rd_set); + n = MAX(n, ctmp->fd); + } } list_for_each(&s.ctl_list.head, ctl_tmp, list) { @@ -1046,9 +1049,12 @@ fork_failed: /* Check for any pending commands */ list_for_each_safe(&s.proc_list.head, ctmp, cpos, list) { - if (FD_ISSET(ctmp->fd, &rd_set)) { + if (ctmp->fd >= 0 && FD_ISSET(ctmp->fd, &rd_set)) { ret = handle_commands(&s, ctmp); - if (ret < 0) { + if (ret == ERR_WORKER_TERMINATED && ctmp->status == PS_AUTH_INIT && + s.config->cisco_client_compat != 0) { + proc_to_zombie(&s, ctmp); + } else if (ret < 0) { remove_proc(&s, ctmp, (ret!=ERR_WORKER_TERMINATED)?1:0); } } diff --git a/src/main.h b/src/main.h index 8acaa5ad..dddb644c 100644 --- a/src/main.h +++ b/src/main.h @@ -64,10 +64,12 @@ struct script_wait_st { struct proc_st* proc; }; +#define MAX_ZOMBIE_SECS 240 enum { - PS_AUTH_INACTIVE, - PS_AUTH_INIT, - PS_AUTH_COMPLETED, + PS_AUTH_INACTIVE, /* no comm with worker */ + 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_COMPLETED, /* successful authentication */ }; /* Each worker process maps to a unique proc_st structure. @@ -88,11 +90,16 @@ struct proc_st { struct sockaddr_storage remote_addr; /* peer address */ socklen_t remote_addr_len; + /* The TLS session ID. + */ + uint8_t tls_session_id[GNUTLS_MAX_SESSION_ID]; + unsigned tls_session_id_size; /* would act as a flag if session_id is set */ + /* The DTLS session ID associated with the TLS session * it is either generated or restored from a cookie. */ - uint8_t session_id[GNUTLS_MAX_SESSION_ID]; - unsigned session_id_size; /* would act as a flag if session_id is set */ + uint8_t dtls_session_id[GNUTLS_MAX_SESSION_ID]; + unsigned dtls_session_id_size; /* would act as a flag if session_id is set */ /* The following are set by the worker process (or by a stored cookie) */ char username[MAX_USERNAME_SIZE]; /* the owner */ @@ -111,7 +118,7 @@ struct proc_st { uint8_t ipv4_seed[4]; void * auth_ctx; /* the context of authentication */ - unsigned auth_status; /* PS_AUTH_ */ + unsigned status; /* PS_AUTH_ */ unsigned auth_reqs; /* the number of requests received */ unsigned applied_iroutes; /* whether the iroutes in the config have been successfully applied */ @@ -193,6 +200,7 @@ 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); +void expire_zombies(main_server_st* s); int send_udp_fd(main_server_st* s, struct proc_st * proc, int fd); @@ -235,6 +243,8 @@ int handle_auth_cookie_req(main_server_st* s, struct proc_st* proc, int generate_cookie(main_server_st *s, struct proc_st* proc); int handle_auth_init(main_server_st *s, struct proc_st* proc, const AuthInitMsg * req); +int handle_auth_reinit(main_server_st *s, struct proc_st** proc, + const AuthReinitMsg * req); int handle_auth_req(main_server_st *s, struct proc_st* proc, const AuthRequestMsg * req); @@ -252,6 +262,7 @@ int parse_group_cfg_file(main_server_st* s, const char* file, struct group_cfg_s void del_additional_config(struct group_cfg_st* config); void remove_proc(main_server_st* s, struct proc_st *proc, unsigned k); +void proc_to_zombie(main_server_st* s, struct proc_st *proc); void put_into_cgroup(main_server_st * s, const char* cgroup, pid_t pid); diff --git a/src/vpn.h b/src/vpn.h index b449a644..88ffc9b7 100644 --- a/src/vpn.h +++ b/src/vpn.h @@ -94,6 +94,7 @@ typedef enum { CMD_TUN_MTU = 11, CMD_TERMINATE = 12, CMD_SESSION_INFO = 13, + AUTH_REINIT = 14, } cmd_request_t; typedef struct diff --git a/src/worker-auth.c b/src/worker-auth.c index 1ea48f85..a68bd772 100644 --- a/src/worker-auth.c +++ b/src/worker-auth.c @@ -65,18 +65,6 @@ static const char login_msg_user[] = "\n" ""; -static const char login_msg_compact[] = - "\n" - "\n" - VERSION_MSG \ - "\n" - "Please enter your username and password\n" - "
\n" - "\n" - "\n" - "
\n" - "
"; - static const char login_msg_no_user[] = "\n" "\n" @@ -90,7 +78,6 @@ static const char login_msg_no_user[] = int get_auth_handler2(worker_st * ws, unsigned http_ver, const char *pmsg) { int ret; - struct http_req_st *req = &ws->req; char login_msg[MAX_MSG_SIZE + sizeof(login_msg_user)]; unsigned int lsize; @@ -107,26 +94,17 @@ int get_auth_handler2(worker_st * ws, unsigned http_ver, const char *pmsg) if (ret < 0) return -1; -#ifdef ANYCONNECT_CLIENT_COMPAT - if (req && req->needs_compact_auth != 0) { - lsize = snprintf(login_msg, sizeof(login_msg), "%s", login_msg_compact); + 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 { -#endif - 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), "%s", login_msg_user); - } - -#ifdef ANYCONNECT_CLIENT_COMPAT + /* ask for username only */ + lsize = snprintf(login_msg, sizeof(login_msg), "%s", login_msg_user); } -#endif ret = tls_printf(ws->session, "Content-Length: %u\r\n", @@ -678,31 +656,64 @@ int post_auth_handler(worker_st * ws, unsigned http_ver) char *password = NULL; char tmp_user[MAX_USERNAME_SIZE]; char tmp_group[MAX_USERNAME_SIZE]; + uint8_t tls_session_id[GNUTLS_MAX_SESSION_ID]; + size_t tls_session_id_size; char msg[MAX_MSG_SIZE]; - unsigned compact_auth = 0; oclog(ws, LOG_HTTP_DEBUG, "POST body: '%.*s'", (int)req->body_length, req->body); -restart: if (ws->auth_state == S_AUTH_INACTIVE) { AuthInitMsg ireq = AUTH_INIT_MSG__INIT; -#ifdef ANYCONNECT_CLIENT_COMPAT - if (req->needs_compact_auth != 0) { - /* the client uses Connection: Close and needs to - * be asked the username and password in one go. - */ - compact_auth = 1; + tls_session_id_size = sizeof(tls_session_id); + ret = gnutls_session_get_id(ws->session, tls_session_id, &tls_session_id_size); + if (ret < 0) { + oclog(ws, LOG_INFO, "failed obtainng session ID"); + goto auth_fail; } -#endif if (ws->config->auth_types & AUTH_TYPE_USERNAME_PASS) { ret = read_user_pass(ws, req->body, req->body_length, &username, NULL); if (ret < 0) { - oclog(ws, LOG_ERR, "failed reading username"); + /* Try if we need to ReInit */ + if (ws->config->cisco_client_compat != 0 && + gnutls_session_is_resumed(ws->session) != 0) { + AuthReinitMsg rreq = AUTH_REINIT_MSG__INIT; + + /* could it be a client reconnecting and sending + * his password? */ + ret = + read_user_pass(ws, req->body, req->body_length, + NULL, &password); + if (ret < 0) { + oclog(ws, LOG_INFO, "failed reading password as well"); + goto ask_auth; + } + + rreq.tls_auth_ok = ws->cert_auth_ok; + rreq.password = password; + rreq.session_id.data = tls_session_id; + rreq.session_id.len = tls_session_id_size; + + ret = send_msg_to_main(ws, AUTH_REINIT, &rreq, + (pack_size_func)auth_reinit_msg__get_packed_size, + (pack_func)auth_reinit_msg__pack); + free(username); + + if (ret < 0) { + oclog(ws, LOG_ERR, + "failed sending auth reinit message to main"); + goto auth_fail; + } + + ws->auth_state = S_AUTH_INIT; + goto recv_reply; + } + + oclog(ws, LOG_INFO, "failed reading username"); goto ask_auth; } @@ -731,6 +742,8 @@ restart: ireq.cert_group_name = tmp_group; } + ireq.session_id.data = tls_session_id; + ireq.session_id.len = tls_session_id_size; ireq.hostname = req->hostname; ret = send_msg_to_main(ws, AUTH_INIT, @@ -783,18 +796,13 @@ restart: goto auth_fail; } + recv_reply: ret = recv_auth_reply(ws, msg, sizeof(msg)); if (ret == ERR_AUTH_CONTINUE) { oclog(ws, LOG_DEBUG, "continuing authentication for '%s'", ws->username); ws->auth_state = S_AUTH_REQ; -#ifdef ANYCONNECT_CLIENT_COMPAT - if (compact_auth != 0) { - compact_auth = 0; /* avoid infinite loop */ - goto restart; - } -#endif return get_auth_handler2(ws, http_ver, msg); } else if (ret < 0) { oclog(ws, LOG_ERR, "failed authentication for '%s'", diff --git a/src/worker-vpn.c b/src/worker-vpn.c index 2f2564c4..24f484bf 100644 --- a/src/worker-vpn.c +++ b/src/worker-vpn.c @@ -190,7 +190,6 @@ static void value_check(struct worker_st *ws, struct http_req_st *req) uint8_t *p; char *token; char *str; - char strtmp[16]; if (req->value.length <= 0) return; @@ -305,22 +304,6 @@ static void value_check(struct worker_st *ws, struct http_req_st *req) case HEADER_DTLS_MTU: req->dtls_mtu = atoi((char *)req->value.data); break; - case HEADER_CONNECTION: - length = req->value.length; - - if (length > sizeof(strtmp)-1) - break; - - memcpy(strtmp, req->value.data, length); - strtmp[length] = 0; - - if (c_strcasecmp(strtmp, "close") == 0) { - oclog(ws, LOG_INFO, "client needs compact auth"); - req->needs_compact_auth = 1; - } else { - req->needs_compact_auth = 0; - } - break; case HEADER_COOKIE: length = req->value.length; diff --git a/src/worker.h b/src/worker.h index 16edc61f..f22ac230 100644 --- a/src/worker.h +++ b/src/worker.h @@ -79,12 +79,7 @@ struct http_req_st { unsigned int next_header; unsigned char cookie[COOKIE_SIZE]; unsigned int cookie_set; - /* some CISCO clients reconnect for each request - * and is impossible to keep state for them. For - * that we ask username and password in one go for - * them. - */ - unsigned int needs_compact_auth; + unsigned char master_secret[TLS_MASTER_SIZE]; unsigned int master_secret_set;