mirror of
git://git.gnupg.org/gnupg.git
synced 2025-01-03 12:11:33 +01:00
ssh: Add support for Putty.
* agent/gpg-agent.c [W32]: Include Several Windows header. (opts): Change help text for enable-ssh-support. (opts, main): Add option --enable-putty-support (putty_support, PUTTY_IPC_MAGIC, PUTTY_IPC_MAXLEN): New for W32. (agent_init_default_ctrl): Add and asssert call. (putty_message_proc, putty_message_thread): New. (handle_connections) [W32]: Start putty message thread. * common/sysutils.c (w32_get_user_sid): New for W32 only * tools/gpgconf-comp.c (gc_options_gpg_agent): Add --enable-ssh-support and --enable-putty-support. Make the configuration group visible at basic level. * agent/command-ssh.c (serve_mmapped_ssh_request): New for W32 only. -- This patch enables support for Putty. It has been tested with Putty 0.62 using an Unix created ssh key copied to the private-keys-v1.d directory on Windows and with a manually crafted sshcontrol file. It also works with a smartcard key. May thanks to gniibe who implemented a proxy in Python to test the putty/gpg-agent communication. Signed-off-by: Werner Koch <wk@gnupg.org> (cherry picked from commit 9f32499f99a0817f63f7a73b09bdcebe60d4775d) Resolved conflicts: NEWS agent/agent.h agent/gpg-agent.c: Convert from pth to npth. common/sysutils.c common/sysutils.h
This commit is contained in:
parent
179012ddd4
commit
5105c8d2d3
3
NEWS
3
NEWS
@ -6,6 +6,9 @@ Noteworthy changes in version 2.1.0-betaN (unreleased)
|
||||
|
||||
* The GNU Pth library has been replaced by the new nPth library.
|
||||
|
||||
* New option --enable-putty-support to allow gpg-agent to act as a
|
||||
Pageant replacement including full smartcard support.
|
||||
|
||||
* Removed support for the original HKP keyserver which is not anymore
|
||||
used by any site.
|
||||
|
||||
|
@ -293,6 +293,11 @@ gpg_error_t pinentry_loopback(ctrl_t, const char *keyword,
|
||||
unsigned char **buffer, size_t *size,
|
||||
size_t max_length);
|
||||
|
||||
#ifdef HAVE_W32_SYSTEM
|
||||
int serve_mmapped_ssh_request (ctrl_t ctrl,
|
||||
unsigned char *request, size_t maxreqlen);
|
||||
#endif /*HAVE_W32_SYSTEM*/
|
||||
|
||||
/*-- command-ssh.c --*/
|
||||
ssh_control_file_t ssh_open_control_file (void);
|
||||
void ssh_close_control_file (ssh_control_file_t cf);
|
||||
|
@ -3443,3 +3443,149 @@ start_command_handler_ssh (ctrl_t ctrl, gnupg_fd_t sock_client)
|
||||
if (stream_sock)
|
||||
es_fclose (stream_sock);
|
||||
}
|
||||
|
||||
|
||||
#ifdef HAVE_W32_SYSTEM
|
||||
/* Serve one ssh-agent request. This is used for the Putty support.
|
||||
REQUEST is the the mmapped memory which may be accessed up to a
|
||||
length of MAXREQLEN. Returns 0 on success which also indicates
|
||||
that a valid SSH response message is now in REQUEST. */
|
||||
int
|
||||
serve_mmapped_ssh_request (ctrl_t ctrl,
|
||||
unsigned char *request, size_t maxreqlen)
|
||||
{
|
||||
gpg_error_t err;
|
||||
int send_err = 0;
|
||||
int valid_response = 0;
|
||||
ssh_request_spec_t *spec;
|
||||
u32 msglen;
|
||||
estream_t request_stream, response_stream;
|
||||
|
||||
if (setup_ssh_env (ctrl))
|
||||
goto leave; /* Error setting up the environment. */
|
||||
|
||||
if (maxreqlen < 5)
|
||||
goto leave; /* Caller error. */
|
||||
|
||||
msglen = uint32_construct (request[0], request[1], request[2], request[3]);
|
||||
if (msglen < 1 || msglen > maxreqlen - 4)
|
||||
{
|
||||
log_error ("ssh message len (%u) out of range", (unsigned int)msglen);
|
||||
goto leave;
|
||||
}
|
||||
|
||||
spec = request_spec_lookup (request[4]);
|
||||
if (!spec)
|
||||
{
|
||||
send_err = 1; /* Unknown request type. */
|
||||
goto leave;
|
||||
}
|
||||
|
||||
/* Create a stream object with the data part of the request. */
|
||||
if (spec->secret_input)
|
||||
request_stream = es_mopen (NULL, 0, 0, 1, realloc_secure, gcry_free, "r+");
|
||||
else
|
||||
request_stream = es_mopen (NULL, 0, 0, 1, gcry_realloc, gcry_free, "r+");
|
||||
if (!request_stream)
|
||||
{
|
||||
err = gpg_error_from_syserror ();
|
||||
goto leave;
|
||||
}
|
||||
/* We have to disable the estream buffering, because the estream
|
||||
core doesn't know about secure memory. */
|
||||
if (es_setvbuf (request_stream, NULL, _IONBF, 0))
|
||||
{
|
||||
err = gpg_error_from_syserror ();
|
||||
goto leave;
|
||||
}
|
||||
/* Copy the request to the stream but omit the request type. */
|
||||
err = stream_write_data (request_stream, request + 5, msglen - 1);
|
||||
if (err)
|
||||
goto leave;
|
||||
es_rewind (request_stream);
|
||||
|
||||
response_stream = es_fopenmem (0, "r+b");
|
||||
if (!response_stream)
|
||||
{
|
||||
err = gpg_error_from_syserror ();
|
||||
goto leave;
|
||||
}
|
||||
|
||||
if (opt.verbose)
|
||||
log_info ("ssh request handler for %s (%u) started\n",
|
||||
spec->identifier, spec->type);
|
||||
|
||||
err = (*spec->handler) (ctrl, request_stream, response_stream);
|
||||
|
||||
if (opt.verbose)
|
||||
{
|
||||
if (err)
|
||||
log_info ("ssh request handler for %s (%u) failed: %s\n",
|
||||
spec->identifier, spec->type, gpg_strerror (err));
|
||||
else
|
||||
log_info ("ssh request handler for %s (%u) ready\n",
|
||||
spec->identifier, spec->type);
|
||||
}
|
||||
|
||||
es_fclose (request_stream);
|
||||
request_stream = NULL;
|
||||
|
||||
if (err)
|
||||
{
|
||||
send_err = 1;
|
||||
goto leave;
|
||||
}
|
||||
|
||||
/* Put the response back into the mmapped buffer. */
|
||||
{
|
||||
void *response_data;
|
||||
size_t response_size;
|
||||
|
||||
/* NB: In contrast to the request-stream, the response stream
|
||||
includes the the message type byte. */
|
||||
if (es_fclose_snatch (response_stream, &response_data, &response_size))
|
||||
{
|
||||
log_error ("snatching ssh response failed: %s",
|
||||
gpg_strerror (gpg_error_from_syserror ()));
|
||||
send_err = 1; /* Ooops. */
|
||||
goto leave;
|
||||
}
|
||||
|
||||
if (opt.verbose > 1)
|
||||
log_info ("sending ssh response of length %u\n",
|
||||
(unsigned int)response_size);
|
||||
if (response_size > maxreqlen - 4)
|
||||
{
|
||||
log_error ("invalid length of the ssh response: %s",
|
||||
gpg_strerror (GPG_ERR_INTERNAL));
|
||||
es_free (response_data);
|
||||
send_err = 1;
|
||||
goto leave;
|
||||
}
|
||||
|
||||
request[0] = response_size >> 24;
|
||||
request[1] = response_size >> 16;
|
||||
request[2] = response_size >> 8;
|
||||
request[3] = response_size >> 0;
|
||||
memcpy (request+4, response_data, response_size);
|
||||
es_free (response_data);
|
||||
valid_response = 1;
|
||||
}
|
||||
|
||||
leave:
|
||||
if (send_err)
|
||||
{
|
||||
request[0] = 0;
|
||||
request[1] = 0;
|
||||
request[2] = 0;
|
||||
request[3] = 1;
|
||||
request[4] = SSH_RESPONSE_FAILURE;
|
||||
valid_response = 1;
|
||||
}
|
||||
|
||||
/* Reset the SCD in case it has been used. */
|
||||
agent_reset_scd (ctrl);
|
||||
|
||||
return valid_response? 0 : -1;
|
||||
}
|
||||
#endif /*HAVE_W32_SYSTEM*/
|
||||
|
@ -1,6 +1,7 @@
|
||||
/* gpg-agent.c - The GnuPG Agent
|
||||
* Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2009,
|
||||
* 2010 Free Software Foundation, Inc.
|
||||
* Copyright (C) 2013 Werner Koch
|
||||
*
|
||||
* This file is part of GnuPG.
|
||||
*
|
||||
@ -30,7 +31,16 @@
|
||||
#include <time.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/stat.h>
|
||||
#ifndef HAVE_W32_SYSTEM
|
||||
#ifdef HAVE_W32_SYSTEM
|
||||
# ifndef WINVER
|
||||
# define WINVER 0x0500 /* Same as in common/sysutils.c */
|
||||
# endif
|
||||
# ifdef HAVE_WINSOCK2_H
|
||||
# include <winsock2.h>
|
||||
# endif
|
||||
# include <aclapi.h>
|
||||
# include <sddl.h>
|
||||
#else /*!HAVE_W32_SYSTEM*/
|
||||
# include <sys/socket.h>
|
||||
# include <sys/un.h>
|
||||
#endif /*!HAVE_W32_SYSTEM*/
|
||||
@ -111,6 +121,7 @@ enum cmd_and_opt_values
|
||||
oKeepTTY,
|
||||
oKeepDISPLAY,
|
||||
oSSHSupport,
|
||||
oPuttySupport,
|
||||
oDisableScdaemon,
|
||||
oDisableCheckOwnSocket,
|
||||
oWriteEnvFile
|
||||
@ -186,7 +197,14 @@ static ARGPARSE_OPTS opts[] = {
|
||||
N_("allow presetting passphrase")},
|
||||
{ oAllowLoopbackPinentry, "allow-loopback-pinentry", 0,
|
||||
N_("allow presetting passphrase")},
|
||||
{ oSSHSupport, "enable-ssh-support", 0, N_("enable ssh-agent emulation") },
|
||||
{ oSSHSupport, "enable-ssh-support", 0, N_("enable ssh support") },
|
||||
{ oPuttySupport, "enable-putty-support", 0,
|
||||
#ifdef HAVE_W32_SYSTEM
|
||||
N_("enable putty support")
|
||||
#else
|
||||
"@"
|
||||
#endif
|
||||
},
|
||||
{ oWriteEnvFile, "write-env-file", 2|8,
|
||||
N_("|FILE|write environment settings also to FILE")},
|
||||
{0}
|
||||
@ -218,6 +236,17 @@ static ARGPARSE_OPTS opts[] = {
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef HAVE_W32_SYSTEM
|
||||
/* Flag indicating that support for Putty has been enabled. */
|
||||
static int putty_support;
|
||||
/* A magic value used with WM_COPYDATA. */
|
||||
#define PUTTY_IPC_MAGIC 0x804e50ba
|
||||
/* To avoid surprises we limit the size of the mapped IPC file to this
|
||||
value. Putty currently (0.62) uses 8k, thus 16k should be enough
|
||||
for the foreseeable future. */
|
||||
#define PUTTY_IPC_MAXLEN 16384
|
||||
#endif /*HAVE_W32_SYSTEM*/
|
||||
|
||||
/* The list of open file descriptors at startup. Note that this list
|
||||
has been allocated using the standard malloc. */
|
||||
static int *startup_fd_list;
|
||||
@ -815,6 +844,13 @@ main (int argc, char **argv )
|
||||
case oKeepDISPLAY: opt.keep_display = 1; break;
|
||||
|
||||
case oSSHSupport: opt.ssh_support = 1; break;
|
||||
case oPuttySupport:
|
||||
# ifdef HAVE_W32_SYSTEM
|
||||
putty_support = 1;
|
||||
opt.ssh_support = 1;
|
||||
# endif
|
||||
break;
|
||||
|
||||
case oWriteEnvFile:
|
||||
if (pargs.r_type)
|
||||
env_file_name = pargs.r.ret_str;
|
||||
@ -976,6 +1012,11 @@ main (int argc, char **argv )
|
||||
GC_OPT_FLAG_NONE|GC_OPT_FLAG_RUNTIME);
|
||||
es_printf ("disable-scdaemon:%lu:\n",
|
||||
GC_OPT_FLAG_NONE|GC_OPT_FLAG_RUNTIME);
|
||||
#ifdef HAVE_W32_SYSTEM
|
||||
es_printf ("enable-putty-support:%lu:\n", GC_OPT_FLAG_NONE);
|
||||
#else
|
||||
es_printf ("enable-ssh-support:%lu:\n", GC_OPT_FLAG_NONE);
|
||||
#endif
|
||||
|
||||
agent_exit (0);
|
||||
}
|
||||
@ -1311,6 +1352,8 @@ agent_exit (int rc)
|
||||
static void
|
||||
agent_init_default_ctrl (ctrl_t ctrl)
|
||||
{
|
||||
assert (ctrl->session_env);
|
||||
|
||||
/* Note we ignore malloc errors because we can't do much about it
|
||||
and the request will fail anyway shortly after this
|
||||
initialization. */
|
||||
@ -1328,7 +1371,6 @@ agent_init_default_ctrl (ctrl_t ctrl)
|
||||
xfree (ctrl->lc_messages);
|
||||
ctrl->lc_messages = default_lc_messages? xtrystrdup (default_lc_messages)
|
||||
/**/ : NULL;
|
||||
|
||||
ctrl->cache_ttl_opt_preset = CACHE_TTL_OPT_PRESET;
|
||||
}
|
||||
|
||||
@ -1820,6 +1862,196 @@ check_nonce (ctrl_t ctrl, assuan_sock_nonce_t *nonce)
|
||||
}
|
||||
|
||||
|
||||
#ifdef HAVE_W32_SYSTEM
|
||||
/* The window message processing function for Putty. Warning: This
|
||||
code runs as a native Windows thread. Use of our own functions
|
||||
needs to be bracket with pth_leave/pth_enter. */
|
||||
static LRESULT CALLBACK
|
||||
putty_message_proc (HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
|
||||
{
|
||||
int ret = 0;
|
||||
int w32rc;
|
||||
COPYDATASTRUCT *cds;
|
||||
const char *mapfile;
|
||||
HANDLE maphd;
|
||||
PSID mysid = NULL;
|
||||
PSID mapsid = NULL;
|
||||
void *data = NULL;
|
||||
PSECURITY_DESCRIPTOR psd = NULL;
|
||||
ctrl_t ctrl = NULL;
|
||||
|
||||
if (msg != WM_COPYDATA)
|
||||
{
|
||||
return DefWindowProc (hwnd, msg, wparam, lparam);
|
||||
}
|
||||
|
||||
cds = (COPYDATASTRUCT*)lparam;
|
||||
if (cds->dwData != PUTTY_IPC_MAGIC)
|
||||
return 0; /* Ignore data with the wrong magic. */
|
||||
mapfile = cds->lpData;
|
||||
if (!cds->cbData || mapfile[cds->cbData - 1])
|
||||
return 0; /* Ignore empty and non-properly terminated strings. */
|
||||
|
||||
if (DBG_ASSUAN)
|
||||
{
|
||||
npth_protect ();
|
||||
log_debug ("ssh map file '%s'", mapfile);
|
||||
npth_unprotect ();
|
||||
}
|
||||
|
||||
maphd = OpenFileMapping (FILE_MAP_ALL_ACCESS, FALSE, mapfile);
|
||||
if (DBG_ASSUAN)
|
||||
{
|
||||
npth_protect ();
|
||||
log_debug ("ssh map handle %p\n", maphd);
|
||||
npth_unprotect ();
|
||||
}
|
||||
|
||||
if (!maphd || maphd == INVALID_HANDLE_VALUE)
|
||||
return 0;
|
||||
|
||||
npth_protect ();
|
||||
|
||||
mysid = w32_get_user_sid ();
|
||||
if (!mysid)
|
||||
{
|
||||
log_error ("error getting my sid\n");
|
||||
goto leave;
|
||||
}
|
||||
|
||||
w32rc = GetSecurityInfo (maphd, SE_KERNEL_OBJECT,
|
||||
OWNER_SECURITY_INFORMATION,
|
||||
&mapsid, NULL, NULL, NULL,
|
||||
&psd);
|
||||
if (w32rc)
|
||||
{
|
||||
log_error ("error getting sid of ssh map file: rc=%d", w32rc);
|
||||
goto leave;
|
||||
}
|
||||
|
||||
if (DBG_ASSUAN)
|
||||
{
|
||||
char *sidstr;
|
||||
|
||||
if (!ConvertSidToStringSid (mysid, &sidstr))
|
||||
sidstr = NULL;
|
||||
log_debug (" my sid: '%s'", sidstr? sidstr: "[error]");
|
||||
LocalFree (sidstr);
|
||||
if (!ConvertSidToStringSid (mapsid, &sidstr))
|
||||
sidstr = NULL;
|
||||
log_debug ("ssh map file sid: '%s'", sidstr? sidstr: "[error]");
|
||||
LocalFree (sidstr);
|
||||
}
|
||||
|
||||
if (!EqualSid (mysid, mapsid))
|
||||
{
|
||||
log_error ("ssh map file has a non-matching sid\n");
|
||||
goto leave;
|
||||
}
|
||||
|
||||
data = MapViewOfFile (maphd, FILE_MAP_ALL_ACCESS, 0, 0, 0);
|
||||
if (DBG_ASSUAN)
|
||||
log_debug ("ssh IPC buffer at %p\n", data);
|
||||
if (!data)
|
||||
goto leave;
|
||||
|
||||
/* log_printhex ("request:", data, 20); */
|
||||
|
||||
ctrl = xtrycalloc (1, sizeof *ctrl);
|
||||
if (!ctrl)
|
||||
{
|
||||
log_error ("error allocating connection control data: %s\n",
|
||||
strerror (errno) );
|
||||
goto leave;
|
||||
}
|
||||
ctrl->session_env = session_env_new ();
|
||||
if (!ctrl->session_env)
|
||||
{
|
||||
log_error ("error allocating session environment block: %s\n",
|
||||
strerror (errno) );
|
||||
goto leave;
|
||||
}
|
||||
|
||||
agent_init_default_ctrl (ctrl);
|
||||
if (!serve_mmapped_ssh_request (ctrl, data, PUTTY_IPC_MAXLEN))
|
||||
ret = 1; /* Valid ssh message has been constructed. */
|
||||
agent_deinit_default_ctrl (ctrl);
|
||||
/* log_printhex (" reply:", data, 20); */
|
||||
|
||||
leave:
|
||||
xfree (ctrl);
|
||||
if (data)
|
||||
UnmapViewOfFile (data);
|
||||
xfree (mapsid);
|
||||
if (psd)
|
||||
LocalFree (psd);
|
||||
xfree (mysid);
|
||||
CloseHandle (maphd);
|
||||
|
||||
npth_unprotect ();
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif /*HAVE_W32_SYSTEM*/
|
||||
|
||||
|
||||
#ifdef HAVE_W32_SYSTEM
|
||||
/* The thread handling Putty's IPC requests. */
|
||||
static void *
|
||||
putty_message_thread (void *arg)
|
||||
{
|
||||
WNDCLASS wndwclass = {0, putty_message_proc, 0, 0,
|
||||
NULL, NULL, NULL, NULL, NULL, "Pageant"};
|
||||
HWND hwnd;
|
||||
MSG msg;
|
||||
|
||||
(void)arg;
|
||||
|
||||
if (opt.verbose)
|
||||
log_info ("putty message loop thread started\n");
|
||||
|
||||
/* The message loop runs as thread independent from our nPth system.
|
||||
This also means that we need to make sure that we switch back to
|
||||
our system before calling any no-windows function. */
|
||||
npth_unprotect ();
|
||||
|
||||
/* First create a window to make sure that a message queue exists
|
||||
for this thread. */
|
||||
if (!RegisterClass (&wndwclass))
|
||||
{
|
||||
npth_protect ();
|
||||
log_error ("error registering Pageant window class");
|
||||
return NULL;
|
||||
}
|
||||
hwnd = CreateWindowEx (0, "Pageant", "Pageant", 0,
|
||||
0, 0, 0, 0,
|
||||
HWND_MESSAGE, /* hWndParent */
|
||||
NULL, /* hWndMenu */
|
||||
NULL, /* hInstance */
|
||||
NULL); /* lpParm */
|
||||
if (!hwnd)
|
||||
{
|
||||
npth_protect ();
|
||||
log_error ("error creating Pageant window");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
while (GetMessage(&msg, NULL, 0, 0))
|
||||
{
|
||||
TranslateMessage(&msg);
|
||||
DispatchMessage(&msg);
|
||||
}
|
||||
|
||||
/* Back to nPth. */
|
||||
npth_protect ();
|
||||
|
||||
if (opt.verbose)
|
||||
log_info ("putty message loop thread stopped\n");
|
||||
return NULL;
|
||||
}
|
||||
#endif /*HAVE_W32_SYSTEM*/
|
||||
|
||||
|
||||
/* This is the standard connection thread's main function. */
|
||||
static void *
|
||||
start_connection_thread (void *arg)
|
||||
@ -1920,6 +2152,22 @@ handle_connections (gnupg_fd_t listen_fd, gnupg_fd_t listen_fd_ssh)
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/* On Windows we need to fire up a separate thread to listen for
|
||||
requests from Putty (an SSH client), so we can replace Putty's
|
||||
Pageant (its ssh-agent implementation). */
|
||||
#ifdef HAVE_W32_SYSTEM
|
||||
if (putty_support)
|
||||
{
|
||||
npth_t thread;
|
||||
|
||||
ret = npth_create (&thread, &tattr, putty_message_thread, NULL);
|
||||
if (ret)
|
||||
{
|
||||
log_error ("error spawning putty message loop: %s\n", strerror (ret));
|
||||
}
|
||||
}
|
||||
#endif /*HAVE_W32_SYSTEM*/
|
||||
|
||||
/* Set a flag to tell call-scd.c that it may enable event
|
||||
notifications. */
|
||||
opt.sigusr2_enabled = 1;
|
||||
|
@ -1,6 +1,7 @@
|
||||
/* sysutils.c - system helpers
|
||||
* Copyright (C) 1998, 1999, 2000, 2001, 2003, 2004,
|
||||
* 2007, 2008 Free Software Foundation, Inc.
|
||||
* Copyright (C) 2013 Werner Koch
|
||||
*
|
||||
* This file is part of GnuPG.
|
||||
*
|
||||
@ -688,3 +689,59 @@ _gnupg_getenv (const char *name)
|
||||
}
|
||||
|
||||
#endif /*HAVE_W32CE_SYSTEM*/
|
||||
|
||||
|
||||
#ifdef HAVE_W32_SYSTEM
|
||||
/* Return the user's security identifier from the current process. */
|
||||
PSID
|
||||
w32_get_user_sid (void)
|
||||
{
|
||||
int okay = 0;
|
||||
HANDLE proc = NULL;
|
||||
HANDLE token = NULL;
|
||||
TOKEN_USER *user = NULL;
|
||||
PSID sid = NULL;
|
||||
DWORD tokenlen, sidlen;
|
||||
|
||||
proc = OpenProcess (PROCESS_QUERY_INFORMATION, FALSE, GetCurrentProcessId());
|
||||
if (!proc)
|
||||
goto leave;
|
||||
|
||||
if (!OpenProcessToken (proc, TOKEN_QUERY, &token))
|
||||
goto leave;
|
||||
|
||||
if (!GetTokenInformation (token, TokenUser, NULL, 0, &tokenlen)
|
||||
&& GetLastError() != ERROR_INSUFFICIENT_BUFFER)
|
||||
goto leave;
|
||||
|
||||
user = xtrymalloc (tokenlen);
|
||||
if (!user)
|
||||
goto leave;
|
||||
|
||||
if (!GetTokenInformation (token, TokenUser, user, tokenlen, &tokenlen))
|
||||
goto leave;
|
||||
if (!IsValidSid (user->User.Sid))
|
||||
goto leave;
|
||||
sidlen = GetLengthSid (user->User.Sid);
|
||||
sid = xtrymalloc (sidlen);
|
||||
if (!sid)
|
||||
goto leave;
|
||||
if (!CopySid (sidlen, sid, user->User.Sid))
|
||||
goto leave;
|
||||
okay = 1;
|
||||
|
||||
leave:
|
||||
xfree (user);
|
||||
if (token)
|
||||
CloseHandle (token);
|
||||
if (proc)
|
||||
CloseHandle (proc);
|
||||
|
||||
if (!okay)
|
||||
{
|
||||
xfree (sid);
|
||||
sid = NULL;
|
||||
}
|
||||
return sid;
|
||||
}
|
||||
#endif /*HAVE_W32_SYSTEM*/
|
||||
|
@ -65,6 +65,7 @@ int gnupg_setenv (const char *name, const char *value, int overwrite);
|
||||
int gnupg_unsetenv (const char *name);
|
||||
|
||||
#ifdef HAVE_W32_SYSTEM
|
||||
void *w32_get_user_sid (void);
|
||||
|
||||
#include "../common/w32help.h"
|
||||
|
||||
|
@ -492,7 +492,7 @@ static gc_option_t gc_options_gpg_agent[] =
|
||||
GC_ARG_TYPE_NONE, GC_BACKEND_GPG_AGENT },
|
||||
|
||||
{ "Configuration",
|
||||
GC_OPT_FLAG_GROUP, GC_LEVEL_EXPERT,
|
||||
GC_OPT_FLAG_GROUP, GC_LEVEL_BASIC,
|
||||
"gnupg", N_("Options controlling the configuration") },
|
||||
{ "options", GC_OPT_FLAG_NONE, GC_LEVEL_EXPERT,
|
||||
"gnupg", "|FILE|read options from FILE",
|
||||
@ -500,6 +500,12 @@ static gc_option_t gc_options_gpg_agent[] =
|
||||
{ "disable-scdaemon", GC_OPT_FLAG_NONE, GC_LEVEL_ADVANCED,
|
||||
"gnupg", "do not use the SCdaemon",
|
||||
GC_ARG_TYPE_NONE, GC_BACKEND_GPG_AGENT },
|
||||
{ "enable-ssh-support", GC_OPT_FLAG_NONE, GC_LEVEL_BASIC,
|
||||
"gnupg", "enable ssh support",
|
||||
GC_ARG_TYPE_NONE, GC_BACKEND_GPG_AGENT },
|
||||
{ "enable-putty-support", GC_OPT_FLAG_NONE, GC_LEVEL_BASIC,
|
||||
"gnupg", "enable putty support",
|
||||
GC_ARG_TYPE_NONE, GC_BACKEND_GPG_AGENT },
|
||||
|
||||
{ "Debug",
|
||||
GC_OPT_FLAG_GROUP, GC_LEVEL_ADVANCED,
|
||||
|
Loading…
x
Reference in New Issue
Block a user