Decouple key-agent and privileged-agent use in sshd (#173)

PowerShell/Win32-OpenSSH#766
PowerShell/Win32-OpenSSH#783
This commit is contained in:
Manoj Ampalam 2017-06-26 21:57:24 -07:00 committed by GitHub
parent ad17ff1b74
commit f8f5e45f02
23 changed files with 390 additions and 198 deletions

View File

@ -226,38 +226,45 @@ sys_auth_passwd(Authctxt *authctxt, const char *password)
#elif defined(WINDOWS)
/*
* Authenticate on Windows - Pass credentials to ssh-agent and retrieve token
* upon successful authentication
* TODO - password is sent in plain text over IPC. Consider implications.
* Authenticate on Windows - Call LogonUser and retrieve user token
*/
int sys_auth_passwd(Authctxt *authctxt, const char *password)
{
struct sshbuf *msg = NULL;
size_t blen = 0;
DWORD token = 0;
extern int auth_sock;
wchar_t *user_utf16 = NULL, *udom_utf16 = NULL, *pwd_utf16 = NULL, *tmp;
HANDLE token = NULL;
int r = 0;
int ssh_request_reply(int, struct sshbuf *, struct sshbuf *);
msg = sshbuf_new();
if (!msg)
fatal("%s: out of memory", __func__);
if (sshbuf_put_u8(msg, SSH_AGENT_AUTHENTICATE) != 0 ||
sshbuf_put_cstring(msg, PASSWD_AUTH_REQUEST) != 0 ||
sshbuf_put_cstring(msg, authctxt->pw->pw_name) != 0 ||
sshbuf_put_cstring(msg, password) != 0 ||
ssh_request_reply(auth_sock, msg, msg) != 0 ||
sshbuf_get_u32(msg, &token) != 0) {
debug("auth agent did not authorize client %s", authctxt->user);
r = 0;
if ((user_utf16 = utf8_to_utf16(authctxt->pw->pw_name)) == NULL ||
(pwd_utf16 = utf8_to_utf16(password)) == NULL) {
fatal("out of memory");
goto done;
}
authctxt->methoddata = (void*)(INT_PTR)token;
if ((tmp = wcschr(user_utf16, L'@')) != NULL) {
udom_utf16 = tmp + 1;
*tmp = L'\0';
}
if (LogonUserW(user_utf16, udom_utf16, pwd_utf16, LOGON32_LOGON_NETWORK_CLEARTEXT,
LOGON32_PROVIDER_DEFAULT, &token) == FALSE) {
if (GetLastError() == ERROR_PASSWORD_MUST_CHANGE)
/*
* TODO - need to add support to force password change
* by sending back SSH_MSG_USERAUTH_PASSWD_CHANGEREQ
*/
error("password for user %s has expired", authctxt->pw->pw_name);
else
debug("failed to logon user: %ls domain: %ls error:%d", user_utf16, udom_utf16, GetLastError());
goto done;
}
authctxt->auth_token = (void*)(INT_PTR)token;
r = 1;
done:
if (msg)
sshbuf_free(msg);
if (user_utf16)
free(user_utf16);
if (pwd_utf16)
SecureZeroMemory(pwd_utf16, sizeof(wchar_t) * wcslen(pwd_utf16));
return r;
}
#endif /* WINDOWS */

4
auth.h
View File

@ -78,7 +78,9 @@ struct Authctxt {
#endif
Buffer *loginmsg;
void *methoddata;
#ifdef WINDOWS
void *auth_token;
#endif
struct sshkey **prev_userkeys;
u_int nprev_userkeys;
};

View File

@ -200,54 +200,14 @@ userauth_pubkey(struct ssh *ssh)
/* test for correct signature */
authenticated = 0;
#ifdef WINDOWS
/* Pass key challenge material to ssh-agent to retrieve token upon successful authentication */
{
struct sshbuf *msg = NULL;
u_char *blob = NULL;
size_t blen = 0;
DWORD token = 0;
extern int auth_sock;
int r = 0;
int ssh_request_reply(int , struct sshbuf *, struct sshbuf *);
while (1) {
msg = sshbuf_new();
if (!msg)
fatal("%s: out of memory", __func__);
if ((r = sshbuf_put_u8(msg, SSH_AGENT_AUTHENTICATE)) != 0 ||
(r = sshbuf_put_cstring(msg, PUBKEY_AUTH_REQUEST)) != 0 ||
(r = sshkey_to_blob(key, &blob, &blen)) != 0 ||
(r = sshbuf_put_string(msg, blob, blen)) != 0 ||
(r = sshbuf_put_cstring(msg, authctxt->pw->pw_name)) != 0 ||
(r = sshbuf_put_string(msg, sig, slen)) != 0 ||
(r = sshbuf_put_string(msg, sshbuf_ptr(b), sshbuf_len(b))) != 0 ||
(r = ssh_request_reply(auth_sock, msg, msg)) != 0 ||
(r = sshbuf_get_u32(msg, &token)) != 0) {
debug("auth agent did not authorize client %s", authctxt->user);
break;
}
debug3("auth agent authenticated %s", authctxt->user);
break;
}
if (blob)
free(blob);
if (msg)
sshbuf_free(msg);
if (token) {
authenticated = 1;
authctxt->methoddata = (void*)(INT_PTR)token;
}
}
#else /* !WINDOWS */
if (PRIVSEP(user_key_allowed(authctxt->pw, key, 1)) &&
#ifdef WINDOWS
(authctxt->auth_token = mm_auth_pubkey(authctxt->pw->pw_name,
key, sig, slen, b)) != NULL) {
#else
PRIVSEP(sshkey_verify(key, sig, slen, sshbuf_ptr(b),
sshbuf_len(b), ssh->compat)) == 0) {
#endif
authenticated = 1;
/* Record the successful key to prevent reuse */
auth2_record_userkey(authctxt, key);
@ -255,7 +215,6 @@ userauth_pubkey(struct ssh *ssh)
}
sshbuf_free(b);
free(sig);
#endif /* !WINDOWS */
} else {
debug("%s: test whether pkalg/pkblob are acceptable for %s %s",

View File

@ -43,6 +43,7 @@ int ssh_agent_sign(int sock, struct sshkey *key,
const u_char *data, size_t datalen, const char *alg, u_int compat);
/* Messages for the authentication agent connection. */
/* Message Id 0 is reserved */
#define SSH_AGENTC_REQUEST_RSA_IDENTITIES 1
#define SSH_AGENT_RSA_IDENTITIES_ANSWER 2
#define SSH_AGENTC_RSA_CHALLENGE 3
@ -88,12 +89,4 @@ int ssh_agent_sign(int sock, struct sshkey *key,
#define SSH_AGENT_RSA_SHA2_256 0x02
#define SSH_AGENT_RSA_SHA2_512 0x04
/*
* Following are used in Windows implementation
* ssh-agent in Windows also serves user authentication
*/
#define SSH_AGENT_AUTHENTICATE 200
#define PUBKEY_AUTH_REQUEST "pubkey"
#define PASSWD_AUTH_REQUEST "password"
#endif /* AUTHFD_H */

View File

@ -246,6 +246,7 @@
<ClCompile Include="$(OpenSSH-Src-Path)sshlogin.c" />
<ClCompile Include="$(OpenSSH-Src-Path)contrib\win32\win32compat\win32_sshpty.c" />
<ClCompile Include="$(OpenSSH-Src-Path)contrib\win32\win32compat\wmain_sshd.c" />
<ClCompile Include="$(OpenSSH-Src-Path)contrib\win32\win32compat\win32_monitor_wrap.c" />
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="version.rc" />

View File

@ -150,6 +150,9 @@
<ClCompile Include="$(OpenSSH-Src-Path)contrib\win32\win32compat\win32_sshpty.c">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="$(OpenSSH-Src-Path)contrib\win32\win32compat\win32_monitor_wrap.c">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="version.rc">

View File

@ -119,4 +119,5 @@ Subsystem sftp sftp-server.exe
# X11Forwarding no
# AllowTcpForwarding no
# ForceCommand cvs server
# PubkeyAcceptedKeyTypes ssh-ed25519*
# PubkeyAcceptedKeyTypes ssh-ed25519*
hostkeyagent \\.\pipe\openssh-ssh-agent

View File

@ -114,7 +114,6 @@ int
fileio_connect(struct w32_io* pio, char* name)
{
wchar_t* name_w = NULL;
wchar_t pipe_name[PATH_MAX];
HANDLE h = INVALID_HANDLE_VALUE;
int ret = 0, r;
@ -129,16 +128,9 @@ fileio_connect(struct w32_io* pio, char* name)
errno = ENOMEM;
return -1;
}
r = _snwprintf_s(pipe_name, PATH_MAX, PATH_MAX, L"\\\\.\\pipe\\%ls", name_w);
if (r < 0 || r >= PATH_MAX) {
debug3("cannot create pipe name with %s", name);
errno = EOTHER;
return -1;
}
do {
h = CreateFileW(pipe_name, GENERIC_READ | GENERIC_WRITE, 0,
h = CreateFileW(name_w, GENERIC_READ | GENERIC_WRITE, 0,
NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED | SECURITY_SQOS_PRESENT | SECURITY_IDENTIFICATION, NULL);
if (h != INVALID_HANDLE_VALUE)

View File

@ -0,0 +1,8 @@
/*
* Definitions for IPC between sshd and privileged agent
*/
#pragma once
#define SSH_PRIV_AGENT_MSG_ID 0
#define PUBKEY_AUTH_REQUEST "pubkey"
#define LOAD_USER_PROFILE_REQUEST "loadprofile"

View File

@ -16,6 +16,6 @@ int process_request_identities(struct sshbuf*, struct sshbuf*, struct agent_conn
int process_sign_request(struct sshbuf*, struct sshbuf*, struct agent_connection*);
int process_remove_key(struct sshbuf*, struct sshbuf*, struct agent_connection*);
int process_remove_all(struct sshbuf*, struct sshbuf*, struct agent_connection*);
int process_authagent_request(struct sshbuf*, struct sshbuf*, struct agent_connection*);
int process_privagent_request(struct sshbuf*, struct sshbuf*, struct agent_connection*);
/* auth */

View File

@ -37,7 +37,7 @@
static HANDLE ioc_port = NULL;
static BOOL debug_mode = FALSE;
#define AGENT_PIPE_ID L"\\\\.\\pipe\\ssh-agent"
#define AGENT_PIPE_ID L"\\\\.\\pipe\\openssh-ssh-agent"
static HANDLE event_stop_agent;
static OVERLAPPED ol;
@ -168,12 +168,14 @@ agent_cleanup_connection(struct agent_connection* con)
{
debug("connection %p clean up", con);
CloseHandle(con->pipe_handle);
if (con->hProfile)
UnloadUserProfile(con->auth_token, con->hProfile);
if (con->auth_token)
CloseHandle(con->auth_token);
if (con->profile_handle)
UnloadUserProfile(con->profile_token, con->profile_handle);
if (con->profile_token)
CloseHandle(con->profile_token);
if (con->client_impersonation_token)
CloseHandle(con->client_impersonation_token);
if (con->client_process_handle)
CloseHandle(con->client_process_handle);
free(con);
CloseHandle(ioc_port);
ioc_port = NULL;
@ -251,13 +253,13 @@ get_con_client_info(struct agent_connection* con)
DWORD sshd_sid_len = 0;
PSID sshd_sid = NULL;
SID_NAME_USE nuse;
HANDLE client_primary_token = NULL, client_impersonation_token = NULL, client_proc_handle = NULL;
HANDLE client_primary_token = NULL, client_impersonation_token = NULL, client_process_handle = NULL;
TOKEN_USER* info = NULL;
BOOL isMember = FALSE;
if (GetNamedPipeClientProcessId(con->pipe_handle, &client_pid) == FALSE ||
(client_proc_handle = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, client_pid)) == NULL ||
OpenProcessToken(client_proc_handle, TOKEN_QUERY | TOKEN_DUPLICATE, &client_primary_token) == FALSE ||
(client_process_handle = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_DUP_HANDLE, FALSE, client_pid)) == NULL ||
OpenProcessToken(client_process_handle, TOKEN_QUERY | TOKEN_DUPLICATE, &client_primary_token) == FALSE ||
DuplicateToken(client_primary_token, SecurityImpersonation, &client_impersonation_token) == FALSE) {
error("cannot retrieve client impersonatin token");
goto done;
@ -341,15 +343,19 @@ done:
free(ref_dom);
if (info)
free(info);
if (client_proc_handle)
CloseHandle(client_proc_handle);
if (client_primary_token)
CloseHandle(client_primary_token);
if (r == 0)
if (r == 0) {
con->client_process_handle = client_process_handle;
con->client_impersonation_token = client_impersonation_token;
else if (client_impersonation_token)
CloseHandle(client_impersonation_token);
}
else {
if (client_process_handle)
CloseHandle(client_process_handle);
if (client_impersonation_token)
CloseHandle(client_impersonation_token);
}
return r;
}

View File

@ -4,17 +4,18 @@
#include "log.h"
#define MAX_MESSAGE_SIZE 256 * 1024
#define SSH_ROOT L"SOFTWARE\\SSH"
#define SSH_ROOT L"SOFTWARE\\OpenSSH"
#define SSH_AGENT_ROOT SSH_ROOT L"\\Agent"
#define SSH_KEYS_KEY L"Keys"
#define SSH_KEYS_ROOT SSH_ROOT L"\\" SSH_KEYS_KEY
#define SSH_KEYS_ROOT SSH_AGENT_ROOT L"\\" SSH_KEYS_KEY
#define HEADER_SIZE 4
struct agent_connection {
OVERLAPPED ol;
HANDLE pipe_handle;
HANDLE client_impersonation_token;
HANDLE client_impersonation_token;
HANDLE client_process_handle;
struct {
DWORD num_bytes;
DWORD transferred;
@ -36,8 +37,9 @@ struct agent_connection {
SYSTEM, /* client is running as System */
SERVICE, /* client is running as LS or NS */
} client_type;
HANDLE auth_token;
HANDLE hProfile;
/* user profile related members */
HANDLE profile_token;
HANDLE profile_handle;
};
void agent_connection_on_io(struct agent_connection*, DWORD, OVERLAPPED*);

View File

@ -72,6 +72,12 @@ mm_user_key_allowed(struct passwd *pw, Key *k, int i)
return 0;
}
void* mm_auth_pubkey(const char* user_name, const struct sshkey *key,
const u_char *sig, size_t slen, struct sshbuf* b)
{
return NULL;
}
int
kexgex_server(struct ssh * sh) {
return -1;

View File

@ -39,6 +39,7 @@
#include "agent-request.h"
#include "key.h"
#include "inc\utf.h"
#include "..\priv-agent.h"
#pragma warning(push, 3)
@ -83,9 +84,11 @@ done:
}
void
LoadProfile(struct agent_connection* con, wchar_t* user, wchar_t* domain) {
static HANDLE
LoadProfile(HANDLE user_token, wchar_t* user, wchar_t* domain) {
PROFILEINFOW profileInfo;
HANDLE ret = NULL;
profileInfo.dwFlags = PI_NOUI;
profileInfo.lpProfilePath = NULL;
profileInfo.lpUserName = user;
@ -96,12 +99,16 @@ LoadProfile(struct agent_connection* con, wchar_t* user, wchar_t* domain) {
profileInfo.dwSize = sizeof(profileInfo);
EnablePrivilege("SeBackupPrivilege", 1);
EnablePrivilege("SeRestorePrivilege", 1);
if (LoadUserProfileW(con->auth_token, &profileInfo) == FALSE)
if (LoadUserProfileW(user_token, &profileInfo) == FALSE) {
debug("Loading user (%ls,%ls) profile failed ERROR: %d", user, domain, GetLastError());
goto done;
}
else
con->hProfile = profileInfo.hProfile;
ret = profileInfo.hProfile;
done:
EnablePrivilege("SeBackupPrivilege", 0);
EnablePrivilege("SeRestorePrivilege", 0);
return ret;
}
#define MAX_USER_LEN 64
@ -238,73 +245,13 @@ done:
return dup_t;
}
/* TODO - SecureZeroMemory password */
int process_passwordauth_request(struct sshbuf* request, struct sshbuf* response, struct agent_connection* con) {
char *user = NULL, *domain = NULL, *pwd = NULL;
size_t user_len, pwd_len;
wchar_t *user_utf16 = NULL, *udom_utf16 = NULL, *pwd_utf16 = NULL, *tmp;
int r = -1;
HANDLE token = 0, dup_token;
if (sshbuf_get_cstring(request, &user, &user_len) != 0 ||
sshbuf_get_cstring(request, &pwd, &pwd_len) != 0 ||
user_len == 0 ||
pwd_len == 0 ||
user_len > MAX_USER_LEN + MAX_FQDN_LEN ||
pwd_len > MAX_PW_LEN) {
debug("bad password auth request");
goto done;
}
if ((user_utf16 = utf8_to_utf16(user)) == NULL ||
(pwd_utf16 = utf8_to_utf16(pwd)) == NULL) {
debug("out of memory");
goto done;
}
if ((tmp = wcschr(user_utf16, L'@') ) != NULL ) {
udom_utf16 = tmp + 1;
*tmp = L'\0';
}
if (LogonUserW(user_utf16, udom_utf16, pwd_utf16, LOGON32_LOGON_NETWORK_CLEARTEXT, LOGON32_PROVIDER_DEFAULT, &token) == FALSE) {
debug("failed to logon user: %ls domain: %ls", user_utf16, udom_utf16);
goto done;
}
if ((dup_token = duplicate_token_for_client(con, token)) == NULL)
goto done;
if (sshbuf_put_u32(response, (int)(intptr_t)dup_token) != 0)
goto done;
con->auth_token = token;
LoadProfile(con, user_utf16, udom_utf16);
r = 0;
done:
/* TODO Fix this hacky protocol*/
if ((r == -1) && (sshbuf_put_u8(response, SSH_AGENT_FAILURE) == 0))
r = 0;
if (user)
free(user);
if (pwd)
free(pwd);
if (user_utf16)
free(user_utf16);
if (pwd_utf16)
free(pwd_utf16);
return r;
}
int process_pubkeyauth_request(struct sshbuf* request, struct sshbuf* response, struct agent_connection* con) {
int r = -1;
char *key_blob, *user, *sig, *blob;
size_t key_blob_len, user_len, sig_len, blob_len;
struct sshkey *key = NULL;
HANDLE token = NULL, dup_token = NULL;
wchar_t *user_utf16 = NULL, *udom_utf16 = NULL, *tmp;
wchar_t *user_utf16 = NULL;
PWSTR wuser_home = NULL;
@ -346,14 +293,6 @@ int process_pubkeyauth_request(struct sshbuf* request, struct sshbuf* response,
if (sshbuf_put_u32(response, (int)(intptr_t)dup_token) != 0)
goto done;
con->auth_token = token;
token = NULL;
if ((tmp = wcschr(user_utf16, L'@')) != NULL) {
udom_utf16 = tmp + 1;
*tmp = L'\0';
}
LoadProfile(con, user_utf16, udom_utf16);
r = 0;
done:
/* TODO Fix this hacky protocol*/
@ -373,7 +312,60 @@ done:
return r;
}
int process_authagent_request(struct sshbuf* request, struct sshbuf* response, struct agent_connection* con) {
int process_loadprofile_request(struct sshbuf* request, struct sshbuf* response, struct agent_connection* con) {
int r = 0, success = 0;
char *user;
size_t user_len;
u_int32_t user_token_int = 0;
HANDLE user_token = NULL;
wchar_t *user_utf16 = NULL, *dom_utf16 = NULL, *tmp;
/* is profile already loaded */
if (con->profile_handle) {
success = 1;
goto done;
}
if (sshbuf_get_cstring(request, &user, &user_len) != 0 ||
user_len > MAX_USER_LEN ||
sshbuf_get_u32(request, &user_token_int) != 0){
debug("invalid loadprofile request");
goto done;
}
if (DuplicateHandle(con->client_process_handle, (HANDLE)(INT_PTR)user_token_int, GetCurrentProcess(),
&user_token, TOKEN_QUERY | TOKEN_IMPERSONATE | TOKEN_DUPLICATE, FALSE, 0) == FALSE) {
debug("cannot duplicate user token, error: %d", GetLastError());
goto done;
}
if ((user_utf16 = utf8_to_utf16(user)) == NULL) {
debug("out of memory");
goto done;
}
/* split user and domain */
if ((tmp = wcschr(user_utf16, L'@')) != NULL) {
dom_utf16 = tmp + 1;
*tmp = L'\0';
}
if ((con->profile_handle = LoadProfile(user_token, user_utf16, dom_utf16)) == NULL)
goto done;
con->profile_token = user_token;
user_token = NULL;
success = 1;
done:
if (sshbuf_put_u8(response, success ? SSH_AGENT_SUCCESS : SSH_AGENT_FAILURE) != 0)
r = -1;
if (user_token)
CloseHandle(user_token);
return r;
}
int process_privagent_request(struct sshbuf* request, struct sshbuf* response, struct agent_connection* con) {
char *opn;
size_t opn_len;
if (sshbuf_get_string_direct(request, &opn, &opn_len) != 0) {
@ -383,14 +375,14 @@ int process_authagent_request(struct sshbuf* request, struct sshbuf* response, s
/* allow only admins and NT Service\sshd to send auth requests */
if (con->client_type != SSHD_SERVICE && con->client_type != ADMIN_USER) {
error("cannot authenticate: client process is not admin or sshd");
error("cannot process request: client process is not admin or sshd");
return -1;
}
if (memcmp(opn, PUBKEY_AUTH_REQUEST, opn_len) == 0)
return process_pubkeyauth_request(request, response, con);
else if (memcmp(opn, PASSWD_AUTH_REQUEST, opn_len) == 0)
return process_passwordauth_request(request, response, con);
else if (memcmp(opn, LOAD_USER_PROFILE_REQUEST, opn_len) == 0)
return process_loadprofile_request(request, response, con);
else {
debug("unknown auth request: %s", opn);
return -1;

View File

@ -30,6 +30,7 @@
*/
#include "agent.h"
#include "agent-request.h"
#include "..\priv-agent.h"
#pragma warning(push, 3)
@ -168,8 +169,8 @@ process_request(struct agent_connection* con)
case SSH2_AGENTC_REMOVE_ALL_IDENTITIES:
r = process_remove_all(request, response, con);
break;
case SSH_AGENT_AUTHENTICATE:
r = process_authagent_request(request, response, con);
case SSH_PRIV_AGENT_MSG_ID:
r = process_privagent_request(request, response, con);
break;
default:
debug("unknown agent request %d", type);

View File

@ -0,0 +1,214 @@
/*
* Author: Manoj Ampalam <manoj.ampalam@microsoft.com>
* mm_* routines that delegate privileged operations to privileged
* agent.
*
* Copyright (c) 2015 Microsoft Corp.
* All rights reserved
*
* Microsoft openssh win32 port
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "includes.h"
#include <sys/types.h>
#include <sys/un.h>
#include <sys/uio.h>
#include <errno.h>
#include <pwd.h>
#include <signal.h>
#include <stdarg.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#ifdef WITH_OPENSSL
#include <openssl/bn.h>
#include <openssl/dh.h>
#include <openssl/evp.h>
#endif
#include "openbsd-compat/sys-queue.h"
#include "xmalloc.h"
#include "ssh.h"
#ifdef WITH_OPENSSL
#include "dh.h"
#endif
#include "buffer.h"
#include "key.h"
#include "cipher.h"
#include "kex.h"
#include "hostfile.h"
#include "auth.h"
#include "auth-options.h"
#include "packet.h"
#include "mac.h"
#include "log.h"
#include "auth-pam.h"
#include "monitor_wrap.h"
#include "atomicio.h"
#include "monitor_fdpass.h"
#include "misc.h"
#include "uuencode.h"
#include "channels.h"
#include "session.h"
#include "servconf.h"
#include "ssherr.h"
#include "priv-agent.h"
#include "authfd.h"
int priv_agent_sock = -1;
int ssh_request_reply(int, struct sshbuf *, struct sshbuf *);
/*
* Get socket connected to privileged agent
* In Windows, this is implemented within ssh-agent
* that server both as a key-agent (like in Unix) and
* privileged agent.
* This is a temporary accomodation until Windows has
* Unix like privilege separation (monitor and less
* privileged worker)
*/
int get_priv_agent_sock()
{
extern int auth_sock;
char env_value[12]; /* enough to accomodate "ssh-agent"*/
size_t tmp;
if (priv_agent_sock != -1)
return priv_agent_sock;
/* check if auth_sock is populated and connected to "ssh-agent"*/
if (auth_sock != -1 &&
getenv_s(&tmp, env_value, 12, SSH_AUTHSOCKET_ENV_NAME) == 0 &&
strncmp(env_value, "ssh-agent", 12) == 0 )
priv_agent_sock = auth_sock;
else {
struct sockaddr_un sunaddr;
int sock;
memset(&sunaddr, 0, sizeof(sunaddr));
sunaddr.sun_family = AF_UNIX;
strlcpy(sunaddr.sun_path, "\\\\.\\pipe\\openssh-ssh-agent", sizeof(sunaddr.sun_path));
if ((sock = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
debug("%s: unable to create AF_UNIX socket, errno:%d", __func__, errno);
return -1;
}
/* close on exec */
if (fcntl(sock, F_SETFD, FD_CLOEXEC) == -1 ||
connect(sock, (struct sockaddr *)&sunaddr, sizeof(sunaddr)) < 0) {
close(sock);
debug("%s: unable to connect to privileged agent, errno:%d", __func__, errno);
return -1;
}
priv_agent_sock = sock;
}
return priv_agent_sock;
}
void* mm_auth_pubkey(const char* user_name, const struct sshkey *key,
const u_char *sig, size_t slen, struct sshbuf* b)
{
/* Pass key challenge material to privileged agent to retrieve token upon successful authentication */
struct sshbuf *msg = NULL;
u_char *blob = NULL;
size_t blen = 0;
DWORD token = 0;
int agent_fd;
while (1) {
if ((agent_fd = get_priv_agent_sock()) == -1)
break;
msg = sshbuf_new();
if (!msg)
fatal("%s: out of memory", __func__);
if (sshbuf_put_u8(msg, SSH_PRIV_AGENT_MSG_ID) != 0 ||
sshbuf_put_cstring(msg, PUBKEY_AUTH_REQUEST) != 0 ||
sshkey_to_blob(key, &blob, &blen) != 0 ||
sshbuf_put_string(msg, blob, blen) != 0 ||
sshbuf_put_cstring(msg, user_name) != 0 ||
sshbuf_put_string(msg, sig, slen) != 0 ||
sshbuf_put_string(msg, sshbuf_ptr(b), sshbuf_len(b)) != 0 ||
ssh_request_reply(agent_fd, msg, msg) != 0) {
debug("unable to send pubkeyauth request");
break;
}
if (sshbuf_get_u32(msg, &token) != 0)
break;
debug3("%s authenticated via pubkey", user_name);
break;
}
if (blob)
free(blob);
if (msg)
sshbuf_free(msg);
return (void*)(INT_PTR)token;
}
int mm_load_profile(const char* user_name, u_int token)
{
struct sshbuf *msg = NULL;
int agent_fd;
u_char result = 0;
while (1) {
if ((agent_fd = get_priv_agent_sock()) == -1)
break;
msg = sshbuf_new();
if (!msg)
fatal("%s: out of memory", __func__);
if (sshbuf_put_u8(msg, SSH_PRIV_AGENT_MSG_ID) != 0 ||
sshbuf_put_cstring(msg, LOAD_USER_PROFILE_REQUEST) != 0 ||
sshbuf_put_cstring(msg, user_name) != 0 ||
sshbuf_put_u32(msg, token) != 0 ||
ssh_request_reply(agent_fd, msg, msg) != 0) {
debug("unable to send loadprofile request %s", user_name);
break;
}
if (sshbuf_get_u8(msg, &result) != 0 || result == SSH_AGENT_FAILURE) {
debug("agent failed to load profile for user %s", user_name);
break;
}
break;
}
return result;
}

View File

@ -51,7 +51,7 @@ wmain(int argc, wchar_t **wargv) {
}
if (getenv("SSH_AUTH_SOCK") == NULL)
_putenv("SSH_AUTH_SOCK=ssh-agent");
_putenv("SSH_AUTH_SOCK=\\\\.\\pipe\\openssh-ssh-agent");
w32posix_initialize();

View File

@ -108,9 +108,6 @@ int sshd_main(int argc, wchar_t **wargv) {
argv[i] = utf16_to_utf8(wargv[i]);
}
if (getenv("SSH_AUTH_SOCK") == NULL)
_putenv("SSH_AUTH_SOCK=ssh-agent");
w32posix_initialize();
if (getenv("SSHD_REMSOC"))
is_child = 1;

View File

@ -98,4 +98,9 @@ int mm_bsdauth_respond(void *, u_int, char **);
int mm_skey_query(void *, char **, char **, u_int *, char ***, u_int **);
int mm_skey_respond(void *, u_int, char **);
/* Windows specific */
void* mm_auth_pubkey(const char*, const struct sshkey *, const u_char *, size_t,
struct sshbuf*);
int mm_load_profile(const char*, u_int );
#endif /* _MM_WRAP_H_ */

View File

@ -125,4 +125,5 @@ PubkeyAcceptedKeyTypes ssh-ed25519*
#DenyUsers denyuser1 deny*2 denyuse?3,
#AllowUsers allowuser1 allowu*r2 allow?se?3 allowuser4 localuser1 localu*r2 loc?lu?er3 localadmin
#DenyGroups denygroup1 denygr*p2 deny?rou?3
#AllowGroups allowgroup1 allowg*2 allowg?ou?3 Adm*
#AllowGroups allowgroup1 allowg*2 allowg?ou?3 Adm*
hostkeyagent \\.\pipe\openssh-ssh-agent

View File

@ -605,8 +605,9 @@ derelativise_path(const char *path)
return xstrdup("none");
expanded = tilde_expand_filename(path, getuid());
#ifdef WINDOWS
/* Windows absolute paths have a drive letter followed by :*/
if (*expanded != '\0' && expanded[1] == ':')
/* Windows absolute paths - \abc, /abc, c:\abc, c:/abc*/
if (*expanded == '/' || *expanded == '\\' ||
(*expanded != '\0' && expanded[1] == ':'))
#else /* !WINDOWS */
if (*expanded == '/')
#endif /* !WINDOWS */

View File

@ -477,6 +477,9 @@ int do_exec_windows(Session *s, const char *command, int pty) {
*cmd = '\0';
}
/* load user profile */
mm_load_profile(s->pw->pw_name, ((INT_PTR)s->authctxt->auth_token) & 0xffffffff);
/* start the process */
{
memset(&si, 0, sizeof(STARTUPINFO));
@ -492,7 +495,7 @@ int do_exec_windows(Session *s, const char *command, int pty) {
si.hStdError = (HANDLE)w32_fd_to_handle(pipeerr[1]);
si.lpDesktop = NULL;
hToken = s->authctxt->methoddata;
hToken = s->authctxt->auth_token;
debug("Executing command: %s", exec_command);
UTF8_TO_UTF16_FATAL(exec_command_w, exec_command);

4
sshd.c
View File

@ -1765,9 +1765,7 @@ main(int ac, char **av)
error("Could not connect to agent \"%s\": %s",
options.host_key_agent, ssh_err(r));
}
#ifdef WINDOWS /* Windows version always needs and has agent running */
have_agent = 1;
#endif
for (i = 0; i < options.num_host_key_files; i++) {
if (options.host_key_files[i] == NULL)
continue;