aboutsummaryrefslogtreecommitdiffstats
path: root/g10
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
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')
-rw-r--r--g10/ChangeLog15
-rw-r--r--g10/Makefile.am1
-rw-r--r--g10/call-dirmngr.c256
-rw-r--r--g10/call-dirmngr.h26
-rw-r--r--g10/gpg.c35
-rw-r--r--g10/gpg.h8
-rw-r--r--g10/keyserver-internal.h2
-rw-r--r--g10/keyserver.c123
-rw-r--r--g10/options.h28
9 files changed, 436 insertions, 58 deletions
diff --git a/g10/ChangeLog b/g10/ChangeLog
index 0c8cbd418..1be035d39 100644
--- a/g10/ChangeLog
+++ b/g10/ChangeLog
@@ -1,3 +1,18 @@
+2011-01-07 Werner Koch <[email protected]>
+
+ * call-dirmngr.c, call-dirmngr.h: New.
+ * gpg.h (server_control_s): Add DIRMNGR_LOCAL.
+ * gpg.c: Include call-dirmngr.h.
+ (gpg_deinit_default_ctrl): Call gpg_dirmngr_deinit_session_data.
+
+2011-01-06 Werner Koch <[email protected]>
+
+ * gpg.c (main): Use keyserver_spec_t.
+
+ * options.h (struct opt): Factor definition of struct keyserver
+ out to ../common/keyserver.h.
+ (keyserver_spec_t): New.
+
2010-12-09 Werner Koch <[email protected]>
* tdbio.c (tdbio_set_dbname) [W32CE]: Take care of missing errno.
diff --git a/g10/Makefile.am b/g10/Makefile.am
index c8fc4821e..475529c4e 100644
--- a/g10/Makefile.am
+++ b/g10/Makefile.am
@@ -102,6 +102,7 @@ gpg2_SOURCES = gpg.c \
helptext.c \
keyserver.c \
keyserver-internal.h \
+ call-dirmngr.c call-dirmngr.h \
photoid.c photoid.h \
call-agent.c call-agent.h \
card-util.c \
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;
+}
diff --git a/g10/call-dirmngr.h b/g10/call-dirmngr.h
new file mode 100644
index 000000000..fa579ad5c
--- /dev/null
+++ b/g10/call-dirmngr.h
@@ -0,0 +1,26 @@
+/* call-dirmngr.h - 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/>.
+ */
+#ifndef GNUPG_G10_CALL_DIRMNGR_H
+#define GNUPG_G10_CALL_DIRMNGR_H
+
+void gpg_dirmngr_deinit_session_data (ctrl_t ctrl);
+
+
+
+#endif /*GNUPG_G10_CALL_DIRMNGR_H*/
diff --git a/g10/gpg.c b/g10/gpg.c
index 4a17b2905..1866c1cc8 100644
--- a/g10/gpg.c
+++ b/g10/gpg.c
@@ -1,6 +1,6 @@
/* gpg.c - The GnuPG utility (main for gpg)
- * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
- * 2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
+ * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
+ * 2008, 2009, 2010, 2011 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
@@ -54,6 +54,7 @@
#include "exec.h"
#include "gc-opt-flags.h"
#include "asshelp.h"
+#include "call-dirmngr.h"
#if defined(HAVE_DOSISH_SYSTEM) || defined(__CYGWIN__)
#define MY_O_BINARY O_BINARY
@@ -1822,7 +1823,7 @@ gpg_init_default_ctrl (ctrl_t ctrl)
static void
gpg_deinit_default_ctrl (ctrl_t ctrl)
{
- (void)ctrl;
+ gpg_dirmngr_deinit_session_data (ctrl);
}
@@ -2658,15 +2659,15 @@ main (int argc, char **argv)
break;
case oKeyServer:
{
- struct keyserver_spec *keyserver;
- keyserver=parse_keyserver_uri(pargs.r.ret_str,0,
- configname,configlineno);
- if(!keyserver)
- log_error(_("could not parse keyserver URL\n"));
+ keyserver_spec_t keyserver;
+ keyserver = parse_keyserver_uri (pargs.r.ret_str,0,
+ configname,configlineno);
+ if (!keyserver)
+ log_error (_("could not parse keyserver URL\n"));
else
{
- keyserver->next=opt.keyserver;
- opt.keyserver=keyserver;
+ keyserver->next = opt.keyserver;
+ opt.keyserver = keyserver;
}
}
break;
@@ -2853,14 +2854,14 @@ main (int argc, char **argv)
break;
case oDefaultKeyserverURL:
{
- struct keyserver_spec *keyserver;
- keyserver=parse_keyserver_uri(pargs.r.ret_str,1,
- configname,configlineno);
- if(!keyserver)
- log_error(_("could not parse keyserver URL\n"));
+ keyserver_spec_t keyserver;
+ keyserver = parse_keyserver_uri (pargs.r.ret_str,1,
+ configname,configlineno);
+ if (!keyserver)
+ log_error (_("could not parse keyserver URL\n"));
else
- free_keyserver_spec(keyserver);
-
+ free_keyserver_spec (keyserver);
+
opt.def_keyserver_url = pargs.r.ret_str;
}
break;
diff --git a/g10/gpg.h b/g10/gpg.h
index 1d645ea25..29db15a45 100644
--- a/g10/gpg.h
+++ b/g10/gpg.h
@@ -48,6 +48,10 @@
/* Object used to keep state locally to server.c . */
struct server_local_s;
+/* Object used to keep state locally to call-dirmngr.c . */
+struct dirmngr_local_s;
+typedef struct dirmngr_local_s *dirmngr_local_t;
+
/* Object used to describe a keyblok node. */
typedef struct kbnode_struct *KBNODE;
typedef struct kbnode_struct *kbnode_t;
@@ -58,7 +62,11 @@ typedef struct kbnode_struct *kbnode_t;
gpg_init_default_ctrl(). */
struct server_control_s
{
+ /* Local data for server.c */
struct server_local_s *server_local;
+
+ /* Local data for call-dirmngr.c */
+ dirmngr_local_t dirmngr_local;
};
diff --git a/g10/keyserver-internal.h b/g10/keyserver-internal.h
index cbf3c04a8..2b1b64e35 100644
--- a/g10/keyserver-internal.h
+++ b/g10/keyserver-internal.h
@@ -40,7 +40,7 @@ int keyserver_import_fprint (ctrl_t ctrl, const byte *fprint,size_t fprint_len,
int keyserver_import_keyid (ctrl_t ctrl, u32 *keyid,
struct keyserver_spec *keyserver);
int keyserver_refresh (ctrl_t ctrl, strlist_t users);
-int keyserver_search (ctrl_t ctrl, strlist_t tokens);
+gpg_error_t keyserver_search (ctrl_t ctrl, strlist_t tokens);
int keyserver_fetch (ctrl_t ctrl, strlist_t urilist);
int keyserver_import_cert (ctrl_t ctrl, const char *name,
unsigned char **fpr,size_t *fpr_len);
diff --git a/g10/keyserver.c b/g10/keyserver.c
index 422e62e78..60a117d2e 100644
--- a/g10/keyserver.c
+++ b/g10/keyserver.c
@@ -45,6 +45,7 @@
#ifdef USE_DNS_SRV
#include "srv.h"
#endif
+#include "membuf.h"
#ifdef HAVE_W32_SYSTEM
@@ -236,9 +237,9 @@ keyserver_match(struct keyserver_spec *spec)
parser any longer so it can be removed, or at least moved to
keyserver/ksutil.c for limited use in gpgkeys_ldap or the like. */
-struct keyserver_spec *
-parse_keyserver_uri(const char *string,int require_scheme,
- const char *configname,unsigned int configlineno)
+keyserver_spec_t
+parse_keyserver_uri (const char *string,int require_scheme,
+ const char *configname,unsigned int configlineno)
{
int assume_hkp=0;
struct keyserver_spec *keyserver;
@@ -1530,6 +1531,7 @@ keyserver_spawn (ctrl_t ctrl,
return ret;
}
+
static int
keyserver_work (ctrl_t ctrl,
enum ks_action action,strlist_t list,KEYDB_SEARCH_DESC *desc,
@@ -1538,23 +1540,16 @@ keyserver_work (ctrl_t ctrl,
{
int rc=0,ret=0;
- if(!keyserver)
+ if (!keyserver)
{
- log_error(_("no keyserver known (use option --keyserver)\n"));
- return G10ERR_BAD_URI;
+ log_error (_("no keyserver known (use option --keyserver)\n"));
+ return gpg_error (GPG_ERR_BAD_URI);
}
-#ifdef DISABLE_KEYSERVER_HELPERS
-
- log_error(_("external keyserver calls are not supported in this build\n"));
- return G10ERR_KEYSERVER;
-
-#else
- /* Spawn a handler */
rc = keyserver_spawn (ctrl, action, list, desc, count,
&ret, fpr, fpr_len, keyserver);
- if(ret)
+ if (ret)
{
switch(ret)
{
@@ -1591,15 +1586,14 @@ keyserver_work (ctrl_t ctrl,
return G10ERR_KEYSERVER;
}
- if(rc)
+ if (rc)
{
- log_error(_("keyserver communications error: %s\n"),g10_errstr(rc));
+ log_error (_("keyserver communications error: %s\n"),g10_errstr(rc));
return rc;
}
return 0;
-#endif /* ! DISABLE_KEYSERVER_HELPERS*/
}
int
@@ -1961,15 +1955,100 @@ keyserver_refresh (ctrl_t ctrl, strlist_t users)
return rc;
}
-int
+/* Search for keys on the keyservers. The patterns are given in the
+ string list TOKENS. */
+gpg_error_t
keyserver_search (ctrl_t ctrl, strlist_t tokens)
{
- if (tokens)
- return keyserver_work (ctrl, KS_SEARCH, tokens, NULL, 0,
- NULL, NULL, opt.keyserver);
- return 0;
+ gpg_error_t err;
+ int rc=0,ret=0;
+ char *searchstr;
+
+ /* FIXME: WORK IN PROGRESS */
+ if (!tokens)
+ return 0; /* Return success if no patterns are given. */
+
+ if (!opt.keyserver)
+ {
+ log_error (_("no keyserver known (use option --keyserver)\n"));
+ return gpg_error (GPG_ERR_NO_KEYSERVER);
+ }
+
+ /* switch(ret) */
+ /* { */
+ /* case KEYSERVER_SCHEME_NOT_FOUND: */
+ /* log_error(_("no handler for keyserver scheme `%s'\n"), */
+ /* opt.keyserver->scheme); */
+ /* break; */
+
+ /* case KEYSERVER_NOT_SUPPORTED: */
+ /* log_error(_("action `%s' not supported with keyserver " */
+ /* "scheme `%s'\n"), "search", opt.keyserver->scheme); */
+ /* break; */
+
+ /* case KEYSERVER_TIMEOUT: */
+ /* log_error(_("keyserver timed out\n")); */
+ /* break; */
+
+ /* case KEYSERVER_INTERNAL_ERROR: */
+ /* default: */
+ /* log_error(_("keyserver internal error\n")); */
+ /* break; */
+ /* } */
+
+ /* return gpg_error (GPG_ERR_KEYSERVER); */
+
+
+ /* Write global options */
+
+ /* for(temp=opt.keyserver_options.other;temp;temp=temp->next) */
+ /* fprintf(spawn->tochild,"OPTION %s\n",temp->d); */
+
+ /* Write per-keyserver options */
+
+ /* for(temp=keyserver->options;temp;temp=temp->next) */
+ /* fprintf(spawn->tochild,"OPTION %s\n",temp->d); */
+
+ /* Which keys do we want? Remember that the gpgkeys_ program
+ is going to lump these together into a search string. */
+ {
+ membuf_t mb;
+ strlist_t item;
+
+ init_membuf (&mb, 1024);
+ for (item = tokens; item; item = item->next)
+ {
+ if (item != tokens)
+ put_membuf (&mb, " ", 1);
+ put_membuf_str (&mb, item->d);
+ }
+ put_membuf (&mb, "", 1); /* Append Nul. */
+ searchstr = get_membuf (&mb, NULL);
+ if (!searchstr)
+ {
+ err = gpg_error_from_syserror ();
+ }
+ }
+ log_info (_("searching for \"%s\" from %s\n"), searchstr, keyserver->uri);
+
+ {
+ estream_t fp;
+ err = gpg_dirmngr_ks_search (ctrl, searchstr, &fp);
+
+ keyserver_search_prompt (ctrl, fp,searchstr);
+ }
+
+ leave:
+ xfree(line);
+ xfree(searchstr);
+
+
+ *prog=exec_finish(spawn);
+
+ return ret;
}
+
int
keyserver_fetch (ctrl_t ctrl, strlist_t urilist)
{
diff --git a/g10/options.h b/g10/options.h
index 28a2805a9..cd0140651 100644
--- a/g10/options.h
+++ b/g10/options.h
@@ -1,6 +1,6 @@
/* options.h
* Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
- * 2007, 2010 Free Software Foundation, Inc.
+ * 2007, 2010, 2011 Free Software Foundation, Inc.
*
* This file is part of GnuPG.
*
@@ -35,6 +35,13 @@
#endif
#endif
+/* Declaration of a keyserver spec type. The definition is found in
+ ../common/keyserver.h. */
+struct keyserver_spec;
+typedef struct keyserver_spec *keyserver_spec_t;
+
+
+/* Global options for GPG. */
EXTERN_UNLESS_MAIN_MODULE
struct
{
@@ -130,22 +137,7 @@ struct
int not_dash_escaped;
int escape_from;
int lock_once;
- struct keyserver_spec
- {
- char *uri;
- char *scheme;
- char *auth;
- char *host;
- char *port;
- char *path;
- char *opaque;
- strlist_t options;
- struct
- {
- unsigned int direct_uri:1;
- } flags;
- struct keyserver_spec *next;
- } *keyserver;
+ keyserver_spec_t keyserver; /* The list of configured keyservers. */
struct
{
unsigned int options;
@@ -245,7 +237,7 @@ struct
AKL_KEYSERVER,
AKL_SPEC
} type;
- struct keyserver_spec *spec;
+ keyserver_spec_t spec;
struct akl *next;
} *auto_key_locate;