diff --git a/g13/Makefile.am b/g13/Makefile.am
index e17d099c3..a3cd1333d 100644
--- a/g13/Makefile.am
+++ b/g13/Makefile.am
@@ -21,6 +21,7 @@
EXTRA_DIST = ChangeLog-2011
bin_PROGRAMS = g13
+sbin_PROGRAMS = g13-syshelp
AM_CPPFLAGS = -I$(top_srcdir)/common
@@ -37,6 +38,7 @@ g13_SOURCES = \
create.c create.h \
mount.c mount.h \
mountinfo.c mountinfo.h \
+ call-syshelp.c call-syshelp.h \
runner.c runner.h \
backend.c backend.h \
be-encfs.c be-encfs.h \
@@ -45,3 +47,18 @@ g13_SOURCES = \
g13_LDADD = $(libcommonpth) \
$(LIBGCRYPT_LIBS) $(LIBASSUAN_LIBS) $(NPTH_LIBS) \
$(GPG_ERROR_LIBS) $(LIBINTL) $(LIBICONV)
+
+
+g13_syshelp_SOURCES = \
+ g13-syshelp.c g13-syshelp.h \
+ g13-common.c g13-common.h \
+ keyblob.h \
+ utils.c utils.h \
+ sh-cmd.c \
+ sh-exectool.c \
+ sh-blockdev.c \
+ sh-dmcrypt.c
+
+g13_syshelp_LDADD = $(libcommon) \
+ $(LIBGCRYPT_LIBS) $(LIBASSUAN_LIBS) \
+ $(GPG_ERROR_LIBS) $(LIBINTL) $(LIBICONV)
diff --git a/g13/backend.c b/g13/backend.c
index 7b08cd52a..52e1e0a34 100644
--- a/g13/backend.c
+++ b/g13/backend.c
@@ -41,6 +41,38 @@ no_such_backend (int conttype)
}
+/* Parse NAME and return the corresponding content type. If the name
+ is not known, a error message is printed and zero returned. If
+ NAME is NULL the supported backend types are listed and 0 is
+ returned. */
+int
+be_parse_conttype_name (const char *name)
+{
+ static struct { const char *name; int conttype; } names[] = {
+ { "encfs", CONTTYPE_ENCFS },
+ { "dm-crypt", CONTTYPE_DM_CRYPT }
+ };
+ int i;
+
+ if (!name)
+ {
+ log_info ("Known backend types:\n");
+ for (i=0; i < DIM (names); i++)
+ log_info (" %s\n", names[i].name);
+ return 0;
+ }
+
+ for (i=0; i < DIM (names); i++)
+ {
+ if (!strcmp (names[i].name, name))
+ return names[i].conttype;
+ }
+
+ log_error ("invalid backend type '%s' given\n", name);
+ return 0;
+}
+
+
/* Return true if CONTTYPE is supported by us. */
int
be_is_supported_conttype (int conttype)
@@ -75,6 +107,9 @@ be_get_detached_name (int conttype, const char *fname,
case CONTTYPE_ENCFS:
return be_encfs_get_detached_name (fname, r_name, r_isdir);
+ case CONTTYPE_DM_CRYPT:
+ return 0;
+
default:
return no_such_backend (conttype);
}
diff --git a/g13/backend.h b/g13/backend.h
index 20d296606..e570fc5a1 100644
--- a/g13/backend.h
+++ b/g13/backend.h
@@ -23,7 +23,8 @@
#include "../common/membuf.h"
#include "utils.h" /* For tupledesc_t */
-int be_is_supported_conttype (int conttype);
+int be_parse_conttype_name (const char *name);
+int be_is_supported_conttype (int conttype);
gpg_error_t be_get_detached_name (int conttype, const char *fname,
char **r_name, int *r_isdir);
gpg_error_t be_create_new_keys (int conttype, membuf_t *mb);
diff --git a/g13/call-syshelp.c b/g13/call-syshelp.c
new file mode 100644
index 000000000..2086dd1db
--- /dev/null
+++ b/g13/call-syshelp.c
@@ -0,0 +1,124 @@
+/* call-syshelp.c - Communication with g13-syshelp
+ * Copyright (C) 2015 Werner Koch
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see .
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "g13.h"
+#include
+#include "i18n.h"
+#include "utils.h"
+
+/* Local data for this module. A pointer to this is stored in the
+ CTRL object of each connection. */
+struct call_syshelp_s
+{
+ assuan_context_t assctx; /* The Assuan context for the current
+ g13-syshep connection. */
+};
+
+
+/* Fork off the syshelp tool if this has not already been done. */
+static gpg_error_t
+start_syshelp (ctrl_t ctrl)
+{
+ gpg_error_t err;
+ assuan_context_t ctx;
+ assuan_fd_t no_close_list[3];
+ int i;
+
+ if (ctrl->syshelp_local->assctx)
+ return 0; /* Already set. */
+
+ if (opt.verbose)
+ log_info ("starting a new syshelp\n");
+
+ if (es_fflush (NULL))
+ {
+ err = gpg_error_from_syserror ();
+ log_error ("error flushing pending output: %s\n", gpg_strerror (err));
+ return err;
+ }
+
+ i = 0;
+ if (log_get_fd () != -1)
+ no_close_list[i++] = assuan_fd_from_posix_fd (log_get_fd ());
+ no_close_list[i++] = assuan_fd_from_posix_fd (es_fileno (es_stderr));
+ no_close_list[i] = ASSUAN_INVALID_FD;
+
+ err = assuan_new (&ctx);
+ if (err)
+ {
+ log_error ("can't allocate assuan context: %s\n", gpg_strerror (err));
+ return err;
+ }
+
+ /* Call userv to start g13-syshelp. This userv script needs tpo be
+ installed under the name "gnupg-g13-syshelp":
+
+ if ( glob service-user root
+ )
+ reset
+ suppress-args
+ execute /home/wk/b/gnupg/g13/g13-syshelp -v
+ else
+ error Nothing to do for this service-user
+ fi
+ quit
+ */
+ {
+ const char *argv[3];
+
+ argv[0] = "userv";
+ argv[1] = "gnupg-g13-syshelp";
+ argv[2] = NULL;
+
+ err = assuan_pipe_connect (ctx, "/usr/bin/userv", argv,
+ no_close_list, NULL, NULL, 0);
+ }
+ if (err)
+ {
+ log_error ("can't connect to '%s' - : %s\n",
+ "g13-syshelp", gpg_strerror (err));
+ log_info ("(is userv and its gnupg-g13-syshelp script installed?)\n");
+ assuan_release (ctx);
+ return err;
+ }
+ ctrl->syshelp_local->assctx = ctx;
+
+ if (DBG_IPC)
+ log_debug ("connection to g13-syshelp established\n");
+
+ return 0;
+}
+
+
+/* Release local resources associated with CTRL. */
+void
+call_syshelp_release (ctrl_t ctrl)
+{
+ assuan_release (ctrl->syshelp_local->assctx);
+ ctrl->syshelp_local->assctx = NULL;
+}
diff --git a/g13/call-syshelp.h b/g13/call-syshelp.h
new file mode 100644
index 000000000..c78d53b5c
--- /dev/null
+++ b/g13/call-syshelp.h
@@ -0,0 +1,26 @@
+/* call-syshelp.h - Communication with g13-syshelp
+ * Copyright (C) 2015 Werner Koch
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see .
+ */
+
+#ifndef GNUPG_G13_CALL_SYSHELP_H
+#define GNUPG_G13_CALL_SYSHELP_H
+
+void call_syshelp_release (ctrl_t ctrl);
+
+
+#endif /*GNUPG_G13_CALL_SYSHELP_H*/
diff --git a/g13/g13-syshelp.c b/g13/g13-syshelp.c
new file mode 100644
index 000000000..c09a5e917
--- /dev/null
+++ b/g13/g13-syshelp.c
@@ -0,0 +1,720 @@
+/* g13-syshelp.c - Helper for disk key management with GnuPG
+ * Copyright (C) 2015 Werner Koch
+ *
+ * This file is part of GnuPG.
+ *
+ * GnuPG is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuPG is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see .
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#ifdef HAVE_PWD_H
+# include
+#endif
+#include
+
+#include "g13-syshelp.h"
+
+#include
+#include
+
+#include "i18n.h"
+#include "sysutils.h"
+#include "asshelp.h"
+#include "../common/init.h"
+#include "keyblob.h"
+
+
+enum cmd_and_opt_values {
+ aNull = 0,
+ oQuiet = 'q',
+ oVerbose = 'v',
+ oRecipient = 'r',
+
+ aGPGConfList = 500,
+
+ oDebug,
+ oDebugLevel,
+ oDebugAll,
+ oDebugNone,
+ oDebugWait,
+ oDebugAllowCoreDump,
+ oLogFile,
+ oNoLogFile,
+ oAuditLog,
+
+ oOutput,
+
+ oAgentProgram,
+ oGpgProgram,
+ oType,
+
+ oDisplay,
+ oTTYname,
+ oTTYtype,
+ oLCctype,
+ oLCmessages,
+ oXauthority,
+
+ oStatusFD,
+ oLoggerFD,
+
+ oNoVerbose,
+ oNoSecmemWarn,
+ oHomedir,
+ oDryRun,
+ oNoDetach,
+
+ oNoRandomSeedFile,
+ oFakedSystemTime
+ };
+
+
+static ARGPARSE_OPTS opts[] = {
+
+ ARGPARSE_s_n (oDryRun, "dry-run", N_("do not make any changes")),
+
+ ARGPARSE_s_n (oVerbose, "verbose", N_("verbose")),
+ ARGPARSE_s_n (oQuiet, "quiet", N_("be somewhat more quiet")),
+
+ ARGPARSE_s_s (oDebug, "debug", "@"),
+ ARGPARSE_s_s (oDebugLevel, "debug-level",
+ N_("|LEVEL|set the debugging level to LEVEL")),
+ ARGPARSE_s_n (oDebugAll, "debug-all", "@"),
+ ARGPARSE_s_n (oDebugNone, "debug-none", "@"),
+ ARGPARSE_s_i (oDebugWait, "debug-wait", "@"),
+ ARGPARSE_s_n (oDebugAllowCoreDump, "debug-allow-core-dump", "@"),
+
+ ARGPARSE_end ()
+};
+
+
+/* The list of supported debug flags. */
+static struct debug_flags_s debug_flags [] =
+ {
+ { DBG_MOUNT_VALUE , "mount" },
+ { DBG_CRYPTO_VALUE , "crypto" },
+ { DBG_MEMORY_VALUE , "memory" },
+ { DBG_MEMSTAT_VALUE, "memstat" },
+ { DBG_IPC_VALUE , "ipc" },
+ { 0, NULL }
+ };
+
+
+/* The timer tick interval used by the idle task. */
+#define TIMERTICK_INTERVAL_SEC (1)
+
+/* It is possible that we are currently running under setuid permissions. */
+static int maybe_setuid = 1;
+
+/* Helper to implement --debug-level and --debug. */
+static const char *debug_level;
+static unsigned int debug_value;
+
+
+/* Local prototypes. */
+static void g13_syshelp_deinit_default_ctrl (ctrl_t ctrl);
+static void release_tab_items (tab_item_t tab);
+static tab_item_t parse_g13tab (const char *username);
+
+
+
+static const char *
+my_strusage( int level )
+{
+ const char *p;
+
+ switch (level)
+ {
+ case 11: p = "@G13@-syshelp (@GNUPG@)";
+ break;
+ case 13: p = VERSION; break;
+ case 17: p = PRINTABLE_OS_NAME; break;
+ case 19: p = _("Please report bugs to <" PACKAGE_BUGREPORT ">.\n");
+ break;
+ case 1:
+ case 40: p = _("Usage: @G13@-syshelp [options] [files] (-h for help)");
+ break;
+ case 41:
+ p = _("Syntax: @G13@-syshelp [options] [files]\n"
+ "Helper to perform root-only tasks for g13\n");
+ break;
+
+ case 31: p = "\nHome: "; break;
+ case 32: p = opt.homedir; break;
+
+ default: p = NULL; break;
+ }
+ return p;
+}
+
+
+/* Setup the debugging. With a DEBUG_LEVEL of NULL only the active
+ debug flags are propagated to the subsystems. With DEBUG_LEVEL
+ set, a specific set of debug flags is set; and individual debugging
+ flags will be added on top. */
+static void
+set_debug (void)
+{
+ int numok = (debug_level && digitp (debug_level));
+ int numlvl = numok? atoi (debug_level) : 0;
+
+ if (!debug_level)
+ ;
+ else if (!strcmp (debug_level, "none") || (numok && numlvl < 1))
+ opt.debug = 0;
+ else if (!strcmp (debug_level, "basic") || (numok && numlvl <= 2))
+ opt.debug = DBG_IPC_VALUE|DBG_MOUNT_VALUE;
+ else if (!strcmp (debug_level, "advanced") || (numok && numlvl <= 5))
+ opt.debug = DBG_IPC_VALUE|DBG_MOUNT_VALUE;
+ else if (!strcmp (debug_level, "expert") || (numok && numlvl <= 8))
+ opt.debug = (DBG_IPC_VALUE|DBG_MOUNT_VALUE|DBG_CRYPTO_VALUE);
+ else if (!strcmp (debug_level, "guru") || numok)
+ {
+ opt.debug = ~0;
+ /* if (numok) */
+ /* opt.debug &= ~(DBG_HASHING_VALUE); */
+ }
+ else
+ {
+ log_error (_("invalid debug-level '%s' given\n"), debug_level);
+ g13_exit(2);
+ }
+
+ opt.debug |= debug_value;
+
+ if (opt.debug && !opt.verbose)
+ opt.verbose = 1;
+ if (opt.debug)
+ opt.quiet = 0;
+
+ if (opt.debug & DBG_CRYPTO_VALUE )
+ gcry_control (GCRYCTL_SET_DEBUG_FLAGS, 1);
+ gcry_control (GCRYCTL_SET_VERBOSITY, (int)opt.verbose);
+
+ if (opt.debug)
+ parse_debug_flag (NULL, &opt.debug, debug_flags);
+}
+
+
+int
+main ( int argc, char **argv)
+{
+ ARGPARSE_ARGS pargs;
+ int orig_argc;
+ char **orig_argv;
+ gpg_error_t err = 0;
+ /* const char *fname; */
+ int may_coredump;
+ FILE *configfp = NULL;
+ char *configname = NULL;
+ unsigned configlineno;
+ int parse_debug = 0;
+ int no_more_options = 0;
+ int default_config =1;
+ char *logfile = NULL;
+ /* int debug_wait = 0; */
+ int use_random_seed = 1;
+ /* int nodetach = 0; */
+ /* int nokeysetup = 0; */
+ struct server_control_s ctrl;
+
+ /*mtrace();*/
+
+ early_system_init ();
+ gnupg_reopen_std (G13_NAME "-syshelp");
+ set_strusage (my_strusage);
+ gcry_control (GCRYCTL_SUSPEND_SECMEM_WARN);
+
+ log_set_prefix (G13_NAME "-syshelp", 1);
+
+ /* Make sure that our subsystems are ready. */
+ i18n_init ();
+ init_common_subsystems (&argc, &argv);
+
+ /* Check that the Libgcrypt is suitable. */
+ if (!gcry_check_version (NEED_LIBGCRYPT_VERSION) )
+ log_fatal (_("%s is too old (need %s, have %s)\n"), "libgcrypt",
+ NEED_LIBGCRYPT_VERSION, gcry_check_version (NULL) );
+
+ /* Take extra care of the random pool. */
+ gcry_control (GCRYCTL_USE_SECURE_RNDPOOL);
+
+ may_coredump = disable_core_dumps ();
+
+ g13_init_signals ();
+
+ dotlock_create (NULL, 0); /* Register locking cleanup. */
+
+ opt.session_env = session_env_new ();
+ if (!opt.session_env)
+ log_fatal ("error allocating session environment block: %s\n",
+ strerror (errno));
+
+ opt.homedir = default_homedir ();
+
+ /* First check whether we have a debug option on the commandline. */
+ orig_argc = argc;
+ orig_argv = argv;
+ pargs.argc = &argc;
+ pargs.argv = &argv;
+ pargs.flags= (ARGPARSE_FLAG_KEEP | ARGPARSE_FLAG_NOVERSION);
+ while (arg_parse( &pargs, opts))
+ {
+ if (pargs.r_opt == oDebug || pargs.r_opt == oDebugAll)
+ parse_debug++;
+ }
+
+ /* Initialize the secure memory. */
+ gcry_control (GCRYCTL_INIT_SECMEM, 16384, 0);
+ maybe_setuid = 0;
+
+ /*
+ Now we are now working under our real uid
+ */
+
+ /* Setup malloc hooks. */
+ {
+ struct assuan_malloc_hooks malloc_hooks;
+
+ malloc_hooks.malloc = gcry_malloc;
+ malloc_hooks.realloc = gcry_realloc;
+ malloc_hooks.free = gcry_free;
+ assuan_set_malloc_hooks (&malloc_hooks);
+ }
+
+ /* Prepare libassuan. */
+ assuan_set_gpg_err_source (GPG_ERR_SOURCE_DEFAULT);
+ /*assuan_set_system_hooks (ASSUAN_SYSTEM_NPTH);*/
+ setup_libassuan_logging (&opt.debug);
+
+ /* Setup a default control structure for command line mode. */
+ memset (&ctrl, 0, sizeof ctrl);
+ g13_syshelp_init_default_ctrl (&ctrl);
+ ctrl.no_server = 1;
+ ctrl.status_fd = -1; /* No status output. */
+
+ if (default_config )
+ configname = make_filename (gnupg_sysconfdir (),
+ G13_NAME"-syshelp.conf", NULL);
+
+ argc = orig_argc;
+ argv = orig_argv;
+ pargs.argc = &argc;
+ pargs.argv = &argv;
+ pargs.flags = 1; /* Do not remove the args. */
+
+ next_pass:
+ if (configname)
+ {
+ configlineno = 0;
+ configfp = fopen (configname, "r");
+ if (!configfp)
+ {
+ if (default_config)
+ {
+ if (parse_debug)
+ log_info (_("NOTE: no default option file '%s'\n"), configname);
+ }
+ else
+ {
+ log_error (_("option file '%s': %s\n"),
+ configname, strerror(errno));
+ g13_exit(2);
+ }
+ xfree (configname);
+ configname = NULL;
+ }
+ if (parse_debug && configname)
+ log_info (_("reading options from '%s'\n"), configname);
+ default_config = 0;
+ }
+
+ while (!no_more_options
+ && optfile_parse (configfp, configname, &configlineno, &pargs, opts))
+ {
+ switch (pargs.r_opt)
+ {
+ case oQuiet: opt.quiet = 1; break;
+
+ case oDryRun: opt.dry_run = 1; break;
+
+ case oVerbose:
+ opt.verbose++;
+ gcry_control (GCRYCTL_SET_VERBOSITY, (int)opt.verbose);
+ break;
+ case oNoVerbose:
+ opt.verbose = 0;
+ gcry_control (GCRYCTL_SET_VERBOSITY, (int)opt.verbose);
+ break;
+
+ case oLogFile: logfile = pargs.r.ret_str; break;
+ case oNoLogFile: logfile = NULL; break;
+
+ case oNoDetach: /*nodetach = 1; */break;
+
+ case oDebug:
+ if (parse_debug_flag (pargs.r.ret_str, &opt.debug, debug_flags))
+ {
+ pargs.r_opt = ARGPARSE_INVALID_ARG;
+ pargs.err = ARGPARSE_PRINT_ERROR;
+ }
+ break;
+ case oDebugAll: debug_value = ~0; break;
+ case oDebugNone: debug_value = 0; break;
+ case oDebugLevel: debug_level = pargs.r.ret_str; break;
+ case oDebugWait: /*debug_wait = pargs.r.ret_int; */break;
+ case oDebugAllowCoreDump:
+ may_coredump = enable_core_dumps ();
+ break;
+
+ case oStatusFD: ctrl.status_fd = pargs.r.ret_int; break;
+ case oLoggerFD: log_set_fd (pargs.r.ret_int ); break;
+
+ case oHomedir: opt.homedir = pargs.r.ret_str; break;
+
+ case oFakedSystemTime:
+ {
+ time_t faked_time = isotime2epoch (pargs.r.ret_str);
+ if (faked_time == (time_t)(-1))
+ faked_time = (time_t)strtoul (pargs.r.ret_str, NULL, 10);
+ gnupg_set_time (faked_time, 0);
+ }
+ break;
+
+ case oNoSecmemWarn: gcry_control (GCRYCTL_DISABLE_SECMEM_WARN); break;
+
+ case oNoRandomSeedFile: use_random_seed = 0; break;
+
+ default:
+ pargs.err = configfp? ARGPARSE_PRINT_WARNING:ARGPARSE_PRINT_ERROR;
+ break;
+ }
+ }
+
+ if (configfp)
+ {
+ fclose (configfp);
+ configfp = NULL;
+ /* Keep a copy of the config filename. */
+ opt.config_filename = configname;
+ configname = NULL;
+ goto next_pass;
+ }
+ xfree (configname);
+ configname = NULL;
+
+ if (!opt.config_filename)
+ opt.config_filename = make_filename (opt.homedir, G13_NAME".conf", NULL);
+
+ if (log_get_errorcount(0))
+ g13_exit(2);
+
+ /* Now that we have the options parsed we need to update the default
+ control structure. */
+ g13_syshelp_init_default_ctrl (&ctrl);
+
+ if (may_coredump && !opt.quiet)
+ log_info (_("WARNING: program may create a core file!\n"));
+
+ if (logfile)
+ {
+ log_set_file (logfile);
+ log_set_prefix (NULL, 1|2|4);
+ }
+
+ if (gnupg_faked_time_p ())
+ {
+ gnupg_isotime_t tbuf;
+
+ log_info (_("WARNING: running with faked system time: "));
+ gnupg_get_isotime (tbuf);
+ dump_isotime (tbuf);
+ log_printf ("\n");
+ }
+
+ /* Print any pending secure memory warnings. */
+ gcry_control (GCRYCTL_RESUME_SECMEM_WARN);
+
+ /* Setup the debug flags for all subsystems. */
+ set_debug ();
+
+ /* Install a regular exit handler to make real sure that the secure
+ memory gets wiped out. */
+ g13_install_emergency_cleanup ();
+
+ /* Terminate if we found any error until now. */
+ if (log_get_errorcount(0))
+ g13_exit (2);
+
+ /* Set the standard GnuPG random seed file. */
+ if (use_random_seed)
+ {
+ char *p = make_filename (opt.homedir, "random_seed", NULL);
+ gcry_control (GCRYCTL_SET_RANDOM_SEED_FILE, p);
+ xfree(p);
+ }
+
+ /* Get the UID of the caller. */
+#if defined(HAVE_PWD_H) && defined(HAVE_GETPWUID)
+ {
+ const char *uidstr;
+ struct passwd *pwd = NULL;
+
+ uidstr = getenv ("USERV_UID");
+
+ /* Print a quick note if we are not started via userv. */
+ if (!uidstr)
+ {
+ if (getuid ())
+ {
+ log_info ("WARNING: Not started via userv\n");
+ ctrl.fail_all_cmds = 1;
+ }
+ ctrl.client.uid = getuid ();
+ }
+ else
+ {
+ unsigned long myuid;
+
+ errno = 0;
+ myuid = strtoul (uidstr, NULL, 10);
+ if (myuid == ULONG_MAX && errno)
+ {
+ log_info ("WARNING: Started via broken userv: %s\n",
+ strerror (errno));
+ ctrl.fail_all_cmds = 1;
+ ctrl.client.uid = getuid ();
+ }
+ else
+ ctrl.client.uid = (uid_t)myuid;
+ }
+
+ pwd = getpwuid (ctrl.client.uid);
+ if (!pwd || !*pwd->pw_name)
+ {
+ log_info ("WARNING: Name for UID not found: %s\n", strerror (errno));
+ ctrl.fail_all_cmds = 1;
+ ctrl.client.uname = xstrdup ("?");
+ }
+ else
+ ctrl.client.uname = xstrdup (pwd->pw_name);
+ }
+#else /*!HAVE_PWD_H || !HAVE_GETPWUID*/
+ log_info ("WARNING: System does not support required syscalls\n");
+ ctrl.fail_all_cmds = 1;
+ ctrl.client.uid = getuid ();
+ ctrl.client.uname = xstrdup ("?");
+#endif /*!HAVE_PWD_H || !HAVE_GETPWUID*/
+
+ /* Read the table entries for this user. */
+ if (!ctrl.fail_all_cmds
+ && !(ctrl.client.tab = parse_g13tab (ctrl.client.uname)))
+ ctrl.fail_all_cmds = 1;
+
+ /* Start the server. */
+ err = syshelp_server (&ctrl);
+ if (err)
+ log_error ("server exited with error: %s <%s>\n",
+ gpg_strerror (err), gpg_strsource (err));
+
+ /* Cleanup. */
+ g13_syshelp_deinit_default_ctrl (&ctrl);
+ g13_exit (0);
+ return 8; /*NOTREACHED*/
+}
+
+
+/* Store defaults into the per-connection CTRL object. */
+void
+g13_syshelp_init_default_ctrl (ctrl_t ctrl)
+{
+ ctrl->conttype = CONTTYPE_DM_CRYPT;
+}
+
+/* Release all resources allocated by default in the CTRl object. */
+static void
+g13_syshelp_deinit_default_ctrl (ctrl_t ctrl)
+{
+ xfree (ctrl->client.uname);
+ release_tab_items (ctrl->client.tab);
+}
+
+
+/* Release the list of g13tab itejms at TAB. */
+static void
+release_tab_items (tab_item_t tab)
+{
+ while (tab)
+ {
+ tab_item_t next = tab->next;
+ xfree (tab->mountpoint);
+ xfree (tab);
+ tab = next;
+ }
+}
+
+
+/* Parse the /etc/gnupg/g13tab for user USERNAME. Return a table for
+ the user on success. Return NULL on error and print
+ diagnostics. */
+static tab_item_t
+parse_g13tab (const char *username)
+{
+ gpg_error_t err;
+ int c, n;
+ char line[512];
+ char *p;
+ char *fname;
+ estream_t fp;
+ int lnr;
+ char **words = NULL;
+ tab_item_t table = NULL;
+ tab_item_t *tabletail, ti;
+
+ fname = make_filename (gnupg_sysconfdir (), G13_NAME"tab", NULL);
+ fp = es_fopen (fname, "r");
+ if (!fp)
+ {
+ err = gpg_error_from_syserror ();
+ log_error (_("error opening '%s': %s\n"), fname, gpg_strerror (err));
+ goto leave;
+ }
+
+ tabletail = &table;
+ err = 0;
+ lnr = 0;
+ while (es_fgets (line, DIM(line)-1, fp))
+ {
+ lnr++;
+ n = strlen (line);
+ if (!n || line[n-1] != '\n')
+ {
+ /* Eat until end of line. */
+ while ((c=es_getc (fp)) != EOF && c != '\n')
+ ;
+ err = gpg_error (*line? GPG_ERR_LINE_TOO_LONG
+ : GPG_ERR_INCOMPLETE_LINE);
+ log_error (_("file '%s', line %d: %s\n"),
+ fname, lnr, gpg_strerror (err));
+ continue;
+ }
+ line[--n] = 0; /* Chop the LF. */
+ if (n && line[n-1] == '\r')
+ line[--n] = 0; /* Chop an optional CR. */
+
+ /* Allow for empty lines and spaces */
+ for (p=line; spacep (p); p++)
+ ;
+ if (!*p || *p == '#')
+ continue;
+
+ /* Parse the line. The format is
+ * [