diff --git a/contrib/win32/win32compat/ssh-agent/agent.c b/contrib/win32/win32compat/ssh-agent/agent.c index 3354e55..7322ca2 100644 --- a/contrib/win32/win32compat/ssh-agent/agent.c +++ b/contrib/win32/win32compat/ssh-agent/agent.c @@ -65,7 +65,7 @@ init_listeners() { listeners[i].pipe_id = pipe_ids[i]; listeners[i].type = pipe_types[i]; listeners[i].pipe = INVALID_HANDLE_VALUE; - listeners[i].sa.bInheritHandle = TRUE; + listeners[i].sa.bInheritHandle = FALSE; if (!ConvertStringSecurityDescriptorToSecurityDescriptorW(pipe_sddls[i], SDDL_REVISION_1, &listeners[i].sa.lpSecurityDescriptor, &listeners[i].sa.nLength)) { debug("cannot convert sddl ERROR:%d", GetLastError()); @@ -111,7 +111,6 @@ iocp_work(LPVOID lpParam) { } } - static void process_connection(HANDLE pipe, int type) { struct agent_connection* con; @@ -124,7 +123,7 @@ process_connection(HANDLE pipe, int type) { con->type = type; if (CreateIoCompletionPort(pipe, ioc_port, (ULONG_PTR)con, 0) != ioc_port) fatal("failed to assign pipe to ioc_port"); - + agent_connection_on_io(con, 0, &con->ol); return iocp_work(NULL); } @@ -185,8 +184,10 @@ agent_listen_loop() { else if ((r > WAIT_OBJECT_0) && (r <= (WAIT_OBJECT_0 + NUM_LISTENERS))) { /* process incoming connection */ HANDLE con = listeners[r - 1].pipe; + DWORD client_pid = 0; listeners[r - 1].pipe = INVALID_HANDLE_VALUE; - verbose("client connected on %ls", pipe_ids[r-1]); + GetNamedPipeClientProcessId(con, &client_pid); + verbose("client pid %d connected on %ls", client_pid, pipe_ids[r-1]); if (debug_mode) { process_connection(con, listeners[r - 1].type); agent_cleanup(); @@ -201,6 +202,7 @@ agent_listen_loop() { si.cb = sizeof(STARTUPINFOW); memset(&si, 0, sizeof(STARTUPINFOW)); GetModuleFileNameW(NULL, module_path, MAX_PATH); + SetHandleInformation(con, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT); if ((swprintf_s(path, MAX_PATH, L"%s %d %d", module_path, con, listeners[r - 1].type) == -1 ) || (CreateProcessW(NULL, path, NULL, NULL, TRUE, DETACHED_PROCESS, NULL, NULL, @@ -212,6 +214,7 @@ agent_listen_loop() { CloseHandle(pi.hProcess); CloseHandle(pi.hThread); } + SetHandleInformation(con, HANDLE_FLAG_INHERIT, 0); CloseHandle(con); } diff --git a/contrib/win32/win32compat/ssh-agent/agent.h b/contrib/win32/win32compat/ssh-agent/agent.h index afc0a44..639c37f 100644 --- a/contrib/win32/win32compat/ssh-agent/agent.h +++ b/contrib/win32/win32compat/ssh-agent/agent.h @@ -31,6 +31,13 @@ struct agent_connection { WRITING, DONE } state; + enum { + UNKNOWN = 0, + OTHER, + LOCAL_SYSTEM, + SSHD, + NETWORK_SERVICE + } client_type; enum agent_type type; }; diff --git a/contrib/win32/win32compat/ssh-agent/connection.c b/contrib/win32/win32compat/ssh-agent/connection.c index 4192e22..2a19282 100644 --- a/contrib/win32/win32compat/ssh-agent/connection.c +++ b/contrib/win32/win32compat/ssh-agent/connection.c @@ -114,17 +114,74 @@ void agent_connection_disconnect(struct agent_connection* con) { DisconnectNamedPipe(con->connection); } +static int +get_con_client_type(HANDLE pipe) { + int r = -1; + wchar_t *sshd_act = L"NT SERVICE\\SSHD", *ref_dom = NULL; + PSID sshd_sid = NULL; + char system_sid[SECURITY_MAX_SID_SIZE]; + char ns_sid[SECURITY_MAX_SID_SIZE]; + DWORD sshd_sid_len = 0, reg_dom_len = 0, info_len = 0, sid_size; + SID_NAME_USE nuse; + HANDLE token; + TOKEN_USER* info = NULL; + + if (ImpersonateNamedPipeClient(pipe) == FALSE) + return -1; + + if (LookupAccountNameW(NULL, sshd_act, NULL, &sshd_sid_len, NULL, ®_dom_len, &nuse) == TRUE || + (sshd_sid = malloc(sshd_sid_len)) == NULL || + (ref_dom = (wchar_t*)malloc(reg_dom_len * 2)) == NULL || + LookupAccountNameW(NULL, sshd_act, sshd_sid, &sshd_sid_len, ref_dom, ®_dom_len, &nuse) == FALSE || + OpenThreadToken(GetCurrentThread(), TOKEN_QUERY, FALSE, &token) == FALSE || + GetTokenInformation(token, TokenUser, NULL, 0, &info_len) == TRUE || + (info = (TOKEN_USER*)malloc(info_len)) == NULL || + GetTokenInformation(token, TokenUser, info, info_len, &info_len) == FALSE) + goto done; + + sid_size = SECURITY_MAX_SID_SIZE; + if (CreateWellKnownSid(WinLocalSystemSid, NULL, system_sid, &sid_size) == FALSE) + goto done; + sid_size = SECURITY_MAX_SID_SIZE; + if (CreateWellKnownSid(WinNetworkServiceSid, NULL, ns_sid, &sid_size) == FALSE) + goto done; + + if (EqualSid(info->User.Sid, system_sid)) + r = LOCAL_SYSTEM; + else if (EqualSid(info->User.Sid, sshd_sid)) + r = SSHD; + else if (EqualSid(info->User.Sid, ns_sid)) + r = NETWORK_SERVICE; + else + r = OTHER; + + debug("client type: %d", r); +done: + if (sshd_sid) + free(sshd_sid); + if (ref_dom) + free(ref_dom); + if (info) + free(info); + RevertToSelf(); + return r; +} + + static int process_request(struct agent_connection* con) { - int r; + int r = -1; struct sshbuf *request = NULL, *response = NULL; + + if (con->client_type == UNKNOWN) + if ((con->client_type = get_con_client_type(con->connection)) == -1) + goto done; + request = sshbuf_from(con->io_buf.buf, con->io_buf.num_bytes); response = sshbuf_new(); - if ((request == NULL) || (response == NULL)) { - r = ENOMEM; + if ((request == NULL) || (response == NULL)) goto done; - } if (con->type == KEY_AGENT) r = process_keyagent_request(request, response, con); @@ -132,8 +189,6 @@ process_request(struct agent_connection* con) { r = process_pubkeyagent_request(request, response, con); else if (con->type == PUBKEY_AUTH_AGENT) r = process_authagent_request(request, response, con); - else - r = EINVAL; done: if (request) diff --git a/contrib/win32/win32compat/ssh-agent/keyagent-request.c b/contrib/win32/win32compat/ssh-agent/keyagent-request.c index b52bedf..287a56a 100644 --- a/contrib/win32/win32compat/ssh-agent/keyagent-request.c +++ b/contrib/win32/win32compat/ssh-agent/keyagent-request.c @@ -40,9 +40,12 @@ static int get_user_root(struct agent_connection* con, HKEY *root){ int r = 0; if (ImpersonateNamedPipeClient(con->connection) == FALSE) - return ERROR_INTERNAL_ERROR; + return -1; - r = RegOpenCurrentUser(KEY_ALL_ACCESS, root); + if (con->client_type > OTHER) + *root = HKEY_LOCAL_MACHINE; + else if (RegOpenCurrentUser(KEY_ALL_ACCESS, root) != ERROR_SUCCESS) + r = -1; RevertToSelf(); return r; @@ -52,8 +55,10 @@ static int convert_blob(struct agent_connection* con, const char *blob, DWORD blen, char **eblob, DWORD *eblen, int encrypt) { int success = 0; DATA_BLOB in, out; - if (ImpersonateNamedPipeClient(con->connection) == FALSE) - return -1; + + if (con->client_type == OTHER) + if (ImpersonateNamedPipeClient(con->connection) == FALSE) + return -1; in.cbData = blen; in.pbData = (char*)blob; @@ -61,12 +66,16 @@ convert_blob(struct agent_connection* con, const char *blob, DWORD blen, char ** out.pbData = NULL; if (encrypt) { - if (!CryptProtectData(&in, NULL, NULL, 0, NULL, 0, &out)) + if (!CryptProtectData(&in, NULL, NULL, 0, NULL, 0, &out)) { + debug("cannot encrypt data"); goto done; + } } else { - if (!CryptUnprotectData(&in, NULL, NULL, 0, NULL, 0, &out)) + if (!CryptUnprotectData(&in, NULL, NULL, 0, NULL, 0, &out)) { + debug("cannot decrypt data"); goto done; + } } *eblob = malloc(out.cbData); @@ -79,7 +88,8 @@ convert_blob(struct agent_connection* con, const char *blob, DWORD blen, char ** done: if (out.pbData) LocalFree(out.pbData); - RevertToSelf(); + if (con->client_type == OTHER) + RevertToSelf(); return success? 0: -1; } @@ -182,9 +192,11 @@ static int sign_blob(const struct sshkey *pubkey, u_char ** sig, size_t *siglen, (tmpbuf = sshbuf_from(keyblob, keyblob_len)) == NULL) goto done; - if ( sshkey_private_deserialize(tmpbuf, &prikey) != 0 || - sshkey_sign(prikey, sig, siglen, blob, blen, 0) != 0) + if (sshkey_private_deserialize(tmpbuf, &prikey) != 0 || + sshkey_sign(prikey, sig, siglen, blob, blen, 0) != 0) { + debug("cannot sign using retrieved key"); goto done; + } success = 1; @@ -221,6 +233,7 @@ process_sign_request(struct sshbuf* request, struct sshbuf* response, struct age sshbuf_get_string_direct(request, &data, &dlen) != 0 || sshbuf_get_u32(request, &flags) != 0 || sshkey_from_blob(blob, blen, &key) != 0) { + debug("sign request is invalid"); request_invalid = 1; goto done; } @@ -403,6 +416,8 @@ int process_keyagent_request(struct sshbuf* request, struct sshbuf* response, st if ((r = sshbuf_get_u8(request, &type)) != 0) return r; + debug2("process key agent request type %d", type); + switch (type) { case SSH2_AGENTC_ADD_IDENTITY: return process_add_identity(request, response, con);