]> granicus.if.org Git - p11-kit/commitdiff
server: Better shell integration
authorDaiki Ueno <dueno@redhat.com>
Fri, 6 Oct 2017 08:58:50 +0000 (10:58 +0200)
committerDaiki Ueno <ueno@gnu.org>
Fri, 6 Oct 2017 14:56:58 +0000 (16:56 +0200)
This adds -k, -c, and -s options to the "p11-kit server" command,
which allows you to terminate the server process, select which C-shell
or Bourne shell command line is printed on startup, respectively.

Makefile.am
p11-kit/Makefile.am
p11-kit/server.c
p11-kit/test-server.sh [new file with mode: 0755]

index b5e1136dbe4f65343455c150107ab632e914b7a9..1dc202d0dfb52afe94e27598c42a1f1e7022bd13 100644 (file)
@@ -17,6 +17,7 @@ AM_CPPFLAGS = \
 bin_PROGRAMS =
 private_PROGRAMS =
 check_PROGRAMS =
+check_SCRIPTS =
 
 CLEANFILES =
 
@@ -31,7 +32,7 @@ noinst_LTLIBRARIES =
 noinst_PROGRAMS =
 noinst_SCRIPTS =
 
-TESTS = $(check_PROGRAMS)
+TESTS = $(check_PROGRAMS) $(check_SCRIPTS)
 
 moduledir = $(p11_module_path)
 module_LTLIBRARIES =
@@ -53,6 +54,9 @@ DISTCHECK_CONFIGURE_FLAGS = \
        --enable-strict \
        CFLAGS='-O2'
 
+AM_TESTS_ENVIRONMENT = \
+       abs_top_builddir="$(abs_top_builddir)"; \
+       export abs_top_builddir;
 
 MEMCHECK_ENV = $(TEST_RUNNER) valgrind --error-exitcode=80 --quiet
 
index f2571d2564d98b50ad9de0a3e9eb2e31f038453d..955719a775acf31d39d2c9447fc8465ebbe67322 100644 (file)
@@ -208,6 +208,10 @@ check_PROGRAMS += \
        test-rpc \
        $(NULL)
 
+if !OS_WIN32
+check_SCRIPTS += p11-kit/test-server.sh
+endif
+
 test_conf_SOURCES = p11-kit/test-conf.c
 test_conf_LDADD = $(p11_kit_LIBS)
 
@@ -306,4 +310,5 @@ mock_five_la_LIBADD = $(mock_one_la_LIBADD)
 EXTRA_DIST += \
        p11-kit/fixtures \
        p11-kit/test-mock.c \
+       $(check_SCRIPTS) \
        $(NULL)
index 96c77ecb833bc6165471a8c06fbc4b2f91fb0e6b..b86d42400417d6319c1c112ffb2720625d2dcd4b 100644 (file)
@@ -45,6 +45,7 @@
 #include <assert.h>
 #include <errno.h>
 #include <fcntl.h>
+#include <limits.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -161,6 +162,10 @@ static bool need_children_cleanup = false;
 static bool terminate = false;
 static unsigned children_avail = 0;
 static bool quiet = false;
+static bool csh = false;
+
+#define P11_KIT_SERVER_ADDRESS_ENV "P11_KIT_SERVER_ADDRESS"
+#define P11_KIT_SERVER_PID_ENV "P11_KIT_SERVER_PID"
 
 static SIGHANDLER_T
 ocsignal (int signum, SIGHANDLER_T handler)
@@ -346,28 +351,42 @@ server_loop (Server *server,
        if (server->socket == -1)
                return 1;
 
-       if (!quiet) {
-               char *path;
-
-               path = p11_path_encode (server->socket_name);
-               printf ("P11_KIT_SERVER_ADDRESS=unix:path=%s\n", path);
-               free (path);
-               printf ("P11_KIT_SERVER_PID=%d\n", getpid ());
-               fflush (stdout);
-               close (STDOUT_FILENO);
-       }
-
        /* run as daemon */
        if (!foreground) {
                pid = fork ();
-               switch (pid) {
-               case -1:
+               if (pid == -1) {
                        p11_message_err (errno, "could not fork() to daemonize");
                        return 1;
-               case 0:
-                       break;
-               default:
-                       _exit (0);
+               }
+               if (pid == 0) {
+                       close (STDIN_FILENO);
+                       close (STDOUT_FILENO);
+               }
+               if (pid != 0) {
+                       char *path, *address;
+
+                       path = p11_path_encode (server->socket_name);
+                       rc = asprintf (&address, "unix:path=%s", path);
+                       free (path);
+                       if (rc < 0)
+                               return 1;
+                       if (csh) {
+                               printf ("setenv %s %s;\n",
+                                       P11_KIT_SERVER_ADDRESS_ENV,
+                                       address);
+                               printf ("setenv %s %d;\n",
+                                       P11_KIT_SERVER_PID_ENV,
+                                       pid);
+                       } else {
+                               printf ("%s=%s; export %s;\n",
+                                       P11_KIT_SERVER_ADDRESS_ENV, address,
+                                       P11_KIT_SERVER_ADDRESS_ENV);
+                               printf ("%s=%d; export %s;\n",
+                                       P11_KIT_SERVER_PID_ENV, pid,
+                                       P11_KIT_SERVER_PID_ENV);
+                       }
+                       free (address);
+                       exit (0);
                }
                if (setsid () == -1) {
                        p11_message_err (errno, "could not create a new session");
@@ -487,6 +506,8 @@ main (int argc,
        const struct passwd *pwd;
        const struct group *grp;
        bool foreground = false;
+       bool csh_opt = false;
+       bool kill_opt = false;
        struct timespec *timeout = NULL, ts;
        char *name = NULL;
        char *provider = NULL;
@@ -504,7 +525,10 @@ main (int argc,
                opt_foreground = 'f',
                opt_timeout = 't',
                opt_name = 'n',
-               opt_provider = 'p'
+               opt_provider = 'p',
+               opt_kill = 'k',
+               opt_csh = 'c',
+               opt_sh = 's'
        };
 
        struct option options[] = {
@@ -519,6 +543,9 @@ main (int argc,
                { "timeout", required_argument, NULL, opt_timeout },
                { "name", required_argument, NULL, opt_name },
                { "provider", required_argument, NULL, opt_provider },
+               { "kill", no_argument, NULL, opt_kill },
+               { "csh", no_argument, NULL, opt_csh },
+               { "sh", no_argument, NULL, opt_sh },
                { 0 },
        };
 
@@ -532,6 +559,9 @@ main (int argc,
                { opt_timeout, "exit if no connection until the given timeout" },
                { opt_name, "specify name of the socket (default: pkcs11-<pid>)" },
                { opt_provider, "specify the module to use" },
+               { opt_kill, "terminate the running server" },
+               { opt_csh, "generate C-shell commands on stdout" },
+               { opt_sh, "generate Bourne shell commands on stdout" },
                { 0 },
        };
 
@@ -589,6 +619,17 @@ main (int argc,
                case opt_provider:
                        provider = optarg;
                        break;
+               case opt_kill:
+                       kill_opt = true;
+                       break;
+               case opt_csh:
+                       csh = true;
+                       csh_opt = true;
+                       break;
+               case opt_sh:
+                       csh = false;
+                       csh_opt = true;
+                       break;
                case opt_help:
                case '?':
                        p11_tool_usage (usages, options);
@@ -602,11 +643,54 @@ main (int argc,
        argc -= optind;
        argv += optind;
 
-       if (argc < 1) {
+       if (argc < 1 && !kill_opt) {
                p11_tool_usage (usages, options);
                return 2;
        }
 
+       if (!csh_opt) {
+               const char *shell = secure_getenv ("SHELL");
+               size_t len;
+               if (shell != NULL && (len = strlen (shell)) > 2 &&
+                   strncmp (shell + len - 3, "csh", 3) == 0)
+                       csh = true;
+       }
+
+       if (kill_opt) {
+               const char *pidstr = secure_getenv (P11_KIT_SERVER_PID_ENV);
+               char *endptr;
+               long pidval;
+
+               if (pidstr == NULL) {
+                       fprintf (stderr, "%s not set, cannot kill server",
+                                P11_KIT_SERVER_PID_ENV);
+                       exit (1);
+               }
+               pidval = strtol (pidstr, &endptr, 10);
+               if (errno == ERANGE &&
+                   (pidval == LONG_MAX || pidval == LONG_MIN)) {
+                       perror ("strtol");
+                       exit (1);
+               }
+               if (kill ((pid_t) pidval, SIGTERM) == -1) {
+                       perror ("kill");
+                       exit (1);
+               }
+
+               if (csh) {
+                       printf ("unsetenv %s;\n",
+                               P11_KIT_SERVER_ADDRESS_ENV);
+                       printf ("unsetenv %s;\n",
+                               P11_KIT_SERVER_PID_ENV);
+               } else {
+                       printf ("unset %s;\n",
+                               P11_KIT_SERVER_ADDRESS_ENV);
+                       printf ("unset %s;\n",
+                               P11_KIT_SERVER_PID_ENV);
+               }
+               exit (0);
+       }
+
        if (run_as_gid != -1) {
                if (setgid (run_as_gid) == -1) {
                        p11_message_err (errno, "cannot set gid to %u", (unsigned)run_as_gid);
diff --git a/p11-kit/test-server.sh b/p11-kit/test-server.sh
new file mode 100755 (executable)
index 0000000..225127c
--- /dev/null
@@ -0,0 +1,39 @@
+#!/bin/sh
+
+testdir=$PWD/test-server-$$
+test -d "$testdir" || mkdir "$testdir"
+
+cleanup () {
+  rm -rf "$testdir"
+}
+trap cleanup 0
+
+cd "$testdir"
+
+unset P11_KIT_SERVER_ADDRESS
+unset P11_KIT_SERVER_PID
+
+XDG_RUNTIME_DIR="$testdir"
+export XDG_RUNTIME_DIR
+
+"$abs_top_builddir"/p11-kit-server -s --provider "$abs_top_builddir"/.libs/mock-one.so pkcs11: > start.env 2> start.err
+if test $? -ne 0; then
+    cat start.err
+    exit 1
+fi
+
+. ./start.env
+
+test "${P11_KIT_SERVER_ADDRESS+set}" == set || exit 1
+test "${P11_KIT_SERVER_PID+set}" == set || exit 1
+
+"$abs_top_builddir"/p11-kit-server -s -k > stop.env 2> stop.err
+if test $? -ne 0; then
+    cat stop.err
+    exit 1
+fi
+
+. ./stop.env
+
+test "${P11_KIT_SERVER_ADDRESS-unset}" == unset || exit 1
+test "${P11_KIT_SERVER_PID-unset}" == unset || exit 1