summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--p11-kit/Makefile.am9
-rw-r--r--p11-kit/server.c541
2 files changed, 511 insertions, 39 deletions
diff --git a/p11-kit/Makefile.am b/p11-kit/Makefile.am
index 6496e8d..573bf61 100644
--- a/p11-kit/Makefile.am
+++ b/p11-kit/Makefile.am
@@ -174,19 +174,24 @@ p11_kit_remote_LDADD = \
libp11-kit.la \
$(NULL)
-if !OS_WIN32
private_PROGRAMS += p11-kit-server
p11_kit_server_SOURCES = \
p11-kit/server.c \
$(NULL)
+if OS_WIN32
+ WIN32_LIBS = -ladvapi32
+else
+ WIN32_LIBS =
+endif
+
p11_kit_server_LDADD = \
libp11-tool.la \
libp11-common.la \
libp11-kit.la \
+ $(WIN32_LIBS) \
$(NULL)
-endif
# Tests ----------------------------------------------------------------
diff --git a/p11-kit/server.c b/p11-kit/server.c
index ce7900a..5eb5bcd 100644
--- a/p11-kit/server.c
+++ b/p11-kit/server.c
@@ -40,18 +40,21 @@
#include "path.h"
#include "p11-kit.h"
#include "remote.h"
-#include "unix-peer.h"
#include "tool.h"
#include <assert.h>
#include <errno.h>
#include <fcntl.h>
-#include <grp.h>
-#include <pwd.h>
-#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+
+#ifdef OS_UNIX
+
+#include "unix-peer.h"
+#include <grp.h>
+#include <pwd.h>
+#include <signal.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/un.h>
@@ -69,10 +72,7 @@ typedef void (*sighandler_t)(int);
#define SIGHANDLER_T sighandler_t
#endif
-static bool need_children_cleanup = false;
-static bool terminate = false;
-static unsigned children_avail = 0;
-static bool quiet = false;
+#endif /* OS_UNIX */
typedef struct {
const char **tokens;
@@ -80,12 +80,88 @@ typedef struct {
const char *provider;
const char *socket_name;
+
+#ifdef OS_UNIX
uid_t uid;
gid_t gid;
int socket;
+#endif /* OS_UNIX */
+
+#ifdef OS_WIN32
+ CK_FUNCTION_LIST *module;
+#endif /* OS_WIN32 */
} Server;
+static void
+server_free (Server *server)
+{
+ if (server == NULL)
+ return;
+
+#ifdef OS_UNIX
+ if (server->socket >= 0)
+ close (server->socket);
+#endif /* OS_UNIX */
+
+#ifdef OS_WIN32
+ if (server->module)
+ p11_kit_module_release (server->module);
+#endif /* OS_WIN32 */
+
+ free (server);
+}
+
+static Server *
+server_new (const char **tokens, size_t n_tokens, const char *provider,
+ const char *socket_name)
+{
+ Server *server;
+
+ return_val_if_fail (tokens, NULL);
+ return_val_if_fail (n_tokens > 0, NULL);
+ return_val_if_fail (socket_name, NULL);
+
+ server = calloc (1, sizeof (Server));
+
+ if (server == NULL)
+ return NULL;
+
+ server->tokens = tokens;
+ server->n_tokens = n_tokens;
+ server->provider = provider;
+ server->socket_name = socket_name;
+
+#ifdef OS_UNIX
+ server->socket = -1;
+#endif /* OS_UNIX */
+
+#ifdef OS_WIN32
+ /* On Windows, we need to load module by ourselves as we don't
+ * launch "p11-kit remote" */
+ if (strncmp (tokens[0], "pkcs11:", 7) == 0) {
+ if (server->provider) {
+ server->module = p11_kit_module_load (server->provider, 0);
+ if (server->module == NULL)
+ return NULL;
+ }
+ } else {
+ server->module = p11_kit_module_load (tokens[0], 0);
+ if (server->module == NULL)
+ return NULL;
+ }
+#endif /* OS_WIN32 */
+
+ return server;
+}
+
+#ifdef OS_UNIX
+
+static bool need_children_cleanup = false;
+static bool terminate = false;
+static unsigned children_avail = 0;
+static bool quiet = false;
+
static SIGHANDLER_T
ocsignal (int signum, SIGHANDLER_T handler)
{
@@ -240,35 +316,6 @@ check_credentials (int fd,
return true;
}
-static void
-server_free (Server *server)
-{
- if (server == NULL)
- return;
- if (server->socket >= 0)
- close (server->socket);
- free (server);
-}
-
-static Server *
-server_new (const char **tokens, size_t n_tokens, const char *provider,
- const char *socket_name)
-{
- Server *server;
-
- server = calloc (1, sizeof (Server));
-
- if (server == NULL)
- return NULL;
-
- server->tokens = tokens;
- server->n_tokens = n_tokens;
- server->socket_name = socket_name;
- server->socket = -1;
-
- return server;
-}
-
static int
server_loop (Server *server,
bool foreground,
@@ -637,3 +684,423 @@ main (int argc,
return ret;
}
+
+#endif /* OS_UNIX */
+
+#ifdef OS_WIN32
+
+#include <aclapi.h>
+#include <io.h>
+#include <process.h>
+#include <windows.h>
+
+#define BUFSIZE 4096
+
+static bool quiet = false;
+
+struct ThreadData {
+ HANDLE handle;
+ Server *server;
+};
+
+static DWORD WINAPI
+server_thread (LPVOID lpvParam)
+{
+ struct ThreadData *data = lpvParam;
+ Server *server = data->server;
+ int fd;
+
+ fd = _open_osfhandle ((intptr_t) data->handle, _O_BINARY);
+ if (fd < 0) {
+ free (data);
+ return 1;
+ }
+
+ if (server->module != NULL && server->provider == NULL) {
+ p11_kit_remote_serve_module (server->module, fd, fd);
+ } else {
+ p11_kit_remote_serve_tokens ((const char **)server->tokens,
+ server->n_tokens,
+ server->module,
+ fd, fd);
+ }
+
+ free (data);
+ _close (fd);
+ return 1;
+}
+
+static bool
+make_private_security_descriptor (DWORD permissions,
+ PSECURITY_DESCRIPTOR *psd,
+ PACL *acl);
+
+static int
+server_loop (Server *server)
+{
+ HANDLE hpipe, hthread;
+ BOOL connected = FALSE;
+ DWORD thread_id = 0;
+ SECURITY_ATTRIBUTES sa;
+ PACL acl;
+ struct ThreadData *data;
+
+ memset (&sa, 0, sizeof (SECURITY_ATTRIBUTES));
+ sa.nLength = sizeof (sa);
+ sa.bInheritHandle = FALSE;
+
+ if (!make_private_security_descriptor (GENERIC_READ | GENERIC_WRITE,
+ &sa.lpSecurityDescriptor,
+ &acl))
+ return 1;
+
+ if (!quiet) {
+ char *path;
+
+ path = p11_path_encode (server->socket_name);
+ printf ("P11_KIT_SERVER_ADDRESS=windows:pipe=%s\n", path);
+ free (path);
+ printf ("P11_KIT_SERVER_PID=%d\n", getpid ());
+ }
+
+ while (1) {
+ hpipe = CreateNamedPipe (server->socket_name,
+ PIPE_ACCESS_DUPLEX,
+ PIPE_TYPE_BYTE |
+ PIPE_READMODE_BYTE |
+ PIPE_WAIT
+#ifdef PIPE_REJECT_REMOTE_CLIENTS
+ | PIPE_REJECT_REMOTE_CLIENTS
+#endif
+ ,
+ PIPE_UNLIMITED_INSTANCES,
+ BUFSIZE,
+ BUFSIZE,
+ 0,
+ &sa);
+ if (hpipe == INVALID_HANDLE_VALUE)
+ return 1;
+ connected = ConnectNamedPipe (hpipe, NULL);
+ if (!connected)
+ connected = GetLastError () == ERROR_PIPE_CONNECTED;
+ if (connected) {
+ data = malloc (sizeof (struct ThreadData));
+ data->handle = hpipe;
+ data->server = server;
+ hthread = CreateThread (NULL, 0, server_thread, data, 0,
+ &thread_id);
+ if (hthread == NULL) {
+ free (data);
+ return 1;
+ } else
+ CloseHandle(hthread);
+ } else {
+ CloseHandle(hpipe);
+ }
+ }
+
+ return 0;
+}
+
+int
+main (int argc,
+ char *argv[])
+{
+ const char *pipe_base = "\\\\.\\pipe\\";
+ char *pipe_name;
+ int opt;
+ const char *name = NULL;
+ char *provider = NULL;
+ Server *server = NULL;
+ int ret = 0;
+
+ enum {
+ opt_verbose = 'v',
+ opt_quiet = 'q',
+ opt_help = 'h',
+ opt_name = 'n',
+ opt_provider = 'p'
+ };
+
+ struct option options[] = {
+ { "verbose", no_argument, NULL, opt_verbose },
+ { "quiet", no_argument, NULL, opt_quiet },
+ { "help", no_argument, NULL, opt_help },
+ { "name", required_argument, NULL, opt_name },
+ { "provider", required_argument, NULL, opt_provider },
+ { 0 },
+ };
+
+ p11_tool_desc usages[] = {
+ { 0, "usage: p11-kit server <token> ..." },
+ { opt_name, "specify name of the pipe (default: pkcs11-<pid>)" },
+ { opt_provider, "specify the module to use" },
+ { 0 },
+ };
+
+ while ((opt = p11_tool_getopt (argc, argv, options)) != -1) {
+ switch (opt) {
+ case opt_verbose:
+ p11_kit_be_loud ();
+ break;
+ case opt_quiet:
+ quiet = true;
+ break;
+ case opt_name:
+ name = optarg;
+ break;
+ case opt_provider:
+ provider = optarg;
+ break;
+ case opt_help:
+ case '?':
+ p11_tool_usage (usages, options);
+ return 0;
+ default:
+ assert_not_reached ();
+ break;
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ if (argc < 1) {
+ p11_tool_usage (usages, options);
+ return 2;
+ }
+
+ if (name == NULL) {
+ if (asprintf (&pipe_name, "%spkcs11-%d",
+ pipe_base, _getpid ()) < 0) {
+ ret = 1;
+ goto out;
+ }
+ } else {
+ pipe_name = strdup (name);
+ }
+
+ server = server_new ((const char **)argv, argc, provider, pipe_name);
+ if (server == NULL) {
+ ret = 1;
+ goto out;
+ }
+
+ ret = server_loop (server);
+
+ out:
+ server_free (server);
+
+ if (pipe_name)
+ free (pipe_name);
+
+ return ret;
+}
+
+/* make_private_security_descriptor() and the helper functions were
+ * copied from putty/windows/winsecur.c in the PuTTY source code as of
+ * git commit 12bd5a6c722152aa27f24598785593e72b3284ea.
+ *
+ * PuTTY is copyright 1997-2017 Simon Tatham.
+ *
+ * Portions copyright Robert de Bath, Joris van Rantwijk, Delian
+ * Delchev, Andreas Schultz, Jeroen Massar, Wez Furlong, Nicolas Barry,
+ * Justin Bradford, Ben Harris, Malcolm Smith, Ahmad Khalifa, Markus
+ * Kuhn, Colin Watson, Christopher Staite, and CORE SDI S.A.
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ */
+
+/* Initialised once, then kept around to reuse forever */
+static PSID world_sid, network_sid, user_sid;
+
+static PSID
+get_user_sid (void)
+{
+ HANDLE proc = NULL, tok = NULL;
+ TOKEN_USER *user = NULL;
+ DWORD toklen, sidlen;
+ PSID sid = NULL, ret = NULL;
+
+ if (user_sid)
+ return user_sid;
+
+ if ((proc = OpenProcess (MAXIMUM_ALLOWED, FALSE,
+ GetCurrentProcessId ())) == NULL)
+ goto cleanup;
+
+ if (!OpenProcessToken (proc, TOKEN_QUERY, &tok))
+ goto cleanup;
+
+ if (!GetTokenInformation (tok, TokenUser, NULL, 0, &toklen) &&
+ GetLastError () != ERROR_INSUFFICIENT_BUFFER)
+ goto cleanup;
+
+ if ((user = (TOKEN_USER *)LocalAlloc (LPTR, toklen)) == NULL)
+ goto cleanup;
+
+ if (!GetTokenInformation (tok, TokenUser, user, toklen, &toklen))
+ goto cleanup;
+
+ sidlen = GetLengthSid (user->User.Sid);
+
+ sid = (PSID)malloc (sidlen);
+
+ if (!CopySid (sidlen, sid, user->User.Sid))
+ goto cleanup;
+
+ /* Success. Move sid into the return value slot, and null it out
+ * to stop the cleanup code freeing it. */
+ ret = user_sid = sid;
+ sid = NULL;
+
+ cleanup:
+ if (proc != NULL)
+ CloseHandle (proc);
+ if (tok != NULL)
+ CloseHandle (tok);
+ if (user != NULL)
+ LocalFree (user);
+ if (sid != NULL)
+ free (sid);
+
+ return ret;
+}
+
+static bool
+get_sids (void)
+{
+#ifdef __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wmissing-braces"
+#endif
+ SID_IDENTIFIER_AUTHORITY world_auth = { SECURITY_WORLD_SID_AUTHORITY };
+ SID_IDENTIFIER_AUTHORITY nt_auth = { SECURITY_NT_AUTHORITY };
+#ifdef __clang__
+#pragma clang diagnostic pop
+#endif
+
+ if (!user_sid) {
+ user_sid = get_user_sid ();
+ if (user_sid == NULL) {
+ p11_message ("unable to construct SID for %s: %lu",
+ "current user",
+ GetLastError ());
+ return false;
+ }
+ }
+
+ if (!world_sid) {
+ if (!AllocateAndInitializeSid (&world_auth, 1,
+ SECURITY_WORLD_RID,
+ 0, 0, 0, 0, 0, 0, 0,
+ &world_sid)) {
+ p11_message ("unable to construct SID for %s: %lu",
+ "world",
+ GetLastError ());
+ return false;
+ }
+ }
+
+ if (!network_sid) {
+ if (!AllocateAndInitializeSid (&nt_auth, 1,
+ SECURITY_NETWORK_RID,
+ 0, 0, 0, 0, 0, 0, 0,
+ &network_sid)) {
+ p11_message ("unable to construct SID for %s: %lu",
+ "local same-user access only",
+ GetLastError ());
+ return false;
+ }
+ }
+
+ return true;
+}
+
+static bool
+make_private_security_descriptor (DWORD permissions,
+ PSECURITY_DESCRIPTOR *psd,
+ PACL *acl)
+{
+ EXPLICIT_ACCESS ea[3];
+ int acl_err;
+
+ *psd = NULL;
+ *acl = NULL;
+
+ if (!get_sids ())
+ goto cleanup;
+
+ memset (ea, 0, sizeof(ea));
+ ea[0].grfAccessPermissions = permissions;
+ ea[0].grfAccessMode = REVOKE_ACCESS;
+ ea[0].grfInheritance = NO_INHERITANCE;
+ ea[0].Trustee.TrusteeForm = TRUSTEE_IS_SID;
+ ea[0].Trustee.ptstrName = (LPTSTR)world_sid;
+ ea[1].grfAccessPermissions = permissions;
+ ea[1].grfAccessMode = GRANT_ACCESS;
+ ea[1].grfInheritance = NO_INHERITANCE;
+ ea[1].Trustee.TrusteeForm = TRUSTEE_IS_SID;
+ ea[1].Trustee.ptstrName = (LPTSTR)user_sid;
+ ea[2].grfAccessPermissions = permissions;
+ ea[2].grfAccessMode = REVOKE_ACCESS;
+ ea[2].grfInheritance = NO_INHERITANCE;
+ ea[2].Trustee.TrusteeForm = TRUSTEE_IS_SID;
+ ea[2].Trustee.ptstrName = (LPTSTR)network_sid;
+
+ acl_err = SetEntriesInAclA (3, ea, NULL, acl);
+ if (acl_err != ERROR_SUCCESS || *acl == NULL) {
+ p11_message ("unable to construct ACL: %d", acl_err);
+ goto cleanup;
+ }
+
+ *psd = (PSECURITY_DESCRIPTOR) LocalAlloc (LPTR, SECURITY_DESCRIPTOR_MIN_LENGTH);
+ if (!*psd) {
+ p11_message ("unable to allocate security descriptor: %lu",
+ GetLastError ());
+ goto cleanup;
+ }
+
+ if (!InitializeSecurityDescriptor (*psd, SECURITY_DESCRIPTOR_REVISION)) {
+ p11_message ("unable to initialise security descriptor: %lu",
+ GetLastError ());
+ goto cleanup;
+ }
+
+ if (!SetSecurityDescriptorOwner (*psd, user_sid, FALSE)) {
+ p11_message ("unable to set owner in security descriptor: %lu",
+ GetLastError ());
+ goto cleanup;
+ }
+
+ if (!SetSecurityDescriptorDacl (*psd, TRUE, *acl, FALSE)) {
+ p11_message ("unable to set DACL in security descriptor: %lu",
+ GetLastError ());
+ goto cleanup;
+ }
+
+ return true;
+
+ cleanup:
+ if (*psd) {
+ LocalFree (*psd);
+ *psd = NULL;
+ }
+ if (*acl) {
+ LocalFree (*acl);
+ *acl = NULL;
+ }
+
+ return false;
+}
+
+#endif /* OS_WIN32 */