aboutsummaryrefslogtreecommitdiffstats
path: root/g10/call-dirmngr.c
diff options
context:
space:
mode:
authorWerner Koch <[email protected]>2011-01-10 13:30:17 +0000
committerWerner Koch <[email protected]>2011-01-10 13:30:17 +0000
commit8c8c45725f60b77adc367f72aa479bfa2f9b1ea2 (patch)
tree2c6bba9dca4692fa9b4a954903f0863e7db84ef6 /g10/call-dirmngr.c
parentSupport the gnuk token pinpad code. (diff)
downloadgnupg-8c8c45725f60b77adc367f72aa479bfa2f9b1ea2.tar.gz
gnupg-8c8c45725f60b77adc367f72aa479bfa2f9b1ea2.zip
Initial code checking for backup - not yet working.
Diffstat (limited to 'g10/call-dirmngr.c')
-rw-r--r--g10/call-dirmngr.c256
1 files changed, 256 insertions, 0 deletions
diff --git a/g10/call-dirmngr.c b/g10/call-dirmngr.c
new file mode 100644
index 000000000..a18eb64b0
--- /dev/null
+++ b/g10/call-dirmngr.c
@@ -0,0 +1,256 @@
+/* call-dirmngr.c - GPG operations to the Dirmngr.
+ * Copyright (C) 2011 Free Software Foundation, Inc.
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <time.h>
+#include <assert.h>
+#ifdef HAVE_LOCALE_H
+# include <locale.h>
+#endif
+
+#include "gpg.h"
+#include <assuan.h>
+#include "util.h"
+#include "membuf.h"
+#include "options.h"
+#include "i18n.h"
+#include "asshelp.h"
+#include "call-dirmngr.h"
+
+
+/* Data used to associate an session with dirmngr contexts. We can't
+ use a simple one to one mapping because we sometimes need two
+ connection s to the dirmngr; for example while doing a listing and
+ being in a data callback we may want to retrieve a key. The local
+ dirmngr data takes care of this. At the end of the session the
+ function dirmngr_deinit_session_data is called bu gpg.c to cleanup
+ these resources. Note that gpg.h defines a typedef dirmngr_local_t
+ for this structure. */
+struct dirmngr_local_s
+{
+ /* Link to other contexts which are used simultaneously. */
+ struct dirmngr_local_s *next;
+
+ /* The active Assuan context. */
+ static assuan_context_t ctx;
+
+ /* Flag set to true while an operation is running on CTX. */
+ int is_active;
+};
+
+
+
+/* Deinitialize all session data of dirmngr pertaining to CTRL. */
+void
+gpg_dirmngr_deinit_session_data (ctrl_t ctrl)
+{
+ dirmngr_local_t dml;
+
+ while ((dml = ctrl->dirmngr_local))
+ {
+ ctrl->dirmngr_local = dml->next;
+ if (dml->is_active)
+ log_error ("oops: trying to cleanup an active dirmngr context\n");
+ else
+ assuan_release (dml->ctx);
+ xfree (dml);
+ }
+}
+
+
+/* Try to connect to the Dirmngr via a socket or fork it off if
+ possible. Handle the server's initial greeting and set global
+ options. */
+static gpg_error_t
+create_context (ctrl_t ctrl, assuan_context_t *r_ctx)
+{
+ gpg_error_t err;
+ assuan_context_t ctx;
+
+ *r_ctx = NULL;
+ err = start_new_dirmngr (&ctx,
+ GPG_ERR_SOURCE_DEFAULT,
+ opt.homedir,
+ NULL,
+ opt.verbose, DBG_ASSUAN,
+ NULL /*gpg_status2*/, ctrl);
+ if (!err)
+ {
+ keyserver_spec_t ksi;
+
+ /* Tell the dirmngr that we want to collect audit event. */
+ /* err = assuan_transact (agent_ctx, "OPTION audit-events=1", */
+ /* NULL, NULL, NULL, NULL, NULL, NULL); */
+
+ /* Set all configured keyservers. We clear existing keyservers
+ so that any keyserver configured in GPG overrides keyservers
+ possibly configured in Dirmngr. */
+ if (ksi = opt.keyservers; !err && ksi; ksi = ksi->next)
+ {
+ char *line;
+
+ line = xtryasprintf ("KEYSERVER%s %s",
+ ksi == opt.keyservers? " --clear":"", ksi->uri);
+ if (!line)
+ err = gpg_error_from_syserror ();
+ else
+ {
+ err = assuan_transact (ctx, line,
+ NULL, NULL, NULL, NULL, NULL, NULL);
+ xfree (line);
+ }
+ }
+ }
+
+ if (err)
+ assuan_release (ctx);
+ else
+ {
+ /* audit_log_ok (ctrl->audit, AUDIT_DIRMNGR_READY, err); */
+ *r_ctx = ctx;
+ }
+
+ return err;
+}
+
+
+/* Get a context for accessing dirmngr. If no context is available a
+ new one is created and - if requred - dirmngr started. On success
+ an assuan context is stored at R_CTX. This Context may only be
+ released by means of close_context. Note that NULL is stored at
+ R_CTX on error. */
+static gpg_error_t
+open_context (ctrl_t ctrl, assuan_context_t *r_ctx)
+{
+ gpg_error_t err;
+ dirmngr_local_t dml;
+
+ *r_ctx = NULL;
+ for (;;)
+ {
+ for (dml = ctrl->dirmngr_local; dml && dml->is_active; dml = dml->next)
+ ;
+ if (dml)
+ {
+ /* Found an inactive local session - return that. */
+ assert (!dml->is_active);
+ dml->is_active = 1;
+ return dml;
+ }
+
+ dml = xtrycalloc (1, sizeof *dml);
+ if (!dml)
+ return gpg_error_from_syserror ();
+ err = create_context (ctrl, &dml->ctx);
+ if (err)
+ {
+ xfree (dml);
+ return err;
+ }
+ /* To be on the Pth thread safe site we need to add it to a
+ list; this is far easier than to have a lock for this
+ function. It should not happen anyway but the code is free
+ because we need it for the is_active check above. */
+ dml->next = ctrl->dirmngr_local;
+ ctrl->dirmngr_local = dml;
+ }
+}
+
+
+/* Close the assuan context CTX or return it to a pool of unused
+ contexts. If CTX is NULL, the function does nothing. */
+static void
+close_context (ctrl_t ctrl, assuan_context_t ctx)
+{
+ dirmngr_local_t dml;
+
+ if (!ctx)
+ return;
+
+ for (dml = ctrl->dirmngr_local; dml; dml = dml->next)
+ {
+ if (dml->ctx == ctx)
+ {
+ if (!ctx->is_active)
+ log_fatal ("closing inactive dirmngr context %p\n", ctx);
+ ctx->is_active = 0;
+ return;
+ }
+ }
+ log_fatal ("closing unknown dirmngr ctx %p\n", ctx);
+}
+
+
+
+
+int
+gpg_dirmngr_ks_search (ctrl_t ctrl, strlist_t names,
+ void (*cb)(void*, ksba_cert_t), void *cb_value)
+{
+ gpg_error_t err;
+ assuan_context_t ctx;
+ char *pattern;
+ char line[ASSUAN_LINELENGTH];
+
+ err = open_context (ctrl, &ctx);
+ if (err)
+ return err;
+
+ pattern = pattern_from_strlist (names);
+ if (!pattern)
+ {
+ if (ctx == dirmngr_ctx)
+ release_dirmngr (ctrl);
+ else
+ release_dirmngr2 (ctrl);
+
+ return out_of_core ();
+ }
+ snprintf (line, DIM(line)-1, "LOOKUP%s %s",
+ cache_only? " --cache-only":"", pattern);
+ line[DIM(line)-1] = 0;
+ xfree (pattern);
+
+ parm.ctrl = ctrl;
+ parm.ctx = ctx;
+ parm.cb = cb;
+ parm.cb_value = cb_value;
+ parm.error = 0;
+ init_membuf (&parm.data, 4096);
+
+ rc = assuan_transact (ctx, line, lookup_cb, &parm,
+ NULL, NULL, lookup_status_cb, &parm);
+ xfree (get_membuf (&parm.data, &len));
+
+ if (ctx == dirmngr_ctx)
+ release_dirmngr (ctrl);
+ else
+ release_dirmngr2 (ctrl);
+
+ if (rc)
+ return rc;
+
+ close_context (ctrl, ctx);
+ return parm.error;
+}