]> granicus.if.org Git - p11-kit/commitdiff
rpc: New rpc_unix transport based on Unix socket
authorNikos Mavrogiannopoulos <nmav@redhat.com>
Wed, 24 Aug 2016 12:41:49 +0000 (14:41 +0200)
committerDaiki Ueno <ueno@gnu.org>
Thu, 16 Feb 2017 15:56:40 +0000 (16:56 +0100)
p11-kit/rpc-transport.c
p11-kit/test-transport.c

index 590215767eb0a0640ba5f755085b99bb8e4e2f2c..d8f0cdaf6f0c1a1901e6ac21a70e0858e132a13c 100644 (file)
@@ -44,6 +44,7 @@
 #include "private.h"
 #include "rpc.h"
 #include "rpc-message.h"
+#include "path.h"
 
 #include <sys/types.h>
 
@@ -1043,6 +1044,84 @@ rpc_exec_init (const char *remote,
        return &rex->base;
 }
 
+#ifdef OS_UNIX
+
+typedef struct {
+       p11_rpc_transport base;
+       struct sockaddr_un sa;
+} rpc_unix;
+
+static CK_RV
+rpc_unix_connect (p11_rpc_client_vtable *vtable,
+                   void *init_reserved)
+{
+       rpc_unix *run = (rpc_unix *)vtable;
+       int fd;
+
+       fd = socket (AF_UNIX, SOCK_STREAM, 0);
+       if (fd < 0) {
+               p11_message_err (errno, "failed to create socket for remote");
+               return CKR_GENERAL_ERROR;
+       }
+
+       if (connect (fd, (struct sockaddr *)&run->sa, sizeof (run->sa)) < 0) {
+               p11_message_err (errno, "failed to connect to socket");
+               close (fd);
+               return CKR_DEVICE_REMOVED;
+       }
+
+       run->base.socket = rpc_socket_new (fd);
+       return_val_if_fail (run->base.socket != NULL, CKR_GENERAL_ERROR);
+
+       return CKR_OK;
+}
+
+static void
+rpc_unix_disconnect (p11_rpc_client_vtable *vtable,
+                     void *fini_reserved)
+{
+       rpc_unix *run = (rpc_unix *)vtable;
+
+       if (run->base.socket)
+               rpc_socket_close (run->base.socket);
+
+       /* Do the common disconnect stuff */
+       rpc_transport_disconnect (vtable, fini_reserved);
+}
+
+static void
+rpc_unix_free (void *data)
+{
+       rpc_unix *run = data;
+       rpc_unix_disconnect (data, NULL);
+       rpc_transport_uninit (&run->base);
+       free (run);
+}
+
+static p11_rpc_transport *
+rpc_unix_init (const char *remote,
+              const char *name)
+{
+       rpc_unix *run;
+
+       run = calloc (1, sizeof (rpc_unix));
+       return_val_if_fail (run != NULL, NULL);
+
+       memset (&run->sa, 0, sizeof (run->sa));
+       run->sa.sun_family = AF_UNIX;
+       snprintf (run->sa.sun_path, sizeof (run->sa.sun_path), "%s", remote);
+
+       run->base.vtable.connect = rpc_unix_connect;
+       run->base.vtable.disconnect = rpc_unix_disconnect;
+       run->base.vtable.transport = rpc_transport_buffer;
+       rpc_transport_init (&run->base, name, rpc_unix_free);
+
+       p11_debug ("initialized rpc socket: %s", remote);
+       return &run->base;
+}
+
+#endif /* OS_UNIX */
+
 p11_rpc_transport *
 p11_rpc_transport_new (p11_virtual *virt,
                        const char *remote,
@@ -1058,6 +1137,16 @@ p11_rpc_transport_new (p11_virtual *virt,
        if (remote[0] == '|') {
                rpc = rpc_exec_init (remote + 1, name);
 
+#ifdef OS_UNIX
+       } else if (strncmp (remote, "unix:path=/", 11) == 0) {
+               /* Only absolute path is supported */
+               char *path;
+
+               path = p11_path_decode (remote + 10);
+               return_val_if_fail (path != NULL, NULL);
+               rpc = rpc_unix_init (path, name);
+               free (path);
+#endif /* OS_UNIX */
        } else {
                p11_message ("remote not supported: %s", remote);
                return NULL;
index 86e5e87c27fd24490f69e65ca0d8a87909c94670..7e9079dd684b6d32a4a8f9b4cef9470b4602a9e0 100644 (file)
 #include "p11-kit.h"
 #include "rpc.h"
 
+#include <errno.h>
 #include <sys/types.h>
 #ifdef OS_UNIX
+#include <sys/socket.h>
+#include <sys/un.h>
 #include <sys/wait.h>
 #endif
 #include <stdlib.h>
@@ -54,6 +57,9 @@ struct {
        char *directory;
        char *user_config;
        char *user_modules;
+#ifdef OS_UNIX
+       pid_t pid;
+#endif
 } test;
 
 static void
@@ -137,6 +143,113 @@ teardown_mock_module (CK_FUNCTION_LIST *module)
        teardown_remote (NULL);
 }
 
+#ifdef OS_UNIX
+
+static void
+launch_server (void)
+{
+       int fd, nfd, rc;
+       socklen_t sa_len;
+       struct sockaddr_un sa;
+       fd_set fds;
+       char *argv[3];
+
+       memset (&sa, 0, sizeof (sa));
+       sa.sun_family = AF_UNIX;
+
+       snprintf (sa.sun_path, sizeof (sa.sun_path), "%s/pkcs11",
+                 test.directory);
+
+       remove (sa.sun_path);
+       fd = socket (AF_UNIX, SOCK_STREAM, 0);
+       assert_num_cmp (fd, !=, -1);
+
+       rc = bind (fd, (struct sockaddr *)&sa, SUN_LEN (&sa));
+       assert_num_cmp (rc, !=, -1);
+
+       rc = listen (fd, 1024);
+       assert_num_cmp (rc, !=, -1);
+
+       FD_ZERO (&fds);
+       FD_SET (fd, &fds);
+       rc = select (fd + 1, &fds, NULL, NULL, NULL);
+       assert_num_cmp (rc, !=, -1);
+
+       assert (FD_ISSET (fd, &fds));
+
+       nfd = accept (fd, (struct sockaddr *)&sa, &sa_len);
+       assert_num_cmp (rc, !=, -1);
+       close (fd);
+
+       rc = dup2 (nfd, STDIN_FILENO);
+       assert_num_cmp (rc, !=, -1);
+
+       rc = dup2 (nfd, STDOUT_FILENO);
+       assert_num_cmp (rc, !=, -1);
+
+       argv[0] = "p11-kit-remote";
+       argv[1] = BUILDDIR "/.libs/mock-two.so";
+       argv[2] = NULL;
+
+       rc = execv (BUILDDIR "/p11-kit-remote", argv);
+       assert_num_cmp (rc, !=, -1);
+}
+
+static void
+setup_remote_unix (void *unused)
+{
+       char *data;
+       char *path;
+       pid_t pid;
+
+       test.directory = p11_test_directory ("p11-test-config");
+       test.user_modules = p11_path_build (test.directory, "modules", NULL);
+       if (mkdir (test.user_modules, 0700) < 0)
+               assert_not_reached ();
+
+       data = "user-config: only\n";
+       test.user_config = p11_path_build (test.directory, "pkcs11.conf", NULL);
+       p11_test_file_write (NULL, test.user_config, data, strlen (data));
+
+       pid = fork ();
+       switch (pid) {
+       case -1:
+               assert_not_reached ();
+               break;
+       case 0:
+               launch_server ();
+               exit (0);
+               break;
+       default:
+               test.pid = pid;
+       }
+
+       setenv ("P11_KIT_PRIVATEDIR", BUILDDIR, 1);
+
+       if (asprintf (&path, "%s/pkcs11", test.directory) < 0)
+               assert_not_reached ();
+       data = p11_path_encode (path);
+       assert_ptr_not_null (data);
+       free (path);
+       path = data;
+       if (asprintf (&data, "remote: unix:path=%s\n", path) < 0)
+               assert_not_reached ();
+       free (path);
+       p11_test_file_write (test.user_modules, "remote.module", data, strlen (data));
+       free (data);
+
+       p11_config_user_modules = test.user_modules;
+       p11_config_user_file = test.user_config;
+}
+
+static void
+teardown_remote_unix (void *unused)
+{
+       kill (test.pid, SIGKILL);
+}
+
+#endif /* OS_UNIX */
+
 static void
 test_basic_exec (void)
 {
@@ -315,5 +428,10 @@ main (int argc,
 
        test_mock_add_tests ("/transport");
 
+#ifdef OS_UNIX
+       p11_fixture (setup_remote_unix, teardown_remote_unix);
+       p11_test (test_basic_exec, "/transport/unix/basic");
+#endif
+
        return  p11_test_run (argc, argv);
 }