summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--NEWS36
-rw-r--r--agent/Makefile.am2
-rw-r--r--agent/agent.h6
-rw-r--r--agent/call-pinentry.c30
-rw-r--r--agent/call-scd.c2
-rw-r--r--agent/command-ssh.c4
-rw-r--r--agent/command.c64
-rw-r--r--agent/cvt-openpgp.c23
-rw-r--r--agent/genkey.c2
-rw-r--r--agent/gpg-agent.c16
-rw-r--r--agent/learncard.c6
-rw-r--r--agent/pksign.c5
-rw-r--r--build-aux/speedo.mk2
-rw-r--r--common/Makefile.am7
-rw-r--r--common/argparse.c233
-rw-r--r--common/argparse.h11
-rw-r--r--common/dns-cert.c46
-rw-r--r--common/dns-cert.h19
-rw-r--r--common/gettime.c180
-rw-r--r--common/gettime.h5
-rw-r--r--common/http.c28
-rw-r--r--common/http.h3
-rw-r--r--common/mapstrings.c2
-rw-r--r--common/mbox-util.c249
-rw-r--r--common/mbox-util.h39
-rw-r--r--common/openpgp-oid.c46
-rw-r--r--common/pka.c340
-rw-r--r--common/pka.h2
-rw-r--r--common/stringhelp.c102
-rw-r--r--common/stringhelp.h4
-rw-r--r--common/strlist.c14
-rw-r--r--common/strlist.h3
-rw-r--r--common/t-dns-cert.c2
-rw-r--r--common/t-gettime.c75
-rw-r--r--common/t-mbox-util.c103
-rw-r--r--common/t-openpgp-oid.c44
-rw-r--r--common/t-pka.c72
-rw-r--r--common/t-stringhelp.c58
-rw-r--r--common/t-zb32.c3
-rw-r--r--common/userids.c2
-rw-r--r--common/util.h91
-rw-r--r--configure.ac21
-rw-r--r--dirmngr/Makefile.am25
-rw-r--r--dirmngr/certcache.c8
-rw-r--r--dirmngr/dirmngr.c15
-rw-r--r--dirmngr/dirmngr.h12
-rw-r--r--dirmngr/ks-action.c94
-rw-r--r--dirmngr/ks-action.h13
-rw-r--r--dirmngr/ks-engine-hkp.c88
-rw-r--r--dirmngr/ks-engine-ldap.c2064
-rw-r--r--dirmngr/ks-engine.h10
-rw-r--r--dirmngr/ldap-parse-uri.c246
-rw-r--r--dirmngr/ldap-parse-uri.h33
-rw-r--r--dirmngr/ldap-wrapper.c2
-rw-r--r--dirmngr/ldap.c2
-rw-r--r--dirmngr/ldapserver.c2
-rw-r--r--dirmngr/misc.c77
-rw-r--r--dirmngr/misc.h6
-rw-r--r--dirmngr/server.c55
-rw-r--r--dirmngr/t-ldap-parse-uri.c255
-rw-r--r--dirmngr/t-support.h42
-rw-r--r--doc/DETAILS49
-rw-r--r--doc/FAQ6
-rw-r--r--doc/Makefile.am23
-rw-r--r--doc/dirmngr.texi33
-rw-r--r--doc/gpg-agent.texi7
-rw-r--r--doc/gpg.texi28
-rw-r--r--doc/gpgsm.texi4
-rw-r--r--g10/Makefile.am3
-rw-r--r--g10/build-packet.c29
-rw-r--r--g10/call-agent.c11
-rw-r--r--g10/call-agent.h2
-rw-r--r--g10/call-dirmngr.c206
-rw-r--r--g10/card-util.c6
-rw-r--r--g10/ecdh.c24
-rw-r--r--g10/encrypt.c14
-rw-r--r--g10/getkey.c179
-rw-r--r--g10/gpg.c133
-rw-r--r--g10/keydb.c12
-rw-r--r--g10/keyedit.c41
-rw-r--r--g10/keygen.c5
-rw-r--r--g10/keyid.c21
-rw-r--r--g10/keylist.c231
-rw-r--r--g10/keyserver.c10
-rw-r--r--g10/main.h7
-rw-r--r--g10/mainproc.c14
-rw-r--r--g10/misc.c94
-rw-r--r--g10/options.h22
-rw-r--r--g10/parse-packet.c56
-rw-r--r--g10/pkglue.c2
-rw-r--r--g10/pubkey-enc.c4
-rw-r--r--g10/seskey.c4
-rw-r--r--g10/sig-check.c2
-rw-r--r--g10/sign.c4
-rw-r--r--g10/tdbdump.c60
-rw-r--r--g10/tdbio.c65
-rw-r--r--g10/tdbio.h2
-rw-r--r--g10/trustdb.c26
-rw-r--r--g13/Makefile.am2
-rw-r--r--g13/call-gpg.c2
-rw-r--r--g13/g13.c8
-rw-r--r--g13/g13.h4
-rw-r--r--g13/utils.c10
-rw-r--r--kbx/Makefile.am3
-rw-r--r--kbx/keybox-search.c59
-rw-r--r--po/ru.po154
-rw-r--r--po/uk.po46
-rw-r--r--scd/Makefile.am2
-rw-r--r--scd/apdu.c14
-rw-r--r--scd/app-openpgp.c6
-rw-r--r--scd/scdaemon.c8
-rw-r--r--scd/scdaemon.h4
-rw-r--r--sm/Makefile.am2
-rw-r--r--sm/call-agent.c2
-rw-r--r--sm/call-dirmngr.c4
-rw-r--r--sm/certreqgen.c2
-rw-r--r--sm/gpgsm.c10
-rw-r--r--sm/gpgsm.h4
-rw-r--r--tools/Makefile.am2
-rw-r--r--tools/gpgparsemail.c40
-rw-r--r--tools/gpgtar-extract.c6
-rw-r--r--tools/rfc822parse.c16
-rw-r--r--tools/watchgnupg.c2
123 files changed, 5517 insertions, 1385 deletions
diff --git a/NEWS b/NEWS
index 3a386f9..c026432 100644
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,39 @@
+Noteworthy changes in version 2.1.3 (2015-04-11)
+------------------------------------------------
+
+ * gpg: LDAP keyservers are now supported by 2.1.
+
+ * gpg: New option --with-icao-spelling.
+
+ * gpg: New option --print-pka-records. Changed the PKA method to use
+ CERT records and hashed names.
+
+ * gpg: New command --list-gcrypt-config. New parameter "curve"
+ for --list-config.
+
+ * gpg: Print a NEWSIG status line like gpgsm always did.
+
+ * gpg: Print MPI values with --list-packets and --verbose.
+
+ * gpg: Write correct MPI lengths with ECC keys.
+
+ * gpg: Skip legacy PGP-2 keys while searching.
+
+ * gpg: Improved searching for mail addresses when using a keybox.
+
+ * gpgsm: Changed default algos to AES-128 and SHA-256.
+
+ * gpgtar: Fixed extracting files with sizes of a multiple of 512.
+
+ * dirmngr: Fixed SNI handling for hkps pools.
+
+ * dirmngr: extra-certs and trusted-certs are now always loaded from
+ the sysconfig dir instead of the homedir.
+
+ * Fixed possible problems due to compiler optimization, two minor
+ regressions, and other bugs.
+
+
Noteworthy changes in version 2.1.2 (2015-02-11)
------------------------------------------------
diff --git a/agent/Makefile.am b/agent/Makefile.am
index bcf1788..b33593d 100644
--- a/agent/Makefile.am
+++ b/agent/Makefile.am
@@ -28,7 +28,7 @@ noinst_PROGRAMS = $(TESTS)
EXTRA_DIST = ChangeLog-2011 gpg-agent-w32info.rc
-AM_CPPFLAGS = -I$(top_srcdir)/gl -I$(top_srcdir)/common -I$(top_srcdir)/intl
+AM_CPPFLAGS = -I$(top_srcdir)/common
include $(top_srcdir)/am/cmacros.am
diff --git a/agent/agent.h b/agent/agent.h
index f60061e..30d0ffb 100644
--- a/agent/agent.h
+++ b/agent/agent.h
@@ -146,7 +146,7 @@ struct
#define DBG_CACHE_VALUE 64 /* debug the caching */
#define DBG_MEMSTAT_VALUE 128 /* show memory statistics */
#define DBG_HASHING_VALUE 512 /* debug hashing operations */
-#define DBG_ASSUAN_VALUE 1024 /* Enable Assuan debugging. */
+#define DBG_IPC_VALUE 1024 /* Enable Assuan debugging. */
/* Test macros for the debug option. */
#define DBG_COMMAND (opt.debug & DBG_COMMAND_VALUE)
@@ -154,7 +154,7 @@ struct
#define DBG_MEMORY (opt.debug & DBG_MEMORY_VALUE)
#define DBG_CACHE (opt.debug & DBG_CACHE_VALUE)
#define DBG_HASHING (opt.debug & DBG_HASHING_VALUE)
-#define DBG_ASSUAN (opt.debug & DBG_ASSUAN_VALUE)
+#define DBG_IPC (opt.debug & DBG_IPC_VALUE)
/* Forward reference for local definitions in command.c. */
struct server_local_s;
@@ -495,7 +495,7 @@ int agent_card_scd (ctrl_t ctrl, const char *cmdline,
/*-- learncard.c --*/
-int agent_handle_learn (ctrl_t ctrl, int send, void *assuan_context);
+int agent_handle_learn (ctrl_t ctrl, int send, void *assuan_context, int force);
/*-- cvt-openpgp.c --*/
diff --git a/agent/call-pinentry.c b/agent/call-pinentry.c
index a96406f..6db429c 100644
--- a/agent/call-pinentry.c
+++ b/agent/call-pinentry.c
@@ -133,6 +133,34 @@ unlock_pinentry (int rc)
assuan_context_t ctx = entry_ctx;
int err;
+ if (rc)
+ {
+ if (DBG_IPC)
+ log_debug ("error calling pinentry: %s <%s>\n",
+ gpg_strerror (rc), gpg_strsource (rc));
+
+ /* Change the source of the error to pinentry so that the final
+ consumer of the error code knows that the problem is with
+ pinentry. For backward compatibility we do not do that for
+ some common error codes. */
+ switch (gpg_err_code (rc))
+ {
+ case GPG_ERR_NO_PIN_ENTRY:
+ case GPG_ERR_CANCELED:
+ case GPG_ERR_FULLY_CANCELED:
+ case GPG_ERR_ASS_UNKNOWN_INQUIRE:
+ case GPG_ERR_ASS_TOO_MUCH_DATA:
+ case GPG_ERR_NO_PASSPHRASE:
+ case GPG_ERR_BAD_PASSPHRASE:
+ case GPG_ERR_BAD_PIN:
+ break;
+
+ default:
+ rc = gpg_err_make (GPG_ERR_SOURCE_PINENTRY, gpg_err_code (rc));
+ break;
+ }
+ }
+
entry_ctx = NULL;
err = npth_mutex_unlock (&entry_lock);
if (err)
@@ -323,7 +351,7 @@ start_pinentry (ctrl_t ctrl)
}
entry_ctx = ctx;
- if (DBG_ASSUAN)
+ if (DBG_IPC)
log_debug ("connection to PIN entry established\n");
rc = assuan_transact (entry_ctx,
diff --git a/agent/call-scd.c b/agent/call-scd.c
index ade7ef1..6cd5825 100644
--- a/agent/call-scd.c
+++ b/agent/call-scd.c
@@ -366,7 +366,7 @@ start_scd (ctrl_t ctrl)
{
memcpy (socket_name, databuf, datalen);
socket_name[datalen] = 0;
- if (DBG_ASSUAN)
+ if (DBG_IPC)
log_debug ("additional connections at '%s'\n", socket_name);
}
}
diff --git a/agent/command-ssh.c b/agent/command-ssh.c
index 51d2c54..fffdb00 100644
--- a/agent/command-ssh.c
+++ b/agent/command-ssh.c
@@ -1220,7 +1220,7 @@ ssh_search_control_file (ssh_control_file_t cf,
/* We need to make sure that HEXGRIP is all uppercase. The easiest
way to do this and also check its length is by copying to a
second buffer. */
- for (i=0, s=hexgrip; i < 40; s++, i++)
+ for (i=0, s=hexgrip; i < 40 && *s; s++, i++)
uphexgrip[i] = *s >= 'a'? (*s & 0xdf): *s;
uphexgrip[i] = 0;
if (i != 40)
@@ -3117,7 +3117,7 @@ ssh_identity_register (ctrl_t ctrl, ssh_key_type_spec_t *spec,
/* Unless the passphrase is empty or the pinentry told us that
it already did the repetition check, ask to confirm it. */
- if (pi->pin && *pi->pin && !pi->repeat_okay)
+ if (*pi->pin && !pi->repeat_okay)
{
err = agent_askpin (ctrl, description2, NULL, NULL, pi2);
if (err == -1)
diff --git a/agent/command.c b/agent/command.c
index ca28e9b..3188bbd 100644
--- a/agent/command.c
+++ b/agent/command.c
@@ -718,7 +718,7 @@ cmd_setkeydesc (assuan_context_t ctx, char *line)
if (p)
*p = 0; /* We ignore any garbage; we might late use it for other args. */
- if (!desc || !*desc)
+ if (!*desc)
return set_error (GPG_ERR_ASS_PARAMETER, "no description given");
/* Note, that we only need to replace the + characters and should
@@ -1481,7 +1481,7 @@ cmd_get_passphrase (assuan_context_t ctx, char *line)
}
}
}
- if (!cacheid || !*cacheid || strlen (cacheid) > 50)
+ if (!*cacheid || strlen (cacheid) > 50)
return set_error (GPG_ERR_ASS_PARAMETER, "invalid length of cacheID");
if (!desc)
return set_error (GPG_ERR_ASS_PARAMETER, "no description given");
@@ -1596,7 +1596,7 @@ cmd_clear_passphrase (assuan_context_t ctx, char *line)
p = strchr (cacheid, ' ');
if (p)
*p = 0; /* ignore garbage */
- if (!cacheid || !*cacheid || strlen (cacheid) > 50)
+ if (!*cacheid || strlen (cacheid) > 50)
return set_error (GPG_ERR_ASS_PARAMETER, "invalid length of cacheID");
agent_put_cache (cacheid, opt_normal ? CACHE_MODE_NORMAL : CACHE_MODE_USER,
@@ -1635,7 +1635,7 @@ cmd_get_confirmation (assuan_context_t ctx, char *line)
if (p)
*p = 0; /* We ignore any garbage -may be later used for other args. */
- if (!desc || !*desc)
+ if (!*desc)
return set_error (GPG_ERR_ASS_PARAMETER, "no description given");
if (!strcmp (desc, "X"))
@@ -1655,25 +1655,27 @@ cmd_get_confirmation (assuan_context_t ctx, char *line)
static const char hlp_learn[] =
- "LEARN [--send][--sendinfo]\n"
+ "LEARN [--send] [--sendinfo] [--force]\n"
"\n"
"Learn something about the currently inserted smartcard. With\n"
"--sendinfo information about the card is returned; with --send\n"
- "the available certificates are returned as D lines.";
+ "the available certificates are returned as D lines; with --force\n"
+ "private key storage will be updated by the result.";
static gpg_error_t
cmd_learn (assuan_context_t ctx, char *line)
{
ctrl_t ctrl = assuan_get_pointer (ctx);
gpg_error_t err;
- int send, sendinfo;
+ int send, sendinfo, force;
send = has_option (line, "--send");
sendinfo = send? 1 : has_option (line, "--sendinfo");
+ force = has_option (line, "--force");
if (ctrl->restricted)
return leave_cmd (ctx, gpg_error (GPG_ERR_FORBIDDEN));
- err = agent_handle_learn (ctrl, send, sendinfo? ctx : NULL);
+ err = agent_handle_learn (ctrl, send, sendinfo? ctx : NULL, force);
return leave_cmd (ctx, err);
}
@@ -2409,12 +2411,10 @@ cmd_keytocard (assuan_context_t ctx, char *line)
gpg_error_t err = 0;
unsigned char grip[20];
gcry_sexp_t s_skey = NULL;
- gcry_sexp_t s_pkey = NULL;
unsigned char *keydata;
size_t keydatalen, timestamplen;
const char *serialno, *timestamp_str, *id;
unsigned char *shadow_info = NULL;
- unsigned char *shdkey;
time_t timestamp;
if (ctrl->restricted)
@@ -2492,48 +2492,8 @@ cmd_keytocard (assuan_context_t ctx, char *line)
snprintf (keydata+keydatalen-1, 30, "(10:created-at10:%010lu))", timestamp);
keydatalen += 10 + 19 - 1;
err = divert_writekey (ctrl, force, serialno, id, keydata, keydatalen);
- if (err)
- {
- xfree (keydata);
- goto leave;
- }
- xfree (keydata);
-
- err = agent_public_key_from_file (ctrl, grip, &s_pkey);
- if (err)
- goto leave;
-
- shadow_info = make_shadow_info (serialno, id);
- if (!shadow_info)
- {
- err = gpg_error (GPG_ERR_ENOMEM);
- gcry_sexp_release (s_pkey);
- goto leave;
- }
- keydatalen = gcry_sexp_sprint (s_pkey, GCRYSEXP_FMT_CANON, NULL, 0);
- keydata = xtrymalloc (keydatalen);
- if (keydata == NULL)
- {
- err = gpg_error_from_syserror ();
- gcry_sexp_release (s_pkey);
- goto leave;
- }
- gcry_sexp_sprint (s_pkey, GCRYSEXP_FMT_CANON, keydata, keydatalen);
- gcry_sexp_release (s_pkey);
- err = agent_shadow_key (keydata, shadow_info, &shdkey);
xfree (keydata);
- xfree (shadow_info);
- if (err)
- {
- log_error ("shadowing the key failed: %s\n", gpg_strerror (err));
- goto leave;
- }
-
- keydatalen = gcry_sexp_canon_len (shdkey, 0, NULL, NULL);
- err = agent_write_private_key (grip, shdkey, keydatalen, 1);
- xfree (shdkey);
- leave:
return leave_cmd (ctx, err);
}
@@ -2568,7 +2528,7 @@ cmd_getval (assuan_context_t ctx, char *line)
if (*p)
return set_error (GPG_ERR_ASS_PARAMETER, "too many arguments");
}
- if (!key || !*key)
+ if (!*key)
return set_error (GPG_ERR_ASS_PARAMETER, "no key given");
@@ -2635,7 +2595,7 @@ cmd_putval (assuan_context_t ctx, char *line)
valuelen = percent_plus_unescape_inplace (value, 0);
}
}
- if (!key || !*key)
+ if (!*key)
return set_error (GPG_ERR_ASS_PARAMETER, "no key given");
diff --git a/agent/cvt-openpgp.c b/agent/cvt-openpgp.c
index cadc871..b00f032 100644
--- a/agent/cvt-openpgp.c
+++ b/agent/cvt-openpgp.c
@@ -1107,14 +1107,33 @@ apply_protection (gcry_mpi_t *array, int npkey, int nskey,
{
if (gcry_mpi_get_flag (array[i], GCRYMPI_FLAG_OPAQUE))
{
- const void *s;
+ const unsigned char *s;
unsigned int n;
s = gcry_mpi_get_opaque (array[i], &n);
+ if (!s)
+ {
+ s = "";
+ n = 0;
+ }
+ /* Strip leading zero bits. */
+ for (; n >= 8 && !*s; s++, n -= 8)
+ ;
+ if (n >= 8 && !(*s & 0x80))
+ if (--n >= 7 && !(*s & 0x40))
+ if (--n >= 6 && !(*s & 0x20))
+ if (--n >= 5 && !(*s & 0x10))
+ if (--n >= 4 && !(*s & 0x08))
+ if (--n >= 3 && !(*s & 0x04))
+ if (--n >= 2 && !(*s & 0x02))
+ if (--n >= 1 && !(*s & 0x01))
+ --n;
+
nbits[j] = n;
n = (n+7)/8;
narr[j] = n;
- bufarr[j] = gcry_is_secure (s)? xtrymalloc_secure (n):xtrymalloc (n);
+ bufarr[j] = (gcry_is_secure (s)? xtrymalloc_secure (n?n:1)
+ /* */ : xtrymalloc (n?n:1));
if (!bufarr[j])
{
err = gpg_error_from_syserror ();
diff --git a/agent/genkey.c b/agent/genkey.c
index d7b6007..ecf676e 100644
--- a/agent/genkey.c
+++ b/agent/genkey.c
@@ -382,7 +382,7 @@ agent_ask_new_passphrase (ctrl_t ctrl, const char *prompt,
}
/* Unless the passphrase is empty or the pinentry told us that
it already did the repetition check, ask to confirm it. */
- if (pi->pin && *pi->pin && !pi->repeat_okay)
+ if (*pi->pin && !pi->repeat_okay)
{
err = agent_askpin (ctrl, text2, NULL, NULL, pi2);
if (err == -1)
diff --git a/agent/gpg-agent.c b/agent/gpg-agent.c
index 6e1c76e..740af75 100644
--- a/agent/gpg-agent.c
+++ b/agent/gpg-agent.c
@@ -435,11 +435,11 @@ set_debug (void)
else if (!strcmp (debug_level, "none") || (numok && numlvl < 1))
opt.debug = 0;
else if (!strcmp (debug_level, "basic") || (numok && numlvl <= 2))
- opt.debug = DBG_ASSUAN_VALUE;
+ opt.debug = DBG_IPC_VALUE;
else if (!strcmp (debug_level, "advanced") || (numok && numlvl <= 5))
- opt.debug = DBG_ASSUAN_VALUE|DBG_COMMAND_VALUE;
+ opt.debug = DBG_IPC_VALUE|DBG_COMMAND_VALUE;
else if (!strcmp (debug_level, "expert") || (numok && numlvl <= 8))
- opt.debug = (DBG_ASSUAN_VALUE|DBG_COMMAND_VALUE
+ opt.debug = (DBG_IPC_VALUE|DBG_COMMAND_VALUE
|DBG_CACHE_VALUE);
else if (!strcmp (debug_level, "guru") || numok)
{
@@ -478,7 +478,7 @@ set_debug (void)
(opt.debug & DBG_CACHE_VALUE )? " cache":"",
(opt.debug & DBG_MEMSTAT_VALUE)? " memstat":"",
(opt.debug & DBG_HASHING_VALUE)? " hashing":"",
- (opt.debug & DBG_ASSUAN_VALUE )? " assuan":"");
+ (opt.debug & DBG_IPC_VALUE )? " ipc":"");
}
@@ -1952,7 +1952,7 @@ putty_message_proc (HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
if (!cds->cbData || mapfile[cds->cbData - 1])
return 0; /* Ignore empty and non-properly terminated strings. */
- if (DBG_ASSUAN)
+ if (DBG_IPC)
{
npth_protect ();
log_debug ("ssh map file '%s'", mapfile);
@@ -1960,7 +1960,7 @@ putty_message_proc (HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
}
maphd = OpenFileMapping (FILE_MAP_ALL_ACCESS, FALSE, mapfile);
- if (DBG_ASSUAN)
+ if (DBG_IPC)
{
npth_protect ();
log_debug ("ssh map handle %p\n", maphd);
@@ -1989,7 +1989,7 @@ putty_message_proc (HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
goto leave;
}
- if (DBG_ASSUAN)
+ if (DBG_IPC)
{
char *sidstr;
@@ -2010,7 +2010,7 @@ putty_message_proc (HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
}
data = MapViewOfFile (maphd, FILE_MAP_ALL_ACCESS, 0, 0, 0);
- if (DBG_ASSUAN)
+ if (DBG_IPC)
log_debug ("ssh IPC buffer at %p\n", data);
if (!data)
goto leave;
diff --git a/agent/learncard.c b/agent/learncard.c
index 62569ce..e0f2340 100644
--- a/agent/learncard.c
+++ b/agent/learncard.c
@@ -299,7 +299,7 @@ send_cert_back (ctrl_t ctrl, const char *id, void *assuan_context)
/* Perform the learn operation. If ASSUAN_CONTEXT is not NULL and
SEND is true all new certificates are send back via Assuan. */
int
-agent_handle_learn (ctrl_t ctrl, int send, void *assuan_context)
+agent_handle_learn (ctrl_t ctrl, int send, void *assuan_context, int force)
{
int rc;
@@ -399,7 +399,7 @@ agent_handle_learn (ctrl_t ctrl, int send, void *assuan_context)
for (p=item->hexgrip, i=0; i < 20; p += 2, i++)
grip[i] = xtoi_2 (p);
- if (!agent_key_available (grip))
+ if (!force && !agent_key_available (grip))
continue; /* The key is already available. */
/* Unknown key - store it. */
@@ -430,7 +430,7 @@ agent_handle_learn (ctrl_t ctrl, int send, void *assuan_context)
n = gcry_sexp_canon_len (shdkey, 0, NULL, NULL);
assert (n);
- rc = agent_write_private_key (grip, shdkey, n, 0);
+ rc = agent_write_private_key (grip, shdkey, n, force);
xfree (shdkey);
if (rc)
{
diff --git a/agent/pksign.c b/agent/pksign.c
index d737bad..1d3d3d8 100644
--- a/agent/pksign.c
+++ b/agent/pksign.c
@@ -363,12 +363,13 @@ agent_pksign_do (ctrl_t ctrl, const char *cache_nonce,
*buf = 0;
}
- rc = gcry_sexp_build (&s_sig, NULL, "(sig-val(rsa(s%b)))", len, buf);
+ rc = gcry_sexp_build (&s_sig, NULL, "(sig-val(rsa(s%b)))",
+ (int)len, buf);
}
else if (is_EdDSA)
{
rc = gcry_sexp_build (&s_sig, NULL, "(sig-val(eddsa(r%b)(s%b)))",
- len/2, buf, len/2, buf + len/2);
+ (int)len/2, buf, (int)len/2, buf + len/2);
}
else if (is_ECDSA)
{
diff --git a/build-aux/speedo.mk b/build-aux/speedo.mk
index 8a2053a..a0e29a5 100644
--- a/build-aux/speedo.mk
+++ b/build-aux/speedo.mk
@@ -206,7 +206,7 @@ endif
# a full installer.
speedo_w64_spkgs =
ifeq ($(WITH_GUI),1)
-speedo_w64_spkgs += ibgpg-error libiconv gettext libassuan gpgex
+speedo_w64_spkgs += libgpg-error libiconv gettext libassuan gpgex
endif
# Packages which use the gnupg autogen.sh build style
diff --git a/common/Makefile.am b/common/Makefile.am
index 6b41062..51923e8 100644
--- a/common/Makefile.am
+++ b/common/Makefile.am
@@ -34,7 +34,7 @@ BUILT_SOURCES = audit-events.h status-codes.h
MAINTAINERCLEANFILES = audit-events.h status-codes.h
-AM_CPPFLAGS = -I$(top_srcdir)/gl -I$(top_srcdir)/intl
+AM_CPPFLAGS =
AM_CFLAGS = $(LIBGCRYPT_CFLAGS) $(LIBASSUAN_CFLAGS) $(KSBA_CFLAGS)
@@ -75,6 +75,7 @@ common_sources = \
b64enc.c b64dec.c zb32.c \
convert.c \
percent.c \
+ mbox-util.c mbox-util.h \
miscellaneous.c \
xasprintf.c \
xreadline.c \
@@ -177,7 +178,7 @@ jnlib_tests += t-w32-reg
endif
module_tests = t-convert t-percent t-gettime t-sysutils t-sexputil \
t-session-env t-openpgp-oid t-ssh-utils t-dns-cert \
- t-mapstrings t-zb32
+ t-pka t-mapstrings t-zb32 t-mbox-util
if !HAVE_W32CE_SYSTEM
module_tests += t-exechelp
endif
@@ -221,8 +222,10 @@ t_session_env_LDADD = $(t_common_ldadd)
t_openpgp_oid_LDADD = $(t_common_ldadd)
t_ssh_utils_LDADD = $(t_common_ldadd)
t_dns_cert_LDADD = $(t_common_ldadd) $(DNSLIBS)
+t_pka_LDADD = $(t_common_ldadd) $(DNSLIBS)
t_mapstrings_LDADD = $(t_common_ldadd)
t_zb32_LDADD = $(t_common_ldadd)
+t_mbox_util_LDADD = $(t_common_ldadd)
# http tests
t_http_SOURCES = t-http.c
diff --git a/common/argparse.c b/common/argparse.c
index b067314..e31b67e 100644
--- a/common/argparse.c
+++ b/common/argparse.c
@@ -1,6 +1,6 @@
/* [argparse.c wk 17.06.97] Argument Parser for option handling
- * Copyright (C) 1998-2001, 2006-2008, 2012 Free Software Foundation, Inc.
- * Copyright (C) 1997-2001, 2006-2008, 2013 Werner Koch
+ * Copyright (C) 1998-2001, 2006-2008, 2012 Free Software Foundation, Inc.
+ * Copyright (C) 1997-2001, 2006-2008, 2013-2015 Werner Koch
*
* This file is part of JNLIB, which is a subsystem of GnuPG.
*
@@ -29,6 +29,11 @@
* if not, see <http://www.gnu.org/licenses/>.
*/
+/* This file may be used as part of GnuPG or standalone. A GnuPG
+ build is detected by the presence of the macro GNUPG_MAJOR_VERSION.
+ Some feature are only availalbe in the GnuPG build mode.
+ */
+
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
@@ -41,20 +46,114 @@
#include <limits.h>
#include <errno.h>
-#include "libjnlib-config.h"
-#include "mischelp.h"
-#include "stringhelp.h"
-#include "logging.h"
-#ifdef JNLIB_NEED_UTF8CONV
-#include "utf8conv.h"
-#endif
+#ifdef GNUPG_MAJOR_VERSION
+# include "libjnlib-config.h"
+# include "mischelp.h"
+# include "stringhelp.h"
+# include "logging.h"
+# ifdef JNLIB_NEED_UTF8CONV
+# include "utf8conv.h"
+# endif
+#endif /*GNUPG_MAJOR_VERSION*/
+
#include "argparse.h"
+/* GnuPG uses GPLv3+ but a standalone version of this defaults to
+ GPLv2+ because that is the license of this file. Change this if
+ you include it in a program which uses GPLv3. If you don't want to
+ set a a copyright string for your usage() you may also hardcode it
+ here. */
+#ifndef GNUPG_MAJOR_VERSION
+
+# define ARGPARSE_GPL_VERSION 2
+# define ARGPARSE_CRIGHT_STR "Copyright (C) YEAR NAME"
+
+#else /* Used by GnuPG */
+
+# define ARGPARSE_GPL_VERSION 3
+# define ARGPARSE_CRIGHT_STR "Copyright (C) 2015 Free Software Foundation, Inc."
+
+#endif /*GNUPG_MAJOR_VERSION*/
+
+/* Replacements for standalone builds. */
+#ifndef GNUPG_MAJOR_VERSION
+# ifndef _
+# define _(a) (a)
+# endif
+# ifndef DIM
+# define DIM(v) (sizeof(v)/sizeof((v)[0]))
+# endif
+# define jnlib_malloc(a) malloc ((a))
+# define jnlib_realloc(a,b) realloc ((a), (b))
+# define jnlib_strdup(a) strdup ((a))
+# define jnlib_free(a) free ((a))
+# define jnlib_log_error my_log_error
+# define jnlib_log_bug my_log_bug
+# define trim_spaces(a) my_trim_spaces ((a))
+# define map_static_macro_string(a) (a)
+#endif /*!GNUPG_MAJOR_VERSION*/
+
+
+#define ARGPARSE_STR(v) #v
+#define ARGPARSE_STR2(v) ARGPARSE_STR(v)
+
+
+/* Replacements for standalone builds. */
+#ifndef GNUPG_MAJOR_VERSION
+static void
+my_log_error (const char *fmt, ...)
+{
+ va_list arg_ptr ;
+
+ va_start (arg_ptr, fmt);
+ fprintf (stderr, "%s: ", strusage (11));
+ vfprintf (stderr, fmt, arg_ptr);
+ va_end (arg_ptr);
+}
+
+static void
+my_log_bug (const char *fmt, ...)
+{
+ va_list arg_ptr ;
+
+ va_start (arg_ptr, fmt);
+ fprintf (stderr, "%s: Ohhhh jeeee: ", strusage (11));
+ vfprintf (stderr, fmt, arg_ptr);
+ va_end (arg_ptr);
+ abort ();
+}
+
+static char *
+my_trim_spaces (char *str)
+{
+ char *string, *p, *mark;
+
+ string = str;
+ /* Find first non space character. */
+ for (p=string; *p && isspace (*(unsigned char*)p) ; p++)
+ ;
+ /* Move characters. */
+ for ((mark = NULL); (*string = *p); string++, p++)
+ if (isspace (*(unsigned char*)p))
+ {
+ if (!mark)
+ mark = string;
+ }
+ else
+ mark = NULL;
+ if (mark)
+ *mark = '\0' ; /* Remove trailing spaces. */
+
+ return str ;
+}
+
+#endif /*!GNUPG_MAJOR_VERSION*/
+
/*********************************
* @Summary arg_parse
- * #include <wk/lib.h>
+ * #include "argparse.h"
*
* typedef struct {
* char *argc; pointer to argc (value subject to change)
@@ -1140,6 +1239,14 @@ show_help (ARGPARSE_OPTS *opts, unsigned int flags)
show_version ();
writestrings (0, "\n", NULL);
+ s = strusage (42);
+ if (s && *s == '1')
+ {
+ s = strusage (40);
+ writestrings (1, s, NULL);
+ if (*s && s[strlen(s)] != '\n')
+ writestrings (1, "\n", NULL);
+ }
s = strusage(41);
writestrings (0, s, "\n", NULL);
if ( opts[0].description )
@@ -1333,6 +1440,14 @@ usage (int level)
}
else if (level == 2)
{
+ p = strusage (42);
+ if (p && *p == '1')
+ {
+ p = strusage (40);
+ writestrings (1, p, NULL);
+ if (*p && p[strlen(p)] != '\n')
+ writestrings (1, "\n", NULL);
+ }
writestrings (0, strusage(41), "\n", NULL);
exit (0);
}
@@ -1356,6 +1471,10 @@ usage (int level)
*30..39: Additional program info (with LFs)
* 40: short usage note (with LF)
* 41: long usage note (with LF)
+ * 42: Flag string:
+ * First char is '1':
+ * The short usage notes needs to be printed
+ * before the long usage note.
*/
const char *
strusage( int level )
@@ -1367,12 +1486,19 @@ strusage( int level )
switch ( level )
{
- case 10: p = ("License GPLv3+: GNU GPL version 3 or later "
- "<http://gnu.org/licenses/gpl.html>");
+
+ case 10:
+#if ARGPARSE_GPL_VERSION == 3
+ p = ("License GPLv3+: GNU GPL version 3 or later "
+ "<http://gnu.org/licenses/gpl.html>");
+#else
+ p = ("License GPLv2+: GNU GPL version 2 or later "
+ "<http://gnu.org/licenses/>");
+#endif
break;
case 11: p = "foo"; break;
case 13: p = "0.0"; break;
- case 14: p = "Copyright (C) 2015 Free Software Foundation, Inc."; break;
+ case 14: p = ARGPARSE_CRIGHT_STR; break;
case 15: p =
"This is free software: you are free to change and redistribute it.\n"
"There is NO WARRANTY, to the extent permitted by law.\n";
@@ -1380,7 +1506,9 @@ strusage( int level )
case 16: p =
"This is free software; you can redistribute it and/or modify\n"
"it under the terms of the GNU General Public License as published by\n"
-"the Free Software Foundation; either version 3 of the License, or\n"
+"the Free Software Foundation; either version "
+ARGPARSE_STR2(ARGPARSE_GPL_VERSION)
+" of the License, or\n"
"(at your option) any later version.\n\n"
"It is distributed in the hope that it will be useful,\n"
"but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
@@ -1414,7 +1542,7 @@ static struct {
int myopt;
int echo;
int a_long_one;
-}opt;
+} opt;
int
main(int argc, char **argv)
@@ -1422,7 +1550,7 @@ main(int argc, char **argv)
ARGPARSE_OPTS opts[] = {
ARGPARSE_x('v', "verbose", NONE, 0, "Laut sein"),
ARGPARSE_s_n('e', "echo" , ("Zeile ausgeben, damit wir sehen, "
- "was wir ein gegeben haben")),
+ "was wir eingegeben haben")),
ARGPARSE_s_n('d', "debug", "Debug\nfalls mal etwas\nschief geht"),
ARGPARSE_s_s('o', "output", 0 ),
ARGPARSE_o_s('c', "cross-ref", "cross-reference erzeugen\n" ),
@@ -1430,43 +1558,50 @@ main(int argc, char **argv)
ARGPARSE_s_n('s', "street","|Straße|set the name of the street to Straße"),
ARGPARSE_o_i('m', "my-option", 0),
ARGPARSE_s_n(500, "a-long-option", 0 ),
- ARGPARSE_end
+ ARGPARSE_end()
};
- ARGPARSE_ARGS pargs = { &argc, &argv, 2|4|32 };
- int i;
+ ARGPARSE_ARGS pargs = { &argc, &argv, (ARGPARSE_FLAG_ALL
+ | ARGPARSE_FLAG_MIXED
+ | ARGPARSE_FLAG_ONEDASH) };
+ int i;
- while( arg_parse ( &pargs, opts) ) {
- switch( pargs.r_opt ) {
- case -1 : printf( "arg='%s'\n", pargs.r.ret_str); break;
- case 'v': opt.verbose++; break;
- case 'e': opt.echo++; break;
- case 'd': opt.debug++; break;
- case 'o': opt.outfile = pargs.r.ret_str; break;
- case 'c': opt.crf = pargs.r_type? pargs.r.ret_str:"a.crf"; break;
- case 'm': opt.myopt = pargs.r_type? pargs.r.ret_int : 1; break;
- case 500: opt.a_long_one++; break;
- default : pargs.err = ARGPARSE_PRINT_WARNING; break;
+ while (arg_parse (&pargs, opts))
+ {
+ switch (pargs.r_opt)
+ {
+ case ARGPARSE_IS_ARG :
+ printf ("arg='%s'\n", pargs.r.ret_str);
+ break;
+ case 'v': opt.verbose++; break;
+ case 'e': opt.echo++; break;
+ case 'd': opt.debug++; break;
+ case 'o': opt.outfile = pargs.r.ret_str; break;
+ case 'c': opt.crf = pargs.r_type? pargs.r.ret_str:"a.crf"; break;
+ case 'm': opt.myopt = pargs.r_type? pargs.r.ret_int : 1; break;
+ case 500: opt.a_long_one++; break;
+ default : pargs.err = ARGPARSE_PRINT_WARNING; break;
}
}
- for(i=0; i < argc; i++ )
- printf("%3d -> (%s)\n", i, argv[i] );
- puts("Options:");
- if( opt.verbose )
- printf(" verbose=%d\n", opt.verbose );
- if( opt.debug )
- printf(" debug=%d\n", opt.debug );
- if( opt.outfile )
- printf(" outfile='%s'\n", opt.outfile );
- if( opt.crf )
- printf(" crffile='%s'\n", opt.crf );
- if( opt.myopt )
- printf(" myopt=%d\n", opt.myopt );
- if( opt.a_long_one )
- printf(" a-long-one=%d\n", opt.a_long_one );
- if( opt.echo )
- printf(" echo=%d\n", opt.echo );
- return 0;
+ for (i=0; i < argc; i++ )
+ printf ("%3d -> (%s)\n", i, argv[i] );
+ puts ("Options:");
+ if (opt.verbose)
+ printf (" verbose=%d\n", opt.verbose );
+ if (opt.debug)
+ printf (" debug=%d\n", opt.debug );
+ if (opt.outfile)
+ printf (" outfile='%s'\n", opt.outfile );
+ if (opt.crf)
+ printf (" crffile='%s'\n", opt.crf );
+ if (opt.myopt)
+ printf (" myopt=%d\n", opt.myopt );
+ if (opt.a_long_one)
+ printf (" a-long-one=%d\n", opt.a_long_one );
+ if (opt.echo)
+ printf (" echo=%d\n", opt.echo );
+
+ return 0;
}
-#endif
+#endif /*TEST*/
/**** bottom of file ****/
diff --git a/common/argparse.h b/common/argparse.h
index 471cf74..b4dc253 100644
--- a/common/argparse.h
+++ b/common/argparse.h
@@ -32,7 +32,6 @@
#define LIBJNLIB_ARGPARSE_H
#include <stdio.h>
-#include "types.h"
typedef struct
{
@@ -193,12 +192,12 @@ typedef struct
#define ARGPARSE_INVALID_ARG (-12)
-int arg_parse( ARGPARSE_ARGS *arg, ARGPARSE_OPTS *opts);
-int optfile_parse( FILE *fp, const char *filename, unsigned *lineno,
+int arg_parse (ARGPARSE_ARGS *arg, ARGPARSE_OPTS *opts);
+int optfile_parse (FILE *fp, const char *filename, unsigned *lineno,
ARGPARSE_ARGS *arg, ARGPARSE_OPTS *opts);
-void usage( int level );
-const char *strusage( int level );
-void set_strusage( const char *(*f)( int ) );
+void usage (int level);
+const char *strusage (int level);
+void set_strusage (const char *(*f)( int ));
void argparse_register_outfnc (int (*fnc)(int, const char *));
#endif /*LIBJNLIB_ARGPARSE_H*/
diff --git a/common/dns-cert.c b/common/dns-cert.c
index 317ebb1..405ca29 100644
--- a/common/dns-cert.c
+++ b/common/dns-cert.c
@@ -60,29 +60,20 @@
#define my_adns_r_cert 37
-/* Certificate types according to RFC-4398. */
-#define CERTTYPE_PKIX 1 /* X.509 as per PKIX. */
-#define CERTTYPE_SPKI 2 /* SPKI certificate. */
-#define CERTTYPE_PGP 3 /* OpenPGP packet. */
-#define CERTTYPE_IPKIX 4 /* The URL of an X.509 data object. */
-#define CERTTYPE_ISPKI 5 /* The URL of an SPKI certificate. */
-#define CERTTYPE_IPGP 6 /* The fingerprint and URL of an OpenPGP packet.*/
-#define CERTTYPE_ACPKIX 7 /* Attribute Certificate. */
-#define CERTTYPE_IACPKIX 8 /* The URL of an Attribute Certificate. */
-#define CERTTYPE_URI 253 /* URI private. */
-#define CERTTYPE_OID 254 /* OID private. */
-
/* Returns 0 on success or an error code. If a PGP CERT record was
found, a new estream with that key will be returned at R_KEY and
the other return parameters are set to NULL/0. If an IPGP CERT
record was found the fingerprint is stored as an allocated block at
R_FPR and its length at R_FPRLEN; an URL is is allocated as a
- string and returned at R_URL. Note that this function returns the
- first CERT found with a supported type; it is expected that only
- one CERT record is used. */
+ string and returned at R_URL. If WANT_CERTTYPE is 0 this function
+ returns the first CERT found with a supported type; it is expected
+ that only one CERT record is used. If WANT_CERTTYPE is one of the
+ supported certtypes only records wih this certtype are considered
+ and the first found is returned. R_KEY is optional. */
gpg_error_t
-get_dns_cert (const char *name, estream_t *r_key,
+get_dns_cert (const char *name, int want_certtype,
+ estream_t *r_key,
unsigned char **r_fpr, size_t *r_fprlen, char **r_url)
{
#ifdef USE_DNS_CERT
@@ -93,7 +84,8 @@ get_dns_cert (const char *name, estream_t *r_key,
unsigned int ctype;
int count;
- *r_key = NULL;
+ if (r_key)
+ *r_key = NULL;
*r_fpr = NULL;
*r_fprlen = 0;
*r_url = NULL;
@@ -136,7 +128,9 @@ get_dns_cert (const char *name, estream_t *r_key,
data += 5;
datalen -= 5;
- if (ctype == CERTTYPE_PGP && datalen >= 11)
+ if (want_certtype && want_certtype != ctype)
+ ; /* Not of the requested certtype. */
+ else if (ctype == DNS_CERTTYPE_PGP && datalen >= 11 && r_key)
{
/* CERT type is PGP. Gpg checks for a minimum length of 11,
thus we do the same. */
@@ -148,7 +142,7 @@ get_dns_cert (const char *name, estream_t *r_key,
err = 0;
goto leave;
}
- else if (ctype == CERTTYPE_IPGP && datalen && datalen < 1023
+ else if (ctype == DNS_CERTTYPE_IPGP && datalen && datalen < 1023
&& datalen >= data[0] + 1 && r_fpr && r_fprlen && r_url)
{
/* CERT type is IPGP. We made sure that the data is
@@ -204,7 +198,8 @@ get_dns_cert (const char *name, estream_t *r_key,
int r;
u16 count;
- *r_key = NULL;
+ if (r_key)
+ *r_key = NULL;
*r_fpr = NULL;
*r_fprlen = 0;
*r_url = NULL;
@@ -268,7 +263,6 @@ get_dns_cert (const char *name, estream_t *r_key,
class = buf16_to_u16 (pt);
pt += 2;
- class |= *pt++;
if (class != C_IN)
break;
@@ -298,8 +292,9 @@ get_dns_cert (const char *name, estream_t *r_key,
dlen -= 5;
/* 15 bytes takes us to here */
-
- if (ctype == CERTTYPE_PGP && dlen)
+ if (want_certtype && want_certtype != ctype)
+ ; /* Not of the requested certtype. */
+ else if (ctype == DNS_CERTTYPE_PGP && dlen && r_key)
{
/* PGP type */
*r_key = es_fopenmem_init (0, "rwb", pt, dlen);
@@ -310,7 +305,7 @@ get_dns_cert (const char *name, estream_t *r_key,
err = 0;
goto leave;
}
- else if (ctype == CERTTYPE_IPGP
+ else if (ctype == DNS_CERTTYPE_IPGP
&& dlen && dlen < 1023 && dlen >= pt[0] + 1)
{
/* IPGP type */
@@ -362,7 +357,8 @@ get_dns_cert (const char *name, estream_t *r_key,
#endif /*!USE_ADNS */
#else /* !USE_DNS_CERT */
(void)name;
- *r_key = NULL;
+ if (r_key)
+ *r_key = NULL;
*r_fpr = NULL;
*r_fprlen = 0;
*r_url = NULL;
diff --git a/common/dns-cert.h b/common/dns-cert.h
index ae38caa..4b49efc 100644
--- a/common/dns-cert.h
+++ b/common/dns-cert.h
@@ -29,7 +29,24 @@
#ifndef GNUPG_COMMON_DNS_CERT_H
#define GNUPG_COMMON_DNS_CERT_H
-gpg_error_t get_dns_cert (const char *name, estream_t *r_key,
+
+#define DNS_CERTTYPE_ANY 0 /* Internal catch all type. */
+/* Certificate types according to RFC-4398: */
+#define DNS_CERTTYPE_PKIX 1 /* X.509 as per PKIX. */
+#define DNS_CERTTYPE_SPKI 2 /* SPKI certificate. */
+#define DNS_CERTTYPE_PGP 3 /* OpenPGP packet. */
+#define DNS_CERTTYPE_IPKIX 4 /* The URL of an X.509 data object. */
+#define DNS_CERTTYPE_ISPKI 5 /* The URL of an SPKI certificate. */
+#define DNS_CERTTYPE_IPGP 6 /* The fingerprint
+ and URL of an OpenPGP packet. */
+#define DNS_CERTTYPE_ACPKIX 7 /* Attribute Certificate. */
+#define DNS_CERTTYPE_IACPKIX 8 /* The URL of an Attribute Certificate. */
+#define DNS_CERTTYPE_URI 253 /* URI private. */
+#define DNS_CERTTYPE_OID 254 /* OID private. */
+
+
+gpg_error_t get_dns_cert (const char *name, int want_certtype,
+ estream_t *r_key,
unsigned char **r_fpr, size_t *r_fprlen,
char **r_url);
diff --git a/common/gettime.c b/common/gettime.c
index 788743f..115f725 100644
--- a/common/gettime.c
+++ b/common/gettime.c
@@ -71,6 +71,29 @@ gnupg_get_time ()
}
+/* Wrapper around gmtime_r.
+
+ On systems without gmtime_r this implementation works within gnupg
+ because we use only one thread a time. FIXME: An independent
+ library may use gmtime in one of its own thread (or via
+ npth_enter/npth_leave) - in this case we run into a problem. The
+ solution would be to use a mutex here. */
+struct tm *
+gnupg_gmtime (const time_t *timep, struct tm *result)
+{
+#ifdef HAVE_GMTIME_R
+ return gmtime_r (timep, result);
+#else
+ struct tm *tp;
+
+ tp = gmtime (timep);
+ if (tp)
+ memcpy (result, tp, sizeof *result);
+ return tp;
+#endif
+}
+
+
/* Return the current time (possibly faked) in ISO format. */
void
gnupg_get_isotime (gnupg_isotime_t timebuf)
@@ -82,16 +105,15 @@ gnupg_get_isotime (gnupg_isotime_t timebuf)
else
{
struct tm *tp;
-#ifdef HAVE_GMTIME_R
struct tm tmbuf;
- tp = gmtime_r (&atime, &tmbuf);
-#else
- tp = gmtime (&atime);
-#endif
- snprintf (timebuf, 16, "%04d%02d%02dT%02d%02d%02d",
- 1900 + tp->tm_year, tp->tm_mon+1, tp->tm_mday,
- tp->tm_hour, tp->tm_min, tp->tm_sec);
+ tp = gnupg_gmtime (&atime, &tmbuf);
+ if (!tp)
+ *timebuf = 0;
+ else
+ snprintf (timebuf, 16, "%04d%02d%02dT%02d%02d%02d",
+ 1900 + tp->tm_year, tp->tm_mon+1, tp->tm_mday,
+ tp->tm_hour, tp->tm_min, tp->tm_sec);
}
}
@@ -216,9 +238,11 @@ isotime_p (const char *string)
/* Scan a string and return true if the string represents the human
readable format of an ISO time. This format is:
yyyy-mm-dd[ hh[:mm[:ss]]]
- Scanning stops at the second space or at a comma. */
+ Scanning stops at the second space or at a comma. If DATE_ONLY is
+ true the time part is not expected and the scanning stops at the
+ first space or at a comma. */
int
-isotime_human_p (const char *string)
+isotime_human_p (const char *string, int date_only)
{
const char *s;
int i;
@@ -247,6 +271,8 @@ isotime_human_p (const char *string)
return 1; /* Okay; only date given. */
if (!spacep (s))
return 0;
+ if (date_only)
+ return 1; /* Okay; only date was requested. */
s++;
if (spacep (s))
return 1; /* Okay, second space stops scanning. */
@@ -303,7 +329,7 @@ string2isotime (gnupg_isotime_t atime, const char *string)
atime[15] = 0;
return 15;
}
- if (!isotime_human_p (string))
+ if (!isotime_human_p (string, 0))
return 0;
atime[0] = string[0];
atime[1] = string[1];
@@ -393,6 +419,138 @@ epoch2isotime (gnupg_isotime_t timebuf, time_t atime)
}
+/* Parse a short ISO date string (YYYY-MM-DD) into a TM structure.
+ Returns 0 on success. */
+int
+isodate_human_to_tm (const char *string, struct tm *t)
+{
+ int year, month, day;
+
+ if (!isotime_human_p (string, 1))
+ return -1;
+
+ year = atoi_4 (string);
+ month = atoi_2 (string + 5);
+ day = atoi_2 (string + 8);
+
+ /* Basic checks. */
+ if (year < 1970 || month < 1 || month > 12 || day < 1 || day > 31)
+ return -1;
+
+ memset (t, 0, sizeof *t);
+ t->tm_sec = 0;
+ t->tm_min = 0;
+ t->tm_hour = 0;
+ t->tm_mday = day;
+ t->tm_mon = month-1;
+ t->tm_year = year - 1900;
+ t->tm_isdst = -1;
+ return 0;
+}
+
+
+/* This function is a copy of gpgme/src/conversion.c:_gpgme_timegm.
+ If you change it, then update the other one too. */
+#ifdef HAVE_W32_SYSTEM
+static time_t
+_win32_timegm (struct tm *tm)
+{
+ /* This one is thread safe. */
+ SYSTEMTIME st;
+ FILETIME ft;
+ unsigned long long cnsecs;
+
+ st.wYear = tm->tm_year + 1900;
+ st.wMonth = tm->tm_mon + 1;
+ st.wDay = tm->tm_mday;
+ st.wHour = tm->tm_hour;
+ st.wMinute = tm->tm_min;
+ st.wSecond = tm->tm_sec;
+ st.wMilliseconds = 0; /* Not available. */
+ st.wDayOfWeek = 0; /* Ignored. */
+
+ /* System time is UTC thus the conversion is pretty easy. */
+ if (!SystemTimeToFileTime (&st, &ft))
+ {
+ gpg_err_set_errno (EINVAL);
+ return (time_t)(-1);
+ }
+
+ cnsecs = (((unsigned long long)ft.dwHighDateTime << 32)
+ | ft.dwLowDateTime);
+ cnsecs -= 116444736000000000ULL; /* The filetime epoch is 1601-01-01. */
+ return (time_t)(cnsecs / 10000000ULL);
+}
+#endif
+
+
+/* Parse the string TIMESTAMP into a time_t. The string may either be
+ seconds since Epoch or in the ISO 8601 format like
+ "20390815T143012". Returns 0 for an empty string or seconds since
+ Epoch. Leading spaces are skipped. If ENDP is not NULL, it will
+ point to the next non-parsed character in TIMESTRING.
+
+ This function is a copy of
+ gpgme/src/conversion.c:_gpgme_parse_timestamp. If you change it,
+ then update the other one too. */
+time_t
+parse_timestamp (const char *timestamp, char **endp)
+{
+ /* Need to skip leading spaces, because that is what strtoul does
+ but not our ISO 8601 checking code. */
+ while (*timestamp && *timestamp== ' ')
+ timestamp++;
+ if (!*timestamp)
+ return 0;
+
+ if (strlen (timestamp) >= 15 && timestamp[8] == 'T')
+ {
+ struct tm buf;
+ int year;
+
+ year = atoi_4 (timestamp);
+ if (year < 1900)
+ return (time_t)(-1);
+
+ if (endp)
+ *endp = (char*)(timestamp + 15);
+
+ /* Fixme: We would better use a configure test to see whether
+ mktime can handle dates beyond 2038. */
+ if (sizeof (time_t) <= 4 && year >= 2038)
+ return (time_t)2145914603; /* 2037-12-31 23:23:23 */
+
+ memset (&buf, 0, sizeof buf);
+ buf.tm_year = year - 1900;
+ buf.tm_mon = atoi_2 (timestamp+4) - 1;
+ buf.tm_mday = atoi_2 (timestamp+6);
+ buf.tm_hour = atoi_2 (timestamp+9);
+ buf.tm_min = atoi_2 (timestamp+11);
+ buf.tm_sec = atoi_2 (timestamp+13);
+
+#ifdef HAVE_W32_SYSTEM
+ return _win32_timegm (&buf);
+#else
+#ifdef HAVE_TIMEGM
+ return timegm (&buf);
+#else
+ {
+ time_t tim;
+
+ putenv ("TZ=UTC");
+ tim = mktime (&buf);
+#ifdef __GNUC__
+#warning fixme: we must somehow reset TZ here. It is not threadsafe anyway.
+#endif
+ return tim;
+ }
+#endif /* !HAVE_TIMEGM */
+#endif /* !HAVE_W32_SYSTEM */
+ }
+ else
+ return (time_t)strtoul (timestamp, endp, 10);
+}
+
u32
diff --git a/common/gettime.h b/common/gettime.h
index 736eb41..ec68faa 100644
--- a/common/gettime.h
+++ b/common/gettime.h
@@ -29,6 +29,7 @@
typedef char gnupg_isotime_t[16];
time_t gnupg_get_time (void);
+struct tm *gnupg_gmtime (const time_t *timep, struct tm *result);
void gnupg_get_isotime (gnupg_isotime_t timebuf);
void gnupg_set_time (time_t newtime, int freeze);
int gnupg_faked_time_p (void);
@@ -37,10 +38,12 @@ char *elapsed_time_string (time_t since, time_t now);
u32 scan_isodatestr (const char *string);
int isotime_p (const char *string);
-int isotime_human_p (const char *string);
+int isotime_human_p (const char *string, int date_only);
size_t string2isotime (gnupg_isotime_t atime, const char *string);
time_t isotime2epoch (const char *string);
void epoch2isotime (gnupg_isotime_t timebuf, time_t atime);
+int isodate_human_to_tm (const char *string, struct tm *t);
+time_t parse_timestamp (const char *timestamp, char **endp);
u32 add_days_to_timestamp (u32 stamp, u16 days);
const char *strtimevalue (u32 stamp);
const char *strtimestamp (u32 stamp); /* GMT */
diff --git a/common/http.c b/common/http.c
index 50c0692..118e3b0 100644
--- a/common/http.c
+++ b/common/http.c
@@ -2,6 +2,7 @@
* Copyright (C) 1999, 2001, 2002, 2003, 2004, 2006, 2009, 2010,
* 2011 Free Software Foundation, Inc.
* Copyright (C) 2014 Werner Koch
+ * Copyright (C) 2015 g10 Code GmbH
*
* This file is part of GnuPG.
*
@@ -1017,9 +1018,10 @@ parse_uri (parsed_uri_t *ret_uri, const char *uri,
/*
* Parse an URI and put the result into the newly allocated RET_URI.
- * On success the caller must use release_parsed_uri() to releases the
- * resources. If NO_SCHEME_CHECK is set, the function tries to parse
- * the URL in the same way it would do for an HTTP style URI.
+ * On success the caller must use http_release_parsed_uri() to
+ * releases the resources. If NO_SCHEME_CHECK is set, the function
+ * tries to parse the URL in the same way it would do for an HTTP
+ * style URI.
*/
gpg_error_t
http_parse_uri (parsed_uri_t *ret_uri, const char *uri,
@@ -1443,7 +1445,8 @@ send_request (http_t hd, const char *httphost, const char *auth,
}
# if HTTP_USE_NTBTLS
- err = ntbtls_set_hostname (hd->session->tls_session, server);
+ err = ntbtls_set_hostname (hd->session->tls_session,
+ hd->session->servername);
if (err)
{
log_info ("ntbtls_set_hostname failed: %s\n", gpg_strerror (err));
@@ -1452,7 +1455,8 @@ send_request (http_t hd, const char *httphost, const char *auth,
# elif HTTP_USE_GNUTLS
rc = gnutls_server_name_set (hd->session->tls_session,
GNUTLS_NAME_DNS,
- server, strlen (server));
+ hd->session->servername,
+ strlen (hd->session->servername));
if (rc < 0)
log_info ("gnutls_server_name_set failed: %s\n", gnutls_strerror (rc));
# endif /*HTTP_USE_GNUTLS*/
@@ -2700,3 +2704,17 @@ http_verify_server_credentials (http_session_t sess)
return gpg_error (GPG_ERR_NOT_IMPLEMENTED);
#endif
}
+
+/* Return the first query variable with the specified key. If there
+ is no such variable, return NULL. */
+struct uri_tuple_s *
+uri_query_lookup (parsed_uri_t uri, const char *key)
+{
+ struct uri_tuple_s *t;
+
+ for (t = uri->query; t; t = t->next)
+ if (strcmp (t->name, key) == 0)
+ return t;
+
+ return NULL;
+}
diff --git a/common/http.h b/common/http.h
index 3a44430..fcab12a 100644
--- a/common/http.h
+++ b/common/http.h
@@ -1,6 +1,7 @@
/* http.h - HTTP protocol handler
* Copyright (C) 1999, 2000, 2001, 2003, 2006,
* 2010 Free Software Foundation, Inc.
+ * Copyright (C) 2015 g10 Code GmbH
*
* This file is part of GnuPG.
*
@@ -61,6 +62,8 @@ struct parsed_uri_s
};
typedef struct parsed_uri_s *parsed_uri_t;
+struct uri_tuple_s *uri_query_lookup (parsed_uri_t uri, const char *key);
+
typedef enum
{
HTTP_REQ_GET = 1,
diff --git a/common/mapstrings.c b/common/mapstrings.c
index 91795d5..5c5bec9 100644
--- a/common/mapstrings.c
+++ b/common/mapstrings.c
@@ -132,7 +132,7 @@ find_macro (const char *string, const char **begptr,
/* If STRING includes known @FOO@ macros, replace these macros and
return a new static string. Warning: STRING must have been
- allocated statically. Note that this function allocated memory
+ allocated statically. Note that this function allocates memory
which will not be released (similar to gettext). */
const char *
map_static_macro_string (const char *string)
diff --git a/common/mbox-util.c b/common/mbox-util.c
new file mode 100644
index 0000000..2029324
--- /dev/null
+++ b/common/mbox-util.c
@@ -0,0 +1,249 @@
+/* mbox-util.c - Mail address helper functions
+ * Copyright (C) 1998-2010 Free Software Foundation, Inc.
+ * Copyright (C) 1998-2015 Werner Koch
+ *
+ * This file is part of GnuPG.
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of either
+ *
+ * - the GNU Lesser General Public License as published by the Free
+ * Software Foundation; either version 3 of the License, or (at
+ * your option) any later version.
+ *
+ * or
+ *
+ * - the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * or both in parallel, as here.
+ *
+ * This file 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 <unistd.h>
+#include <errno.h>
+
+#include "util.h"
+#include "mbox-util.h"
+
+
+static int
+string_count_chr (const char *string, int c)
+{
+ int count;
+
+ for (count=0; *string; string++ )
+ if ( *string == c )
+ count++;
+ return count;
+}
+
+static int
+mem_count_chr (const void *buffer, int c, size_t length)
+{
+ const char *s = buffer;
+ int count;
+
+ for (count=0; length; length--, s++)
+ if (*s == c)
+ count++;
+ return count;
+}
+
+
+/* This is a case-sensitive version of our memistr. I wonder why no
+ standard function memstr exists but I better do not use the name
+ memstr to avoid future conflicts. */
+static const char *
+my_memstr (const void *buffer, size_t buflen, const char *sub)
+{
+ const unsigned char *buf = buffer;
+ const unsigned char *t = (const unsigned char *)buf;
+ const unsigned char *s = (const unsigned char *)sub;
+ size_t n = buflen;
+
+ for ( ; n ; t++, n-- )
+ {
+ if (*t == *s)
+ {
+ for (buf = t++, buflen = n--, s++; n && *t ==*s; t++, s++, n--)
+ ;
+ if (!*s)
+ return (const char*)buf;
+ t = (const unsigned char *)buf;
+ s = (const unsigned char *)sub ;
+ n = buflen;
+ }
+ }
+ return NULL;
+}
+
+
+
+static int
+string_has_ctrl_or_space (const char *string)
+{
+ for (; *string; string++ )
+ if (!(*string & 0x80) && *string <= 0x20)
+ return 1;
+ return 0;
+}
+
+
+/* Return true if STRING has two consecutive '.' after an '@'
+ sign. */
+static int
+has_dotdot_after_at (const char *string)
+{
+ string = strchr (string, '@');
+ if (!string)
+ return 0; /* No at-sign. */
+ string++;
+ return !!strstr (string, "..");
+}
+
+
+/* Check whether BUFFER has characters not valid in an RFC-822
+ address. LENGTH gives the length of BUFFER.
+
+ To cope with OpenPGP we ignore non-ascii characters so that for
+ example umlauts are legal in an email address. An OpenPGP user ID
+ must be utf-8 encoded but there is no strict requirement for
+ RFC-822. Thus to avoid IDNA encoding we put the address verbatim
+ as utf-8 into the user ID under the assumption that mail programs
+ handle IDNA at a lower level and take OpenPGP user IDs as utf-8.
+ Note that we can't do an utf-8 encoding checking here because in
+ keygen.c this function is called with the native encoding and
+ native to utf-8 encoding is only done later. */
+int
+has_invalid_email_chars (const void *buffer, size_t length)
+{
+ const unsigned char *s = buffer;
+ int at_seen=0;
+ const char *valid_chars=
+ "01234567890_-.abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
+
+ for ( ; length && *s; length--, s++ )
+ {
+ if ((*s & 0x80))
+ continue; /* We only care about ASCII. */
+ if (*s == '@')
+ at_seen=1;
+ else if (!at_seen && !(strchr (valid_chars, *s)
+ || strchr ("!#$%&'*+/=?^`{|}~", *s)))
+ return 1;
+ else if (at_seen && !strchr (valid_chars, *s))
+ return 1;
+ }
+ return 0;
+}
+
+
+/* Same as is_valid_mailbox (see below) but operates on non-nul
+ terminated buffer. */
+int
+is_valid_mailbox_mem (const void *name_arg, size_t namelen)
+{
+ const char *name = name_arg;
+
+ return !( !name
+ || !namelen
+ || has_invalid_email_chars (name, namelen)
+ || mem_count_chr (name, '@', namelen) != 1
+ || *name == '@'
+ || name[namelen-1] == '@'
+ || name[namelen-1] == '.'
+ || my_memstr (name, namelen, ".."));
+}
+
+
+/* Check whether NAME represents a valid mailbox according to
+ RFC822. Returns true if so. */
+int
+is_valid_mailbox (const char *name)
+{
+ return name? is_valid_mailbox_mem (name, strlen (name)) : 0;
+}
+
+
+/* Return the mailbox (local-part@domain) form a standard user id.
+ All plain ASCII characters in the result are converted to
+ lowercase. Caller must free the result. Returns NULL if no valid
+ mailbox was found (or we are out of memory). */
+char *
+mailbox_from_userid (const char *userid)
+{
+ const char *s, *s_end;
+ size_t len;
+ char *result = NULL;
+
+ s = strchr (userid, '<');
+ if (s)
+ {
+ /* Seems to be a standard user id. */
+ s++;
+ s_end = strchr (s, '>');
+ if (s_end && s_end > s)
+ {
+ len = s_end - s;
+ result = xtrymalloc (len + 1);
+ if (!result)
+ return NULL; /* Ooops - out of core. */
+ strncpy (result, s, len);
+ result[len] = 0;
+ /* Apply some basic checks on the address. We do not use
+ is_valid_mailbox because those checks are too strict. */
+ if (string_count_chr (result, '@') != 1 /* Need exactly one '@. */
+ || *result == '@' /* local-part missing. */
+ || result[len-1] == '@' /* domain missing. */
+ || result[len-1] == '.' /* ends with a dot. */
+ || string_has_ctrl_or_space (result)
+ || has_dotdot_after_at (result))
+ {
+ xfree (result);
+ result = NULL;
+ errno = EINVAL;
+ }
+ }
+ else
+ errno = EINVAL;
+ }
+ else if (is_valid_mailbox (userid))
+ {
+ /* The entire user id is a mailbox. Return that one. Note that
+ this fallback method has some restrictions on the valid
+ syntax of the mailbox. However, those who want weird
+ addresses should know about it and use the regular <...>
+ syntax. */
+ result = xtrystrdup (userid);
+ }
+ else
+ errno = EINVAL;
+
+ return result? ascii_strlwr (result): NULL;
+}
+
+
+/* Check whether UID is a valid standard user id of the form
+ "Heinrich Heine <heinrichh@duesseldorf.de>"
+ and return true if this is the case. */
+int
+is_valid_user_id (const char *uid)
+{
+ if (!uid || !*uid)
+ return 0;
+
+ return 1;
+}
diff --git a/common/mbox-util.h b/common/mbox-util.h
new file mode 100644
index 0000000..4dd48ec
--- /dev/null
+++ b/common/mbox-util.h
@@ -0,0 +1,39 @@
+/* mbox-util.h - Defs for mail address helper functions
+ * Copyright (C) 2015 Werner Koch
+ *
+ * This file is part of GnuPG.
+ *
+ * This file is free software; you can redistribute it and/or modify
+ * it under the terms of either
+ *
+ * - the GNU Lesser General Public License as published by the Free
+ * Software Foundation; either version 3 of the License, or (at
+ * your option) any later version.
+ *
+ * or
+ *
+ * - the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * or both in parallel, as here.
+ *
+ * This file 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_COMMON_MBOX_UTIL_H
+#define GNUPG_COMMON_MBOX_UTIL_H
+
+int has_invalid_email_chars (const void *buffer, size_t length);
+int is_valid_mailbox (const char *name);
+int is_valid_mailbox_mem (const void *buffer, size_t length);
+char *mailbox_from_userid (const char *userid);
+int is_valid_user_id (const char *uid);
+
+
+#endif /*GNUPG_COMMON_MBOX_UTIL_H*/
diff --git a/common/openpgp-oid.c b/common/openpgp-oid.c
index d3d1f2a..7a75801 100644
--- a/common/openpgp-oid.c
+++ b/common/openpgp-oid.c
@@ -41,7 +41,7 @@
static struct {
const char *name; /* Standard name. */
const char *oidstr; /* IETF formatted OID. */
- unsigned int nbits; /* Nominla bit length of the curve. */
+ unsigned int nbits; /* Nominal bit length of the curve. */
const char *alias; /* NULL or alternative name of the curve. */
} oidtable[] = {
@@ -192,7 +192,9 @@ openpgp_oid_to_str (gcry_mpi_t a)
valmask = (unsigned long)0xfe << (8 * (sizeof (valmask) - 1));
- if (!a || !gcry_mpi_get_flag (a, GCRYMPI_FLAG_OPAQUE))
+ if (!a
+ || !gcry_mpi_get_flag (a, GCRYMPI_FLAG_OPAQUE)
+ || !(buf = gcry_mpi_get_opaque (a, &lengthi)))
{
gpg_err_set_errno (EINVAL);
return NULL;
@@ -217,7 +219,7 @@ openpgp_oid_to_str (gcry_mpi_t a)
string = p = xtrymalloc (length*(1+3)+2+1);
if (!string)
return NULL;
- if (!buf || !length)
+ if (!length)
{
*p = 0;
return string;
@@ -347,3 +349,41 @@ openpgp_oid_to_curve (const char *oidstr)
return "?";
}
+
+
+/* Return true if the curve with NAME is supported. */
+static int
+curve_supported_p (const char *name)
+{
+ int result = 0;
+ gcry_sexp_t keyparms;
+
+ if (!gcry_sexp_build (&keyparms, NULL, "(public-key(ecc(curve %s)))", name))
+ {
+ result = !!gcry_pk_get_curve (keyparms, 0, NULL);
+ gcry_sexp_release (keyparms);
+ }
+ return result;
+}
+
+
+/* Enumerate available and supported OpenPGP curves. The caller needs
+ to set the integer variable at ITERP to zero and keep on calling
+ this fucntion until NULL is returned. */
+const char *
+openpgp_enum_curves (int *iterp)
+{
+ int idx = *iterp;
+
+ while (idx >= 0 && idx < DIM (oidtable) && oidtable[idx].name)
+ {
+ if (curve_supported_p (oidtable[idx].name))
+ {
+ *iterp = idx + 1;
+ return oidtable[idx].alias? oidtable[idx].alias : oidtable[idx].name;
+ }
+ idx++;
+ }
+ *iterp = idx;
+ return NULL;
+}
diff --git a/common/pka.c b/common/pka.c
index 4ead97f..1aa5b33 100644
--- a/common/pka.c
+++ b/common/pka.c
@@ -33,307 +33,75 @@
#include <stdlib.h>
#include <string.h>
-#ifdef USE_DNS_PKA
-#include <sys/types.h>
-#ifdef _WIN32
-# ifdef HAVE_WINSOCK2_H
-# include <winsock2.h>
-# endif
-# include <windows.h>
-#else
-#include <netinet/in.h>
-#include <arpa/nameser.h>
-#include <resolv.h>
-#endif
-#endif /* USE_DNS_PKA */
-#ifdef USE_ADNS
-# include <adns.h>
-#endif
-
#include "util.h"
-#include "host2net.h"
+#include "mbox-util.h"
+#include "dns-cert.h"
#include "pka.h"
-#ifdef USE_DNS_PKA
-/* Parse the TXT resource record. Format is:
-
- v=pka1;fpr=a4d94e92b0986ab5ee9dcd755de249965b0358a2;uri=string
-
- For simplicity white spaces are not allowed. Because we expect to
- use a new RRTYPE for this in the future we define the TXT really
- strict for simplicity: No white spaces, case sensitivity of the
- names, order must be as given above. Only URI is optional.
-
- This function modifies BUFFER. On success 0 is returned, the 20
- byte fingerprint stored at FPR and BUFFER contains the URI or an
- empty string.
-*/
-static int
-parse_txt_record (char *buffer, unsigned char *fpr)
-{
- char *p, *pend;
- int i;
-
- p = buffer;
- pend = strchr (p, ';');
- if (!pend)
- return -1;
- *pend++ = 0;
- if (strcmp (p, "v=pka1"))
- return -1; /* Wrong or missing version. */
-
- p = pend;
- pend = strchr (p, ';');
- if (pend)
- *pend++ = 0;
- if (strncmp (p, "fpr=", 4))
- return -1; /* Missing fingerprint part. */
- p += 4;
- for (i=0; i < 20 && hexdigitp (p) && hexdigitp (p+1); i++, p += 2)
- fpr[i] = xtoi_2 (p);
- if (i != 20)
- return -1; /* Fingerprint consists not of exactly 40 hexbytes. */
-
- p = pend;
- if (!p || !*p)
- {
- *buffer = 0;
- return 0; /* Success (no URI given). */
- }
- if (strncmp (p, "uri=", 4))
- return -1; /* Unknown part. */
- p += 4;
- /* There is an URI, copy it to the start of the buffer. */
- while (*p)
- *buffer++ = *p++;
- *buffer = 0;
- return 0;
-}
-
/* For the given email ADDRESS lookup the PKA information in the DNS.
- On success the 20 byte SHA-1 fingerprint is stored at FPR and the
- URI will be returned in an allocated buffer. Note that the URI
- might be an zero length string as this information is optional.
- Caller must xfree the returned string.
+ On success the fingerprint is stored at FPRBUF and the URI will be
+ returned in an allocated buffer. Note that the URI might be a zero
+ length string as this information is optional. Caller must xfree
+ the returned string. FPRBUFLEN gives the size of the expected
+ fingerprint (usually 20).
- On error NULL is returned and the 20 bytes at FPR are not
- defined. */
+ On error NULL is returned and the FPRBUF is not defined. */
char *
-get_pka_info (const char *address, unsigned char *fpr)
+get_pka_info (const char *address, void *fprbuf, size_t fprbuflen)
{
-#ifdef USE_ADNS
- int rc;
- adns_state state;
- const char *domain;
- char *name;
- adns_answer *answer = NULL;
- char *buffer = NULL;
-
- domain = strrchr (address, '@');
- if (!domain || domain == address || !domain[1])
- return NULL; /* Invalid mail address given. */
- name = xtrymalloc (strlen (address) + 5 + 1);
+ char *result = NULL;
+ char *mbox;
+ char *domain; /* Points to mbox. */
+ char hashbuf[20];
+ char *hash = NULL;
+ char *name = NULL;
+ unsigned char *fpr = NULL;
+ size_t fpr_len;
+ char *url = NULL;
+
+ mbox = mailbox_from_userid (address);
+ if (!mbox)
+ goto leave;
+ domain = strchr (mbox, '@');
+ if (!domain)
+ goto leave;
+ *domain++ = 0;
+
+ gcry_md_hash_buffer (GCRY_MD_SHA1, hashbuf, mbox, strlen (mbox));
+ hash = zb32_encode (hashbuf, 8*20);
+ if (!hash)
+ goto leave;
+ name = strconcat (hash, "._pka.", domain, NULL);
if (!name)
- return NULL;
- memcpy (name, address, domain - address);
- strcpy (stpcpy (name + (domain-address), "._pka."), domain+1);
-
- rc = adns_init (&state, adns_if_noerrprint, NULL);
- if (rc)
- {
- log_error ("error initializing adns: %s\n", strerror (errno));
- xfree (name);
- return NULL;
- }
+ goto leave;
- rc = adns_synchronous (state, name, adns_r_txt, adns_qf_quoteok_query,
- &answer);
- xfree (name);
- if (rc)
- {
- log_error ("DNS query failed: %s\n", strerror (errno));
- adns_finish (state);
- return NULL;
- }
- if (answer->status != adns_s_ok
- || answer->type != adns_r_txt || !answer->nrrs)
- {
- log_error ("DNS query returned an error: %s (%s)\n",
- adns_strerror (answer->status),
- adns_errabbrev (answer->status));
- adns_free (answer);
- adns_finish (state);
- return NULL;
- }
+ if (get_dns_cert (name, DNS_CERTTYPE_IPGP, NULL, &fpr, &fpr_len, &url))
+ goto leave;
+ if (!fpr)
+ goto leave;
- /* We use a PKA records iff there is exactly one record. */
- if (answer->nrrs == 1 && answer->rrs.manyistr[0]->i != -1)
+ /* Return the fingerprint. */
+ if (fpr_len != fprbuflen)
{
- buffer = xtrystrdup (answer->rrs.manyistr[0]->str);
- if (parse_txt_record (buffer, fpr))
- {
- xfree (buffer);
- buffer = NULL; /* Not a valid gpg trustdns RR. */
- }
+ /* fprintf (stderr, "get_dns_cert failed: fprlen (%zu/%zu)\n", */
+ /* fpr_len, fprbuflen); */
+ goto leave;
}
+ memcpy (fprbuf, fpr, fpr_len);
- adns_free (answer);
- adns_finish (state);
- return buffer;
-
-#else /*!USE_ADNS*/
- unsigned char answer[PACKETSZ];
- int anslen;
- int qdcount, ancount;
- int rc;
- unsigned char *p, *pend;
- const char *domain;
- char *name;
- HEADER header;
-
- domain = strrchr (address, '@');
- if (!domain || domain == address || !domain[1])
- return NULL; /* invalid mail address given. */
+ /* We return the URL or an empty string. */
+ if (!url)
+ url = xtrycalloc (1, 1);
+ result = url;
+ url = NULL;
- name = xtrymalloc (strlen (address) + 5 + 1);
- if (!name)
- return NULL;
- memcpy (name, address, domain - address);
- strcpy (stpcpy (name + (domain-address), "._pka."), domain+1);
-
- anslen = res_query (name, C_IN, T_TXT, answer, PACKETSZ);
+ leave:
+ xfree (fpr);
+ xfree (url);
xfree (name);
- if (anslen < sizeof(HEADER))
- return NULL; /* DNS resolver returned a too short answer. */
-
- /* Don't despair: A good compiler should optimize this away, as
- header is just 32 byte and constant at compile time. It's
- one way to comply with strict aliasing rules. */
- memcpy (&header, answer, sizeof (header));
-
- if ( (rc=header.rcode) != NOERROR )
- return NULL; /* DNS resolver returned an error. */
-
- /* We assume that PACKETSZ is large enough and don't do dynmically
- expansion of the buffer. */
- if (anslen > PACKETSZ)
- return NULL; /* DNS resolver returned a too long answer */
-
- qdcount = ntohs (header.qdcount);
- ancount = ntohs (header.ancount);
-
- if (!ancount)
- return NULL; /* Got no answer. */
-
- p = answer + sizeof (HEADER);
- pend = answer + anslen; /* Actually points directly behind the buffer. */
-
- while (qdcount-- && p < pend)
- {
- rc = dn_skipname (p, pend);
- if (rc == -1)
- return NULL;
- p += rc + QFIXEDSZ;
- }
-
- if (ancount > 1)
- return NULL; /* more than one possible gpg trustdns record - none used. */
-
- while (ancount-- && p <= pend)
- {
- unsigned int type, class, txtlen, n;
- char *buffer, *bufp;
-
- rc = dn_skipname (p, pend);
- if (rc == -1)
- return NULL;
- p += rc;
- if (p >= pend - 10)
- return NULL; /* RR too short. */
-
- type = buf16_to_uint (p);
- p += 2;
- class = buf16_to_uint (p);
- p += 2;
- p += 4;
- txtlen = buf16_to_uint (p);
- p += 2;
-
- if (type != T_TXT || class != C_IN)
- return NULL; /* Answer does not match the query. */
-
- buffer = bufp = xmalloc (txtlen + 1);
- while (txtlen && p < pend)
- {
- for (n = *p++, txtlen--; txtlen && n && p < pend; txtlen--, n--)
- *bufp++ = *p++;
- }
- *bufp = 0;
- if (parse_txt_record (buffer, fpr))
- {
- xfree (buffer);
- return NULL; /* Not a valid gpg trustdns RR. */
- }
- return buffer;
- }
-
- return NULL;
-#endif /*!USE_ADNS*/
+ xfree (hash);
+ xfree (mbox);
+ return result;
}
-
-#else /* !USE_DNS_PKA */
-
-/* Dummy version of the function if we can't use the resolver
- functions. */
-char *
-get_pka_info (const char *address, unsigned char *fpr)
-{
- (void)address;
- (void)fpr;
- return NULL;
-}
-#endif /* !USE_DNS_PKA */
-
-
-#ifdef TEST
-int
-main(int argc,char *argv[])
-{
- unsigned char fpr[20];
- char *uri;
- int i;
-
- if (argc < 2)
- {
- fprintf (stderr, "usage: pka mail-addresses\n");
- return 1;
- }
- argc--;
- argv++;
-
- for (; argc; argc--, argv++)
- {
- uri = get_pka_info ( *argv, fpr );
- printf ("%s", *argv);
- if (uri)
- {
- putchar (' ');
- for (i=0; i < 20; i++)
- printf ("%02X", fpr[i]);
- if (*uri)
- printf (" %s", uri);
- xfree (uri);
- }
- putchar ('\n');
- }
- return 0;
-}
-#endif /* TEST */
-
-/*
-Local Variables:
-compile-command: "cc -DUSE_DNS_PKA -DTEST -I.. -I../include -Wall -g -o pka pka.c -lresolv ../tools/no-libgcrypt.o ../jnlib/libjnlib.a"
-End:
-*/
diff --git a/common/pka.h b/common/pka.h
index 68b4c2e..93a4eb3 100644
--- a/common/pka.h
+++ b/common/pka.h
@@ -29,7 +29,7 @@
#ifndef GNUPG_COMMON_PKA_H
#define GNUPG_COMMON_PKA_H
-char *get_pka_info (const char *address, unsigned char *fpr);
+char *get_pka_info (const char *address, void *fprbuf, size_t fprbuflen);
#endif /*GNUPG_COMMON_PKA_H*/
diff --git a/common/stringhelp.c b/common/stringhelp.c
index 7128de5..7f40c7f 100644
--- a/common/stringhelp.c
+++ b/common/stringhelp.c
@@ -2,6 +2,7 @@
* Copyright (C) 1998, 1999, 2000, 2001, 2003, 2004, 2005, 2006, 2007,
* 2008, 2009, 2010 Free Software Foundation, Inc.
* Copyright (C) 2014 Werner Koch
+ * Copyright (C) 2015 g10 Code GmbH
*
* This file is part of JNLIB, which is a subsystem of GnuPG.
*
@@ -48,6 +49,7 @@
# include <windows.h>
#endif
+#include "util.h"
#include "libjnlib-config.h"
#include "utf8conv.h"
#include "sysutils.h"
@@ -158,7 +160,7 @@ ascii_memistr ( const void *buffer, size_t buflen, const char *sub )
/* This function is similar to strncpy(). However it won't copy more
than N - 1 characters and makes sure that a '\0' is appended. With
N given as 0, nothing will happen. With DEST given as NULL, memory
- will be allocated using jnlib_xmalloc (i.e. if it runs out of core
+ will be allocated using xmalloc (i.e. if it runs out of core
the function terminates). Returns DES or a pointer to the
allocated memory.
*/
@@ -170,7 +172,7 @@ mem2str( char *dest , const void *src , size_t n )
if( n ) {
if( !dest )
- dest = jnlib_xmalloc( n ) ;
+ dest = xmalloc( n ) ;
d = dest;
s = src ;
for(n--; n && *s; n-- )
@@ -318,10 +320,10 @@ make_basename(const char *filepath, const char *inputpath)
if ( !(p=strrchr(filepath, ':')) )
#endif
{
- return jnlib_xstrdup(filepath);
+ return xstrdup(filepath);
}
- return jnlib_xstrdup(p+1);
+ return xstrdup(p+1);
#endif
}
@@ -347,11 +349,11 @@ make_dirname(const char *filepath)
if ( !(p=strrchr(filepath, ':')) )
#endif
{
- return jnlib_xstrdup(".");
+ return xstrdup(".");
}
dirname_length = p-filepath;
- dirname = jnlib_xmalloc(dirname_length+1);
+ dirname = xmalloc(dirname_length+1);
strncpy(dirname, filepath, dirname_length);
dirname[dirname_length] = 0;
@@ -384,9 +386,9 @@ get_pwdir (int xmode, const char *name)
if (pwd)
{
if (xmode)
- result = jnlib_xstrdup (pwd->pw_dir);
+ result = xstrdup (pwd->pw_dir);
else
- result = jnlib_strdup (pwd->pw_dir);
+ result = xtrystrdup (pwd->pw_dir);
}
#else /*!HAVE_PWD_H*/
/* No support at all. */
@@ -450,10 +452,10 @@ do_make_filename (int xmode, const char *first_part, va_list arg_ptr)
char *user;
if (xmode)
- user = jnlib_xstrdup (first_part+1);
+ user = xstrdup (first_part+1);
else
{
- user = jnlib_strdup (first_part+1);
+ user = xtrystrdup (first_part+1);
if (!user)
return NULL;
}
@@ -463,7 +465,7 @@ do_make_filename (int xmode, const char *first_part, va_list arg_ptr)
skip = 1 + strlen (user);
home = home_buffer = get_pwdir (xmode, user);
- jnlib_free (user);
+ xfree (user);
if (home)
n += strlen (home);
else
@@ -472,13 +474,13 @@ do_make_filename (int xmode, const char *first_part, va_list arg_ptr)
}
if (xmode)
- name = jnlib_xmalloc (n);
+ name = xmalloc (n);
else
{
- name = jnlib_malloc (n);
+ name = xtrymalloc (n);
if (!name)
{
- jnlib_free (home_buffer);
+ xfree (home_buffer);
return NULL;
}
}
@@ -488,7 +490,7 @@ do_make_filename (int xmode, const char *first_part, va_list arg_ptr)
else
p = stpcpy (name, first_part);
- jnlib_free (home_buffer);
+ xfree (home_buffer);
for (argc=0; argv[argc]; argc++)
p = stpcpy (stpcpy (p, "/"), argv[argc]);
@@ -518,18 +520,18 @@ do_make_filename (int xmode, const char *first_part, va_list arg_ptr)
strerror (errno));
exit(2);
}
- jnlib_free (name);
+ xfree (name);
return NULL;
}
n = strlen (home) + 1 + strlen (name) + 1;
if (xmode)
- home_buffer = jnlib_xmalloc (n);
+ home_buffer = xmalloc (n);
else
{
- home_buffer = jnlib_malloc (n);
+ home_buffer = xtrymalloc (n);
if (!home_buffer)
{
- jnlib_free (name);
+ xfree (name);
return NULL;
}
}
@@ -541,7 +543,7 @@ do_make_filename (int xmode, const char *first_part, va_list arg_ptr)
p = home_buffer + (p - name + 1);
}
strcpy (stpcpy (stpcpy (p, home), "/"), name);
- jnlib_free (name);
+ xfree (name);
name = home_buffer;
/* Let's do a simple compression to catch the most common
case of using "." for gpg's --homedir option. */
@@ -699,7 +701,7 @@ sanitize_buffer (const void *p_arg, size_t n, int delim)
p = save_p;
n = save_n;
/* And now make the string */
- d = buffer = jnlib_xmalloc( buflen );
+ d = buffer = xmalloc( buflen );
for ( ; n; n--, p++ )
{
if (*p < 0x20 || *p == 0x7f || *p == delim || (delim && *p=='\\')) {
@@ -804,6 +806,18 @@ ascii_tolower (int c)
return c;
}
+/* Lowercase all ASCII characters in S. */
+char *
+ascii_strlwr (char *s)
+{
+ char *p = s;
+
+ for (p=s; *p; p++ )
+ if (isascii (*p) && *p >= 'A' && *p <= 'Z')
+ *p |= 0x20;
+
+ return s;
+}
int
ascii_strcasecmp( const char *a, const char *b )
@@ -1050,10 +1064,10 @@ do_percent_escape (const char *str, const char *extra, int die)
if (str[i] == ':' || str[i] == '%' || (extra && strchr (extra, str[i])))
j++;
if (die)
- ptr = jnlib_xmalloc (i + 2 * j + 1);
+ ptr = xmalloc (i + 2 * j + 1);
else
{
- ptr = jnlib_malloc (i + 2 * j + 1);
+ ptr = xtrymalloc (i + 2 * j + 1);
if (!ptr)
return NULL;
}
@@ -1128,7 +1142,7 @@ do_strconcat (const char *s1, va_list arg_ptr)
argc++;
}
needed++;
- buffer = jnlib_malloc (needed);
+ buffer = xtrymalloc (needed);
if (buffer)
{
for (p = buffer, argc=0; argv[argc]; argc++)
@@ -1148,7 +1162,7 @@ strconcat (const char *s1, ...)
char *result;
if (!s1)
- result = jnlib_strdup ("");
+ result = xtrystrdup ("");
else
{
va_start (arg_ptr, s1);
@@ -1167,7 +1181,7 @@ xstrconcat (const char *s1, ...)
char *result;
if (!s1)
- result = jnlib_xstrdup ("");
+ result = xstrdup ("");
else
{
va_start (arg_ptr, s1);
@@ -1184,3 +1198,39 @@ xstrconcat (const char *s1, ...)
}
return result;
}
+
+/* Split a string into fields at DELIM. REPLACEMENT is the character
+ to replace the delimiter with (normally: '\0' so that each field is
+ NUL terminated). The caller is responsible for freeing the result.
+ Note: this function modifies STRING! If you need the original
+ value, then you should pass a copy to this function.
+
+ If malloc fails, this function returns NULL. */
+char **
+strsplit (char *string, char delim, char replacement, int *count)
+{
+ int fields = 1;
+ char *t;
+ char **result;
+
+ /* First, count the number of fields. */
+ for (t = strchr (string, delim); t; t = strchr (t + 1, delim))
+ fields ++;
+
+ result = xtrycalloc (sizeof (*result), (fields + 1));
+ if (! result)
+ return NULL;
+
+ result[0] = string;
+ fields = 1;
+ for (t = strchr (string, delim); t; t = strchr (t + 1, delim))
+ {
+ result[fields ++] = t + 1;
+ *t = replacement;
+ }
+
+ if (count)
+ *count = fields;
+
+ return result;
+}
diff --git a/common/stringhelp.h b/common/stringhelp.h
index d4fe169..864a689 100644
--- a/common/stringhelp.h
+++ b/common/stringhelp.h
@@ -1,6 +1,7 @@
/* stringhelp.h
* Copyright (C) 1998, 1999, 2000, 2001, 2003,
* 2006, 2007, 2009 Free Software Foundation, Inc.
+ * 2015 g10 Code GmbH
*
* This file is part of JNLIB, which is a subsystem of GnuPG.
*
@@ -75,6 +76,7 @@ int ascii_isupper (int c);
int ascii_islower (int c);
int ascii_toupper (int c);
int ascii_tolower (int c);
+char *ascii_strlwr (char *s);
int ascii_strcasecmp( const char *a, const char *b );
int ascii_strncasecmp (const char *a, const char *b, size_t n);
int ascii_memcasecmp( const void *a, const void *b, size_t n );
@@ -141,9 +143,9 @@ char *strconcat (const char *s1, ...) GNUPG_GCC_A_SENTINEL(0);
/* Ditto, but die on error. */
char *xstrconcat (const char *s1, ...) GNUPG_GCC_A_SENTINEL(0);
+char **strsplit (char *string, char delim, char replacement, int *count);
/*-- mapstrings.c --*/
const char *map_static_macro_string (const char *string);
-
#endif /*LIBJNLIB_STRINGHELP_H*/
diff --git a/common/strlist.c b/common/strlist.c
index d9aed16..6816dcf 100644
--- a/common/strlist.c
+++ b/common/strlist.c
@@ -1,5 +1,6 @@
/* strlist.c - string helpers
* Copyright (C) 1998, 2000, 2001, 2006 Free Software Foundation, Inc.
+ * Copyright (C) 2015 g10 Code GmbH
*
* This file is part of JNLIB, which is a subsystem of GnuPG.
*
@@ -212,3 +213,16 @@ strlist_pop (strlist_t *list)
return str;
}
+
+/* Return the first element of the string list HAYSTACK whose string
+ matches NEEDLE. If no elements match, return NULL. */
+strlist_t
+strlist_find (strlist_t haystack, const char *needle)
+{
+ for (;
+ haystack;
+ haystack = haystack->next)
+ if (strcmp (haystack->d, needle) == 0)
+ return haystack;
+ return NULL;
+}
diff --git a/common/strlist.h b/common/strlist.h
index c72549f..94567df 100644
--- a/common/strlist.h
+++ b/common/strlist.h
@@ -55,6 +55,9 @@ strlist_t strlist_prev (strlist_t head, strlist_t node);
strlist_t strlist_last (strlist_t node);
char * strlist_pop (strlist_t *list);
+strlist_t strlist_find (strlist_t haystack, const char *needle);
+
+
#define FREE_STRLIST(a) do { free_strlist((a)); (a) = NULL ; } while(0)
diff --git a/common/t-dns-cert.c b/common/t-dns-cert.c
index 71c7a9c..a170ffb 100644
--- a/common/t-dns-cert.c
+++ b/common/t-dns-cert.c
@@ -54,7 +54,7 @@ main (int argc, char **argv)
printf ("CERT lookup on '%s'\n", name);
- err = get_dns_cert (name, &key, &fpr, &fpr_len, &url);
+ err = get_dns_cert (name, DNS_CERTTYPE_ANY, &key, &fpr, &fpr_len, &url);
if (err)
printf ("get_dns_cert failed: %s <%s>\n",
gpg_strerror (err), gpg_strsource (err));
diff --git a/common/t-gettime.c b/common/t-gettime.c
index 5d554ee..9b3139d 100644
--- a/common/t-gettime.c
+++ b/common/t-gettime.c
@@ -174,6 +174,80 @@ test_string2isotime (void)
}
+static void
+test_isodate_human_to_tm (void)
+{
+ struct {
+ const char *string;
+ int okay;
+ int year, mon, mday;
+ } array [] = {
+ { "1970-01-01", 1, 1970, 1, 1 },
+ { "1970-02-01", 1, 1970, 2, 1 },
+ { "1970-12-31", 1, 1970, 12, 31 },
+ { "1971-01-01", 1, 1971, 1, 1 },
+ { "1998-08-15", 1, 1998, 8, 15 },
+ { "2015-04-10", 1, 2015, 4, 10 },
+ { "2015-04-10 11:30",1, 2015, 4, 10 },
+ { "1969-12-31", 0, 0, 0, 0 },
+ { "1900-01-01", 0, 0, 0, 0 },
+ { "", 0, 0, 0, 0 },
+ { "1970-12-32", 0, 0, 0, 0 },
+ { "1970-13-01", 0, 0, 0, 0 },
+ { "1970-01-00", 0, 0, 0, 0 },
+ { "1970-00-01", 0, 0, 0, 0 },
+ { "1970-00-01", 0, 0, 0, 0 },
+ { "1970", 0, 0, 0, 0 },
+ { "1970-01", 0, 0, 0, 0 },
+ { "1970-01-1", 0, 0, 0, 0 },
+ { "1970-1--01", 0, 0, 0, 0 },
+ { "1970-01-01,", 1, 1970, 1, 1 },
+ { "1970-01-01 ", 1, 1970, 1, 1 },
+ { "1970-01-01\t", 1, 1970, 1, 1 },
+ { "1970-01-01;", 0, 0, 0, 0 },
+ { "1970-01-01:", 0, 0, 0, 0 },
+ { "1970_01-01", 0, 0, 0, 0 },
+ { "1970-01_01", 0, 0, 0, 0 },
+ { NULL, 0 }
+ };
+ int idx;
+ int okay;
+ struct tm tmbuf;
+
+ for (idx=0; array[idx].string; idx++)
+ {
+ okay = !isodate_human_to_tm (array[idx].string, &tmbuf);
+ if (okay != array[idx].okay)
+ {
+ fail (idx);
+ if (verbose)
+ fprintf (stderr, "string '%s' expected: %d, got: %d\n",
+ array[idx].string, (int)array[idx].okay, okay);
+ }
+ else if (!okay)
+ ;
+ else if (tmbuf.tm_year + 1900 != array[idx].year
+ || tmbuf.tm_mon +1 != array[idx].mon
+ || tmbuf.tm_mday != array[idx].mday)
+ {
+ fail (idx);
+ if (verbose)
+ fprintf (stderr, "string '%s' returned %04d-%02d-%02d\n",
+ array[idx].string,
+ tmbuf.tm_year + 1900, tmbuf.tm_mon + 1, tmbuf.tm_mday);
+ }
+ else if (tmbuf.tm_sec || tmbuf.tm_min || tmbuf.tm_hour
+ || tmbuf.tm_isdst != -1)
+ {
+ fail (idx);
+ if (verbose)
+ fprintf (stderr, "string '%s' returned bad time part\n",
+ array[idx].string);
+ }
+ }
+}
+
+
int
main (int argc, char **argv)
{
@@ -182,6 +256,7 @@ main (int argc, char **argv)
test_isotime2epoch ();
test_string2isotime ();
+ test_isodate_human_to_tm ();
return !!errcount;
}
diff --git a/common/t-mbox-util.c b/common/t-mbox-util.c
new file mode 100644
index 0000000..dfa4ada
--- /dev/null
+++ b/common/t-mbox-util.c
@@ -0,0 +1,103 @@
+/* t-mbox-util.c - Module test for mbox-util.c
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "util.h"
+#include "mbox-util.h"
+
+#define pass() do { ; } while(0)
+#define fail(a) do { fprintf (stderr, "%s:%d: test %d failed\n",\
+ __FILE__,__LINE__, (a)); \
+ exit (1); \
+ } while(0)
+
+
+static void
+run_test (void)
+{
+ static struct
+ {
+ const char *userid;
+ const char *mbox;
+ } testtbl[] =
+ {
+ { "Werner Koch <wk@gnupg.org>", "wk@gnupg.org" },
+ { "<wk@gnupg.org>", "wk@gnupg.org" },
+ { "wk@gnupg.org", "wk@gnupg.org" },
+ { "wk@gnupg.org ", NULL },
+ { " wk@gnupg.org", NULL },
+ { "Werner Koch (test) <wk@gnupg.org>", "wk@gnupg.org" },
+ { "Werner Koch <wk@gnupg.org> (test)", "wk@gnupg.org" },
+ { "Werner Koch <wk@gnupg.org (test)", NULL },
+ { "Werner Koch <wk@gnupg.org >", NULL },
+ { "Werner Koch <wk@gnupg.org", NULL },
+ { "", NULL },
+ { "@", NULL },
+ { "bar <>", NULL },
+ { "<foo@example.org>", "foo@example.org" },
+ { "<foo.@example.org>", "foo.@example.org" },
+ { "<.foo.@example.org>", ".foo.@example.org" },
+ { "<foo..@example.org>", "foo..@example.org" },
+ { "<foo..bar@example.org>", "foo..bar@example.org" },
+ { "<foo@example.org.>", NULL },
+ { "<foo@example..org>", NULL },
+ { "<foo@.>", NULL },
+ { "<@example.org>", NULL },
+ { "<foo@@example.org>", NULL },
+ { "<@foo@example.org>", NULL },
+ { "<foo@example.org> ()", "foo@example.org" },
+ { "<fo()o@example.org> ()", "fo()o@example.org" },
+ { "<fo()o@example.org> ()", "fo()o@example.org" },
+ { "fo()o@example.org", NULL},
+ { "Mr. Foo <foo@example.org><bar@example.net>", "foo@example.org"},
+ { NULL, NULL }
+ };
+ int idx;
+
+ for (idx=0; testtbl[idx].userid; idx++)
+ {
+ char *mbox = mailbox_from_userid (testtbl[idx].userid);
+
+ if (!testtbl[idx].mbox)
+ {
+ if (mbox)
+ fail (idx);
+ }
+ else if (!mbox)
+ fail (idx);
+ else if (strcmp (mbox, testtbl[idx].mbox))
+ fail (idx);
+ }
+}
+
+
+int
+main (int argc, char **argv)
+{
+ (void)argc;
+ (void)argv;
+
+ run_test ();
+
+ return 0;
+}
diff --git a/common/t-openpgp-oid.c b/common/t-openpgp-oid.c
index 5cd778d..afb6ebe 100644
--- a/common/t-openpgp-oid.c
+++ b/common/t-openpgp-oid.c
@@ -35,6 +35,10 @@
#define BADOID "1.3.6.1.4.1.11591.2.12242973"
+static int verbose;
+
+
+
static void
test_openpgp_oid_from_str (void)
{
@@ -184,15 +188,51 @@ test_openpgp_oid_is_ed25519 (void)
}
+static void
+test_openpgp_enum_curves (void)
+{
+ int iter = 0;
+ const char *name;
+ int p256 = 0;
+ int p384 = 0;
+ int p521 = 0;
+
+ while ((name = openpgp_enum_curves (&iter)))
+ {
+ if (verbose)
+ printf ("curve: %s\n", name);
+ if (!strcmp (name, "nistp256"))
+ p256++;
+ else if (!strcmp (name, "nistp384"))
+ p384++;
+ else if (!strcmp (name, "nistp521"))
+ p521++;
+ }
+
+ if (p256 != 1 || p384 != 1 || p521 != 1)
+ {
+ /* We can only check the basic RFC-6637 requirements. */
+ fputs ("standard ECC curve missing\n", stderr);
+ exit (1);
+ }
+}
+
+
int
main (int argc, char **argv)
{
- (void)argc;
- (void)argv;
+ if (argc)
+ { argc--; argv++; }
+ if (argc && !strcmp (argv[0], "--verbose"))
+ {
+ verbose = 1;
+ argc--; argv++;
+ }
test_openpgp_oid_from_str ();
test_openpgp_oid_to_str ();
test_openpgp_oid_is_ed25519 ();
+ test_openpgp_enum_curves ();
return 0;
}
diff --git a/common/t-pka.c b/common/t-pka.c
new file mode 100644
index 0000000..7c4d7c3
--- /dev/null
+++ b/common/t-pka.c
@@ -0,0 +1,72 @@
+/* t-pak.c - Module test for pka.c
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+
+#include "util.h"
+#include "pka.h"
+
+
+int
+main (int argc, char **argv)
+{
+ unsigned char fpr[20];
+ char *url;
+ char const *name;
+ int i;
+
+ if (argc)
+ {
+ argc--;
+ argv++;
+ }
+
+ if (!argc)
+ name = "wk@gnupg.org";
+ else if (argc == 1)
+ name = *argv;
+ else
+ {
+ fputs ("usage: t-pka [userid]\n", stderr);
+ return 1;
+ }
+
+ printf ("User id ...: %s\n", name);
+
+ url = get_pka_info (name, fpr, sizeof fpr);
+ printf ("Fingerprint: ");
+ if (url)
+ {
+ for (i = 0; i < sizeof fpr; i++)
+ printf ("%02X", fpr[i]);
+ }
+ else
+ printf ("[not found]");
+
+ putchar ('\n');
+
+ printf ("URL .......: %s\n", (url && *url)? url : "[none]");
+
+ xfree (url);
+
+ return 0;
+}
diff --git a/common/t-stringhelp.c b/common/t-stringhelp.c
index dcd5a45..f5b6cd9 100644
--- a/common/t-stringhelp.c
+++ b/common/t-stringhelp.c
@@ -1,5 +1,6 @@
/* t-stringhelp.c - Regression tests for stringhelp.c
* Copyright (C) 2007 Free Software Foundation, Inc.
+ * 2015 g10 Code GmbH
*
* This file is part of JNLIB, which is a subsystem of GnuPG.
*
@@ -478,6 +479,62 @@ test_make_absfilename_try (void)
xfree (cwd);
}
+static void
+test_strsplit (void)
+{
+ int test_count = 0;
+ void test (const char *s, char delim, char replacement,
+ const char *fields_expected[])
+ {
+ char *s2;
+ int field_count;
+ char **fields;
+ int field_count_expected;
+ int i;
+
+ /* Count the fields. */
+ for (field_count_expected = 0;
+ fields_expected[field_count_expected];
+ field_count_expected ++)
+ ;
+
+ test_count ++;
+
+ /* We need to copy s since strsplit modifies it in place. */
+ s2 = xstrdup (s);
+ fields = strsplit (s2, delim, replacement, &field_count);
+
+ if (field_count != field_count_expected)
+ fail (test_count * 1000);
+
+ for (i = 0; i < field_count_expected; i ++)
+ if (strcmp (fields_expected[i], fields[i]) != 0)
+ {
+ printf ("For field %d, expected '%s', but got '%s'\n",
+ i, fields_expected[i], fields[i]);
+ fail (test_count * 1000 + i + 1);
+ }
+
+ xfree (s2);
+ }
+
+ {
+ const char *expected_result[] =
+ { "a", "bc", "cde", "fghi", "jklmn", "", "foo", "", NULL };
+ test ("a:bc:cde:fghi:jklmn::foo:", ':', '\0', expected_result);
+ }
+
+ {
+ const char *expected_result[] =
+ { "!a!bc!!def!", "a!bc!!def!", "bc!!def!", "!def!", "def!", "", NULL };
+ test (",a,bc,,def,", ',', '!', expected_result);
+ }
+
+ {
+ const char *expected_result[] = { "", NULL };
+ test ("", ':', ',', expected_result);
+ }
+}
int
main (int argc, char **argv)
@@ -491,6 +548,7 @@ main (int argc, char **argv)
test_xstrconcat ();
test_make_filename_try ();
test_make_absfilename_try ();
+ test_strsplit ();
xfree (home_buffer);
return 0;
diff --git a/common/t-zb32.c b/common/t-zb32.c
index 7d509da..2b19c09 100644
--- a/common/t-zb32.c
+++ b/common/t-zb32.c
@@ -76,6 +76,9 @@ test_zb32enc (void)
{ 20, "\x81\x81\x81", "ogya" },
{ 64, "\x81\x81\x81\x81\x81\x81\x81\x81", "ogyadycbogyan" },
/* More tests. */
+ { 160, "\x80\x61\x58\x70\xF5\xBA\xD6\x90\x33\x36"
+ /* */"\x86\xD0\xF2\xAD\x85\xAC\x1E\x42\xB3\x67",
+ /* */"oboioh8izmmjyc3so5exfmcfioxrfc58" },
{ 0, "", "" }
};
int tidx;
diff --git a/common/userids.c b/common/userids.c
index 61e88cc..e1304be 100644
--- a/common/userids.c
+++ b/common/userids.c
@@ -38,7 +38,7 @@
/* Parse the user-id NAME and build a search description for it.
- * Returns 0 on succdess or an error code. DESC may be NULL to merely
+ * Returns 0 on success or an error code. DESC may be NULL to merely
* check the validity of a user-id.
*
* Some used rules:
diff --git a/common/util.h b/common/util.h
index 9103e09..d22820d 100644
--- a/common/util.h
+++ b/common/util.h
@@ -42,7 +42,89 @@
# define GPG_ERR_OBJ_TERM_STATE 225
# define GPG_ERR_FORBIDDEN 251
#endif
-
+#if GPG_ERROR_VERSION_NUMBER < 0x011300 /* 1.19 */
+# define GPG_ERR_LDAP_GENERAL 721
+# define GPG_ERR_LDAP_ATTR_GENERAL 722
+# define GPG_ERR_LDAP_NAME_GENERAL 723
+# define GPG_ERR_LDAP_SECURITY_GENERAL 724
+# define GPG_ERR_LDAP_SERVICE_GENERAL 725
+# define GPG_ERR_LDAP_UPDATE_GENERAL 726
+# define GPG_ERR_LDAP_E_GENERAL 727
+# define GPG_ERR_LDAP_X_GENERAL 728
+# define GPG_ERR_LDAP_OTHER_GENERAL 729
+# define GPG_ERR_LDAP_X_CONNECTING 750
+# define GPG_ERR_LDAP_REFERRAL_LIMIT 751
+# define GPG_ERR_LDAP_CLIENT_LOOP 752
+# define GPG_ERR_LDAP_NO_RESULTS 754
+# define GPG_ERR_LDAP_CONTROL_NOT_FOUND 755
+# define GPG_ERR_LDAP_NOT_SUPPORTED 756
+# define GPG_ERR_LDAP_CONNECT 757
+# define GPG_ERR_LDAP_NO_MEMORY 758
+# define GPG_ERR_LDAP_PARAM 759
+# define GPG_ERR_LDAP_USER_CANCELLED 760
+# define GPG_ERR_LDAP_FILTER 761
+# define GPG_ERR_LDAP_AUTH_UNKNOWN 762
+# define GPG_ERR_LDAP_TIMEOUT 763
+# define GPG_ERR_LDAP_DECODING 764
+# define GPG_ERR_LDAP_ENCODING 765
+# define GPG_ERR_LDAP_LOCAL 766
+# define GPG_ERR_LDAP_SERVER_DOWN 767
+# define GPG_ERR_LDAP_SUCCESS 768
+# define GPG_ERR_LDAP_OPERATIONS 769
+# define GPG_ERR_LDAP_PROTOCOL 770
+# define GPG_ERR_LDAP_TIMELIMIT 771
+# define GPG_ERR_LDAP_SIZELIMIT 772
+# define GPG_ERR_LDAP_COMPARE_FALSE 773
+# define GPG_ERR_LDAP_COMPARE_TRUE 774
+# define GPG_ERR_LDAP_UNSUPPORTED_AUTH 775
+# define GPG_ERR_LDAP_STRONG_AUTH_RQRD 776
+# define GPG_ERR_LDAP_PARTIAL_RESULTS 777
+# define GPG_ERR_LDAP_REFERRAL 778
+# define GPG_ERR_LDAP_ADMINLIMIT 779
+# define GPG_ERR_LDAP_UNAVAIL_CRIT_EXTN 780
+# define GPG_ERR_LDAP_CONFIDENT_RQRD 781
+# define GPG_ERR_LDAP_SASL_BIND_INPROG 782
+# define GPG_ERR_LDAP_NO_SUCH_ATTRIBUTE 784
+# define GPG_ERR_LDAP_UNDEFINED_TYPE 785
+# define GPG_ERR_LDAP_BAD_MATCHING 786
+# define GPG_ERR_LDAP_CONST_VIOLATION 787
+# define GPG_ERR_LDAP_TYPE_VALUE_EXISTS 788
+# define GPG_ERR_LDAP_INV_SYNTAX 789
+# define GPG_ERR_LDAP_NO_SUCH_OBJ 800
+# define GPG_ERR_LDAP_ALIAS_PROBLEM 801
+# define GPG_ERR_LDAP_INV_DN_SYNTAX 802
+# define GPG_ERR_LDAP_IS_LEAF 803
+# define GPG_ERR_LDAP_ALIAS_DEREF 804
+# define GPG_ERR_LDAP_X_PROXY_AUTH_FAIL 815
+# define GPG_ERR_LDAP_BAD_AUTH 816
+# define GPG_ERR_LDAP_INV_CREDENTIALS 817
+# define GPG_ERR_LDAP_INSUFFICIENT_ACC 818
+# define GPG_ERR_LDAP_BUSY 819
+# define GPG_ERR_LDAP_UNAVAILABLE 820
+# define GPG_ERR_LDAP_UNWILL_TO_PERFORM 821
+# define GPG_ERR_LDAP_LOOP_DETECT 822
+# define GPG_ERR_LDAP_NAMING_VIOLATION 832
+# define GPG_ERR_LDAP_OBJ_CLS_VIOLATION 833
+# define GPG_ERR_LDAP_NOT_ALLOW_NONLEAF 834
+# define GPG_ERR_LDAP_NOT_ALLOW_ON_RDN 835
+# define GPG_ERR_LDAP_ALREADY_EXISTS 836
+# define GPG_ERR_LDAP_NO_OBJ_CLASS_MODS 837
+# define GPG_ERR_LDAP_RESULTS_TOO_LARGE 838
+# define GPG_ERR_LDAP_AFFECTS_MULT_DSAS 839
+# define GPG_ERR_LDAP_VLV 844
+# define GPG_ERR_LDAP_OTHER 848
+# define GPG_ERR_LDAP_CUP_RESOURCE_LIMIT 881
+# define GPG_ERR_LDAP_CUP_SEC_VIOLATION 882
+# define GPG_ERR_LDAP_CUP_INV_DATA 883
+# define GPG_ERR_LDAP_CUP_UNSUP_SCHEME 884
+# define GPG_ERR_LDAP_CUP_RELOAD 885
+# define GPG_ERR_LDAP_CANCELLED 886
+# define GPG_ERR_LDAP_NO_SUCH_OPERATION 887
+# define GPG_ERR_LDAP_TOO_LATE 888
+# define GPG_ERR_LDAP_CANNOT_CANCEL 889
+# define GPG_ERR_LDAP_ASSERTION_FAILED 890
+# define GPG_ERR_LDAP_PROX_AUTH_DENIED 891
+#endif /*GPG_ERROR_VERSION_NUMBER < 0x011300*/
/* Hash function used with libksba. */
#define HASH_FNC ((void (*)(void *, const void*,size_t))gcry_md_write)
@@ -77,6 +159,12 @@
# define GNUPG_GCC_A_SENTINEL(a)
#endif
+#if __GNUC__ >= 4
+# define GNUPG_GCC_A_USED __attribute__ ((used))
+#else
+# define GNUPG_GCC_A_USED
+#endif
+
/* We need this type even if we are not using libreadline and or we
did not include libreadline in the current file. */
@@ -224,6 +312,7 @@ char *openpgp_oid_to_str (gcry_mpi_t a);
int openpgp_oid_is_ed25519 (gcry_mpi_t a);
const char *openpgp_curve_to_oid (const char *name, unsigned int *r_nbits);
const char *openpgp_oid_to_curve (const char *oid);
+const char *openpgp_enum_curves (int *idxp);
diff --git a/configure.ac b/configure.ac
index ef04588..d02137a 100644
--- a/configure.ac
+++ b/configure.ac
@@ -28,7 +28,7 @@ min_automake_version="1.14"
m4_define([mym4_package],[gnupg])
m4_define([mym4_major], [2])
m4_define([mym4_minor], [1])
-m4_define([mym4_micro], [2])
+m4_define([mym4_micro], [3])
# To start a new development series, i.e a new major or minor number
# you need to mark an arbitrary commit before the first beta release
@@ -920,18 +920,12 @@ AC_ARG_ENABLE(dns-srv,
[disable the use of DNS SRV in HKP and HTTP]),
use_dns_srv=$enableval,use_dns_srv=yes)
-AC_ARG_ENABLE(dns-pka,
- AC_HELP_STRING([--disable-dns-pka],
- [disable the use of PKA records in DNS]),
- use_dns_pka=$enableval,use_dns_pka=yes)
-
AC_ARG_ENABLE(dns-cert,
AC_HELP_STRING([--disable-dns-cert],
[disable the use of CERT records in DNS]),
use_dns_cert=$enableval,use_dns_cert=yes)
-if test x"$use_dns_pka" = xyes || test x"$use_dns_srv" = xyes \
- || test x"$use_dns_cert" = xyes; then
+if test x"$use_dns_srv" = xyes || test x"$use_dns_cert" = xyes; then
_dns_save_libs=$LIBS
LIBS=""
# the double underscore thing is a glibc-ism?
@@ -988,10 +982,6 @@ if test x"$use_dns_pka" = xyes || test x"$use_dns_srv" = xyes \
AC_DEFINE(USE_DNS_SRV,1,[define to use DNS SRV])
fi
- if test x"$use_dns_pka" = xyes ; then
- AC_DEFINE(USE_DNS_PKA,1,[define to use our experimental DNS PKA])
- fi
-
if test x"$use_dns_cert" = xyes ; then
AC_DEFINE(USE_DNS_CERT,1,[define to use DNS CERT])
fi
@@ -1010,16 +1000,11 @@ if test x"$use_dns_pka" = xyes || test x"$use_dns_srv" = xyes \
AC_DEFINE(USE_DNS_SRV,1)
fi
- if test x"$use_dns_pka" = xyes ; then
- AC_DEFINE(USE_DNS_PKA,1)
- fi
-
if test x"$use_dns_cert" = xyes ; then
AC_DEFINE(USE_DNS_CERT,1,[define to use DNS CERT])
fi
else
use_dns_srv=no
- use_dns_pka=no
use_dns_cert=no
fi
fi
@@ -1814,7 +1799,7 @@ if test x"$use_regex" != xyes ; then
echo "
Warning: No regular expression support available.
OpenPGP trust signatures won't work.
- gpg-check-pattern will not be build.
+ gpg-check-pattern will not be built.
"
fi
if test "x${gpg_config_script_warn}" != x; then
diff --git a/dirmngr/Makefile.am b/dirmngr/Makefile.am
index 2d8d336..a8b1c52 100644
--- a/dirmngr/Makefile.am
+++ b/dirmngr/Makefile.am
@@ -27,7 +27,10 @@ if USE_LDAPWRAPPER
libexec_PROGRAMS = dirmngr_ldap
endif
-AM_CPPFLAGS = -I$(top_srcdir)/gl -I$(top_srcdir)/intl -I$(top_srcdir)/common
+noinst_PROGRAMS = $(module_tests)
+TESTS = $(module_tests)
+
+AM_CPPFLAGS = -I$(top_srcdir)/common
include $(top_srcdir)/am/cmacros.am
@@ -59,7 +62,9 @@ dirmngr_SOURCES = dirmngr.c dirmngr.h server.c crlcache.c crlfetch.c \
cdb.h cdblib.c misc.c dirmngr-err.h \
ocsp.c ocsp.h validate.c validate.h \
ks-action.c ks-action.h ks-engine.h \
- ks-engine-hkp.c ks-engine-http.c ks-engine-finger.c ks-engine-kdns.c
+ ks-engine-hkp.c ks-engine-http.c ks-engine-finger.c ks-engine-kdns.c \
+ ks-engine-ldap.c \
+ ldap-parse-uri.c ldap-parse-uri.h
if USE_LDAP
dirmngr_SOURCES += ldapserver.h ldapserver.c ldap.c w32-ldap-help.h \
@@ -74,6 +79,9 @@ dirmngr_LDADD = $(libcommontlsnpth) $(libcommonpth) \
$(DNSLIBS) $(LIBASSUAN_LIBS) \
$(LIBGCRYPT_LIBS) $(KSBA_LIBS) $(NPTH_LIBS) \
$(NTBTLS_LIBS) $(LIBGNUTLS_LIBS) $(LIBINTL) $(LIBICONV)
+if USE_LDAP
+dirmngr_LDADD += $(ldaplibs)
+endif
if !USE_LDAPWRAPPER
dirmngr_LDADD += $(ldaplibs)
endif
@@ -99,4 +107,17 @@ no-libgcrypt.c : $(top_srcdir)/tools/no-libgcrypt.c
cat $(top_srcdir)/tools/no-libgcrypt.c > no-libgcrypt.c
+t_common_src = t-support.h
+# We need libcommontls, because we use the http functions.
+t_common_ldadd = $(libcommontls) $(libcommon) no-libgcrypt.o \
+ $(GPG_ERROR_LIBS) $(NETLIBS) \
+ $(NTBTLS_LIBS) $(LIBGNUTLS_LIBS) \
+ $(DNSLIBS) $(LIBINTL) $(LIBICONV)
+
+module_tests = t-ldap-parse-uri
+t_ldap_parse_uri_SOURCES = \
+ t-ldap-parse-uri.c ldap-parse-uri.c ldap-parse-uri.h \
+ $(ldap_url) $(t_common_src)
+t_ldap_parse_uri_LDADD = $(ldaplibs) $(t_common_ldadd)
+
$(PROGRAMS) : $(libcommon) $(libcommonpth) $(libcommontls) $(libcommontlsnpth)
diff --git a/dirmngr/certcache.c b/dirmngr/certcache.c
index 969b3ec..8c5feef 100644
--- a/dirmngr/certcache.c
+++ b/dirmngr/certcache.c
@@ -78,7 +78,7 @@ typedef struct cert_item_s *cert_item_t;
the first byte of the fingerprint. */
static cert_item_t cert_cache[256];
-/* This is the global cache_lock variable. In general looking is not
+/* This is the global cache_lock variable. In general locking is not
needed but it would take extra efforts to make sure that no
indirect use of npth functions is done, so we simply lock it
always. Note: We can't use static initialization, as that is not
@@ -153,7 +153,7 @@ compare_serialno (ksba_sexp_t serial1, ksba_sexp_t serial2 )
-/* Return a malloced canonical S-Expression with the serialnumber
+/* Return a malloced canonical S-Expression with the serial number
converted from the hex string HEXSN. Return NULL on memory
error. */
ksba_sexp_t
@@ -435,11 +435,11 @@ cert_cache_init (void)
init_cache_lock ();
acquire_cache_write_lock ();
- dname = make_filename (opt.homedir, "trusted-certs", NULL);
+ dname = make_filename (gnupg_sysconfdir (), "trusted-certs", NULL);
load_certs_from_dir (dname, 1);
xfree (dname);
- dname = make_filename (opt.homedir_data, "extra-certs", NULL);
+ dname = make_filename (gnupg_sysconfdir (), "extra-certs", NULL);
load_certs_from_dir (dname, 0);
xfree (dname);
diff --git a/dirmngr/dirmngr.c b/dirmngr/dirmngr.c
index fd31b7f..4c17c8c 100644
--- a/dirmngr/dirmngr.c
+++ b/dirmngr/dirmngr.c
@@ -251,7 +251,7 @@ static const char *redir_socket_name;
POSIX systems). */
static assuan_sock_nonce_t socket_nonce;
-/* Only if this flag has been set we will remove the socket file. */
+/* Only if this flag has been set will we remove the socket file. */
static int cleanup_socket;
/* Keep track of the current log file so that we can avoid updating
@@ -393,11 +393,11 @@ set_debug (void)
else if (!strcmp (debug_level, "none") || (numok && numlvl < 1))
opt.debug = 0;
else if (!strcmp (debug_level, "basic") || (numok && numlvl <= 2))
- opt.debug = DBG_ASSUAN_VALUE;
+ opt.debug = DBG_IPC_VALUE;
else if (!strcmp (debug_level, "advanced") || (numok && numlvl <= 5))
- opt.debug = (DBG_ASSUAN_VALUE|DBG_X509_VALUE|DBG_LOOKUP_VALUE);
+ opt.debug = (DBG_IPC_VALUE|DBG_X509_VALUE|DBG_LOOKUP_VALUE);
else if (!strcmp (debug_level, "expert") || (numok && numlvl <= 8))
- opt.debug = (DBG_ASSUAN_VALUE|DBG_X509_VALUE|DBG_LOOKUP_VALUE
+ opt.debug = (DBG_IPC_VALUE|DBG_X509_VALUE|DBG_LOOKUP_VALUE
|DBG_CACHE_VALUE|DBG_CRYPTO_VALUE);
else if (!strcmp (debug_level, "guru") || numok)
{
@@ -800,7 +800,6 @@ main (int argc, char **argv)
#else
opt.homedir = gnupg_sysconfdir ();
#endif
- opt.homedir_data = gnupg_datadir ();
opt.homedir_cache = gnupg_cachedir ();
socket_name = dirmngr_sys_socket_name ();
}
@@ -926,8 +925,6 @@ main (int argc, char **argv)
if (nogreeting )
greeting = 0;
- if (!opt.homedir_data)
- opt.homedir_data = opt.homedir;
if (!opt.homedir_cache)
opt.homedir_cache = opt.homedir;
@@ -1884,8 +1881,8 @@ handle_tick (void)
}
-/* Check the nonce on a new connection. This is a NOP unless we we
- are using our Unix domain socket emulation under Windows. */
+/* Check the nonce on a new connection. This is a NOP unless we are
+ using our Unix domain socket emulation under Windows. */
static int
check_nonce (assuan_fd_t fd, assuan_sock_nonce_t *nonce)
{
diff --git a/dirmngr/dirmngr.h b/dirmngr/dirmngr.h
index bb368f2..56abc86 100644
--- a/dirmngr/dirmngr.h
+++ b/dirmngr/dirmngr.h
@@ -1,6 +1,6 @@
/* dirmngr.h - Common definitions for the dirmngr
* Copyright (C) 2002 Klarälvdalens Datakonsult AB
- * Copyright (C) 2004 g10 Code GmbH
+ * Copyright (C) 2004, 2015 g10 Code GmbH
* Copyright (C) 2014 Werner Koch
*
* This file is part of GnuPG.
@@ -80,7 +80,6 @@ struct
int dry_run; /* don't change any persistent data */
int batch; /* batch mode */
const char *homedir; /* Configuration directory name */
- const char *homedir_data; /* Ditto for data files (/usr/share/dirmngr). */
const char *homedir_cache; /* Ditto for cache files (/var/cache/dirmngr). */
char *config_filename; /* Name of a config file, which will be
@@ -134,21 +133,21 @@ struct
#define DBG_X509_VALUE 1 /* debug x.509 parsing */
-#define DBG_LOOKUP_VALUE 2 /* debug lookup details */
#define DBG_CRYPTO_VALUE 4 /* debug low level crypto */
#define DBG_MEMORY_VALUE 32 /* debug memory allocation stuff */
#define DBG_CACHE_VALUE 64 /* debug the caching */
#define DBG_MEMSTAT_VALUE 128 /* show memory statistics */
#define DBG_HASHING_VALUE 512 /* debug hashing operations */
-#define DBG_ASSUAN_VALUE 1024 /* debug assuan communication */
+#define DBG_IPC_VALUE 1024 /* debug assuan communication */
+#define DBG_LOOKUP_VALUE 8192 /* debug lookup details */
#define DBG_X509 (opt.debug & DBG_X509_VALUE)
-#define DBG_LOOKUP (opt.debug & DBG_LOOKUP_VALUE)
#define DBG_CRYPTO (opt.debug & DBG_CRYPTO_VALUE)
#define DBG_MEMORY (opt.debug & DBG_MEMORY_VALUE)
#define DBG_CACHE (opt.debug & DBG_CACHE_VALUE)
#define DBG_HASHING (opt.debug & DBG_HASHING_VALUE)
-#define DBG_ASSUAN (opt.debug & DBG_ASSUAN_VALUE)
+#define DBG_IPC (opt.debug & DBG_IPC_VALUE)
+#define DBG_LOOKUP (opt.debug & DBG_LOOKUP_VALUE)
/* A simple list of certificate references. */
struct cert_ref_s
@@ -175,7 +174,6 @@ struct server_control_s
response. */
int audit_events; /* Send audit events to client. */
- uri_item_t keyservers; /* List of keyservers. */
};
diff --git a/dirmngr/ks-action.c b/dirmngr/ks-action.c
index e4cd8f1..c76aaaa 100644
--- a/dirmngr/ks-action.c
+++ b/dirmngr/ks-action.c
@@ -1,6 +1,7 @@
/* ks-action.c - OpenPGP keyserver actions
* Copyright (C) 2011 Free Software Foundation, Inc.
* Copyright (C) 2011, 2014 Werner Koch
+ * Copyright (C) 2015 g10 Code GmbH
*
* This file is part of GnuPG.
*
@@ -29,26 +30,7 @@
#include "misc.h"
#include "ks-engine.h"
#include "ks-action.h"
-
-
-/* Copy all data from IN to OUT. */
-static gpg_error_t
-copy_stream (estream_t in, estream_t out)
-{
- char buffer[512];
- size_t nread;
-
- while (!es_read (in, buffer, sizeof buffer, &nread))
- {
- if (!nread)
- return 0; /* EOF */
- if (es_write (out, buffer, nread, NULL))
- break;
-
- }
- return gpg_error_from_syserror ();
-}
-
+#include "ldap-parse-uri.h"
/* Called by the engine's help functions to print the actual help. */
gpg_error_t
@@ -91,7 +73,11 @@ ks_action_help (ctrl_t ctrl, const char *url)
}
else
{
- err = http_parse_uri (&parsed_uri, url, 1);
+ if (ldap_uri_p (url))
+ err = ldap_parse_uri (&parsed_uri, url);
+ else
+ err = http_parse_uri (&parsed_uri, url, 1);
+
if (err)
return err;
}
@@ -104,6 +90,8 @@ ks_action_help (ctrl_t ctrl, const char *url)
err = ks_finger_help (ctrl, parsed_uri);
if (!err)
err = ks_kdns_help (ctrl, parsed_uri);
+ if (!err)
+ err = ks_ldap_help (ctrl, parsed_uri);
if (!parsed_uri)
ks_print_help (ctrl,
@@ -117,13 +105,13 @@ ks_action_help (ctrl_t ctrl, const char *url)
/* Resolve all host names. This is useful for looking at the status
of configured keyservers. */
gpg_error_t
-ks_action_resolve (ctrl_t ctrl)
+ks_action_resolve (ctrl_t ctrl, uri_item_t keyservers)
{
gpg_error_t err = 0;
int any_server = 0;
uri_item_t uri;
- for (uri = ctrl->keyservers; !err && uri; uri = uri->next)
+ for (uri = keyservers; !err && uri; uri = uri->next)
{
if (uri->parsed_uri->is_http)
{
@@ -143,7 +131,8 @@ ks_action_resolve (ctrl_t ctrl)
/* Search all configured keyservers for keys matching PATTERNS and
write the result to the provided output stream. */
gpg_error_t
-ks_action_search (ctrl_t ctrl, strlist_t patterns, estream_t outfp)
+ks_action_search (ctrl_t ctrl, uri_item_t keyservers,
+ strlist_t patterns, estream_t outfp)
{
gpg_error_t err = 0;
int any_server = 0;
@@ -159,12 +148,20 @@ ks_action_search (ctrl_t ctrl, strlist_t patterns, estream_t outfp)
errors - it might not be the best idea to ignore an error from
one server and silently continue with another server. For now we
stop at the first error. */
- for (uri = ctrl->keyservers; !err && uri; uri = uri->next)
+ for (uri = keyservers; !err && uri; uri = uri->next)
{
- if (uri->parsed_uri->is_http)
+ int is_http = uri->parsed_uri->is_http;
+ int is_ldap = (strcmp (uri->parsed_uri->scheme, "ldap") == 0
+ || strcmp (uri->parsed_uri->scheme, "ldaps") == 0
+ || strcmp (uri->parsed_uri->scheme, "ldapi") == 0);
+ if (is_http || is_ldap)
{
any_server = 1;
- err = ks_hkp_search (ctrl, uri->parsed_uri, patterns->d, &infp);
+ if (is_http)
+ err = ks_hkp_search (ctrl, uri->parsed_uri, patterns->d, &infp);
+ else if (is_ldap)
+ err = ks_ldap_search (ctrl, uri->parsed_uri, patterns->d, &infp);
+
if (!err)
{
err = copy_stream (infp, outfp);
@@ -183,7 +180,8 @@ ks_action_search (ctrl_t ctrl, strlist_t patterns, estream_t outfp)
/* Get the requested keys (matching PATTERNS) using all configured
keyservers and write the result to the provided output stream. */
gpg_error_t
-ks_action_get (ctrl_t ctrl, strlist_t patterns, estream_t outfp)
+ks_action_get (ctrl_t ctrl, uri_item_t keyservers,
+ strlist_t patterns, estream_t outfp)
{
gpg_error_t err = 0;
gpg_error_t first_err = 0;
@@ -202,14 +200,22 @@ ks_action_get (ctrl_t ctrl, strlist_t patterns, estream_t outfp)
keyservers might not all be fully synced thus it is not clear
whether the first keyserver has the freshest copy of the key.
Need to think about a better strategy. */
- for (uri = ctrl->keyservers; !err && uri; uri = uri->next)
+ for (uri = keyservers; !err && uri; uri = uri->next)
{
- if (uri->parsed_uri->is_http)
+ int is_http = uri->parsed_uri->is_http;
+ int is_ldap = (strcmp (uri->parsed_uri->scheme, "ldap") == 0
+ || strcmp (uri->parsed_uri->scheme, "ldaps") == 0
+ || strcmp (uri->parsed_uri->scheme, "ldapi") == 0);
+ if (is_http || is_ldap)
{
any_server = 1;
for (sl = patterns; !err && sl; sl = sl->next)
{
- err = ks_hkp_get (ctrl, uri->parsed_uri, sl->d, &infp);
+ if (is_http)
+ err = ks_hkp_get (ctrl, uri->parsed_uri, sl->d, &infp);
+ else
+ err = ks_ldap_get (ctrl, uri->parsed_uri, sl->d, &infp);
+
if (err)
{
/* It is possible that a server does not carry a
@@ -301,21 +307,37 @@ ks_action_fetch (ctrl_t ctrl, const char *url, estream_t outfp)
/* Send an OpenPGP key to all keyservers. The key in {DATA,DATALEN}
- is expected in OpenPGP binary transport format. */
+ is expected to be in OpenPGP binary transport format. The metadata
+ in {INFO,INFOLEN} is in colon-separated format (concretely, it is
+ the output of 'for x in keys sigs; do gpg --list-$x --with-colons
+ KEYID; done'. This function may modify DATA and INFO. If this is
+ a problem, then the caller should create a copy. */
gpg_error_t
-ks_action_put (ctrl_t ctrl, const void *data, size_t datalen)
+ks_action_put (ctrl_t ctrl, uri_item_t keyservers,
+ void *data, size_t datalen,
+ void *info, size_t infolen)
{
gpg_error_t err = 0;
gpg_error_t first_err = 0;
int any_server = 0;
uri_item_t uri;
- for (uri = ctrl->keyservers; !err && uri; uri = uri->next)
+ for (uri = keyservers; !err && uri; uri = uri->next)
{
- if (uri->parsed_uri->is_http)
+ int is_http = uri->parsed_uri->is_http;
+ int is_ldap = (strcmp (uri->parsed_uri->scheme, "ldap") == 0
+ || strcmp (uri->parsed_uri->scheme, "ldaps") == 0
+ || strcmp (uri->parsed_uri->scheme, "ldapi") == 0);
+
+ if (is_http || is_ldap)
{
any_server = 1;
- err = ks_hkp_put (ctrl, uri->parsed_uri, data, datalen);
+ if (is_http)
+ err = ks_hkp_put (ctrl, uri->parsed_uri, data, datalen);
+ else
+ err = ks_ldap_put (ctrl, uri->parsed_uri, data, datalen,
+ info, infolen);
+
if (err)
{
first_err = err;
diff --git a/dirmngr/ks-action.h b/dirmngr/ks-action.h
index 5c8a5cd..c373bf9 100644
--- a/dirmngr/ks-action.h
+++ b/dirmngr/ks-action.h
@@ -1,5 +1,6 @@
/* ks-action.h - OpenPGP keyserver actions definitions
* Copyright (C) 2011 Free Software Foundation, Inc.
+ * 2015 g10 Code GmbH
*
* This file is part of GnuPG.
*
@@ -21,11 +22,15 @@
#define DIRMNGR_KS_ACTION_H 1
gpg_error_t ks_action_help (ctrl_t ctrl, const char *url);
-gpg_error_t ks_action_resolve (ctrl_t ctrl);
-gpg_error_t ks_action_search (ctrl_t ctrl, strlist_t patterns, estream_t outfp);
-gpg_error_t ks_action_get (ctrl_t ctrl, strlist_t patterns, estream_t outfp);
+gpg_error_t ks_action_resolve (ctrl_t ctrl, uri_item_t keyservers);
+gpg_error_t ks_action_search (ctrl_t ctrl, uri_item_t keyservers,
+ strlist_t patterns, estream_t outfp);
+gpg_error_t ks_action_get (ctrl_t ctrl, uri_item_t keyservers,
+ strlist_t patterns, estream_t outfp);
gpg_error_t ks_action_fetch (ctrl_t ctrl, const char *url, estream_t outfp);
-gpg_error_t ks_action_put (ctrl_t ctrl, const void *data, size_t datalen);
+gpg_error_t ks_action_put (ctrl_t ctrl, uri_item_t keyservers,
+ void *data, size_t datalen,
+ void *info, size_t infolen);
#endif /*DIRMNGR_KS_ACTION_H*/
diff --git a/dirmngr/ks-engine-hkp.c b/dirmngr/ks-engine-hkp.c
index ea607cb..fcdd71e 100644
--- a/dirmngr/ks-engine-hkp.c
+++ b/dirmngr/ks-engine-hkp.c
@@ -521,6 +521,14 @@ map_host (ctrl_t ctrl, const char *name, int force_reselect,
hi = hosttable[idx];
if (hi->pool)
{
+ /* Deal with the pool name before selecting a host. */
+ if (r_poolname && hi->cname)
+ {
+ *r_poolname = xtrystrdup (hi->cname);
+ if (!*r_poolname)
+ return gpg_error_from_syserror ();
+ }
+
/* If the currently selected host is now marked dead, force a
re-selection . */
if (force_reselect)
@@ -536,6 +544,11 @@ map_host (ctrl_t ctrl, const char *name, int force_reselect,
if (hi->poolidx == -1)
{
log_error ("no alive host found in pool '%s'\n", name);
+ if (r_poolname)
+ {
+ xfree (*r_poolname);
+ *r_poolname = NULL;
+ }
return gpg_error (GPG_ERR_NO_KEYSERVER);
}
}
@@ -548,6 +561,11 @@ map_host (ctrl_t ctrl, const char *name, int force_reselect,
if (hi->dead)
{
log_error ("host '%s' marked as dead\n", hi->name);
+ if (r_poolname)
+ {
+ xfree (*r_poolname);
+ *r_poolname = NULL;
+ }
return gpg_error (GPG_ERR_NO_KEYSERVER);
}
@@ -564,13 +582,6 @@ map_host (ctrl_t ctrl, const char *name, int force_reselect,
*r_httpflags |= HTTP_FLAG_IGNORE_IPv6;
}
- if (r_poolname && hi->pool && hi->cname)
- {
- *r_poolname = xtrystrdup (hi->cname);
- if (!*r_poolname)
- return gpg_error_from_syserror ();
- }
-
*r_host = xtrystrdup (hi->name);
if (!*r_host)
{
@@ -1103,64 +1114,6 @@ handle_send_request_error (gpg_error_t err, const char *request,
return retry;
}
-static gpg_error_t
-armor_data (char **r_string, const void *data, size_t datalen)
-{
- gpg_error_t err;
- struct b64state b64state;
- estream_t fp;
- long length;
- char *buffer;
- size_t nread;
-
- *r_string = NULL;
-
- fp = es_fopenmem (0, "rw,samethread");
- if (!fp)
- return gpg_error_from_syserror ();
-
- if ((err=b64enc_start_es (&b64state, fp, "PGP PUBLIC KEY BLOCK"))
- || (err=b64enc_write (&b64state, data, datalen))
- || (err = b64enc_finish (&b64state)))
- {
- es_fclose (fp);
- return err;
- }
-
- /* FIXME: To avoid the extra buffer allocation estream should
- provide a function to snatch the internal allocated memory from
- such a memory stream. */
- length = es_ftell (fp);
- if (length < 0)
- {
- err = gpg_error_from_syserror ();
- es_fclose (fp);
- return err;
- }
-
- buffer = xtrymalloc (length+1);
- if (!buffer)
- {
- err = gpg_error_from_syserror ();
- es_fclose (fp);
- return err;
- }
-
- es_rewind (fp);
- if (es_read (fp, buffer, length, &nread))
- {
- err = gpg_error_from_syserror ();
- es_fclose (fp);
- return err;
- }
- buffer[nread] = 0;
- es_fclose (fp);
-
- *r_string = buffer;
- return 0;
-}
-
-
/* Search the keyserver identified by URI for keys matching PATTERN.
On success R_FP has an open stream to read the data. */
@@ -1300,7 +1253,8 @@ ks_hkp_search (ctrl_t ctrl, parsed_uri_t uri, const char *pattern,
/* Get the key described key the KEYSPEC string from the keyserver
identified by URI. On success R_FP has an open stream to read the
- data. */
+ data. The data will be provided in a format GnuPG can import
+ (either a binary OpenPGP message or an armored one). */
gpg_error_t
ks_hkp_get (ctrl_t ctrl, parsed_uri_t uri, const char *keyspec, estream_t *r_fp)
{
@@ -1443,7 +1397,7 @@ put_post_cb (void *opaque, http_t http)
}
-/* Send the key in {DATA,DATALEN} to the keyserver identified by URI. */
+/* Send the key in {DATA,DATALEN} to the keyserver identified by URI. */
gpg_error_t
ks_hkp_put (ctrl_t ctrl, parsed_uri_t uri, const void *data, size_t datalen)
{
diff --git a/dirmngr/ks-engine-ldap.c b/dirmngr/ks-engine-ldap.c
new file mode 100644
index 0000000..aefd12a
--- /dev/null
+++ b/dirmngr/ks-engine-ldap.c
@@ -0,0 +1,2064 @@
+/* ks-engine-ldap.c - talk to a LDAP keyserver
+ * Copyright (C) 2001, 2002, 2004, 2005, 2006
+ * 2007 Free Software Foundation, Inc.
+ * Copyright (C) 2015 g10 Code GmbH
+ *
+ * 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 <string.h>
+#include <time.h>
+#include <unistd.h>
+#ifdef HAVE_GETOPT_H
+# include <getopt.h>
+#endif
+#include <stdlib.h>
+#include <errno.h>
+#include <assert.h>
+
+#ifdef _WIN32
+# include <winsock2.h>
+# include <winldap.h>
+#else
+# ifdef NEED_LBER_H
+# include <lber.h>
+# endif
+/* For OpenLDAP, to enable the API that we're using. */
+# define LDAP_DEPRECATED 1
+# include <ldap.h>
+#endif
+
+#include "dirmngr.h"
+#include "misc.h"
+#include "userids.h"
+#include "ks-engine.h"
+#include "ldap-parse-uri.h"
+
+#ifndef HAVE_TIMEGM
+time_t timegm(struct tm *tm);
+#endif
+
+/* Convert an LDAP error to a GPG error. */
+static int
+ldap_err_to_gpg_err (int code)
+{
+ gpg_err_code_t ec;
+
+ switch (code)
+ {
+#ifdef LDAP_X_CONNECTING
+ case LDAP_X_CONNECTING: ec = GPG_ERR_LDAP_X_CONNECTING; break;
+#endif
+
+ case LDAP_REFERRAL_LIMIT_EXCEEDED: ec = GPG_ERR_LDAP_REFERRAL_LIMIT; break;
+ case LDAP_CLIENT_LOOP: ec = GPG_ERR_LDAP_CLIENT_LOOP; break;
+ case LDAP_NO_RESULTS_RETURNED: ec = GPG_ERR_LDAP_NO_RESULTS; break;
+ case LDAP_CONTROL_NOT_FOUND: ec = GPG_ERR_LDAP_CONTROL_NOT_FOUND; break;
+ case LDAP_NOT_SUPPORTED: ec = GPG_ERR_LDAP_NOT_SUPPORTED; break;
+ case LDAP_CONNECT_ERROR: ec = GPG_ERR_LDAP_CONNECT; break;
+ case LDAP_NO_MEMORY: ec = GPG_ERR_LDAP_NO_MEMORY; break;
+ case LDAP_PARAM_ERROR: ec = GPG_ERR_LDAP_PARAM; break;
+ case LDAP_USER_CANCELLED: ec = GPG_ERR_LDAP_USER_CANCELLED; break;
+ case LDAP_FILTER_ERROR: ec = GPG_ERR_LDAP_FILTER; break;
+ case LDAP_AUTH_UNKNOWN: ec = GPG_ERR_LDAP_AUTH_UNKNOWN; break;
+ case LDAP_TIMEOUT: ec = GPG_ERR_LDAP_TIMEOUT; break;
+ case LDAP_DECODING_ERROR: ec = GPG_ERR_LDAP_DECODING; break;
+ case LDAP_ENCODING_ERROR: ec = GPG_ERR_LDAP_ENCODING; break;
+ case LDAP_LOCAL_ERROR: ec = GPG_ERR_LDAP_LOCAL; break;
+ case LDAP_SERVER_DOWN: ec = GPG_ERR_LDAP_SERVER_DOWN; break;
+
+ case LDAP_SUCCESS: ec = GPG_ERR_LDAP_SUCCESS; break;
+
+ case LDAP_OPERATIONS_ERROR: ec = GPG_ERR_LDAP_OPERATIONS; break;
+ case LDAP_PROTOCOL_ERROR: ec = GPG_ERR_LDAP_PROTOCOL; break;
+ case LDAP_TIMELIMIT_EXCEEDED: ec = GPG_ERR_LDAP_TIMELIMIT; break;
+ case LDAP_SIZELIMIT_EXCEEDED: ec = GPG_ERR_LDAP_SIZELIMIT; break;
+ case LDAP_COMPARE_FALSE: ec = GPG_ERR_LDAP_COMPARE_FALSE; break;
+ case LDAP_COMPARE_TRUE: ec = GPG_ERR_LDAP_COMPARE_TRUE; break;
+ case LDAP_AUTH_METHOD_NOT_SUPPORTED: ec=GPG_ERR_LDAP_UNSUPPORTED_AUTH;break;
+ case LDAP_STRONG_AUTH_REQUIRED: ec = GPG_ERR_LDAP_STRONG_AUTH_RQRD; break;
+ case LDAP_PARTIAL_RESULTS: ec = GPG_ERR_LDAP_PARTIAL_RESULTS; break;
+ case LDAP_REFERRAL: ec = GPG_ERR_LDAP_REFERRAL; break;
+
+#ifdef LDAP_ADMINLIMIT_EXCEEDED
+ case LDAP_ADMINLIMIT_EXCEEDED: ec = GPG_ERR_LDAP_ADMINLIMIT; break;
+#endif
+
+#ifdef LDAP_UNAVAILABLE_CRITICAL_EXTENSION
+ case LDAP_UNAVAILABLE_CRITICAL_EXTENSION:
+ ec = GPG_ERR_LDAP_UNAVAIL_CRIT_EXTN; break;
+#endif
+
+ case LDAP_CONFIDENTIALITY_REQUIRED: ec = GPG_ERR_LDAP_CONFIDENT_RQRD; break;
+ case LDAP_SASL_BIND_IN_PROGRESS: ec = GPG_ERR_LDAP_SASL_BIND_INPROG; break;
+ case LDAP_NO_SUCH_ATTRIBUTE: ec = GPG_ERR_LDAP_NO_SUCH_ATTRIBUTE; break;
+ case LDAP_UNDEFINED_TYPE: ec = GPG_ERR_LDAP_UNDEFINED_TYPE; break;
+ case LDAP_INAPPROPRIATE_MATCHING: ec = GPG_ERR_LDAP_BAD_MATCHING; break;
+ case LDAP_CONSTRAINT_VIOLATION: ec = GPG_ERR_LDAP_CONST_VIOLATION; break;
+
+#ifdef LDAP_TYPE_OR_VALUE_EXISTS
+ case LDAP_TYPE_OR_VALUE_EXISTS: ec = GPG_ERR_LDAP_TYPE_VALUE_EXISTS; break;
+#endif
+
+ case LDAP_INVALID_SYNTAX: ec = GPG_ERR_LDAP_INV_SYNTAX; break;
+ case LDAP_NO_SUCH_OBJECT: ec = GPG_ERR_LDAP_NO_SUCH_OBJ; break;
+ case LDAP_ALIAS_PROBLEM: ec = GPG_ERR_LDAP_ALIAS_PROBLEM; break;
+ case LDAP_INVALID_DN_SYNTAX: ec = GPG_ERR_LDAP_INV_DN_SYNTAX; break;
+ case LDAP_IS_LEAF: ec = GPG_ERR_LDAP_IS_LEAF; break;
+ case LDAP_ALIAS_DEREF_PROBLEM: ec = GPG_ERR_LDAP_ALIAS_DEREF; break;
+
+#ifdef LDAP_X_PROXY_AUTHZ_FAILURE
+ case LDAP_X_PROXY_AUTHZ_FAILURE: ec = GPG_ERR_LDAP_X_PROXY_AUTH_FAIL; break;
+#endif
+
+ case LDAP_INAPPROPRIATE_AUTH: ec = GPG_ERR_LDAP_BAD_AUTH; break;
+ case LDAP_INVALID_CREDENTIALS: ec = GPG_ERR_LDAP_INV_CREDENTIALS; break;
+
+#ifdef LDAP_INSUFFICIENT_ACCESS
+ case LDAP_INSUFFICIENT_ACCESS: ec = GPG_ERR_LDAP_INSUFFICIENT_ACC; break;
+#endif
+
+ case LDAP_BUSY: ec = GPG_ERR_LDAP_BUSY; break;
+ case LDAP_UNAVAILABLE: ec = GPG_ERR_LDAP_UNAVAILABLE; break;
+ case LDAP_UNWILLING_TO_PERFORM: ec = GPG_ERR_LDAP_UNWILL_TO_PERFORM; break;
+ case LDAP_LOOP_DETECT: ec = GPG_ERR_LDAP_LOOP_DETECT; break;
+ case LDAP_NAMING_VIOLATION: ec = GPG_ERR_LDAP_NAMING_VIOLATION; break;
+ case LDAP_OBJECT_CLASS_VIOLATION: ec = GPG_ERR_LDAP_OBJ_CLS_VIOLATION; break;
+ case LDAP_NOT_ALLOWED_ON_NONLEAF: ec=GPG_ERR_LDAP_NOT_ALLOW_NONLEAF;break;
+ case LDAP_NOT_ALLOWED_ON_RDN: ec = GPG_ERR_LDAP_NOT_ALLOW_ON_RDN; break;
+ case LDAP_ALREADY_EXISTS: ec = GPG_ERR_LDAP_ALREADY_EXISTS; break;
+ case LDAP_NO_OBJECT_CLASS_MODS: ec = GPG_ERR_LDAP_NO_OBJ_CLASS_MODS; break;
+ case LDAP_RESULTS_TOO_LARGE: ec = GPG_ERR_LDAP_RESULTS_TOO_LARGE; break;
+ case LDAP_AFFECTS_MULTIPLE_DSAS: ec = GPG_ERR_LDAP_AFFECTS_MULT_DSAS; break;
+
+#ifdef LDAP_VLV_ERROR
+ case LDAP_VLV_ERROR: ec = GPG_ERR_LDAP_VLV; break;
+#endif
+
+ case LDAP_OTHER: ec = GPG_ERR_LDAP_OTHER; break;
+
+#ifdef LDAP_CUP_RESOURCES_EXHAUSTED
+ case LDAP_CUP_RESOURCES_EXHAUSTED: ec=GPG_ERR_LDAP_CUP_RESOURCE_LIMIT;break;
+ case LDAP_CUP_SECURITY_VIOLATION: ec=GPG_ERR_LDAP_CUP_SEC_VIOLATION; break;
+ case LDAP_CUP_INVALID_DATA: ec = GPG_ERR_LDAP_CUP_INV_DATA; break;
+ case LDAP_CUP_UNSUPPORTED_SCHEME: ec = GPG_ERR_LDAP_CUP_UNSUP_SCHEME; break;
+ case LDAP_CUP_RELOAD_REQUIRED: ec = GPG_ERR_LDAP_CUP_RELOAD; break;
+#endif
+
+#ifdef LDAP_CANCELLED
+ case LDAP_CANCELLED: ec = GPG_ERR_LDAP_CANCELLED; break;
+#endif
+
+#ifdef LDAP_NO_SUCH_OPERATION
+ case LDAP_NO_SUCH_OPERATION: ec = GPG_ERR_LDAP_NO_SUCH_OPERATION; break;
+#endif
+
+#ifdef LDAP_TOO_LATE
+ case LDAP_TOO_LATE: ec = GPG_ERR_LDAP_TOO_LATE; break;
+#endif
+
+#ifdef LDAP_CANNOT_CANCEL
+ case LDAP_CANNOT_CANCEL: ec = GPG_ERR_LDAP_CANNOT_CANCEL; break;
+#endif
+
+#ifdef LDAP_ASSERTION_FAILED
+ case LDAP_ASSERTION_FAILED: ec = GPG_ERR_LDAP_ASSERTION_FAILED; break;
+#endif
+
+#ifdef LDAP_PROXIED_AUTHORIZATION_DENIED
+ case LDAP_PROXIED_AUTHORIZATION_DENIED:
+ ec = GPG_ERR_LDAP_PROX_AUTH_DENIED; break;
+#endif
+
+ default:
+#if defined(LDAP_E_ERROR) && defined(LDAP_X_ERROR)
+ if (LDAP_E_ERROR (code))
+ ec = GPG_ERR_LDAP_E_GENERAL;
+ else if (LDAP_X_ERROR (code))
+ ec = GPG_ERR_LDAP_X_GENERAL;
+ else
+#endif
+ ec = GPG_ERR_LDAP_GENERAL;
+ break;
+ }
+
+ return ec;
+}
+
+/* Retrieve an LDAP error and return it's GPG equivalent. */
+static int
+ldap_to_gpg_err (LDAP *ld)
+{
+#if defined(HAVE_LDAP_GET_OPTION) && defined(LDAP_OPT_ERROR_NUMBER)
+ int err;
+
+ if (ldap_get_option (ld, LDAP_OPT_ERROR_NUMBER, &err) == 0)
+ return ldap_err_to_gpg_err (err);
+ else
+ return GPG_ERR_GENERAL;
+#elif defined(HAVE_LDAP_LD_ERRNO)
+ return ldap_err_to_gpg_err (ld->ld_errno);
+#else
+ /* We should never get here since the LDAP library should always
+ have either ldap_get_option or ld_errno, but just in case... */
+ return GPG_ERR_INTERNAL;
+#endif
+}
+
+static time_t
+ldap2epochtime (const char *timestr)
+{
+ struct tm pgptime;
+ time_t answer;
+
+ memset (&pgptime, 0, sizeof(pgptime));
+
+ /* YYYYMMDDHHmmssZ */
+
+ sscanf (timestr, "%4d%2d%2d%2d%2d%2d",
+ &pgptime.tm_year,
+ &pgptime.tm_mon,
+ &pgptime.tm_mday,
+ &pgptime.tm_hour,
+ &pgptime.tm_min,
+ &pgptime.tm_sec);
+
+ pgptime.tm_year -= 1900;
+ pgptime.tm_isdst = -1;
+ pgptime.tm_mon--;
+
+ /* mktime() takes the timezone into account, so we use timegm() */
+
+ answer = timegm (&pgptime);
+
+ return answer;
+}
+
+/* Caller must free the result. */
+static char *
+tm2ldaptime (struct tm *tm)
+{
+ struct tm tmp = *tm;
+ char buf[16];
+
+ /* YYYYMMDDHHmmssZ */
+
+ tmp.tm_year += 1900;
+ tmp.tm_mon ++;
+
+ snprintf (buf, sizeof buf, "%04d%02d%02d%02d%02d%02dZ",
+ tmp.tm_year,
+ tmp.tm_mon,
+ tmp.tm_mday,
+ tmp.tm_hour,
+ tmp.tm_min,
+ tmp.tm_sec);
+
+ return xstrdup (buf);
+}
+
+#if 0
+/* Caller must free */
+static char *
+epoch2ldaptime (time_t stamp)
+{
+ struct tm tm;
+ if (gmtime_r (&stamp, &tm))
+ return tm2ldaptime (&tm);
+ else
+ return xstrdup ("INVALID TIME");
+}
+#endif
+
+/* Print a help output for the schemata supported by this module. */
+gpg_error_t
+ks_ldap_help (ctrl_t ctrl, parsed_uri_t uri)
+{
+ const char const data[] =
+ "Handler for LDAP URLs:\n"
+ " ldap://host:port/[BASEDN]???[bindname=BINDNAME,password=PASSWORD]\n"
+ "\n"
+ "Note: basedn, bindname and password need to be percent escaped. In\n"
+ "particular, spaces need to be replaced with %20 and commas with %2c.\n"
+ "bindname will typically be of the form:\n"
+ "\n"
+ " uid=user%2cou=PGP%20Users%2cdc=EXAMPLE%2cdc=ORG\n"
+ "\n"
+ "The ldaps:// and ldapi:// schemes are also supported. If ldaps is used\n"
+ "then the server's certificate will be checked. If it is not valid, any\n"
+ "operation will be aborted.\n"
+ "\n"
+ "Supported methods: search, get, put\n";
+ gpg_error_t err;
+
+ if (strcmp (uri->scheme, "ldap") == 0
+ || strcmp (uri->scheme, "ldaps") == 0
+ || strcmp (uri->scheme, "ldapi") == 0)
+ err = ks_print_help (ctrl, data);
+ else
+ err = 0;
+
+ return err;
+}
+
+/* Convert a keyspec to a filter. Return an error if the keyspec is
+ bad or is not supported. The filter is escaped and returned in
+ *filter. It is the caller's responsibility to free *filter.
+ *filter is only set if this function returns success (i.e., 0). */
+static gpg_error_t
+keyspec_to_ldap_filter (const char *keyspec, char **filter, int only_exact)
+{
+ /* Remove search type indicator and adjust PATTERN accordingly.
+ Note: don't include a preceding 0x when searching by keyid. */
+
+ /* XXX: Should we include disabled / revoke options? */
+ KEYDB_SEARCH_DESC desc;
+ char *f = NULL;
+ char *freeme = NULL;
+
+ gpg_error_t err = classify_user_id (keyspec, &desc, 1);
+ if (err)
+ return err;
+
+ switch (desc.mode)
+ {
+ case KEYDB_SEARCH_MODE_EXACT:
+ f = xasprintf ("(pgpUserID=%s)",
+ (freeme = ldap_escape_filter (desc.u.name)));
+ break;
+
+ case KEYDB_SEARCH_MODE_SUBSTR:
+ if (! only_exact)
+ f = xasprintf ("(pgpUserID=*%s*)",
+ (freeme = ldap_escape_filter (desc.u.name)));
+ break;
+
+ case KEYDB_SEARCH_MODE_MAIL:
+ if (! only_exact)
+ f = xasprintf ("(pgpUserID=*<%s>*)",
+ (freeme = ldap_escape_filter (desc.u.name)));
+ break;
+
+ case KEYDB_SEARCH_MODE_MAILSUB:
+ if (! only_exact)
+ f = xasprintf ("(pgpUserID=*<*%s*>*)",
+ (freeme = ldap_escape_filter (desc.u.name)));
+ break;
+
+ case KEYDB_SEARCH_MODE_MAILEND:
+ if (! only_exact)
+ f = xasprintf ("(pgpUserID=*<*%s>*)",
+ (freeme = ldap_escape_filter (desc.u.name)));
+ break;
+
+ case KEYDB_SEARCH_MODE_SHORT_KID:
+ f = xasprintf ("(pgpKeyID=%08lX)", (ulong) desc.u.kid[1]);
+ break;
+ case KEYDB_SEARCH_MODE_LONG_KID:
+ f = xasprintf ("(pgpCertID=%08lX%08lX)",
+ (ulong) desc.u.kid[0], (ulong) desc.u.kid[1]);
+ break;
+
+ case KEYDB_SEARCH_MODE_FPR16:
+ case KEYDB_SEARCH_MODE_FPR20:
+ case KEYDB_SEARCH_MODE_FPR:
+ case KEYDB_SEARCH_MODE_ISSUER:
+ case KEYDB_SEARCH_MODE_ISSUER_SN:
+ case KEYDB_SEARCH_MODE_SN:
+ case KEYDB_SEARCH_MODE_SUBJECT:
+ case KEYDB_SEARCH_MODE_KEYGRIP:
+ case KEYDB_SEARCH_MODE_WORDS:
+ case KEYDB_SEARCH_MODE_FIRST:
+ case KEYDB_SEARCH_MODE_NEXT:
+ default:
+ break;
+ }
+
+ xfree (freeme);
+
+ if (! f)
+ {
+ log_error ("Unsupported search mode.\n");
+ return gpg_error (GPG_ERR_NOT_SUPPORTED);
+ }
+
+ *filter = f;
+
+ return 0;
+}
+
+
+
+/* Connect to an LDAP server and interrogate it.
+
+ - uri describes the server to connect to and various options
+ including whether to use TLS and the username and password (see
+ ldap_parse_uri for a description of the various fields).
+
+ This function returns:
+
+ - The ldap connection handle in *LDAP_CONNP.
+
+ - The base DN for the PGP key space by querying the
+ pgpBaseKeySpaceDN attribute (This is normally
+ 'ou=PGP Keys,dc=EXAMPLE,dc=ORG').
+
+ - The attribute to lookup to find the pgp key. This is either
+ 'pgpKey' or 'pgpKeyV2'.
+
+ - Whether this is a real ldap server. (It's unclear what this
+ exactly means.)
+
+ The values are returned in the passed variables. If you pass NULL,
+ then the value won't be returned. It is the caller's
+ responsibility to release *LDAP_CONNP with ldap_unbind and xfree
+ *BASEDNP and *PGPKEYATTRP.
+
+ If this function successfully interrogated the server, it returns
+ 0. If there was an LDAP error, it returns the LDAP error code. If
+ an error occured, *basednp, etc., are undefined (and don't need to
+ be freed.)
+
+ If no LDAP error occured, you still need to check that *basednp is
+ valid. If it is NULL, then the server does not appear to be an
+ OpenPGP Keyserver. In this case, you also do not need to xfree
+ *pgpkeyattrp. */
+static int
+my_ldap_connect (parsed_uri_t uri, LDAP **ldap_connp,
+ char **basednp, char **pgpkeyattrp, int *real_ldapp)
+{
+ int err = 0;
+
+ LDAP *ldap_conn = NULL;
+
+ char *user = uri->auth;
+ struct uri_tuple_s *password_param = uri_query_lookup (uri, "password");
+ char *password = password_param ? password_param->value : NULL;
+
+ char *basedn = NULL;
+ /* Whether to look for the pgpKey or pgpKeyv2 attribute. */
+ char *pgpkeyattr = "pgpKey";
+ int real_ldap = 0;
+
+ log_debug ("my_ldap_connect(%s:%d/%s????%s%s%s%s%s)\n",
+ uri->host, uri->port,
+ uri->path ?: "",
+ uri->auth ? "bindname=" : "", uri->auth ?: "",
+ uri->auth && password ? "," : "",
+ password ? "password=" : "", password ?: "");
+
+ /* If the uri specifies a secure connection and we don't support
+ TLS, then fail; don't silently revert to an insecure
+ connection. */
+ if (uri->use_tls)
+ {
+#ifndef HAVE_LDAP_START_TLS_S
+ log_error ("Can't use LDAP to connect to the server: no TLS support.");
+ err = GPG_ERR_LDAP_NOT_SUPPORTED;
+ goto out;
+#endif
+ }
+
+ ldap_conn = ldap_init (uri->host, uri->port);
+ if (! ldap_conn)
+ {
+ err = gpg_err_code_from_syserror ();
+ log_error ("Failed to open connection to LDAP server (%s://%s:%d)\n",
+ uri->scheme, uri->host, uri->port);
+ goto out;
+ }
+
+#ifdef HAVE_LDAP_SET_OPTION
+ {
+ int ver = LDAP_VERSION3;
+
+ err = ldap_set_option (ldap_conn, LDAP_OPT_PROTOCOL_VERSION, &ver);
+ if (err != LDAP_SUCCESS)
+ {
+ log_error ("gpgkeys: unable to go to LDAP 3: %s\n",
+ ldap_err2string (err));
+ goto out;
+ }
+ }
+#endif
+
+ /* XXX: It would be nice to have an option to provide the server's
+ certificate. */
+#if 0
+#if defined(LDAP_OPT_X_TLS_CACERTFILE) && defined(HAVE_LDAP_SET_OPTION)
+ err = ldap_set_option (NULL, LDAP_OPT_X_TLS_CACERTFILE, ca_cert_file);
+ if (err)
+ {
+ log_error ("unable to set ca-cert-file to '%s': %s\n",
+ ca_cert_file, ldap_err2string (err));
+ goto out;
+ }
+#endif /* LDAP_OPT_X_TLS_CACERTFILE && HAVE_LDAP_SET_OPTION */
+#endif
+
+#ifndef HAVE_LDAP_START_TLS_S
+ if (uri->use_tls)
+ {
+ /* XXX: We need an option to determine whether to abort if the
+ certificate is bad or not. Right now we conservatively
+ default to checking the certificate and aborting. */
+ int check_cert = LDAP_OPT_X_TLS_HARD; /* LDAP_OPT_X_TLS_NEVER */
+
+ err = ldap_set_option (ldap_conn,
+ LDAP_OPT_X_TLS_REQUIRE_CERT, &check_cert);
+ if (err)
+ {
+ log_error ("Failed to set TLS option on LDAP connection.\n");
+ goto out;
+ }
+
+ err = ldap_start_tls_s (ldap_conn, NULL, NULL);
+ if (err)
+ {
+ log_error ("Failed to connect to LDAP server with TLS.\n");
+ goto out;
+ }
+ }
+#endif
+
+ /* By default we don't bind as there is usually no need to. */
+ if (uri->auth)
+ {
+ log_debug ("LDAP bind to %s, password %s\n",
+ user, password ? ">not shown<" : ">none<");
+
+ err = ldap_simple_bind_s (ldap_conn, user, password);
+ if (err != LDAP_SUCCESS)
+ {
+ log_error ("Internal LDAP bind error: %s\n",
+ ldap_err2string (err));
+ goto out;
+ }
+ }
+
+ if (uri->path && *uri->path)
+ /* User specified base DN. */
+ {
+ basedn = xstrdup (uri->path);
+
+ /* If the user specifies a base DN, then we know the server is a
+ real LDAP server. */
+ real_ldap = 1;
+ }
+ else
+ {
+ LDAPMessage *res = NULL;
+ /* Look for namingContexts. */
+ char *attr[] = { "namingContexts", NULL };
+
+ err = ldap_search_s (ldap_conn, "", LDAP_SCOPE_BASE,
+ "(objectClass=*)", attr, 0, &res);
+ if (err == LDAP_SUCCESS)
+ {
+ char **context = ldap_get_values (ldap_conn, res, "namingContexts");
+ if (context)
+ /* We found some, so try each namingContext as the search
+ base and look for pgpBaseKeySpaceDN. Because we found
+ this, we know we're talking to a regular-ish LDAP
+ server and not an LDAP keyserver. */
+ {
+ int i;
+ char *attr2[] =
+ { "pgpBaseKeySpaceDN", "pgpVersion", "pgpSoftware", NULL };
+
+ real_ldap = 1;
+
+ for (i = 0; context[i] && ! basedn; i++)
+ {
+ char **vals;
+ LDAPMessage *si_res;
+
+ {
+ char *object = xasprintf ("cn=pgpServerInfo,%s",
+ context[i]);
+ err = ldap_search_s (ldap_conn, object, LDAP_SCOPE_BASE,
+ "(objectClass=*)", attr2, 0, &si_res);
+ xfree (object);
+ }
+
+ if (err == LDAP_SUCCESS)
+ {
+ vals = ldap_get_values (ldap_conn, si_res,
+ "pgpBaseKeySpaceDN");
+ if (vals)
+ {
+ basedn = xtrystrdup (vals[0]);
+ ldap_value_free (vals);
+ }
+
+ vals = ldap_get_values (ldap_conn, si_res,
+ "pgpSoftware");
+ if (vals)
+ {
+ log_debug ("Server: \t%s\n", vals[0]);
+ ldap_value_free (vals);
+ }
+
+ vals = ldap_get_values (ldap_conn, si_res,
+ "pgpVersion");
+ if (vals)
+ {
+ log_debug ("Version:\t%s\n", vals[0]);
+ ldap_value_free (vals);
+ }
+ }
+
+ /* From man ldap_search_s: "res parameter of
+ ldap_search_ext_s() and ldap_search_s() should be
+ freed with ldap_msgfree() regardless of return
+ value of these functions. */
+ ldap_msgfree (si_res);
+ }
+
+ ldap_value_free (context);
+ }
+ }
+ else
+ {
+ /* We don't have an answer yet, which means the server might
+ be an LDAP keyserver. */
+ char **vals;
+ LDAPMessage *si_res = NULL;
+
+ char *attr2[] = { "pgpBaseKeySpaceDN", "version", "software", NULL };
+
+ err = ldap_search_s (ldap_conn, "cn=pgpServerInfo", LDAP_SCOPE_BASE,
+ "(objectClass=*)", attr2, 0, &si_res);
+ if (err == LDAP_SUCCESS)
+ {
+ /* For the LDAP keyserver, this is always
+ "OU=ACTIVE,O=PGP KEYSPACE,C=US", but it might not be
+ in the future. */
+
+ vals = ldap_get_values (ldap_conn, si_res, "baseKeySpaceDN");
+ if (vals)
+ {
+ basedn = xtrystrdup (vals[0]);
+ ldap_value_free (vals);
+ }
+
+ vals = ldap_get_values (ldap_conn, si_res, "software");
+ if (vals)
+ {
+ log_debug ("ldap: Server: \t%s\n", vals[0]);
+ ldap_value_free (vals);
+ }
+
+ vals = ldap_get_values (ldap_conn, si_res, "version");
+ if (vals)
+ {
+ log_debug ("ldap: Version:\t%s\n", vals[0]);
+
+ /* If the version is high enough, use the new
+ pgpKeyV2 attribute. This design is iffy at best,
+ but it matches how PGP does it. I figure the NAI
+ folks assumed that there would never be an LDAP
+ keyserver vendor with a different numbering
+ scheme. */
+ if (atoi (vals[0]) > 1)
+ pgpkeyattr = "pgpKeyV2";
+
+ ldap_value_free (vals);
+ }
+ }
+
+ ldap_msgfree (si_res);
+ }
+
+ /* From man ldap_search_s: "res parameter of ldap_search_ext_s()
+ and ldap_search_s() should be freed with ldap_msgfree()
+ regardless of return value of these functions. */
+ ldap_msgfree (res);
+ }
+
+ out:
+ if (! err)
+ {
+ log_debug ("ldap_conn: %p\n", ldap_conn);
+ log_debug ("real_ldap: %d\n", real_ldap);
+ log_debug ("basedn: %s\n", basedn);
+ log_debug ("pgpkeyattr: %s\n", pgpkeyattr);
+ }
+
+ if (! err && real_ldapp)
+ *real_ldapp = real_ldap;
+
+ if (err)
+ xfree (basedn);
+ else
+ {
+ if (pgpkeyattrp)
+ {
+ if (basedn)
+ *pgpkeyattrp = xstrdup (pgpkeyattr);
+ else
+ *pgpkeyattrp = NULL;
+ }
+
+ if (basednp)
+ *basednp = basedn;
+ else
+ xfree (basedn);
+ }
+
+ if (err)
+ {
+ if (ldap_conn)
+ ldap_unbind (ldap_conn);
+ }
+ else
+ *ldap_connp = ldap_conn;
+
+ return err;
+}
+
+/* Extract keys from an LDAP reply and write them out to the output
+ stream OUTPUT in a format GnuPG can import (either the OpenPGP
+ binary format or armored format). */
+static void
+extract_keys (estream_t output,
+ LDAP *ldap_conn, const char *certid, LDAPMessage *message)
+{
+ char **vals;
+
+ es_fprintf (output, "INFO %s BEGIN\n", certid);
+ es_fprintf (output, "pub:%s:", certid);
+
+ /* Note: ldap_get_values returns a NULL terminates array of
+ strings. */
+ vals = ldap_get_values (ldap_conn, message, "pgpkeytype");
+ if (vals && vals[0])
+ {
+ if (strcmp (vals[0], "RSA") == 0)
+ es_fprintf (output, "1");
+ else if (strcmp (vals[0],"DSS/DH") == 0)
+ es_fprintf (output, "17");
+ ldap_value_free (vals);
+ }
+
+ es_fprintf (output, ":");
+
+ vals = ldap_get_values (ldap_conn, message, "pgpkeysize");
+ if (vals && vals[0])
+ {
+ int v = atoi (vals[0]);
+ if (v > 0)
+ es_fprintf (output, "%d", v);
+ ldap_value_free (vals);
+ }
+
+ es_fprintf (output, ":");
+
+ vals = ldap_get_values (ldap_conn, message, "pgpkeycreatetime");
+ if (vals && vals[0])
+ {
+ if (strlen (vals[0]) == 15)
+ es_fprintf (output, "%u", (unsigned int) ldap2epochtime (vals[0]));
+ ldap_value_free (vals);
+ }
+
+ es_fprintf (output, ":");
+
+ vals = ldap_get_values (ldap_conn, message, "pgpkeyexpiretime");
+ if (vals && vals[0])
+ {
+ if (strlen (vals[0]) == 15)
+ es_fprintf (output, "%u", (unsigned int) ldap2epochtime (vals[0]));
+ ldap_value_free (vals);
+ }
+
+ es_fprintf (output, ":");
+
+ vals = ldap_get_values (ldap_conn, message, "pgprevoked");
+ if (vals && vals[0])
+ {
+ if (atoi (vals[0]) == 1)
+ es_fprintf (output, "r");
+ ldap_value_free (vals);
+ }
+
+ es_fprintf (output, "\n");
+
+ vals = ldap_get_values (ldap_conn, message, "pgpuserid");
+ if (vals && vals[0])
+ {
+ int i;
+ for (i = 0; vals[i]; i++)
+ es_fprintf (output, "uid:%s\n", vals[i]);
+ ldap_value_free (vals);
+ }
+
+ es_fprintf (output, "INFO %s END\n", certid);
+}
+
+/* Get the key described key the KEYSPEC string from the keyserver
+ identified by URI. On success R_FP has an open stream to read the
+ data. */
+gpg_error_t
+ks_ldap_get (ctrl_t ctrl, parsed_uri_t uri, const char *keyspec,
+ estream_t *r_fp)
+{
+ gpg_error_t err = 0;
+ int ldap_err;
+
+ char *filter = NULL;
+
+ LDAP *ldap_conn = NULL;
+
+ char *basedn = NULL;
+ char *pgpkeyattr = NULL;
+
+ estream_t fp = NULL;
+
+ LDAPMessage *message = NULL;
+
+ (void) ctrl;
+
+ /* Before connecting to the server, make sure we have a sane
+ keyspec. If not, there is no need to establish a network
+ connection. */
+ err = keyspec_to_ldap_filter (keyspec, &filter, 1);
+ if (err)
+ return (err);
+
+ /* Make sure we are talking to an OpenPGP LDAP server. */
+ ldap_err = my_ldap_connect (uri, &ldap_conn, &basedn, &pgpkeyattr, NULL);
+ if (ldap_err || !basedn)
+ {
+ if (ldap_err)
+ err = ldap_err_to_gpg_err (ldap_err);
+ else
+ err = GPG_ERR_GENERAL;
+ goto out;
+ }
+
+ {
+ /* The ordering is significant. Specifically, "pgpcertid" needs
+ to be the second item in the list, since everything after it
+ may be discarded we aren't in verbose mode. */
+ char *attrs[] =
+ {
+ pgpkeyattr,
+ "pgpcertid", "pgpuserid", "pgpkeyid", "pgprevoked", "pgpdisabled",
+ "pgpkeycreatetime", "modifytimestamp", "pgpkeysize", "pgpkeytype",
+ NULL
+ };
+ /* 1 if we want just attribute types; 0 if we want both attribute
+ types and values. */
+ int attrsonly = 0;
+
+ int count;
+
+ ldap_err = ldap_search_s (ldap_conn, basedn, LDAP_SCOPE_SUBTREE,
+ filter, attrs, attrsonly, &message);
+ if (ldap_err)
+ {
+ err = ldap_err_to_gpg_err (ldap_err);
+
+ log_error ("gpgkeys: LDAP search error: %s\n",
+ ldap_err2string (ldap_err));
+ goto out;
+ }
+
+ count = ldap_count_entries (ldap_conn, message);
+ if (count < 1)
+ {
+ log_error ("gpgkeys: key %s not found on keyserver\n", keyspec);
+
+ if (count == -1)
+ err = ldap_to_gpg_err (ldap_conn);
+ else
+ err = gpg_error (GPG_ERR_NO_DATA);
+
+ goto out;
+ }
+
+ {
+ /* There may be more than one unique result for a given keyID,
+ so we should fetch them all (test this by fetching short key
+ id 0xDEADBEEF). */
+
+ /* The set of entries that we've seen. */
+ strlist_t seen = NULL;
+ LDAPMessage *each;
+
+ for (each = ldap_first_entry (ldap_conn, message);
+ each;
+ each = ldap_next_entry (ldap_conn, each))
+ {
+ char **vals;
+ char **certid;
+
+ /* Use the long keyid to remove duplicates. The LDAP
+ server returns the same keyid more than once if there
+ are multiple user IDs on the key. Note that this does
+ NOT mean that a keyid that exists multiple times on the
+ keyserver will not be fetched. It means that each KEY,
+ no matter how many user IDs share its keyid, will be
+ fetched only once. If a keyid that belongs to more
+ than one key is fetched, the server quite properly
+ responds with all matching keys. -ds */
+
+ certid = ldap_get_values (ldap_conn, each, "pgpcertid");
+ if (certid && certid[0])
+ {
+ if (! strlist_find (seen, certid[0]))
+ {
+ /* It's not a duplicate, add it */
+
+ add_to_strlist (&seen, certid[0]);
+
+ if (! fp)
+ fp = es_fopenmem(0, "rw");
+
+ extract_keys (fp, ldap_conn, certid[0], each);
+
+ vals = ldap_get_values (ldap_conn, each, pgpkeyattr);
+ if (! vals)
+ {
+ err = ldap_to_gpg_err (ldap_conn);
+ log_error("gpgkeys: unable to retrieve key %s "
+ "from keyserver\n", certid[0]);
+ goto out;
+ }
+ else
+ {
+ /* We should strip the new lines. */
+ es_fprintf (fp, "KEY 0x%s BEGIN\n", certid[0]);
+ es_fputs (vals[0], fp);
+ es_fprintf (fp, "\nKEY 0x%s END\n", certid[0]);
+
+ ldap_value_free (vals);
+ }
+ }
+ }
+
+ ldap_value_free (certid);
+ }
+
+ free_strlist (seen);
+
+ if (! fp)
+ err = gpg_error (GPG_ERR_NO_DATA);
+ }
+ }
+
+ out:
+ if (message)
+ ldap_msgfree (message);
+
+ if (err)
+ {
+ if (fp)
+ es_fclose (fp);
+ }
+ else
+ {
+ if (fp)
+ es_fseek (fp, 0, SEEK_SET);
+
+ *r_fp = fp;
+ }
+
+ xfree (pgpkeyattr);
+ xfree (basedn);
+
+ if (ldap_conn)
+ ldap_unbind (ldap_conn);
+
+ xfree (filter);
+
+ return err;
+}
+
+/* Search the keyserver identified by URI for keys matching PATTERN.
+ On success R_FP has an open stream to read the data. */
+gpg_error_t
+ks_ldap_search (ctrl_t ctrl, parsed_uri_t uri, const char *pattern,
+ estream_t *r_fp)
+{
+ gpg_error_t err;
+ int ldap_err;
+
+ char *filter = NULL;
+
+ LDAP *ldap_conn = NULL;
+
+ char *basedn = NULL;
+
+ estream_t fp = NULL;
+
+ (void) ctrl;
+
+ /* Before connecting to the server, make sure we have a sane
+ keyspec. If not, there is no need to establish a network
+ connection. */
+ err = keyspec_to_ldap_filter (pattern, &filter, 0);
+ if (err)
+ {
+ log_error ("Bad search pattern: '%s'\n", pattern);
+ return (err);
+ }
+
+ /* Make sure we are talking to an OpenPGP LDAP server. */
+ ldap_err = my_ldap_connect (uri, &ldap_conn, &basedn, NULL, NULL);
+ if (ldap_err || !basedn)
+ {
+ if (ldap_err)
+ err = ldap_err_to_gpg_err (ldap_err);
+ else
+ err = GPG_ERR_GENERAL;
+ goto out;
+ }
+
+ /* Even if we have no results, we want to return a stream. */
+ fp = es_fopenmem(0, "rw");
+ if (!fp)
+ {
+ err = gpg_error_from_syserror ();
+ goto out;
+ }
+
+ {
+ char **vals;
+ LDAPMessage *res, *each;
+ int count = 0;
+ strlist_t dupelist = NULL;
+
+ /* The maximum size of the search, including the optional stuff
+ and the trailing \0 */
+ char *attrs[] =
+ {
+ "pgpcertid", "pgpuserid", "pgprevoked", "pgpdisabled",
+ "pgpkeycreatetime", "pgpkeyexpiretime", "modifytimestamp",
+ "pgpkeysize", "pgpkeytype", NULL
+ };
+
+ log_debug ("SEARCH '%s' => '%s' BEGIN\n", pattern, filter);
+
+ ldap_err = ldap_search_s (ldap_conn, basedn,
+ LDAP_SCOPE_SUBTREE, filter, attrs, 0, &res);
+
+ xfree (filter);
+ filter = NULL;
+
+ if (ldap_err != LDAP_SUCCESS && ldap_err != LDAP_SIZELIMIT_EXCEEDED)
+ {
+ err = ldap_err_to_gpg_err (ldap_err);
+
+ log_error ("SEARCH %s FAILED %d\n", pattern, err);
+ log_error ("gpgkeys: LDAP search error: %s\n",
+ ldap_err2string (err));
+ goto out;
+ }
+
+ /* The LDAP server doesn't return a real count of unique keys, so we
+ can't use ldap_count_entries here. */
+ for (each = ldap_first_entry (ldap_conn, res);
+ each;
+ each = ldap_next_entry (ldap_conn, each))
+ {
+ char **certid = ldap_get_values (ldap_conn, each, "pgpcertid");
+ if (certid && certid[0] && ! strlist_find (dupelist, certid[0]))
+ {
+ add_to_strlist (&dupelist, certid[0]);
+ count++;
+ }
+ }
+
+ if (ldap_err == LDAP_SIZELIMIT_EXCEEDED)
+ {
+ if (count == 1)
+ log_error ("gpgkeys: search results exceeded server limit."
+ " First 1 result shown.\n");
+ else
+ log_error ("gpgkeys: search results exceeded server limit."
+ " First %d results shown.\n", count);
+ }
+
+ free_strlist (dupelist);
+ dupelist = NULL;
+
+ if (count < 1)
+ es_fputs ("info:1:0\n", fp);
+ else
+ {
+ es_fprintf (fp, "info:1:%d\n", count);
+
+ for (each = ldap_first_entry (ldap_conn, res);
+ each;
+ each = ldap_next_entry (ldap_conn, each))
+ {
+ char **certid;
+ LDAPMessage *uids;
+
+ certid = ldap_get_values (ldap_conn, each, "pgpcertid");
+ if (! certid || ! certid[0])
+ continue;
+
+ /* Have we seen this certid before? */
+ if (! strlist_find (dupelist, certid[0]))
+ {
+ add_to_strlist (&dupelist, certid[0]);
+
+ es_fprintf (fp, "pub:%s:",certid[0]);
+
+ vals = ldap_get_values (ldap_conn, each, "pgpkeytype");
+ if (vals)
+ {
+ /* The LDAP server doesn't exactly handle this
+ well. */
+ if (strcasecmp (vals[0], "RSA") == 0)
+ es_fputs ("1", fp);
+ else if (strcasecmp (vals[0], "DSS/DH") == 0)
+ es_fputs ("17", fp);
+ ldap_value_free (vals);
+ }
+
+ es_fputc (':', fp);
+
+ vals = ldap_get_values (ldap_conn, each, "pgpkeysize");
+ if (vals)
+ {
+ /* Not sure why, but some keys are listed with a
+ key size of 0. Treat that like an unknown. */
+ if (atoi (vals[0]) > 0)
+ es_fprintf (fp, "%d", atoi (vals[0]));
+ ldap_value_free (vals);
+ }
+
+ es_fputc (':', fp);
+
+ /* YYYYMMDDHHmmssZ */
+
+ vals = ldap_get_values (ldap_conn, each, "pgpkeycreatetime");
+ if(vals && strlen (vals[0]) == 15)
+ {
+ es_fprintf (fp, "%u",
+ (unsigned int) ldap2epochtime(vals[0]));
+ ldap_value_free (vals);
+ }
+
+ es_fputc (':', fp);
+
+ vals = ldap_get_values (ldap_conn, each, "pgpkeyexpiretime");
+ if (vals && strlen (vals[0]) == 15)
+ {
+ es_fprintf (fp, "%u",
+ (unsigned int) ldap2epochtime (vals[0]));
+ ldap_value_free (vals);
+ }
+
+ es_fputc (':', fp);
+
+ vals = ldap_get_values (ldap_conn, each, "pgprevoked");
+ if (vals)
+ {
+ if (atoi (vals[0]) == 1)
+ es_fprintf (fp, "r");
+ ldap_value_free (vals);
+ }
+
+ vals = ldap_get_values (ldap_conn, each, "pgpdisabled");
+ if (vals)
+ {
+ if (atoi (vals[0]) ==1)
+ es_fprintf (fp, "d");
+ ldap_value_free (vals);
+ }
+
+#if 0
+ /* This is not yet specified in the keyserver
+ protocol, but may be someday. */
+ es_fputc (':', fp);
+
+ vals = ldap_get_values (ldap_conn, each, "modifytimestamp");
+ if(vals && strlen (vals[0]) == 15)
+ {
+ es_fprintf (fp, "%u",
+ (unsigned int) ldap2epochtime (vals[0]));
+ ldap_value_free (vals);
+ }
+#endif
+
+ es_fprintf (fp, "\n");
+
+ /* Now print all the uids that have this certid */
+ for (uids = ldap_first_entry (ldap_conn, res);
+ uids;
+ uids = ldap_next_entry (ldap_conn, uids))
+ {
+ vals = ldap_get_values (ldap_conn, uids, "pgpcertid");
+ if (! vals)
+ continue;
+
+ if (strcasecmp (certid[0], vals[0]) == 0)
+ {
+ char **uidvals;
+
+ es_fprintf (fp, "uid:");
+
+ uidvals = ldap_get_values (ldap_conn,
+ uids, "pgpuserid");
+ if (uidvals)
+ {
+ /* Need to escape any colons */
+ char *quoted = percent_escape (uidvals[0], NULL);
+ es_fputs (quoted, fp);
+ xfree (quoted);
+ ldap_value_free (uidvals);
+ }
+
+ es_fprintf (fp, "\n");
+ }
+
+ ldap_value_free(vals);
+ }
+ }
+
+ ldap_value_free (certid);
+ }
+ }
+
+ ldap_msgfree (res);
+ free_strlist (dupelist);
+ }
+
+ log_debug ("SEARCH %s END\n", pattern);
+
+ out:
+ if (err)
+ {
+ if (fp)
+ es_fclose (fp);
+ }
+ else
+ {
+ /* Return the read stream. */
+ if (fp)
+ es_fseek (fp, 0, SEEK_SET);
+
+ *r_fp = fp;
+ }
+
+ xfree (basedn);
+
+ if (ldap_conn)
+ ldap_unbind (ldap_conn);
+
+ xfree (filter);
+
+ return err;
+}
+
+
+
+/* A modlist describes a set of changes to an LDAP entry. (An entry
+ consists of 1 or more attributes. Attributes are <name, value>
+ pairs. Note: an attribute may be multi-valued in which case
+ multiple values are associated with a single name.)
+
+ A modlist is a NULL terminated array of struct LDAPMod's.
+
+ Thus, if we have:
+
+ LDAPMod **modlist;
+
+ Then:
+
+ modlist[i]
+
+ Is the ith modification.
+
+ Each LDAPMod describes a change to a single attribute. Further,
+ there is one modification for each attribute that we want to
+ change. The attribute's new value is stored in LDAPMod.mod_values.
+ If the attribute is multi-valued, we still only use a single
+ LDAPMod structure: mod_values is a NULL-terminated array of
+ strings. To delete an attribute from an entry, we set mod_values
+ to NULL.
+
+ Thus, if:
+
+ modlist[i]->mod_values == NULL
+
+ then we remove the attribute.
+
+ (Using LDAP_MOD_DELETE doesn't work here as we don't know if the
+ attribute in question exists or not.)
+
+ Note: this function does NOT copy or free ATTR. It does copy
+ VALUE. */
+static void
+modlist_add (LDAPMod ***modlistp, char *attr, const char *value)
+{
+ LDAPMod **modlist = *modlistp;
+
+ LDAPMod **m;
+ int nummods = 0;
+
+ /* Search modlist for the attribute we're playing with. If modlist
+ is NULL, then the list is empty. Recall: modlist is a NULL
+ terminated array. */
+ for (m = modlist; m && *m; m++, nummods ++)
+ {
+ /* The attribute is already on the list. */
+ char **ptr;
+ int numvalues = 0;
+
+ if (strcasecmp ((*m)->mod_type, attr) != 0)
+ continue;
+
+ /* We have this attribute already, so when the REPLACE happens,
+ the server attributes will be replaced anyway. */
+ if (! value)
+ return;
+
+ /* Attributes can be multi-valued. See if the value is already
+ present. mod_values is a NULL terminated array of pointers.
+ Note: mod_values can be NULL. */
+ for (ptr = (*m)->mod_values; ptr && *ptr; ptr++)
+ {
+ if (strcmp (*ptr, value) == 0)
+ /* Duplicate value, we're done. */
+ return;
+ numvalues ++;
+ }
+
+ /* Append the value. */
+ ptr = xrealloc ((*m)->mod_values, sizeof (char *) * (numvalues + 2));
+
+ (*m)->mod_values = ptr;
+ ptr[numvalues] = xstrdup (value);
+
+ ptr[numvalues + 1] = NULL;
+
+ return;
+ }
+
+ /* We didn't find the attr, so make one and add it to the end */
+
+ /* Like attribute values, the list of attributes is NULL terminated
+ array of pointers. */
+ modlist = xrealloc (modlist, sizeof (LDAPMod *) * (nummods + 2));
+
+ *modlistp = modlist;
+ modlist[nummods] = xmalloc (sizeof (LDAPMod));
+
+ modlist[nummods]->mod_op = LDAP_MOD_REPLACE;
+ modlist[nummods]->mod_type = attr;
+ if (value)
+ {
+ modlist[nummods]->mod_values = xmalloc (sizeof(char *) * 2);
+
+ modlist[nummods]->mod_values[0] = xstrdup (value);
+ modlist[nummods]->mod_values[1] = NULL;
+ }
+ else
+ modlist[nummods]->mod_values = NULL;
+
+ modlist[nummods + 1] = NULL;
+
+ return;
+}
+
+/* Look up the value of an attribute in the specified modlist. If the
+ attribute is not on the mod list, returns NULL. The result is a
+ NULL-terminated array of strings. Don't change it. */
+static char **
+modlist_lookup (LDAPMod **modlist, const char *attr)
+{
+ LDAPMod **m;
+ for (m = modlist; m && *m; m++)
+ {
+ if (strcasecmp ((*m)->mod_type, attr) != 0)
+ continue;
+
+ return (*m)->mod_values;
+ }
+
+ return NULL;
+}
+
+/* Dump a modlist to a file. This is useful for debugging. */
+static estream_t modlist_dump (LDAPMod **modlist, estream_t output)
+ GNUPG_GCC_A_USED;
+
+static estream_t
+modlist_dump (LDAPMod **modlist, estream_t output)
+{
+ LDAPMod **m;
+
+ int opened = 0;
+
+ if (! output)
+ {
+ output = es_fopenmem (0, "rw");
+ if (!output)
+ return NULL;
+ opened = 1;
+ }
+
+ for (m = modlist; m && *m; m++)
+ {
+ es_fprintf (output, " %s:", (*m)->mod_type);
+
+ if (! (*m)->mod_values)
+ es_fprintf(output, " delete.\n");
+ else
+ {
+ char **ptr;
+ int i;
+
+ int multi = 0;
+ if ((*m)->mod_values[0] && (*m)->mod_values[1])
+ /* Have at least 2. */
+ multi = 1;
+
+ if (multi)
+ es_fprintf (output, "\n");
+
+ for ((ptr = (*m)->mod_values), (i = 1); ptr && *ptr; ptr++, i ++)
+ {
+ /* Assuming terminals are about 80 characters wide,
+ display at most most about 10 lines of debugging
+ output. If we do trim the buffer, append '...' to
+ the end. */
+ const int max_len = 10 * 70;
+ size_t value_len = strlen (*ptr);
+ int elide = value_len > max_len;
+
+ if (multi)
+ es_fprintf (output, " %d. ", i);
+ es_fprintf (output, "`%.*s", max_len, *ptr);
+ if (elide)
+ es_fprintf (output, "...' (%zd bytes elided)",
+ value_len - max_len);
+ else
+ es_fprintf (output, "'");
+ es_fprintf (output, "\n");
+ }
+ }
+ }
+
+ if (opened)
+ es_fseek (output, 0, SEEK_SET);
+
+ return output;
+}
+
+/* Free all of the memory allocated by the mod list. This assumes
+ that the attribute names don't have to be freed, but the attributes
+ values do. (Which is what modlist_add does.) */
+static void
+modlist_free (LDAPMod **modlist)
+{
+ LDAPMod **ml;
+
+ if (! modlist)
+ return;
+
+ /* Unwind and free the whole modlist structure */
+
+ /* The modlist is a NULL terminated array of pointers. */
+ for (ml = modlist; *ml; ml++)
+ {
+ LDAPMod *mod = *ml;
+ char **ptr;
+
+ /* The list of values is a NULL termianted array of pointers.
+ If the list is NULL, there are no values. */
+
+ if (mod->mod_values)
+ {
+ for (ptr = mod->mod_values; *ptr; ptr++)
+ xfree (*ptr);
+
+ xfree (mod->mod_values);
+ }
+
+ xfree (mod);
+ }
+ xfree (modlist);
+}
+
+/* Append two onto the end of one. Two is not freed, but its pointers
+ are now part of one. Make sure you don't free them both!
+
+ As long as you don't add anything to ONE, TWO is still valid.
+ After that all bets are off. */
+static void
+modlists_join (LDAPMod ***one, LDAPMod **two)
+{
+ int i, one_count = 0, two_count = 0;
+ LDAPMod **grow;
+
+ if (!*two)
+ /* two is empty. Nothing to do. */
+ return;
+
+ if (!*one)
+ /* one is empty. Just set it equal to *two. */
+ {
+ *one = two;
+ return;
+ }
+
+ for (grow = *one; *grow; grow++)
+ one_count ++;
+
+ for (grow = two; *grow; grow++)
+ two_count ++;
+
+ grow = xrealloc (*one, sizeof(LDAPMod *) * (one_count + two_count + 1));
+
+ for (i = 0; i < two_count; i++)
+ grow[one_count + i] = two[i];
+
+ grow[one_count + i] = NULL;
+
+ *one = grow;
+}
+
+/* Given a string, unescape C escapes. In particular, \xXX. This
+ modifies the string in place. */
+static void
+uncescape (char *str)
+{
+ size_t r = 0;
+ size_t w = 0;
+
+ char *first = strchr (str, '\\');
+ if (! first)
+ /* No backslashes => no escaping. We're done. */
+ return;
+
+ /* Start at the first '\\'. */
+ r = w = (uintptr_t) first - (uintptr_t) str;
+
+ while (str[r])
+ {
+ /* XXX: What to do about bad escapes?
+ XXX: hextobyte already checks the string thus the hexdigitp
+ could be removed. */
+ if (str[r] == '\\' && str[r + 1] == 'x'
+ && str[r+2] && str[r+3]
+ && hexdigitp (str + r + 2)
+ && hexdigitp (str + r + 3))
+ {
+ int x = hextobyte (&str[r + 2]);
+ assert (0 <= x && x <= 0xff);
+
+ str[w] = x;
+
+ /* We consumed 4 characters and wrote 1. */
+ r += 4;
+ w ++;
+ }
+ else
+ str[w ++] = str[r ++];
+ }
+
+ str[w] = '\0';
+}
+
+/* Given one line from an info block (`gpg --list-{keys,sigs}
+ --with-colons KEYID'), pull it apart and fill in the modlist with
+ the relevant (for the LDAP schema) attributes. */
+static void
+extract_attributes (LDAPMod ***modlist, char *line)
+{
+ int field_count;
+ char **fields;
+
+ char *keyid;
+
+ int is_pub, is_sub, is_uid, is_sig;
+
+ /* Remove trailing whitespace */
+ trim_trailing_spaces (line);
+
+ fields = strsplit (line, ':', '\0', &field_count);
+ if (field_count == 1)
+ /* We only have a single field. There is definately nothing to
+ do. */
+ goto out;
+
+ if (field_count < 7)
+ goto out;
+
+ is_pub = strcasecmp ("pub", fields[0]) == 0;
+ is_sub = strcasecmp ("sub", fields[0]) == 0;
+ is_uid = strcasecmp ("uid", fields[0]) == 0;
+ is_sig = strcasecmp ("sig", fields[0]) == 0;
+
+ if (!is_pub && !is_sub && !is_uid && !is_sig)
+ /* Not a relevant line. */
+ goto out;
+
+ keyid = fields[4];
+
+ if (is_uid && strlen (keyid) == 0)
+ /* The uid record type can have an empty keyid. */
+ ;
+ else if (strlen (keyid) == 16
+ && strspn (keyid, "0123456789aAbBcCdDeEfF") == 16)
+ /* Otherwise, we expect exactly 16 hex characters. */
+ ;
+ else
+ {
+ log_error ("malformed record!\n");
+ goto out;
+ }
+
+ if (is_pub)
+ {
+ int disabled = 0;
+ int revoked = 0;
+ char *flags;
+ for (flags = fields[1]; *flags; flags ++)
+ switch (*flags)
+ {
+ case 'r':
+ case 'R':
+ revoked = 1;
+ break;
+
+ case 'd':
+ case 'D':
+ disabled = 1;
+ break;
+ }
+
+ /* Note: we always create the pgpDisabled and pgpRevoked
+ attributes, regardless of whether the key is disabled/revoked
+ or not. This is because a very common search is like
+ "(&(pgpUserID=*isabella*)(pgpDisabled=0))" */
+
+ if (is_pub)
+ {
+ modlist_add (modlist,"pgpDisabled", disabled ? "1" : "0");
+ modlist_add (modlist,"pgpRevoked", revoked ? "1" : "0");
+ }
+ }
+
+ if (is_pub || is_sub)
+ {
+ char *size = fields[2];
+ int val = atoi (size);
+ size = NULL;
+
+ if (val > 0)
+ {
+ /* We zero pad this on the left to make PGP happy. */
+ char padded[6];
+ if (val < 99999 && val > 0)
+ {
+ snprintf (padded, sizeof padded, "%05u", val);
+ size = padded;
+ }
+ }
+
+ if (size)
+ {
+ if (is_pub || is_sub)
+ modlist_add (modlist, "pgpKeySize", size);
+ }
+ }
+
+ if (is_pub)
+ {
+ char *algo = fields[3];
+ int val = atoi (algo);
+ switch (val)
+ {
+ case 1:
+ algo = "RSA";
+ break;
+
+ case 17:
+ algo = "DSS/DH";
+ break;
+
+ default:
+ algo = NULL;
+ break;
+ }
+
+ if (algo)
+ {
+ if (is_pub)
+ modlist_add (modlist, "pgpKeyType", algo);
+ }
+ }
+
+ if (is_pub || is_sub || is_sig)
+ {
+ if (is_pub)
+ {
+ modlist_add (modlist, "pgpCertID", keyid);
+ modlist_add (modlist, "pgpKeyID", &keyid[8]);
+ }
+
+ if (is_sub)
+ modlist_add (modlist, "pgpSubKeyID", keyid);
+
+ if (is_sig)
+ modlist_add (modlist, "pgpSignerID", keyid);
+ }
+
+ if (is_pub)
+ {
+ char *create_time = fields[5];
+
+ if (strlen (create_time) == 0)
+ create_time = NULL;
+ else
+ {
+ char *create_time_orig = create_time;
+ struct tm tm;
+ time_t t;
+ char *end;
+
+ memset (&tm, 0, sizeof (tm));
+
+ /* parse_timestamp handles both seconds fromt he epoch and
+ ISO 8601 format. We also need to handle YYYY-MM-DD
+ format (as generated by gpg1 --with-colons --list-key).
+ Check that first and then if it fails, then try
+ parse_timestamp. */
+
+ if (!isodate_human_to_tm (create_time, &tm))
+ create_time = tm2ldaptime (&tm);
+ else if ((t = parse_timestamp (create_time, &end)) != (time_t) -1
+ && *end == '\0')
+ {
+
+ if (!gnupg_gmtime (&t, &tm))
+ create_time = NULL;
+ else
+ create_time = tm2ldaptime (&tm);
+ }
+ else
+ create_time = NULL;
+
+ if (! create_time)
+ /* Failed to parse string. */
+ log_error ("Failed to parse creation time ('%s')",
+ create_time_orig);
+ }
+
+ if (create_time)
+ {
+ modlist_add (modlist, "pgpKeyCreateTime", create_time);
+ xfree (create_time);
+ }
+ }
+
+ if (is_pub)
+ {
+ char *expire_time = fields[6];
+
+ if (strlen (expire_time) == 0)
+ expire_time = NULL;
+ else
+ {
+ char *expire_time_orig = expire_time;
+ struct tm tm;
+ time_t t;
+ char *end;
+
+ memset (&tm, 0, sizeof (tm));
+
+ /* parse_timestamp handles both seconds fromt he epoch and
+ ISO 8601 format. We also need to handle YYYY-MM-DD
+ format (as generated by gpg1 --with-colons --list-key).
+ Check that first and then if it fails, then try
+ parse_timestamp. */
+
+ if (!isodate_human_to_tm (expire_time, &tm))
+ expire_time = tm2ldaptime (&tm);
+ else if ((t = parse_timestamp (expire_time, &end)) != (time_t) -1
+ && *end == '\0')
+ {
+ if (!gnupg_gmtime (&t, &tm))
+ expire_time = NULL;
+ else
+ expire_time = tm2ldaptime (&tm);
+ }
+ else
+ expire_time = NULL;
+
+ if (! expire_time)
+ /* Failed to parse string. */
+ log_error ("Failed to parse creation time ('%s')",
+ expire_time_orig);
+ }
+
+ if (expire_time)
+ {
+ modlist_add (modlist, "pgpKeyExpireTime", expire_time);
+ xfree (expire_time);
+ }
+ }
+
+ if ((is_uid || is_pub) && field_count >= 10)
+ {
+ char *uid = fields[9];
+
+ if (is_pub && strlen (uid) == 0)
+ /* When using gpg --list-keys, the uid is included. When
+ passed via gpg, it is not. It is important to process it
+ when it is present, because gpg 1 won't print a UID record
+ if there is only one key. */
+ ;
+ else
+ {
+ uncescape (uid);
+ modlist_add (modlist, "pgpUserID", uid);
+ }
+ }
+
+ out:
+ free (fields);
+}
+
+/* Send the key in {KEY,KEYLEN} with the metadata {INFO,INFOLEN} to
+ the keyserver identified by URI. See server.c:cmd_ks_put for the
+ format of the data and metadata. */
+gpg_error_t
+ks_ldap_put (ctrl_t ctrl, parsed_uri_t uri,
+ void *data, size_t datalen,
+ void *info, size_t infolen)
+{
+ gpg_error_t err = 0;
+ int ldap_err;
+
+ LDAP *ldap_conn = NULL;
+ char *basedn = NULL;
+ char *pgpkeyattr = NULL;
+ int real_ldap;
+
+ LDAPMod **modlist = NULL;
+ LDAPMod **addlist = NULL;
+
+ char *data_armored = NULL;
+
+ /* The last byte of the info block. */
+ const char *infoend = (const char *) info + infolen - 1;
+
+ /* Enable this code to dump the modlist to /tmp/modlist.txt. */
+#if 0
+# warning Disable debug code before checking in.
+ const int dump_modlist = 1;
+#else
+ const int dump_modlist = 0;
+#endif
+ estream_t dump = NULL;
+
+ /* Elide a warning. */
+ (void) ctrl;
+
+ ldap_err = my_ldap_connect (uri,
+ &ldap_conn, &basedn, &pgpkeyattr, &real_ldap);
+ if (ldap_err || !basedn)
+ {
+ if (ldap_err)
+ err = ldap_err_to_gpg_err (ldap_err);
+ else
+ err = GPG_ERR_GENERAL;
+ goto out;
+ }
+
+ if (! real_ldap)
+ /* We appear to have an OpenPGP Keyserver, which can unpack the key
+ on its own (not just a dumb LDAP server). */
+ {
+ LDAPMod mod, *attrs[2];
+ char *key[] = { data, NULL };
+ char *dn;
+
+ memset (&mod, 0, sizeof (mod));
+ mod.mod_op = LDAP_MOD_ADD;
+ mod.mod_type = pgpkeyattr;
+ mod.mod_values = key;
+ attrs[0] = &mod;
+ attrs[1] = NULL;
+
+ dn = xasprintf ("pgpCertid=virtual,%s", basedn);
+ ldap_err = ldap_add_s (ldap_conn, dn, attrs);
+ xfree (dn);
+
+ if (ldap_err != LDAP_SUCCESS)
+ {
+ err = ldap_err_to_gpg_err (err);
+ goto out;
+ }
+
+ goto out;
+ }
+
+ modlist = xmalloc (sizeof (LDAPMod *));
+ *modlist = NULL;
+
+ if (dump_modlist)
+ {
+ dump = es_fopen("/tmp/modlist.txt", "w");
+ if (! dump)
+ log_error ("Failed to open /tmp/modlist.txt: %s\n",
+ strerror (errno));
+
+ if (dump)
+ {
+ es_fprintf(dump, "data (%zd bytes)\n", datalen);
+ es_fprintf(dump, "info (%zd bytes): '\n", infolen);
+ es_fwrite(info, infolen, 1, dump);
+ es_fprintf(dump, "'\n");
+ }
+ }
+
+ /* Start by nulling out all attributes. We try and do a modify
+ operation first, so this ensures that we don't leave old
+ attributes lying around. */
+ modlist_add (&modlist, "pgpDisabled", NULL);
+ modlist_add (&modlist, "pgpKeyID", NULL);
+ modlist_add (&modlist, "pgpKeyType", NULL);
+ modlist_add (&modlist, "pgpUserID", NULL);
+ modlist_add (&modlist, "pgpKeyCreateTime", NULL);
+ modlist_add (&modlist, "pgpSignerID", NULL);
+ modlist_add (&modlist, "pgpRevoked", NULL);
+ modlist_add (&modlist, "pgpSubKeyID", NULL);
+ modlist_add (&modlist, "pgpKeySize", NULL);
+ modlist_add (&modlist, "pgpKeyExpireTime", NULL);
+ modlist_add (&modlist, "pgpCertID", NULL);
+
+ /* Assemble the INFO stuff into LDAP attributes */
+
+ while (infolen > 0)
+ {
+ char *temp = NULL;
+
+ char *newline = memchr (info, '\n', infolen);
+ if (! newline)
+ /* The last line is not \n terminated! Make a copy so we can
+ add a NUL terminator. */
+ {
+ temp = xmalloc (infolen + 1);
+ memcpy (temp, info, infolen);
+ info = temp;
+ newline = (char *) info + infolen;
+ }
+
+ *newline = '\0';
+
+ extract_attributes (&modlist, info);
+
+ infolen = infolen - ((uintptr_t) newline - (uintptr_t) info + 1);
+ info = newline + 1;
+
+ /* Sanity check. */
+ if (! temp)
+ assert ((char *) info + infolen - 1 == infoend);
+ else
+ {
+ assert (infolen == -1);
+ xfree (temp);
+ }
+ }
+
+ modlist_add (&addlist, "objectClass", "pgpKeyInfo");
+
+ err = armor_data (&data_armored, data, datalen);
+ if (err)
+ goto out;
+
+ modlist_add (&addlist, pgpkeyattr, data_armored);
+
+ /* Now append addlist onto modlist. */
+ modlists_join (&modlist, addlist);
+
+ if (dump)
+ {
+ estream_t input = modlist_dump (modlist, NULL);
+ if (input)
+ {
+ copy_stream (input, dump);
+ es_fclose (input);
+ }
+ }
+
+ /* Going on the assumption that modify operations are more frequent
+ than adds, we try a modify first. If it's not there, we just
+ turn around and send an add command for the same key. Otherwise,
+ the modify brings the server copy into compliance with our copy.
+ Note that unlike the LDAP keyserver (and really, any other
+ keyserver) this does NOT merge signatures, but replaces the whole
+ key. This should make some people very happy. */
+ {
+ char **certid;
+ char *dn;
+
+ certid = modlist_lookup (modlist, "pgpCertID");
+ if (/* We should have a value. */
+ ! certid
+ /* Exactly one. */
+ || !(certid[0] && !certid[1]))
+ {
+ log_error ("Bad certid.\n");
+ err = GPG_ERR_GENERAL;
+ goto out;
+ }
+
+ dn = xasprintf ("pgpCertID=%s,%s", certid[0], basedn);
+
+ err = ldap_modify_s (ldap_conn, dn, modlist);
+ if (err == LDAP_NO_SUCH_OBJECT)
+ err = ldap_add_s (ldap_conn, dn, addlist);
+
+ xfree (dn);
+
+ if (err != LDAP_SUCCESS)
+ {
+ log_error ("gpgkeys: error adding key to keyserver: %s\n",
+ ldap_err2string (err));
+ err = ldap_err_to_gpg_err (err);
+ }
+ }
+
+ out:
+ if (dump)
+ es_fclose (dump);
+
+ if (ldap_conn)
+ ldap_unbind (ldap_conn);
+
+ xfree (basedn);
+ xfree (pgpkeyattr);
+
+ modlist_free (modlist);
+ xfree (addlist);
+
+ xfree (data_armored);
+
+ return err;
+}
diff --git a/dirmngr/ks-engine.h b/dirmngr/ks-engine.h
index dc950cf..5bfe29b 100644
--- a/dirmngr/ks-engine.h
+++ b/dirmngr/ks-engine.h
@@ -1,5 +1,6 @@
/* ks-engine.h - Keyserver engines definitions
* Copyright (C) 2011 Free Software Foundation, Inc.
+ * Copyright (C) 2015 g10 Code GmbH
*
* This file is part of GnuPG.
*
@@ -52,6 +53,15 @@ gpg_error_t ks_finger_fetch (ctrl_t ctrl, parsed_uri_t uri, estream_t *r_fp);
gpg_error_t ks_kdns_help (ctrl_t ctrl, parsed_uri_t uri);
gpg_error_t ks_kdns_fetch (ctrl_t ctrl, parsed_uri_t uri, estream_t *r_fp);
+/*-- ks-engine-ldap.c --*/
+gpg_error_t ks_ldap_help (ctrl_t ctrl, parsed_uri_t uri);
+gpg_error_t ks_ldap_search (ctrl_t ctrl, parsed_uri_t uri, const char *pattern,
+ estream_t *r_fp);
+gpg_error_t ks_ldap_get (ctrl_t ctrl, parsed_uri_t uri,
+ const char *keyspec, estream_t *r_fp);
+gpg_error_t ks_ldap_put (ctrl_t ctrl, parsed_uri_t uri,
+ void *data, size_t datalen,
+ void *info, size_t infolen);
#endif /*DIRMNGR_KS_ENGINE_H*/
diff --git a/dirmngr/ldap-parse-uri.c b/dirmngr/ldap-parse-uri.c
new file mode 100644
index 0000000..62f8f6d
--- /dev/null
+++ b/dirmngr/ldap-parse-uri.c
@@ -0,0 +1,246 @@
+/* ldap-parse-uri.c - Parse an LDAP URI.
+ * Copyright (C) 2015 g10 Code GmbH
+ *
+ * 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 <gpg-error.h>
+
+#ifdef HAVE_W32_SYSTEM
+# include "ldap-url.h"
+#else
+# include <ldap.h>
+#endif
+
+#include "util.h"
+#include "http.h"
+
+/* Returns 1 if the string is an LDAP URL (begins with ldap:, ldaps:
+ or ldapi:). */
+int
+ldap_uri_p (const char *url)
+{
+ char *colon = strchr (url, ':');
+ if (! colon)
+ return 0;
+ else
+ {
+ int offset = (uintptr_t) colon - (uintptr_t) url;
+
+ if (/* All lower case. */
+ (offset == 4 && memcmp (url, "ldap", 4) == 0)
+ || (offset == 5
+ && (memcmp (url, "ldaps", 5) == 0
+ && memcmp (url, "ldapi", 5) == 0))
+ /* Mixed case. */
+ || ((url[0] == 'l' || url[0] == 'L')
+ && (url[1] == 'd' || url[1] == 'D')
+ && (url[2] == 'a' || url[2] == 'A')
+ && (url[3] == 'p' || url[3] == 'P')
+ && (url[4] == ':'
+ || ((url[4] == 's' || url[4] == 'S'
+ || url[4] == 'i' || url[4] == 'i')
+ && url[5] == ':'))))
+ return 1;
+ return 0;
+ }
+}
+
+/* Parse a URI and put the result into *purip. On success the
+ caller must use http_release_parsed_uri() to releases the resources.
+
+ uri->path is the base DN (or NULL for the default).
+ uri->auth is the bindname (or NULL for none).
+ The uri->query variable "password" is the password.
+
+ Note: any specified scope, any attributes, any filter and any
+ unknown extensions are simply ignored. */
+gpg_error_t
+ldap_parse_uri (parsed_uri_t *purip, const char *uri)
+{
+ gpg_err_code_t err = 0;
+ parsed_uri_t puri = NULL;
+
+ int result;
+ LDAPURLDesc *lud = NULL;
+
+ char *scheme = NULL;
+ char *host = NULL;
+ char *dn = NULL;
+ char *bindname = NULL;
+ char *password = NULL;
+
+ char **s;
+
+ char *buffer;
+ int len;
+
+ result = ldap_url_parse (uri, &lud);
+ if (result != 0)
+ {
+ log_error ("Unable to parse LDAP uri '%s'\n", uri);
+ err = GPG_ERR_GENERAL;
+ goto out;
+ }
+
+ scheme = lud->lud_scheme;
+ host = lud->lud_host;
+ dn = lud->lud_dn;
+
+ for (s = lud->lud_exts; s && *s; s ++)
+ {
+ if (strncmp (*s, "bindname=", 9) == 0)
+ {
+ if (bindname)
+ log_error ("bindname given multiple times in URL '%s', ignoring.\n",
+ uri);
+ else
+ bindname = *s + 9;
+ }
+ else if (strncmp (*s, "password=", 9) == 0)
+ {
+ if (password)
+ log_error ("password given multiple times in URL '%s', ignoring.\n",
+ uri);
+ else
+ password = *s + 9;
+ }
+ else
+ log_error ("Unhandled extension (%s) in URL '%s', ignoring.",
+ *s, uri);
+ }
+
+ len = 0;
+
+#define add(s) do { if (s) len += strlen (s) + 1; } while (0)
+
+ add (scheme);
+ add (host);
+ add (dn);
+ add (bindname);
+ add (password);
+
+ puri = xtrycalloc (1, sizeof *puri + len);
+ if (! puri)
+ {
+ err = gpg_err_code_from_syserror ();
+ goto out;
+ }
+
+ buffer = puri->buffer;
+
+#define copy(to, s) \
+ do \
+ { \
+ if (s) \
+ { \
+ to = buffer; \
+ buffer = stpcpy (buffer, s) + 1; \
+ } \
+ } \
+ while (0)
+
+ copy (puri->scheme, scheme);
+ /* Make sure the scheme is lower case. */
+ ascii_strlwr (puri->scheme);
+
+ copy (puri->host, host);
+ copy (puri->path, dn);
+ copy (puri->auth, bindname);
+
+ if (password)
+ {
+ puri->query = calloc (sizeof (*puri->query), 1);
+ if (!puri->query)
+ {
+ err = gpg_err_code_from_syserror ();
+ goto out;
+ }
+ puri->query->name = "password";
+ copy (puri->query->value, password);
+ puri->query->valuelen = strlen (password) + 1;
+ }
+
+ puri->use_tls = strcmp (puri->scheme, "ldaps") == 0;
+ puri->port = lud->lud_port;
+
+ out:
+ if (lud)
+ ldap_free_urldesc (lud);
+
+ if (err)
+ {
+ if (puri)
+ http_release_parsed_uri (puri);
+ }
+ else
+ *purip = puri;
+
+ return gpg_err_make (default_errsource, err);
+}
+
+/* The following characters need to be escaped to be part of an LDAP
+ filter: *, (, ), \, NUL and /. Note: we don't handle NUL, since a
+ NUL can't be part of a C string.
+
+ This function always allocates a new string on success. It is the
+ caller's responsibility to free it.
+*/
+char *
+ldap_escape_filter (const char *filter)
+{
+ int l = strcspn (filter, "*()\\/");
+ if (l == strlen (filter))
+ /* Nothing to escape. */
+ return xstrdup (filter);
+
+ {
+ /* In the worst case we need to escape every letter. */
+ char *escaped = xmalloc (1 + 3 * strlen (filter));
+
+ /* Indices into filter and escaped. */
+ int filter_i = 0;
+ int escaped_i = 0;
+
+ for (filter_i = 0; filter_i < strlen (filter); filter_i ++)
+ {
+ switch (filter[filter_i])
+ {
+ case '*':
+ case '(':
+ case ')':
+ case '\\':
+ case '/':
+ snprintf (&escaped[escaped_i], 4, "%%%02x",
+ ((const unsigned char *)filter)[filter_i]);
+ escaped_i += 3;
+ break;
+
+ default:
+ escaped[escaped_i ++] = filter[filter_i];
+ break;
+ }
+ }
+ /* NUL terminate it. */
+ escaped[escaped_i] = 0;
+
+ /* We could shrink escaped to be just escaped_i bytes, but the
+ result will probably be freed very quickly anyways. */
+ return escaped;
+ }
+}
diff --git a/dirmngr/ldap-parse-uri.h b/dirmngr/ldap-parse-uri.h
new file mode 100644
index 0000000..1ef1b91
--- /dev/null
+++ b/dirmngr/ldap-parse-uri.h
@@ -0,0 +1,33 @@
+/* ldap-parse-uri.h - Parse an LDAP URI.
+ * Copyright (C) 2015 g10 Code GmbH
+ *
+ * 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 DIRMNGR_LDAP_PARSE_URI_H
+#define DIRMNGR_LDAP_PARSE_URI_H
+
+#include "util.h"
+#include "http.h"
+
+extern int ldap_uri_p (const char *url);
+
+extern gpg_error_t ldap_parse_uri (parsed_uri_t *ret_uri, const char *uri);
+
+extern char *ldap_escape_filter (const char *filter);
+
+
+#endif
diff --git a/dirmngr/ldap-wrapper.c b/dirmngr/ldap-wrapper.c
index f2aaf59..5588468 100644
--- a/dirmngr/ldap-wrapper.c
+++ b/dirmngr/ldap-wrapper.c
@@ -630,7 +630,7 @@ reader_callback (void *cb_value, char *buffer, size_t count, size_t *nread)
return 0;
}
-/* Fork and exec the LDAP wrapper and returns a new libksba reader
+/* Fork and exec the LDAP wrapper and return a new libksba reader
object at READER. ARGV is a NULL terminated list of arguments for
the wrapper. The function returns 0 on success or an error code.
diff --git a/dirmngr/ldap.c b/dirmngr/ldap.c
index c596198..e4c6aa2 100644
--- a/dirmngr/ldap.c
+++ b/dirmngr/ldap.c
@@ -131,7 +131,7 @@ run_ldap_wrapper (ctrl_t ctrl,
*reader = NULL;
argc = 0;
- if (pass) /* Note, that the password most be the first item. */
+ if (pass) /* Note, that the password must be the first item. */
{
argv[argc++] = "--pass";
argv[argc++] = pass;
diff --git a/dirmngr/ldapserver.c b/dirmngr/ldapserver.c
index 5808c5b..16e13e2 100644
--- a/dirmngr/ldapserver.c
+++ b/dirmngr/ldapserver.c
@@ -47,7 +47,7 @@ ldapserver_list_free (ldap_server_t servers)
/* Parse a single LDAP server configuration line. Returns the server
- or NULL in case of errors. The configuration lineis assumed to be
+ or NULL in case of errors. The configuration line is assumed to be
colon seprated with these fields:
1. field: Hostname
diff --git a/dirmngr/misc.c b/dirmngr/misc.c
index 25652a2..244919e 100644
--- a/dirmngr/misc.c
+++ b/dirmngr/misc.c
@@ -125,7 +125,7 @@ serial_to_buffer (const ksba_sexp_t serial, size_t *length)
}
-/* Do an in-place percent unescaping of STRING. Returns STRING. Noet
+/* Do an in-place percent unescaping of STRING. Returns STRING. Note
that this function does not do a '+'-to-space unescaping.*/
char *
unpercent_string (char *string)
@@ -562,3 +562,78 @@ create_estream_ksba_reader (ksba_reader_t *r_reader, estream_t fp)
*r_reader = reader;
return 0;
}
+
+gpg_error_t
+armor_data (char **r_string, const void *data, size_t datalen)
+{
+ gpg_error_t err;
+ struct b64state b64state;
+ estream_t fp;
+ long length;
+ char *buffer;
+ size_t nread;
+
+ *r_string = NULL;
+
+ fp = es_fopenmem (0, "rw,samethread");
+ if (!fp)
+ return gpg_error_from_syserror ();
+
+ if ((err=b64enc_start_es (&b64state, fp, "PGP PUBLIC KEY BLOCK"))
+ || (err=b64enc_write (&b64state, data, datalen))
+ || (err = b64enc_finish (&b64state)))
+ {
+ es_fclose (fp);
+ return err;
+ }
+
+ /* FIXME: To avoid the extra buffer allocation estream should
+ provide a function to snatch the internal allocated memory from
+ such a memory stream. */
+ length = es_ftell (fp);
+ if (length < 0)
+ {
+ err = gpg_error_from_syserror ();
+ es_fclose (fp);
+ return err;
+ }
+
+ buffer = xtrymalloc (length+1);
+ if (!buffer)
+ {
+ err = gpg_error_from_syserror ();
+ es_fclose (fp);
+ return err;
+ }
+
+ es_rewind (fp);
+ if (es_read (fp, buffer, length, &nread))
+ {
+ err = gpg_error_from_syserror ();
+ es_fclose (fp);
+ return err;
+ }
+ buffer[nread] = 0;
+ es_fclose (fp);
+
+ *r_string = buffer;
+ return 0;
+}
+
+/* Copy all data from IN to OUT. */
+gpg_error_t
+copy_stream (estream_t in, estream_t out)
+{
+ char buffer[512];
+ size_t nread;
+
+ while (!es_read (in, buffer, sizeof buffer, &nread))
+ {
+ if (!nread)
+ return 0; /* EOF */
+ if (es_write (out, buffer, nread, NULL))
+ break;
+
+ }
+ return gpg_error_from_syserror ();
+}
diff --git a/dirmngr/misc.h b/dirmngr/misc.h
index 2dc2985..d8c53d3 100644
--- a/dirmngr/misc.h
+++ b/dirmngr/misc.h
@@ -80,6 +80,12 @@ char *host_and_port_from_url (const char *url, int *port);
/* Create a KSBA reader object and connect it to the estream FP. */
gpg_error_t create_estream_ksba_reader (ksba_reader_t *r_reader, estream_t fp);
+/* Encode the binary data in {DATA,DATALEN} as ASCII-armored data and
+ stored it as a NUL-terminated string in *R_STRING. The caller is
+ responsible for freeing *R_STRING. */
+gpg_error_t armor_data (char **r_string, const void *data, size_t datalen);
+/* Copy all data from IN to OUT. */
+gpg_error_t copy_stream (estream_t in, estream_t out);
#endif /* MISC_H */
diff --git a/dirmngr/server.c b/dirmngr/server.c
index 6094bc9..506b137 100644
--- a/dirmngr/server.c
+++ b/dirmngr/server.c
@@ -1,6 +1,6 @@
/* server.c - LDAP and Keyserver access server
* Copyright (C) 2002 Klarälvdalens Datakonsult AB
- * Copyright (C) 2003, 2004, 2005, 2007, 2008, 2009, 2011 g10 Code GmbH
+ * Copyright (C) 2003, 2004, 2005, 2007, 2008, 2009, 2011, 2015 g10 Code GmbH
* Copyright (C) 2014 Werner Koch
*
* This file is part of GnuPG.
@@ -48,6 +48,7 @@
#endif
#include "ks-action.h"
#include "ks-engine.h" /* (ks_hkp_print_hosttable) */
+#include "ldap-parse-uri.h"
/* To avoid DoS attacks we limit the size of a certificate to
something reasonable. */
@@ -74,6 +75,9 @@ struct server_local_s
/* Per-session LDAP servers. */
ldap_server_t ldapservers;
+ /* Per-session list of keyservers. */
+ uri_item_t keyservers;
+
/* If this flag is set to true this dirmngr process will be
terminated after the end of this session. */
int stopme;
@@ -111,12 +115,15 @@ get_ldapservers_from_ctrl (ctrl_t ctrl)
void
release_ctrl_keyservers (ctrl_t ctrl)
{
- while (ctrl->keyservers)
+ if (! ctrl->server_local)
+ return;
+
+ while (ctrl->server_local->keyservers)
{
- uri_item_t tmp = ctrl->keyservers->next;
- http_release_parsed_uri (ctrl->keyservers->parsed_uri);
- xfree (ctrl->keyservers);
- ctrl->keyservers = tmp;
+ uri_item_t tmp = ctrl->server_local->keyservers->next;
+ http_release_parsed_uri (ctrl->server_local->keyservers->parsed_uri);
+ xfree (ctrl->server_local->keyservers);
+ ctrl->server_local->keyservers = tmp;
}
}
@@ -125,7 +132,6 @@ release_ctrl_keyservers (ctrl_t ctrl)
/* Helper to print a message while leaving a command. */
static gpg_error_t
leave_cmd (assuan_context_t ctx, gpg_error_t err)
-
{
if (err)
{
@@ -1474,7 +1480,7 @@ cmd_keyserver (assuan_context_t ctx, char *line)
if (resolve_flag)
{
- err = ks_action_resolve (ctrl);
+ err = ks_action_resolve (ctrl, ctrl->server_local->keyservers);
if (err)
goto leave;
}
@@ -1524,7 +1530,10 @@ cmd_keyserver (assuan_context_t ctx, char *line)
item->parsed_uri = NULL;
strcpy (item->uri, line);
- err = http_parse_uri (&item->parsed_uri, line, 1);
+ if (ldap_uri_p (item->uri))
+ err = ldap_parse_uri (&item->parsed_uri, line);
+ else
+ err = http_parse_uri (&item->parsed_uri, line, 1);
if (err)
{
xfree (item);
@@ -1535,15 +1544,15 @@ cmd_keyserver (assuan_context_t ctx, char *line)
release_ctrl_keyservers (ctrl);
if (add_flag)
{
- item->next = ctrl->keyservers;
- ctrl->keyservers = item;
+ item->next = ctrl->server_local->keyservers;
+ ctrl->server_local->keyservers = item;
}
if (!add_flag && !clear_flag && !help_flag) /* List configured keyservers. */
{
uri_item_t u;
- for (u=ctrl->keyservers; u; u = u->next)
+ for (u=ctrl->server_local->keyservers; u; u = u->next)
dirmngr_status (ctrl, "KEYSERVER", u->uri, NULL);
}
err = 0;
@@ -1601,7 +1610,8 @@ cmd_ks_search (assuan_context_t ctx, char *line)
err = set_error (GPG_ERR_ASS_GENERAL, "error setting up a data stream");
else
{
- err = ks_action_search (ctrl, list, outfp);
+ err = ks_action_search (ctrl, ctrl->server_local->keyservers,
+ list, outfp);
es_fclose (outfp);
}
@@ -1630,7 +1640,7 @@ cmd_ks_get (assuan_context_t ctx, char *line)
/* No options for now. */
line = skip_options (line);
- /* Break the line down into an strlist. Each pattern is by
+ /* Break the line into a strlist. Each pattern is by
definition percent-plus escaped. However we only support keyids
and fingerprints and thus the client has no need to apply the
escaping. */
@@ -1662,7 +1672,7 @@ cmd_ks_get (assuan_context_t ctx, char *line)
err = set_error (GPG_ERR_ASS_GENERAL, "error setting up a data stream");
else
{
- err = ks_action_get (ctrl, list, outfp);
+ err = ks_action_get (ctrl, ctrl->server_local->keyservers, list, outfp);
es_fclose (outfp);
}
@@ -1709,13 +1719,15 @@ static const char hlp_ks_put[] =
"\n"
" INQUIRE KEYBLOCK\n"
"\n"
- "The client shall respond with a binary version of the keyblock. For LDAP\n"
+ "The client shall respond with a binary version of the keyblock (e.g.,\n"
+ "the output of `gpg --export KEYID'). For LDAP\n"
"keyservers Dirmngr may ask for meta information of the provided keyblock\n"
"using:\n"
"\n"
" INQUIRE KEYBLOCK_INFO\n"
"\n"
- "The client shall respond with a colon delimited info lines";
+ "The client shall respond with a colon delimited info lines (the output\n"
+ "of 'for x in keys sigs; do gpg --list-$x --with-colons KEYID; done').\n";
static gpg_error_t
cmd_ks_put (assuan_context_t ctx, char *line)
{
@@ -1745,7 +1757,7 @@ cmd_ks_put (assuan_context_t ctx, char *line)
}
/* Ask for the key meta data. Not actually needed for HKP servers
- but we do it anyway test the client implementaion. */
+ but we do it anyway to test the client implementaion. */
err = assuan_inquire (ctx, "KEYBLOCK_INFO",
&info, &infolen, MAX_KEYBLOCK_LENGTH);
if (err)
@@ -1755,7 +1767,8 @@ cmd_ks_put (assuan_context_t ctx, char *line)
}
/* Send the key. */
- err = ks_action_put (ctrl, value, valuelen);
+ err = ks_action_put (ctrl, ctrl->server_local->keyservers,
+ value, valuelen, info, infolen);
leave:
xfree (info);
@@ -1937,8 +1950,8 @@ reset_notify (assuan_context_t ctx, char *line)
}
-/* Startup the server and run the main command loop. With FD = -1
- used stdin/stdout. */
+/* Startup the server and run the main command loop. With FD = -1,
+ use stdin/stdout. */
void
start_command_handler (assuan_fd_t fd)
{
diff --git a/dirmngr/t-ldap-parse-uri.c b/dirmngr/t-ldap-parse-uri.c
new file mode 100644
index 0000000..100ce0d
--- /dev/null
+++ b/dirmngr/t-ldap-parse-uri.c
@@ -0,0 +1,255 @@
+/* t-ldap-parse-uri.c - Regression tests for ldap-parse-uri.c.
+ * Copyright (C) 2015 g10 Code GmbH
+ *
+ * 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 "ldap-parse-uri.h"
+
+#include "t-support.h"
+
+struct test_ldap_uri_p
+{
+ const char *uri;
+ int result;
+};
+
+void
+check_ldap_uri_p (int test_count, struct test_ldap_uri_p *test)
+{
+ int result = ldap_uri_p (test->uri);
+ if (result != test->result)
+ {
+ printf ("'%s' is %san LDAP schema, but ldap_uri_p says opposite.\n",
+ test->uri, test->result ? "" : "not ");
+ fail(1000 * test_count);
+ }
+}
+
+static void
+test_ldap_uri_p (void)
+{
+ struct test_ldap_uri_p tests[] = {
+ { "ldap://foo", 1 },
+ { "ldap://", 1 },
+ { "ldap:", 1 },
+ { "ldap", 0 },
+ { "ldapfoobar", 0 },
+
+ { "ldaps://foo", 1 },
+ { "ldaps://", 1 },
+ { "ldaps:", 1 },
+ { "ldaps", 0 },
+ { "ldapsfoobar", 0 },
+
+ { "ldapi://foo", 1 },
+ { "ldapi://", 1 },
+ { "ldapi:", 1 },
+ { "ldapi", 0 },
+ { "ldapifoobar", 0 },
+
+ { "LDAP://FOO", 1 },
+ { "LDAP://", 1 },
+ { "LDAP:", 1 },
+ { "LDAP", 0 },
+ { "LDAPFOOBAR", 0 }
+ };
+
+ int test_count;
+ for (test_count = 1;
+ test_count <= sizeof (tests) / sizeof (tests[0]);
+ test_count ++)
+ check_ldap_uri_p (test_count, &tests[test_count - 1]);
+}
+
+struct test_ldap_parse_uri
+{
+ const char *uri;
+ const char *scheme;
+ const char *host;
+ const int port;
+ const int use_tls;
+ const char *path; /* basedn. */
+ const char *auth; /* binddn. */
+ const char *password; /* query[1]. */
+};
+
+static int
+cmp (const char *a, const char *b)
+{
+ if (! a)
+ a = "";
+ if (! b)
+ b = "";
+
+ return strcmp (a, b) == 0;
+}
+
+void
+check_ldap_parse_uri (int test_count, struct test_ldap_parse_uri *test)
+{
+ gpg_error_t err;
+ parsed_uri_t puri;
+
+ err = ldap_parse_uri (&puri, test->uri);
+ if (err)
+ {
+ printf ("Parsing '%s' failed (%d).\n", test->uri, err);
+ fail (test_count * 1000 + 0);
+ }
+
+ if (! cmp(test->scheme, puri->scheme))
+ {
+ printf ("scheme mismatch: got '%s', expected '%s'.\n",
+ puri->scheme, test->scheme);
+ fail (test_count * 1000 + 1);
+ }
+
+ if (! cmp(test->host, puri->host))
+ {
+ printf ("host mismatch: got '%s', expected '%s'.\n",
+ puri->host, test->host);
+ fail (test_count * 1000 + 2);
+ }
+
+ if (test->port != puri->port)
+ {
+ printf ("port mismatch: got '%d', expected '%d'.\n",
+ puri->port, test->port);
+ fail (test_count * 1000 + 3);
+ }
+
+ if (test->use_tls != puri->use_tls)
+ {
+ printf ("use_tls mismatch: got '%d', expected '%d'.\n",
+ puri->use_tls, test->use_tls);
+ fail (test_count * 1000 + 4);
+ }
+
+ if (! cmp(test->path, puri->path))
+ {
+ printf ("path mismatch: got '%s', expected '%s'.\n",
+ puri->path, test->path);
+ fail (test_count * 1000 + 5);
+ }
+
+ if (! cmp(test->auth, puri->auth))
+ {
+ printf ("auth mismatch: got '%s', expected '%s'.\n",
+ puri->auth, test->auth);
+ fail (test_count * 1000 + 6);
+ }
+
+ if (! test->password && ! puri->query)
+ /* Ok. */
+ ;
+ else if (test->password && ! puri->query)
+ {
+ printf ("password mismatch: got NULL, expected '%s'.\n",
+ test->auth);
+ fail (test_count * 1000 + 7);
+ }
+ else if (! test->password && puri->query)
+ {
+ printf ("password mismatch: got something, expected NULL.\n");
+ fail (test_count * 1000 + 8);
+ }
+ else if (! (test->password && puri->query
+ && puri->query->name && puri->query->value
+ && strcmp (puri->query->name, "password") == 0
+ && cmp (puri->query->value, test->password)))
+ {
+ printf ("password mismatch: got '%s:%s', expected 'password:%s'.\n",
+ puri->query->name, puri->query->value,
+ test->password);
+ fail (test_count * 1000 + 9);
+ }
+
+ http_release_parsed_uri (puri);
+}
+
+static void
+test_ldap_parse_uri (void)
+{
+ struct test_ldap_parse_uri tests[] = {
+ { "ldap://", "ldap", NULL, 389, 0, NULL, NULL, NULL },
+ { "ldap://host", "ldap", "host", 389, 0, NULL, NULL, NULL },
+ { "ldap://host:100", "ldap", "host", 100, 0, NULL, NULL, NULL },
+ { "ldaps://host", "ldaps", "host", 636, 1, NULL, NULL, NULL },
+ { "ldap://host/ou%3DPGP%20Keys%2Cdc%3DEXAMPLE%2Cdc%3DORG",
+ "ldap", "host", 389, 0, "ou=PGP Keys,dc=EXAMPLE,dc=ORG" },
+ { "ldap://host/????bindname=uid%3Duser%2Cou%3DPGP%20Users%2Cdc%3DEXAMPLE%2Cdc%3DORG,password=foobar",
+ "ldap", "host", 389, 0, "",
+ "uid=user,ou=PGP Users,dc=EXAMPLE,dc=ORG", "foobar" }
+ };
+
+ int test_count;
+ for (test_count = 1;
+ test_count <= sizeof (tests) / sizeof (tests[0]);
+ test_count ++)
+ check_ldap_parse_uri (test_count, &tests[test_count - 1]);
+}
+
+struct test_ldap_escape_filter
+{
+ const char *filter;
+ const char *result;
+};
+
+static void
+check_ldap_escape_filter (int test_count, struct test_ldap_escape_filter *test)
+{
+ char *result = ldap_escape_filter (test->filter);
+
+ if (strcmp (result, test->result) != 0)
+ {
+ printf ("Filter: '%s'. Escaped: '%s'. Expected: '%s'.\n",
+ test->filter, result, test->result);
+ fail (test_count * 1000);
+ }
+}
+
+static void
+test_ldap_escape_filter (void)
+{
+ struct test_ldap_escape_filter tests[] = {
+ { "foobar", "foobar" },
+ { "", "" },
+ { "(foo)", "%28foo%29" },
+ { "* ( ) \\ /", "%2a %28 %29 %5c %2f" }
+ };
+
+ int test_count;
+ for (test_count = 1;
+ test_count <= sizeof (tests) / sizeof (tests[0]);
+ test_count ++)
+ check_ldap_escape_filter (test_count, &tests[test_count - 1]);
+}
+
+int
+main (int argc, char **argv)
+{
+ (void)argc;
+ (void)argv;
+
+ test_ldap_uri_p ();
+ test_ldap_parse_uri ();
+ test_ldap_escape_filter ();
+
+ return 0;
+}
diff --git a/dirmngr/t-support.h b/dirmngr/t-support.h
new file mode 100644
index 0000000..99fd267
--- /dev/null
+++ b/dirmngr/t-support.h
@@ -0,0 +1,42 @@
+/* t-support.h - Helper for the regression tests
+ * Copyright (C) 2007 Free Software Foundation, Inc.
+ *
+ * This file is part of JNLIB, which is a subsystem of GnuPG.
+ *
+ * JNLIB is free software; you can redistribute it and/or modify it
+ * under the terms of either
+ *
+ * - the GNU Lesser General Public License as published by the Free
+ * Software Foundation; either version 3 of the License, or (at
+ * your option) any later version.
+ *
+ * or
+ *
+ * - the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * or both in parallel, as here.
+ *
+ * JNLIB 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 copies of the GNU General Public License
+ * and the GNU Lesser General Public License along with this program;
+ * if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef DIRMNGR_T_SUPPORT_H
+#define DIRMNGR_T_SUPPORT_H 1
+
+/* Macros to print the result of a test. */
+#define pass() do { ; } while(0)
+#define fail(a) do { fprintf (stderr, "%s:%d: test %d failed\n",\
+ __FILE__,__LINE__, (a)); \
+ exit (1); \
+ } while(0)
+
+
+#endif /* DIRMNGR_T_SUPPORT_H */
diff --git a/doc/DETAILS b/doc/DETAILS
index 59ccaec..fd72b88 100644
--- a/doc/DETAILS
+++ b/doc/DETAILS
@@ -32,7 +32,7 @@ fpr:::::::::AB059359A3B81F410FCFF97F5CE086B5B5A18FF4:
#+end_example
The double =--with-fingerprint= prints the fingerprint for the subkeys
-too. Old versions of gpg used a slighrly different format and required
+too. Old versions of gpg used a slightly different format and required
the use of the option =--fixed-list-mode= to conform to the format
described here.
@@ -192,7 +192,7 @@ described here.
*** Field 15 - S/N of a token
- Used in sec/sbb to print the serial number of a token (internal
+ Used in sec/ssb to print the serial number of a token (internal
protect mode 1002) or a '#' if that key is a simple stub (internal
protect mode 1001). If the option --with-secret is used and a
secret key is available for the public key, a '+' indicates this.
@@ -204,7 +204,7 @@ described here.
*** Field 17 - Curve name
- For pub, sub, sec, and sbb records this field is used for the ECC
+ For pub, sub, sec, and ssb records this field is used for the ECC
curve name.
** Special fields
@@ -287,19 +287,22 @@ pkd:0:1024:B665B1435F4C2 .... FF26ABB:
semicolons. The algorithm numbers are as specified in
RFC-4880. Note that in contrast to the --status-fd
interface these are _not_ the Libgcrypt identifiers.
+ Using =pubkeyname= prints names instead of numbers.
: cfg:pubkey:1;2;3;16;17
- cipher :: The third field contains the symmetric ciphers this
version of GnuPG supports, separated by semicolons.
The cipher numbers are as specified in RFC-4880.
+ Using =ciphername= prints names instead of numbers.
: cfg:cipher:2;3;4;7;8;9;10
- digest :: The third field contains the digest (hash) algorithms
this version of GnuPG supports, separated by
semicolons. The digest numbers are as specified in
- RFC-4880.
+ RFC-4880. Using =digestname= prints names instead of
+ numbers.
: cfg:digest:1;2;3;8;9;10
@@ -319,6 +322,12 @@ pkd:0:1024:B665B1435F4C2 .... FF26ABB:
would result in:
: cfg:group:mynames:patti;joe;0x12345678;paige
+ - curve :: The third field contains the curve names this version
+ of GnuPG supports, separated by semicolons. Using
+ =curveoid= prints OIDs instead of numbers.
+
+ : cfg:curve:ed25519;nistp256;nistp384;nistp521
+
* Format of the --status-fd output
@@ -329,9 +338,9 @@ pkd:0:1024:B665B1435F4C2 .... FF26ABB:
** General status codes
*** NEWSIG
- May be issued right before a signature verification starts. This
- is useful to define a context for parsing ERROR status messages.
- No arguments are currently defined.
+ Is issued right before a signature verification starts. This is
+ useful to define a context for parsing ERROR status messages. No
+ arguments are currently defined.
*** GOODSIG <long_keyid_or_fpr> <username>
The signature with the keyid is good. For each signature only one
@@ -1125,12 +1134,26 @@ pkd:0:1024:B665B1435F4C2 .... FF26ABB:
* GNU extensions to the S2K algorithm
- S2K mode 101 is used to identify these extensions.
- After the hash algorithm the 3 bytes "GNU" are used to make
- clear that these are extensions for GNU, the next bytes gives the
- GNU protection mode - 1000. Defined modes are:
- - 1001 :: Do not store the secret part at all.
- - 1002 :: A stub to access smartcards (not used in 1.2.x)
+ 1 octet - S2K Usage: either 254 or 255.
+ 1 octet - S2K Cipher Algo: 0
+ 1 octet - S2K Specifier: 101
+ 3 octets - "GNU"
+ 1 octet - GNU S2K Extension Number.
+
+ If such a GNU extension is used neither an IV nor any kind of
+ checksum is used. The defined GNU S2K Extension Numbers are:
+
+ - 1 :: Do not store the secret part at all. No specific data
+ follows.
+
+ - 2 :: A stub to access smartcards. This data follows:
+ - One octet with the length of the following serial number.
+ - The serial number. Regardless of what the length octet
+ indicates no more than 16 octets are stored.
+
+ Note that gpg stores the GNU S2K Extension Number internally as an
+ S2K Specifier with an offset of 1000.
+
* Keyserver helper message format
diff --git a/doc/FAQ b/doc/FAQ
index 32d0744..309788c 100644
--- a/doc/FAQ
+++ b/doc/FAQ
@@ -3,11 +3,11 @@ GnuPG Frequently Asked Questions
A FAQ is a fast moving target and thus we don't distribute it anymore
with GnuPG. You may retrieve the current FAQ in HTML format at
- http://www.gnupg.org/faq/GnuPG-FAQ.html
+ https://gnupg.org/faq/gnupg-faq.html
-or in plain text format at the FTP server:
+or in plain text format at
- ftp://ftp.gnupg.org/gcrypt/gnupg/GnuPG-FAQ.txt
+ https://gnupg.org/faq/gnupg-faq.txt
diff --git a/doc/Makefile.am b/doc/Makefile.am
index a308444..240bcf3 100644
--- a/doc/Makefile.am
+++ b/doc/Makefile.am
@@ -75,7 +75,7 @@ man_MANS = $(myman_pages) gnupg.7
watchgnupg_SOURCE = gnupg.texi
-CLEANFILES = yat2m faq.txt faq.html
+CLEANFILES = yat2m
DISTCLEANFILES = gnupg.tmp gnupg.ops yat2m-stamp.tmp yat2m-stamp \
$(myman_pages) gnupg.7
@@ -139,24 +139,3 @@ online: gnupg.html gnupg.pdf
cd gnupg.html ; \
rsync -vr --exclude='.git' . \
$${user}@$${webhost}:webspace/manuals/gnupg$${dashdevel}/
-
-# Note that you need a recent version of emacs23 with org-mode 7.01h
-faq.txt faq.html: faq.org
- @set -e; expopt="t nil nil nil \"$$(pwd)\""; \
- emacs --batch \
- --eval "(require 'org)" \
- --visit "$(srcdir)/faq.org" \
- --eval "(setq org-export-ascii-entities 'utf8)" \
- --eval "(org-export-as-ascii org-export-headline-levels $${expopt})"\
- --visit "$(srcdir)/faq.org" \
- --eval "(setq org-export-html-style-include-default nil)" \
- --eval "(setq org-export-html-style-include-scripts nil)" \
- --eval "(org-export-as-html org-export-headline-levels $${expopt})"
-
-faq-online: faq.txt faq.html
- set -e; \
- user=werner ; webhost="ftp.gnupg.org" ; ftphost="ftp.gnupg.org" ; \
- echo "Uploading current FAQ to {www,ftp}.gnupg.org ..."; \
- scp faq.html $${user}@$${webhost}:webspace/manuals/GnuPG-FAQ.html ; \
- scp faq.txt $${user}@$${ftphost}:gcrypt/gnupg/GnuPG-FAQ.txt ; \
- echo "...ready"
diff --git a/doc/dirmngr.texi b/doc/dirmngr.texi
index 5f2cfd4..6c413de 100644
--- a/doc/dirmngr.texi
+++ b/doc/dirmngr.texi
@@ -143,9 +143,8 @@ running mode:
@table @asis
@item With @code{--daemon} given on the commandline
-the directory named @file{/etc/gnupg} for configuration files,
-@file{/var/lib/gnupg/} for extra data and @file{/var/cache/gnupg}
-for cached CRLs.
+the directory named @file{/etc/gnupg} is used for configuration files
+and @file{/var/cache/gnupg} for cached CRLs.
@item Without @code{--daemon} given on the commandline
the directory named @file{.gnupg} directly below the home directory
@@ -428,11 +427,9 @@ Dirmngr makes use of several directories when running in daemon mode:
The first is the standard home directory for all configuration files.
In the deprecated system daemon mode the second directory is used instead.
-@item ~/.gnupg/trusted-certs
-@itemx /etc/gnupg/trusted-certs
-The first directory should be filled with certificates of Root CAs you
-are trusting in checking the CRLs and signing OCSP Reponses. The
-second directory is used in the deprecated systems daemon mode.
+@item /etc/gnupg/trusted-certs
+This directory should be filled with certificates of Root CAs you
+are trusting in checking the CRLs and signing OCSP Reponses.
Usually these are the same certificates you use with the applications
making use of dirmngr. It is expected that each of these certificate
@@ -442,20 +439,22 @@ those certificates on startup and when given a SIGHUP. Certificates
which are not readable or do not make up a proper X.509 certificate
are ignored; see the log file for details.
+Applications using dirmngr (e.g. gpgsm) can request these
+certificates to complete a trust chain in the same way as with the
+extra-certs directory (see below).
+
Note that for OCSP responses the certificate specified using the option
@option{--ocsp-signer} is always considered valid to sign OCSP requests.
-
-@item ~/.gnupg/extra-certs
-@itemx /var/lib/gnupg/extra-certs
-The first directory may contain extra certificates which are preloaded
-into the interal cache on startup.This is convenient in cases you have
-a couple intermediate CA certificates or certificates ususally used to
-sign OCSP reponses. These certificates are first tried before going
+@item /etc/gnupg/extra-certs
+This directory may contain extra certificates which are preloaded
+into the interal cache on startup. Applications using dirmngr (e.g. gpgsm)
+can request cached certificates to complete a trust chain.
+This is convenient in cases you have a couple intermediate CA certificates
+or certificates ususally used to sign OCSP reponses.
+These certificates are first tried before going
out to the net to look for them. These certificates must also be
@acronym{DER} encoded and suffixed with @file{.crt} or @file{.der}.
-The second directory is used instead in the deprecated systems daemon
-mode.
@item /var/run/gnupg
This directory is only used in the deprecated system daemon mode. It
diff --git a/doc/gpg-agent.texi b/doc/gpg-agent.texi
index 84a7d60..3e77909 100644
--- a/doc/gpg-agent.texi
+++ b/doc/gpg-agent.texi
@@ -295,7 +295,7 @@ debugger.
@item --debug-quick-random
@opindex debug-quick-random
-This option inhibits the use the very secure random quality level
+This option inhibits the use of the very secure random quality level
(Libgcrypt’s @code{GCRY_VERY_STRONG_RANDOM}) and degrades all request
down to standard random quality. It is only used for testing and
shall not be used for any production quality keys. This option is
@@ -485,11 +485,14 @@ debugging purposes.
@item --use-standard-socket
@itemx --no-use-standard-socket
+@itemx --use-standard-socket-p
@opindex use-standard-socket
@opindex no-use-standard-socket
+@opindex use-standard-socket-p
@ifset gpgtwoone
Since GnuPG 2.1 the standard socket is always used. These options
-have no more effect.
+have no more effect. The command @code{gpg-agent
+--use-standard-socket-p} will thus always return success.
@end ifset
@ifclear gpgtwoone
By enabling this option @command{gpg-agent} will listen on the socket
diff --git a/doc/gpg.texi b/doc/gpg.texi
index 77df55c..393cf24 100644
--- a/doc/gpg.texi
+++ b/doc/gpg.texi
@@ -333,8 +333,9 @@ listed too.
@item --list-packets
@opindex list-packets
-List only the sequence of packets. This is mainly
-useful for debugging.
+List only the sequence of packets. This is mainly useful for
+debugging. When used with option @option{--verbose} the actual MPI
+values are dumped and not only their lengths.
@item --card-edit
@@ -2019,7 +2020,7 @@ opposite meaning. The options are:
generally useful unless a shared keyring scheme is being used.
Defaults to no.
- @item import-keep-ownertrust
+ @item keep-ownertrust
Normally possible still existing ownertrust values of a key are
cleared if a key is imported. This is in general desirable so that
a formerly deleted key does not automatically gain an ownertrust
@@ -2114,6 +2115,13 @@ as it is easily machine parsed. The details of this format are
documented in the file @file{doc/DETAILS}, which is included in the GnuPG
source distribution.
+
+@item --print-pka-records
+@opindex print-pka-records
+Modify the output of the list commands to print PKA records suitable
+to put into DNS zone files. An ORIGIN line is printed before each
+record to allow diverting the records to the corresponding zone file.
+
@item --fixed-list-mode
@opindex fixed-list-mode
Do not merge primary user ID and primary key in @option{--with-colon}
@@ -2136,6 +2144,11 @@ Same as the command @option{--fingerprint} but changes only the format
of the output and may be used together with another command.
@ifset gpgtwoone
+
+@item --with-icao-spelling
+@opindex with-icao-spelling
+Print the ICAO spelling of the fingerprint in addition to the hex digits.
+
@item --with-keygrip
@opindex with-keygrip
Include the keygrip in the key listings.
@@ -2438,6 +2451,11 @@ be given in C syntax (e.g. 0x0042).
@opindex debug-all
Set all useful debugging flags.
+@item --debug-iolbf
+@opindex debug-iolbf
+Set stdout into line buffered mode. This option is only honored when
+given on the command line.
+
@item --faked-system-time @var{epoch}
@opindex faked-system-time
This option is only useful for testing; it sets the system time back or
@@ -2940,6 +2958,10 @@ source distribution for the details of which configuration items may be
listed. @option{--list-config} is only usable with
@option{--with-colons} set.
+@item --list-gcrypt-config
+@opindex list-gcrypt-config
+Display various internal configuration parameters of Libgcrypt.
+
@item --gpgconf-list
@opindex gpgconf-list
This command is similar to @option{--list-config} but in general only
diff --git a/doc/gpgsm.texi b/doc/gpgsm.texi
index dcfe292..9f16f82 100644
--- a/doc/gpgsm.texi
+++ b/doc/gpgsm.texi
@@ -622,7 +622,7 @@ certificates starting with the signer cert. The default is -2.
Use the cipher algorithm with the ASN.1 object identifier @var{oid} for
encryption. For convenience the strings @code{3DES}, @code{AES} and
@code{AES256} may be used instead of their OIDs. The default is
-@code{3DES} (1.2.840.113549.3.7).
+@code{AES} (2.16.840.1.101.3.4.1.2).
@item --digest-algo @code{name}
Use @code{name} as the message digest algorithm. Usually this
@@ -1144,7 +1144,7 @@ keygrip with a @samp{&}.
Use @var{hash-algo} for this CSR or certificate. The supported hash
algorithms are: @samp{sha1}, @samp{sha256}, @samp{sha384} and
@samp{sha512}; they may also be specified with uppercase letters. The
-default is @samp{sha1}.
+default is @samp{sha256}.
@end table
diff --git a/g10/Makefile.am b/g10/Makefile.am
index 0a02119..b66abb8 100644
--- a/g10/Makefile.am
+++ b/g10/Makefile.am
@@ -21,8 +21,7 @@
EXTRA_DIST = options.skel distsigkey.gpg ChangeLog-2011 gpg-w32info.rc \
gpg.w32-manifest.in
-AM_CPPFLAGS = -I$(top_srcdir)/gl -I$(top_srcdir)/common \
- -I$(top_srcdir)/include -I$(top_srcdir)/intl
+AM_CPPFLAGS = -I$(top_srcdir)/common
include $(top_srcdir)/am/cmacros.am
diff --git a/g10/build-packet.c b/g10/build-packet.c
index e44350e..269c63c 100644
--- a/g10/build-packet.c
+++ b/g10/build-packet.c
@@ -164,14 +164,32 @@ gpg_mpi_write (iobuf_t out, gcry_mpi_t a)
if (gcry_mpi_get_flag (a, GCRYMPI_FLAG_OPAQUE))
{
unsigned int nbits;
- const void *p;
- unsigned int lenhdr[2];
+ const unsigned char *p;
+ unsigned char lenhdr[2];
+ /* gcry_log_debugmpi ("a", a); */
p = gcry_mpi_get_opaque (a, &nbits);
+ if (p)
+ {
+ /* Strip leading zero bits. */
+ for (; nbits >= 8 && !*p; p++, nbits -= 8)
+ ;
+ if (nbits >= 8 && !(*p & 0x80))
+ if (--nbits >= 7 && !(*p & 0x40))
+ if (--nbits >= 6 && !(*p & 0x20))
+ if (--nbits >= 5 && !(*p & 0x10))
+ if (--nbits >= 4 && !(*p & 0x08))
+ if (--nbits >= 3 && !(*p & 0x04))
+ if (--nbits >= 2 && !(*p & 0x02))
+ if (--nbits >= 1 && !(*p & 0x01))
+ --nbits;
+ }
+ /* gcry_log_debug (" [%u bit]\n", nbits); */
+ /* gcry_log_debughex (" ", p, (nbits+7)/8); */
lenhdr[0] = nbits >> 8;
lenhdr[1] = nbits;
rc = iobuf_write (out, lenhdr, 2);
- if (!rc)
+ if (!rc && p)
rc = iobuf_write (out, p, (nbits+7)/8);
}
else
@@ -209,7 +227,7 @@ gpg_mpi_write_nohdr (iobuf_t out, gcry_mpi_t a)
const void *p;
p = gcry_mpi_get_opaque (a, &nbits);
- rc = iobuf_write (out, p, (nbits+7)/8);
+ rc = p ? iobuf_write (out, p, (nbits+7)/8) : 0;
}
else
rc = gpg_error (GPG_ERR_BAD_MPI);
@@ -393,7 +411,8 @@ do_key (iobuf_t out, int ctb, PKT_public_key *pk)
assert (gcry_mpi_get_flag (pk->pkey[npkey], GCRYMPI_FLAG_OPAQUE));
p = gcry_mpi_get_opaque (pk->pkey[npkey], &ndatabits);
- iobuf_write (a, p, (ndatabits+7)/8 );
+ if (p)
+ iobuf_write (a, p, (ndatabits+7)/8 );
}
else
{
diff --git a/g10/call-agent.c b/g10/call-agent.c
index 4bac8a0..017e916 100644
--- a/g10/call-agent.c
+++ b/g10/call-agent.c
@@ -43,10 +43,6 @@
#include "../common/shareddefs.h"
#include "host2net.h"
-#ifndef DBG_ASSUAN
-# define DBG_ASSUAN 1
-#endif
-
#define CONTROL_D ('D' - 'A' + 1)
@@ -286,7 +282,7 @@ start_agent (ctrl_t ctrl, int for_card)
opt.agent_program,
opt.lc_ctype, opt.lc_messages,
opt.session_env,
- opt.autostart, opt.verbose, DBG_ASSUAN,
+ opt.autostart, opt.verbose, DBG_IPC,
NULL, NULL);
if (!opt.autostart && gpg_err_code (rc) == GPG_ERR_NO_AGENT)
{
@@ -673,7 +669,7 @@ learn_status_cb (void *opaque, const char *line)
/* Call the scdaemon to learn about a smartcard */
int
-agent_scd_learn (struct agent_card_info_s *info)
+agent_scd_learn (struct agent_card_info_s *info, int force)
{
int rc;
struct default_inq_parm_s parm;
@@ -701,7 +697,8 @@ agent_scd_learn (struct agent_card_info_s *info)
return rc;
parm.ctx = agent_ctx;
- rc = assuan_transact (agent_ctx, "LEARN --sendinfo",
+ rc = assuan_transact (agent_ctx,
+ force ? "LEARN --sendinfo --force" : "LEARN --sendinfo",
dummy_data_cb, NULL, default_inq_cb, &parm,
learn_status_cb, info);
/* Also try to get the key attributes. */
diff --git a/g10/call-agent.h b/g10/call-agent.h
index 9c104e8..df570a4 100644
--- a/g10/call-agent.h
+++ b/g10/call-agent.h
@@ -77,7 +77,7 @@ struct agent_card_genkey_s {
void agent_release_card_info (struct agent_card_info_s *info);
/* Return card info. */
-int agent_scd_learn (struct agent_card_info_s *info);
+int agent_scd_learn (struct agent_card_info_s *info, int force);
/* Send an APDU to the card. */
gpg_error_t agent_scd_apdu (const char *hexapdu, unsigned int *r_sw);
diff --git a/g10/call-dirmngr.c b/g10/call-dirmngr.c
index b802f81..ef4ca76 100644
--- a/g10/call-dirmngr.c
+++ b/g10/call-dirmngr.c
@@ -1,5 +1,6 @@
/* call-dirmngr.c - GPG operations to the Dirmngr.
* Copyright (C) 2011 Free Software Foundation, Inc.
+ * Copyright (C) 2015 g10 Code GmbH
*
* This file is part of GnuPG.
*
@@ -130,7 +131,7 @@ create_context (ctrl_t ctrl, assuan_context_t *r_ctx)
GPG_ERR_SOURCE_DEFAULT,
opt.homedir,
opt.dirmngr_program,
- opt.autostart, opt.verbose, DBG_ASSUAN,
+ opt.autostart, opt.verbose, DBG_IPC,
NULL /*gpg_status2*/, ctrl);
if (!opt.autostart && gpg_err_code (err) == GPG_ERR_NO_DIRMNGR)
{
@@ -585,6 +586,117 @@ gpg_dirmngr_ks_fetch (ctrl_t ctrl, const char *url, estream_t *r_fp)
+static void
+record_output (estream_t output,
+ pkttype_t type,
+ const char *validity,
+ /* The public key length or -1. */
+ int pub_key_length,
+ /* The public key algo or -1. */
+ int pub_key_algo,
+ /* 2 ulongs or NULL. */
+ const u32 *keyid,
+ /* The creation / expiration date or 0. */
+ u32 creation_date,
+ u32 expiration_date,
+ const char *userid)
+{
+ const char *type_str = NULL;
+ char *pub_key_length_str = NULL;
+ char *pub_key_algo_str = NULL;
+ char *keyid_str = NULL;
+ char *creation_date_str = NULL;
+ char *expiration_date_str = NULL;
+ char *userid_escaped = NULL;
+
+ switch (type)
+ {
+ case PKT_PUBLIC_KEY:
+ type_str = "pub";
+ break;
+ case PKT_PUBLIC_SUBKEY:
+ type_str = "sub";
+ break;
+ case PKT_USER_ID:
+ type_str = "uid";
+ break;
+ case PKT_SIGNATURE:
+ type_str = "sig";
+ break;
+ default:
+ assert (! "Unhandled type.");
+ }
+
+ if (pub_key_length > 0)
+ pub_key_length_str = xasprintf ("%d", pub_key_length);
+
+ if (pub_key_algo != -1)
+ pub_key_algo_str = xasprintf ("%d", pub_key_algo);
+
+ if (keyid)
+ keyid_str = xasprintf ("%08lX%08lX", (ulong) keyid[0], (ulong) keyid[1]);
+
+ if (creation_date)
+ creation_date_str = xstrdup (colon_strtime (creation_date));
+
+ if (expiration_date)
+ expiration_date_str = xstrdup (colon_strtime (expiration_date));
+
+ /* Quote ':', '%', and any 8-bit characters. */
+ if (userid)
+ {
+ int r;
+ int w = 0;
+
+ int len = strlen (userid);
+ /* A 100k character limit on the uid should be way more than
+ enough. */
+ if (len > 100 * 1024)
+ len = 100 * 1024;
+
+ /* The minimum amount of space that we need. */
+ userid_escaped = xmalloc (len * 3 + 1);
+
+ for (r = 0; r < len; r++)
+ {
+ if (userid[r] == ':' || userid[r]== '%' || (userid[r] & 0x80))
+ {
+ sprintf (&userid_escaped[w], "%%%02X", (byte) userid[r]);
+ w += 3;
+ }
+ else
+ userid_escaped[w ++] = userid[r];
+ }
+ userid_escaped[w] = '\0';
+ }
+
+ es_fprintf (output, "%s:%s:%s:%s:%s:%s:%s:%s:%s:%s:%s:%s:%s:%s:%s:%s:%s\n",
+ type_str,
+ validity ?: "",
+ pub_key_length_str ?: "",
+ pub_key_algo_str ?: "",
+ keyid_str ?: "",
+ creation_date_str ?: "",
+ expiration_date_str ?: "",
+ "" /* Certificate S/N */,
+ "" /* Ownertrust. */,
+ userid_escaped ?: "",
+ "" /* Signature class. */,
+ "" /* Key capabilities. */,
+ "" /* Issuer certificate fingerprint. */,
+ "" /* Flag field. */,
+ "" /* S/N of a token. */,
+ "" /* Hash algo. */,
+ "" /* Curve name. */);
+
+ xfree (userid_escaped);
+ xfree (expiration_date_str);
+ xfree (creation_date_str);
+ xfree (keyid_str);
+ xfree (pub_key_algo_str);
+ xfree (pub_key_length_str);
+}
+
/* Handle the KS_PUT inquiries. */
static gpg_error_t
ks_put_inq_cb (void *opaque, const char *line)
@@ -607,53 +719,80 @@ ks_put_inq_cb (void *opaque, const char *line)
if (!fp)
err = gpg_error_from_syserror ();
+ /* Note: the output format for the INFO block follows the colon
+ format as described in doc/DETAILS. We don't actually reuse
+ the functionality from g10/keylist.c to produce the output,
+ because we don't need all of it and some of it is quite
+ expensive to generate.
+
+ The fields are (the starred fields are the ones we need):
+
+ * Field 1 - Type of record
+ * Field 2 - Validity
+ * Field 3 - Key length
+ * Field 4 - Public key algorithm
+ * Field 5 - KeyID
+ * Field 6 - Creation date
+ * Field 7 - Expiration date
+ Field 8 - Certificate S/N, UID hash, trust signature info
+ Field 9 - Ownertrust
+ * Field 10 - User-ID
+ Field 11 - Signature class
+ Field 12 - Key capabilities
+ Field 13 - Issuer certificate fingerprint or other info
+ Field 14 - Flag field
+ Field 15 - S/N of a token
+ Field 16 - Hash algorithm
+ Field 17 - Curve name
+ */
for (node = parm->keyblock; !err && node; node=node->next)
{
- switch(node->pkt->pkttype)
+ switch (node->pkt->pkttype)
{
case PKT_PUBLIC_KEY:
case PKT_PUBLIC_SUBKEY:
{
PKT_public_key *pk = node->pkt->pkt.public_key;
+ char validity[3];
+ int i;
+
+ i = 0;
+ if (pk->flags.revoked)
+ validity[i ++] = 'r';
+ if (pk->has_expired)
+ validity[i ++] = 'e';
+ validity[i] = '\0';
+
keyid_from_pk (pk, NULL);
- es_fprintf (fp, "%s:%08lX%08lX:%u:%u:%u:%u:%s%s:\n",
- node->pkt->pkttype==PKT_PUBLIC_KEY? "pub" : "sub",
- (ulong)pk->keyid[0], (ulong)pk->keyid[1],
- pk->pubkey_algo,
- nbits_from_pk (pk),
- pk->timestamp,
- pk->expiredate,
- pk->flags.revoked? "r":"",
- pk->has_expired? "e":"");
+ record_output (fp, node->pkt->pkttype, validity,
+ nbits_from_pk (pk), pk->pubkey_algo,
+ pk->keyid, pk->timestamp, pk->expiredate,
+ NULL);
}
break;
case PKT_USER_ID:
{
PKT_user_id *uid = node->pkt->pkt.user_id;
- int r;
if (!uid->attrib_data)
{
- es_fprintf (fp, "uid:");
-
- /* Quote ':', '%', and any 8-bit characters. */
- for (r=0; r < uid->len; r++)
- {
- if (uid->name[r] == ':'
- || uid->name[r]== '%'
- || (uid->name[r]&0x80))
- es_fprintf (fp, "%%%02X", (byte)uid->name[r]);
- else
- es_putc (uid->name[r], fp);
- }
-
- es_fprintf (fp, ":%u:%u:%s%s:\n",
- uid->created,uid->expiredate,
- uid->is_revoked? "r":"",
- uid->is_expired? "e":"");
+ char validity[3];
+ int i;
+
+ i = 0;
+ if (uid->is_revoked)
+ validity[i ++] = 'r';
+ if (uid->is_expired)
+ validity[i ++] = 'e';
+ validity[i] = '\0';
+
+ record_output (fp, node->pkt->pkttype, validity,
+ -1, -1, NULL,
+ uid->created, uid->expiredate,
+ uid->name);
}
}
break;
@@ -667,12 +806,9 @@ ks_put_inq_cb (void *opaque, const char *line)
PKT_signature *sig = node->pkt->pkt.signature;
if (IS_UID_SIG (sig))
- {
- es_fprintf (fp, "sig:%08lX%08lX:%X:%u:%u:\n",
- (ulong)sig->keyid[0],(ulong)sig->keyid[1],
- sig->sig_class, sig->timestamp,
- sig->expiredate);
- }
+ record_output (fp, node->pkt->pkttype, NULL,
+ -1, -1, sig->keyid,
+ sig->timestamp, sig->expiredate, NULL);
}
break;
diff --git a/g10/card-util.c b/g10/card-util.c
index 4b584bf..a291a07 100644
--- a/g10/card-util.c
+++ b/g10/card-util.c
@@ -81,7 +81,7 @@ change_pin (int unblock_v2, int allow_admin)
struct agent_card_info_s info;
int rc;
- rc = agent_scd_learn (&info);
+ rc = agent_scd_learn (&info, 0);
if (rc)
{
log_error (_("OpenPGP card not available: %s\n"),
@@ -374,7 +374,7 @@ card_status (estream_t fp, char *serialno, size_t serialnobuflen)
if (serialno && serialnobuflen)
*serialno = 0;
- rc = agent_scd_learn (&info);
+ rc = agent_scd_learn (&info, 0);
if (rc)
{
if (opt.with_colons)
@@ -1702,7 +1702,7 @@ factory_reset (void)
but tries to find out something about the card first.
*/
- err = agent_scd_learn (&info);
+ err = agent_scd_learn (&info, 0);
if (gpg_err_code (err) == GPG_ERR_OBJ_TERM_STATE
&& gpg_err_source (err) == GPG_ERR_SOURCE_SCD)
termstate = 1;
diff --git a/g10/ecdh.c b/g10/ecdh.c
index 07f3983..9576a1c 100644
--- a/g10/ecdh.c
+++ b/g10/ecdh.c
@@ -76,7 +76,7 @@ pk_ecdh_default_params (unsigned int qbits)
}
}
assert (i < DIM (kek_params_table));
- if (DBG_CIPHER)
+ if (DBG_CRYPTO)
log_printhex ("ECDH KEK params are", kek_params, sizeof(kek_params) );
return gcry_mpi_set_opaque (NULL, kek_params, 4 * 8);
@@ -138,7 +138,7 @@ pk_ecdh_encrypt_with_shared_point (int is_encrypt, gcry_mpi_t shared_mpi,
memmove (secret_x, secret_x+1, secret_x_size);
memset (secret_x+secret_x_size, 0, nbytes-secret_x_size);
- if (DBG_CIPHER)
+ if (DBG_CRYPTO)
log_printhex ("ECDH shared secret X is:", secret_x, secret_x_size );
}
@@ -158,7 +158,7 @@ pk_ecdh_encrypt_with_shared_point (int is_encrypt, gcry_mpi_t shared_mpi,
kek_params = gcry_mpi_get_opaque (pkey[2], &nbits);
kek_params_size = (nbits+7)/8;
- if (DBG_CIPHER)
+ if (DBG_CRYPTO)
log_printhex ("ecdh KDF params:", kek_params, kek_params_size);
/* Expect 4 bytes 03 01 hash_alg symm_alg. */
@@ -171,7 +171,7 @@ pk_ecdh_encrypt_with_shared_point (int is_encrypt, gcry_mpi_t shared_mpi,
kdf_hash_algo = kek_params[2];
kdf_encr_algo = kek_params[3];
- if (DBG_CIPHER)
+ if (DBG_CRYPTO)
log_debug ("ecdh KDF algorithms %s+%s with aeswrap\n",
openpgp_md_algo_name (kdf_hash_algo),
openpgp_cipher_algo_name (kdf_encr_algo));
@@ -215,7 +215,7 @@ pk_ecdh_encrypt_with_shared_point (int is_encrypt, gcry_mpi_t shared_mpi,
return err;
}
- if(DBG_CIPHER)
+ if(DBG_CRYPTO)
log_printhex ("ecdh KDF message params are:", message, message_size);
}
@@ -251,7 +251,7 @@ pk_ecdh_encrypt_with_shared_point (int is_encrypt, gcry_mpi_t shared_mpi,
/* We could have allocated more, so clean the tail before returning. */
memset (secret_x+secret_x_size, 0, old_size - secret_x_size);
- if (DBG_CIPHER)
+ if (DBG_CRYPTO)
log_printhex ("ecdh KEK is:", secret_x, secret_x_size );
}
@@ -317,7 +317,7 @@ pk_ecdh_encrypt_with_shared_point (int is_encrypt, gcry_mpi_t shared_mpi,
return err;
}
- if (DBG_CIPHER)
+ if (DBG_CRYPTO)
log_printhex ("ecdh encrypting :", in, data_buf_size );
err = gcry_cipher_encrypt (hd, data_buf+1, data_buf_size+8,
@@ -333,7 +333,7 @@ pk_ecdh_encrypt_with_shared_point (int is_encrypt, gcry_mpi_t shared_mpi,
}
data_buf[0] = data_buf_size+8;
- if (DBG_CIPHER)
+ if (DBG_CRYPTO)
log_printhex ("ecdh encrypted to:", data_buf+1, data_buf[0] );
result = gcry_mpi_set_opaque (NULL, data_buf, 8 * (1+data_buf[0]));
@@ -370,7 +370,7 @@ pk_ecdh_encrypt_with_shared_point (int is_encrypt, gcry_mpi_t shared_mpi,
in = data_buf+data_buf_size;
data_buf_size = data_buf[0];
- if (DBG_CIPHER)
+ if (DBG_CRYPTO)
log_printhex ("ecdh decrypting :", data_buf+1, data_buf_size);
err = gcry_cipher_decrypt (hd, in, data_buf_size, data_buf+1,
@@ -386,7 +386,7 @@ pk_ecdh_encrypt_with_shared_point (int is_encrypt, gcry_mpi_t shared_mpi,
data_buf_size -= 8;
- if (DBG_CIPHER)
+ if (DBG_CRYPTO)
log_printhex ("ecdh decrypted to :", in, data_buf_size);
/* Padding is removed later. */
@@ -420,12 +420,12 @@ gen_k (unsigned nbits)
gcry_mpi_t k;
k = gcry_mpi_snew (nbits);
- if (DBG_CIPHER)
+ if (DBG_CRYPTO)
log_debug ("choosing a random k of %u bits\n", nbits);
gcry_mpi_randomize (k, nbits-1, GCRY_STRONG_RANDOM);
- if (DBG_CIPHER)
+ if (DBG_CRYPTO)
{
unsigned char *buffer;
if (gcry_mpi_aprint (GCRYMPI_FMT_HEX, &buffer, NULL, k))
diff --git a/g10/encrypt.c b/g10/encrypt.c
index 8d2b325..d5835d4 100644
--- a/g10/encrypt.c
+++ b/g10/encrypt.c
@@ -453,6 +453,9 @@ write_symkey_enc (STRING2KEY *symkey_s2k, DEK *symkey_dek, DEK *dek,
* supplied). Either FILENAME or FILEFD must be given, but not both.
* The caller may provide a checked list of public keys in
* PROVIDED_PKS; if not the function builds a list of keys on its own.
+ *
+ * Note that FILEFD is currently only used by cmd_encrypt in the the
+ * not yet finished server.c.
*/
int
encrypt_crypt (ctrl_t ctrl, int filefd, const char *filename,
@@ -476,7 +479,7 @@ encrypt_crypt (ctrl_t ctrl, int filefd, const char *filename,
int do_compress;
if (filefd != -1 && filename)
- return gpg_error (GPG_ERR_INV_ARG);
+ return gpg_error (GPG_ERR_INV_ARG); /* Both given. */
do_compress = !!opt.compress_algo;
@@ -618,7 +621,7 @@ encrypt_crypt (ctrl_t ctrl, int filefd, const char *filename,
}
make_session_key (cfx.dek);
- if (DBG_CIPHER)
+ if (DBG_CRYPTO)
log_printhex ("DEK is: ", cfx.dek->key, cfx.dek->keylen );
rc = write_pubkey_enc_from_list (pk_list, cfx.dek, out);
@@ -635,8 +638,9 @@ encrypt_crypt (ctrl_t ctrl, int filefd, const char *filename,
if (!opt.no_literal)
pt = setup_plaintext_name (filename, inp);
- if (filefd != -1
- && !iobuf_is_pipe_filename (filename) && *filename && !opt.textmode )
+ /* Get the size of the file if possible, i.e., if it is a real file. */
+ if (filename && *filename
+ && !iobuf_is_pipe_filename (filename) && !opt.textmode )
{
off_t tmpsize;
int overflow;
@@ -811,7 +815,7 @@ encrypt_filter (void *opaque, int control,
efx->cfx.dek->use_mdc = use_mdc (efx->pk_list,efx->cfx.dek->algo);
make_session_key ( efx->cfx.dek );
- if (DBG_CIPHER)
+ if (DBG_CRYPTO)
log_printhex ("DEK is: ", efx->cfx.dek->key, efx->cfx.dek->keylen);
rc = write_pubkey_enc_from_list (efx->pk_list, efx->cfx.dek, a);
diff --git a/g10/getkey.c b/g10/getkey.c
index 30c454b..20b37d8 100644
--- a/g10/getkey.c
+++ b/g10/getkey.c
@@ -37,7 +37,7 @@
#include "keyserver-internal.h"
#include "call-agent.h"
#include "host2net.h"
-
+#include "mbox-util.h"
#define MAX_PK_CACHE_ENTRIES PK_UID_CACHE_SIZE
#define MAX_UID_CACHE_ENTRIES PK_UID_CACHE_SIZE
@@ -116,7 +116,7 @@ print_stats ()
for (i = 0; i < DIM (lkup_stats); i++)
{
if (lkup_stats[i].any)
- fprintf (stderr,
+ es_fprintf (es_stderr,
"lookup stats: mode=%-2d ok=%-6d nokey=%-6d err=%-6d\n",
i,
lkup_stats[i].okay_count,
@@ -2373,7 +2373,7 @@ finish_lookup (GETKEY_CTX ctx)
}
}
- if (DBG_CACHE)
+ if (DBG_LOOKUP)
log_debug ("finish_lookup: checking key %08lX (%s)(req_usage=%x)\n",
(ulong) keyid_from_pk (keyblock->pkt->pkt.public_key, NULL),
foundk ? "one" : "all", req_usage);
@@ -2400,43 +2400,43 @@ finish_lookup (GETKEY_CTX ctx)
if (foundk)
nextk = NULL; /* what a hack */
pk = k->pkt->pkt.public_key;
- if (DBG_CACHE)
+ if (DBG_LOOKUP)
log_debug ("\tchecking subkey %08lX\n",
(ulong) keyid_from_pk (pk, NULL));
if (!pk->flags.valid)
{
- if (DBG_CACHE)
+ if (DBG_LOOKUP)
log_debug ("\tsubkey not valid\n");
continue;
}
if (pk->flags.revoked)
{
- if (DBG_CACHE)
+ if (DBG_LOOKUP)
log_debug ("\tsubkey has been revoked\n");
continue;
}
if (pk->has_expired)
{
- if (DBG_CACHE)
+ if (DBG_LOOKUP)
log_debug ("\tsubkey has expired\n");
continue;
}
if (pk->timestamp > curtime && !opt.ignore_valid_from)
{
- if (DBG_CACHE)
+ if (DBG_LOOKUP)
log_debug ("\tsubkey not yet valid\n");
continue;
}
if (!((pk->pubkey_usage & USAGE_MASK) & req_usage))
{
- if (DBG_CACHE)
+ if (DBG_LOOKUP)
log_debug ("\tusage does not match: want=%x have=%x\n",
req_usage, pk->pubkey_usage);
continue;
}
- if (DBG_CACHE)
+ if (DBG_LOOKUP)
log_debug ("\tsubkey might be fine\n");
/* In case a key has a timestamp of 0 set, we make sure
that it is used. A better change would be to compare
@@ -2455,33 +2455,33 @@ finish_lookup (GETKEY_CTX ctx)
if ((!latest_key && !(ctx->exact && foundk != keyblock)) || req_prim)
{
PKT_public_key *pk;
- if (DBG_CACHE && !foundk && !req_prim)
+ if (DBG_LOOKUP && !foundk && !req_prim)
log_debug ("\tno suitable subkeys found - trying primary\n");
pk = keyblock->pkt->pkt.public_key;
if (!pk->flags.valid)
{
- if (DBG_CACHE)
+ if (DBG_LOOKUP)
log_debug ("\tprimary key not valid\n");
}
else if (pk->flags.revoked)
{
- if (DBG_CACHE)
+ if (DBG_LOOKUP)
log_debug ("\tprimary key has been revoked\n");
}
else if (pk->has_expired)
{
- if (DBG_CACHE)
+ if (DBG_LOOKUP)
log_debug ("\tprimary key has expired\n");
}
else if (!((pk->pubkey_usage & USAGE_MASK) & req_usage))
{
- if (DBG_CACHE)
+ if (DBG_LOOKUP)
log_debug ("\tprimary key usage does not match: "
"want=%x have=%x\n", req_usage, pk->pubkey_usage);
}
else /* Okay. */
{
- if (DBG_CACHE)
+ if (DBG_LOOKUP)
log_debug ("\tprimary key may be used\n");
latest_key = keyblock;
latest_date = pk->timestamp;
@@ -2490,13 +2490,13 @@ finish_lookup (GETKEY_CTX ctx)
if (!latest_key)
{
- if (DBG_CACHE)
+ if (DBG_LOOKUP)
log_debug ("\tno suitable key found - giving up\n");
return 0; /* Not found. */
}
found:
- if (DBG_CACHE)
+ if (DBG_LOOKUP)
log_debug ("\tusing key %08lX\n",
(ulong) keyid_from_pk (latest_key->pkt->pkt.public_key, NULL));
@@ -2525,6 +2525,29 @@ found:
}
+/* Return true if all the search modes are fingerprints. */
+static int
+search_modes_are_fingerprint (getkey_ctx_t ctx)
+{
+ size_t n, found;
+
+ for (n=found=0; n < ctx->nitems; n++)
+ {
+ switch (ctx->items[n].mode)
+ {
+ case KEYDB_SEARCH_MODE_FPR16:
+ case KEYDB_SEARCH_MODE_FPR20:
+ case KEYDB_SEARCH_MODE_FPR:
+ found++;
+ break;
+ default:
+ break;
+ }
+ }
+ return found && found == ctx->nitems;
+}
+
+
/* The main function to lookup a key. On success the found keyblock
is stored at RET_KEYBLOCK and also in CTX. If WANT_SECRET is true
a corresponding secret key is required. */
@@ -2534,9 +2557,21 @@ lookup (getkey_ctx_t ctx, kbnode_t *ret_keyblock, int want_secret)
int rc;
int no_suitable_key = 0;
- rc = 0;
- while (!(rc = keydb_search (ctx->kr_handle, ctx->items, ctx->nitems, NULL)))
+ for (;;)
{
+ rc = keydb_search (ctx->kr_handle, ctx->items, ctx->nitems, NULL);
+ /* Skip over all legacy keys but only if they are not requested
+ by fingerprints.
+ Fixme: The lower level keydb code should actually do that but
+ then it would be harder to report the number of skipped
+ legacy keys during import. */
+ if (gpg_err_code (rc) == GPG_ERR_LEGACY_KEY
+ && !(ctx->nitems && ctx->items->mode == KEYDB_SEARCH_MODE_FIRST)
+ && !search_modes_are_fingerprint (ctx))
+ continue;
+ if (rc)
+ break;
+
/* If we are searching for the first key we have to make sure
that the next iteration does not do an implicit reset.
This can be triggered by an empty key ring. */
@@ -2719,34 +2754,69 @@ enum_secret_keys (void **context, PKT_public_key *sk)
/* Return a string with a printable representation of the user_id.
* this string must be freed by xfree. */
static char *
-get_user_id_string (u32 * keyid)
+get_user_id_string (u32 * keyid, int mode, size_t *r_len)
{
user_id_db_t r;
+ keyid_list_t a;
int pass = 0;
+ char *p;
+
/* Try it two times; second pass reads from key resources. */
do
{
for (r = user_id_db; r; r = r->next)
{
- keyid_list_t a;
for (a = r->keyids; a; a = a->next)
{
if (a->keyid[0] == keyid[0] && a->keyid[1] == keyid[1])
{
- return xasprintf ("%s %.*s", keystr (keyid), r->len, r->name);
+ if (mode == 2)
+ {
+ /* An empty string as user id is possible. Make
+ sure that the malloc allocates one byte and
+ does not bail out. */
+ p = xmalloc (r->len? r->len : 1);
+ memcpy (p, r->name, r->len);
+ if (r_len)
+ *r_len = r->len;
+ }
+ else
+ {
+ if (mode)
+ p = xasprintf ("%08lX%08lX %.*s",
+ (ulong) keyid[0], (ulong) keyid[1],
+ r->len, r->name);
+ else
+ p = xasprintf ("%s %.*s", keystr (keyid),
+ r->len, r->name);
+ if (r_len)
+ *r_len = strlen (p);
+ }
+
+ return p;
}
}
}
}
while (++pass < 2 && !get_pubkey (NULL, keyid));
- return xasprintf ("%s [?]", keystr (keyid));
+
+ if (mode == 2)
+ p = xstrdup (user_id_not_found_utf8 ());
+ else if (mode)
+ p = xasprintf ("%08lX%08lX [?]", (ulong) keyid[0], (ulong) keyid[1]);
+ else
+ p = xasprintf ("%s [?]", keystr (keyid));
+
+ if (r_len)
+ *r_len = strlen (p);
+ return p;
}
char *
get_user_id_string_native (u32 * keyid)
{
- char *p = get_user_id_string (keyid);
+ char *p = get_user_id_string (keyid, 0, NULL);
char *p2 = utf8_to_native (p, strlen (p), 0);
xfree (p);
return p2;
@@ -2756,65 +2826,18 @@ get_user_id_string_native (u32 * keyid)
char *
get_long_user_id_string (u32 * keyid)
{
- user_id_db_t r;
- keyid_list_t a;
- int pass = 0;
- /* Try it two times; second pass reads from key resources. */
- do
- {
- for (r = user_id_db; r; r = r->next)
- {
- for (a = r->keyids; a; a = a->next)
- {
- if (a->keyid[0] == keyid[0] && a->keyid[1] == keyid[1])
- {
- return xasprintf ("%08lX%08lX %.*s",
- (ulong) keyid[0], (ulong) keyid[1],
- r->len, r->name);
- }
- }
- }
- }
- while (++pass < 2 && !get_pubkey (NULL, keyid));
- return xasprintf ("%08lX%08lX [?]", (ulong) keyid[0], (ulong) keyid[1]);
+ return get_user_id_string (keyid, 1, NULL);
}
-/* Please try to use get_user_id_native instead of this one. */
+/* Please try to use get_user_byfpr instead of this one. */
char *
get_user_id (u32 * keyid, size_t * rn)
{
- user_id_db_t r;
- char *p;
- int pass = 0;
-
- /* Try it two times; second pass reads from key resources. */
- do
- {
- for (r = user_id_db; r; r = r->next)
- {
- keyid_list_t a;
- for (a = r->keyids; a; a = a->next)
- {
- if (a->keyid[0] == keyid[0] && a->keyid[1] == keyid[1])
- {
- /* An empty string as user id is possible. Make
- sure that the malloc allocates one byte and does
- not bail out. */
- p = xmalloc (r->len? r->len : 1);
- memcpy (p, r->name, r->len);
- *rn = r->len;
- return p;
- }
- }
- }
- }
- while (++pass < 2 && !get_pubkey (NULL, keyid));
- p = xstrdup (user_id_not_found_utf8 ());
- *rn = strlen (p);
- return p;
+ return get_user_id_string (keyid, 2, rn);
}
+
/* Please try to use get_user_id_byfpr_native instead of this one. */
char *
get_user_id_native (u32 * keyid)
@@ -2828,7 +2851,7 @@ get_user_id_native (u32 * keyid)
/* Return a user id from the caching by looking it up using the FPR
- which mustbe of size MAX_FINGERPRINT_LEN. */
+ which must be of size MAX_FINGERPRINT_LEN. */
char *
get_user_id_byfpr (const byte *fpr, size_t *rn)
{
@@ -2936,10 +2959,8 @@ parse_auto_key_locate (char *options)
else if (ascii_strcasecmp (tok, "cert") == 0)
akl->type = AKL_CERT;
#endif
-#ifdef USE_DNS_PKA
else if (ascii_strcasecmp (tok, "pka") == 0)
akl->type = AKL_PKA;
-#endif
else if ((akl->spec = parse_keyserver_uri (tok, 1)))
akl->type = AKL_SPEC;
else
diff --git a/g10/gpg.c b/g10/gpg.c
index 9a6b104..aec6e80 100644
--- a/g10/gpg.c
+++ b/g10/gpg.c
@@ -1,6 +1,7 @@
/* gpg.c - The GnuPG utility (main for gpg)
* Copyright (C) 1998-2011 Free Software Foundation, Inc.
* Copyright (C) 1997-2014 Werner Koch
+ * Copyright (C) 2015 g10 Code GmbH
*
* This file is part of GnuPG.
*
@@ -116,6 +117,7 @@ enum cmd_and_opt_values
aQuickSignKey,
aQuickLSignKey,
aListConfig,
+ aListGcryptConfig,
aGPGConfList,
aGPGConfTest,
aListPackets,
@@ -176,6 +178,7 @@ enum cmd_and_opt_values
oNoAskCertLevel,
oFingerprint,
oWithFingerprint,
+ oWithICAOSpelling,
oWithKeygrip,
oWithSecret,
oAnswerYes,
@@ -193,7 +196,7 @@ enum cmd_and_opt_values
oDebug,
oDebugLevel,
oDebugAll,
- oDebugCCIDDriver,
+ oDebugIOLBF,
oStatusFD,
oStatusFile,
oAttributeFD,
@@ -380,6 +383,7 @@ enum cmd_and_opt_values
oAllowWeakDigestAlgos,
oFakedSystemTime,
oNoAutostart,
+ oPrintPKARecords,
oNoop
};
@@ -446,6 +450,7 @@ static ARGPARSE_OPTS opts[] = {
ARGPARSE_c (aChangePIN, "change-pin", N_("change a card's PIN")),
#endif
ARGPARSE_c (aListConfig, "list-config", "@"),
+ ARGPARSE_c (aListGcryptConfig, "list-gcrypt-config", "@"),
ARGPARSE_c (aGPGConfList, "gpgconf-list", "@" ),
ARGPARSE_c (aGPGConfTest, "gpgconf-test", "@" ),
ARGPARSE_c (aListPackets, "list-packets","@"),
@@ -552,6 +557,7 @@ static ARGPARSE_OPTS opts[] = {
ARGPARSE_p_u (oDebug, "debug", "@"),
ARGPARSE_s_s (oDebugLevel, "debug-level", "@"),
ARGPARSE_s_n (oDebugAll, "debug-all", "@"),
+ ARGPARSE_s_n (oDebugIOLBF, "debug-iolbf", "@"),
ARGPARSE_s_i (oStatusFD, "status-fd", "@"),
ARGPARSE_s_s (oStatusFile, "status-file", "@"),
ARGPARSE_s_i (oAttributeFD, "attribute-fd", "@"),
@@ -692,6 +698,7 @@ static ARGPARSE_OPTS opts[] = {
ARGPARSE_s_n (oUtf8Strings, "utf8-strings", "@"),
ARGPARSE_s_n (oNoUtf8Strings, "no-utf8-strings", "@"),
ARGPARSE_s_n (oWithFingerprint, "with-fingerprint", "@"),
+ ARGPARSE_s_n (oWithICAOSpelling, "with-icao-spelling", "@"),
ARGPARSE_s_n (oWithKeygrip, "with-keygrip", "@"),
ARGPARSE_s_n (oWithSecret, "with-secret", "@"),
ARGPARSE_s_s (oDisableCipherAlgo, "disable-cipher-algo", "@"),
@@ -706,6 +713,7 @@ static ARGPARSE_OPTS opts[] = {
ARGPARSE_s_n (oFixedListMode, "fixed-list-mode", "@"),
ARGPARSE_s_n (oLegacyListMode, "legacy-list-mode", "@"),
ARGPARSE_s_n (oListOnly, "list-only", "@"),
+ ARGPARSE_s_n (oPrintPKARecords, "print-pka-records", "@"),
ARGPARSE_s_n (oIgnoreTimeConflict, "ignore-time-conflict", "@"),
ARGPARSE_s_n (oIgnoreValidFrom, "ignore-valid-from", "@"),
ARGPARSE_s_n (oIgnoreCrcError, "ignore-crc-error", "@"),
@@ -1038,7 +1046,7 @@ build_list (const char *text, char letter,
static void
wrong_args( const char *text)
{
- fprintf (stderr, _("usage: %s [options] %s\n"), GPG_NAME, text);
+ es_fprintf (es_stderr, _("usage: %s [options] %s\n"), GPG_NAME, text);
g10_exit(2);
}
@@ -1086,7 +1094,7 @@ set_debug (const char *level)
opt.debug = DBG_MEMSTAT_VALUE|DBG_TRUST_VALUE|DBG_EXTPROG_VALUE;
else if (!strcmp (level, "expert") || (numok && numlvl <= 8))
opt.debug = (DBG_MEMSTAT_VALUE|DBG_TRUST_VALUE|DBG_EXTPROG_VALUE
- |DBG_CACHE_VALUE|DBG_FILTER_VALUE|DBG_PACKET_VALUE);
+ |DBG_CACHE_VALUE|DBG_LOOKUP|DBG_FILTER_VALUE|DBG_PACKET_VALUE);
else if (!strcmp (level, "guru") || numok)
{
opt.debug = ~0;
@@ -1109,17 +1117,17 @@ set_debug (const char *level)
memory_stat_debug_mode = 1;
if (opt.debug & DBG_MPI_VALUE)
gcry_control (GCRYCTL_SET_DEBUG_FLAGS, 2);
- if (opt.debug & DBG_CIPHER_VALUE )
+ if (opt.debug & DBG_CRYPTO_VALUE )
gcry_control (GCRYCTL_SET_DEBUG_FLAGS, 1);
if (opt.debug & DBG_IOBUF_VALUE )
iobuf_debug_mode = 1;
gcry_control (GCRYCTL_SET_VERBOSITY, (int)opt.verbose);
if (opt.debug)
- log_info ("enabled debug flags:%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n",
+ log_info ("enabled debug flags:%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\n",
(opt.debug & DBG_PACKET_VALUE )? " packet":"",
(opt.debug & DBG_MPI_VALUE )? " mpi":"",
- (opt.debug & DBG_CIPHER_VALUE )? " cipher":"",
+ (opt.debug & DBG_CRYPTO_VALUE )? " crypto":"",
(opt.debug & DBG_FILTER_VALUE )? " filter":"",
(opt.debug & DBG_IOBUF_VALUE )? " iobuf":"",
(opt.debug & DBG_MEMORY_VALUE )? " memory":"",
@@ -1129,8 +1137,9 @@ set_debug (const char *level)
(opt.debug & DBG_HASHING_VALUE)? " hashing":"",
(opt.debug & DBG_EXTPROG_VALUE)? " extprog":"",
(opt.debug & DBG_CARD_IO_VALUE)? " cardio":"",
- (opt.debug & DBG_ASSUAN_VALUE )? " assuan":"",
- (opt.debug & DBG_CLOCK_VALUE )? " clock":"");
+ (opt.debug & DBG_IPC_VALUE )? " ipc":"",
+ (opt.debug & DBG_CLOCK_VALUE )? " clock":"",
+ (opt.debug & DBG_LOOKUP_VALUE )? " lookup":"");
}
@@ -1574,8 +1583,11 @@ print_algo_names(int (*checker)(int),const char *(*mapper)(int))
static void
list_config(char *items)
{
- int show_all=(items==NULL);
- char *name=NULL;
+ int show_all = !items;
+ char *name = NULL;
+ const char *s;
+ struct groupitem *giter;
+ int first, iter;
if(!opt.with_colons)
return;
@@ -1586,18 +1598,16 @@ list_config(char *items)
if(show_all || ascii_strcasecmp(name,"group")==0)
{
- struct groupitem *iter;
-
- for(iter=opt.grouplist;iter;iter=iter->next)
+ for (giter = opt.grouplist; giter; giter = giter->next)
{
strlist_t sl;
es_fprintf (es_stdout, "cfg:group:");
- es_write_sanitized (es_stdout, iter->name, strlen(iter->name),
+ es_write_sanitized (es_stdout, giter->name, strlen(giter->name),
":", NULL);
es_putc (':', es_stdout);
- for(sl=iter->values;sl;sl=sl->next)
+ for(sl=giter->values; sl; sl=sl->next)
{
es_write_sanitized (es_stdout, sl->d, strlen (sl->d),
":;", NULL);
@@ -1682,20 +1692,31 @@ list_config(char *items)
any=1;
}
- if(show_all || ascii_strcasecmp(name,"ccid-reader-id")==0)
+ if (show_all || !ascii_strcasecmp(name,"ccid-reader-id"))
{
-#if defined(ENABLE_CARD_SUPPORT) && defined(HAVE_LIBUSB) \
- && GNUPG_MAJOR_VERSION == 1
+ /* We ignore this for GnuPG 1.4 backward compatibility. */
+ any=1;
+ }
- char *p, *p2, *list = ccid_get_reader_list ();
+ if (show_all || !ascii_strcasecmp (name,"curve"))
+ {
+ es_printf ("cfg:curve:");
+ for (iter=0, first=1; (s = openpgp_enum_curves (&iter)); first=0)
+ es_printf ("%s%s", first?"":";", s);
+ es_printf ("\n");
+ any=1;
+ }
- for (p=list; p && (p2 = strchr (p, '\n')); p = p2+1)
+ /* Curve OIDs are rarely useful and thus only printed if requested. */
+ if (name && !ascii_strcasecmp (name,"curveoid"))
+ {
+ es_printf ("cfg:curveoid:");
+ for (iter=0, first=1; (s = openpgp_enum_curves (&iter)); first = 0)
{
- *p2 = 0;
- es_printf ("cfg:ccid-reader-id:%s\n", p);
+ s = openpgp_curve_to_oid (s, NULL);
+ es_printf ("%s%s", first?"":";", s? s:"[?]");
}
- free (list);
-#endif
+ es_printf ("\n");
any=1;
}
@@ -2138,6 +2159,8 @@ main (int argc, char **argv)
while( arg_parse( &pargs, opts) ) {
if( pargs.r_opt == oDebug || pargs.r_opt == oDebugAll )
parse_debug++;
+ else if (pargs.r_opt == oDebugIOLBF)
+ es_setvbuf (es_stdout, NULL, _IOLBF, 0);
else if( pargs.r_opt == oOptions ) {
/* yes there is one, so we do not try the default one, but
* read the option file when it is encountered at the commandline
@@ -2261,6 +2284,7 @@ main (int argc, char **argv)
{
case aCheckKeys:
case aListConfig:
+ case aListGcryptConfig:
case aGPGConfList:
case aGPGConfTest:
case aListPackets:
@@ -2398,6 +2422,8 @@ main (int argc, char **argv)
case oDebugAll: opt.debug = ~0; break;
case oDebugLevel: debug_level = pargs.r.ret_str; break;
+ case oDebugIOLBF: break; /* Already set in pre-parse step. */
+
case oStatusFD:
set_status_fd ( translate_sys2libc_fd_int (pargs.r.ret_int, 1) );
break;
@@ -2421,6 +2447,9 @@ main (int argc, char **argv)
opt.with_fingerprint = 1;
opt.fingerprint++;
break;
+ case oWithICAOSpelling:
+ opt.with_icao_spelling = 1;
+ break;
case oFingerprint:
opt.fingerprint++;
fpr_maybe_cmd = 1;
@@ -2807,7 +2836,13 @@ main (int argc, char **argv)
log_error (_("could not parse keyserver URL\n"));
else
{
- keyserver->next = opt.keyserver;
+ /* We only support a single keyserver. Later ones
+ override earlier ones. (Since we parse the
+ config file first and then the command line
+ arguments, the command line takes
+ precedence.) */
+ if (opt.keyserver)
+ free_keyserver_spec (opt.keyserver);
opt.keyserver = keyserver;
}
}
@@ -2947,6 +2982,7 @@ main (int argc, char **argv)
case oFastListMode: opt.fast_list_mode = 1; break;
case oFixedListMode: /* Dummy */ break;
case oLegacyListMode: opt.legacy_list_mode = 1; break;
+ case oPrintPKARecords: opt.print_pka_records = 1; break;
case oListOnly: opt.list_only=1; break;
case oIgnoreTimeConflict: opt.ignore_time_conflict = 1; break;
case oIgnoreValidFrom: opt.ignore_valid_from = 1; break;
@@ -4021,7 +4057,7 @@ main (int argc, char **argv)
mpi_print (es_stdout, generate_elg_prime(
1, atoi(argv[1]),
atoi(argv[2]), NULL,&factors ), 1);
- putchar('\n');
+ es_putc ('\n', es_stdout);
mpi_print (es_stdout, factors[0], 1 ); /* print q */
}
else if( mode == 4 && argc == 3 ) {
@@ -4029,13 +4065,13 @@ main (int argc, char **argv)
mpi_print (es_stdout, generate_elg_prime(
0, atoi(argv[1]),
atoi(argv[2]), g, NULL ), 1);
- putchar('\n');
+ es_putc ('\n', es_stdout);
mpi_print (es_stdout, g, 1 );
mpi_free (g);
}
else
wrong_args("--gen-prime mode bits [qbits] ");
- putchar('\n');
+ es_putc ('\n', es_stdout);
}
#endif
wrong_args("--gen-prime not yet supported ");
@@ -4064,21 +4100,21 @@ main (int argc, char **argv)
#endif
if (opt.armor) {
char *tmp = make_radix64_string (p, n);
- fputs (tmp, stdout);
+ es_fputs (tmp, es_stdout);
xfree (tmp);
if (n%3 == 1)
- putchar ('=');
+ es_putc ('=', es_stdout);
if (n%3)
- putchar ('=');
+ es_putc ('=', es_stdout);
} else {
- fwrite( p, n, 1, stdout );
+ es_fwrite( p, n, 1, es_stdout );
}
xfree(p);
if( !endless )
count -= n;
}
if (opt.armor)
- putchar ('\n');
+ es_putc ('\n', es_stdout);
}
break;
@@ -4203,6 +4239,13 @@ main (int argc, char **argv)
}
break;
+ case aListGcryptConfig:
+ /* Fixme: It would be nice to integrate that with
+ --list-config but unfortunately there is no way yet to have
+ libgcrypt print it to an estream for further parsing. */
+ gcry_control (GCRYCTL_PRINT_CONFIG, stdout);
+ break;
+
case aListPackets:
opt.list_packets=2;
default:
@@ -4298,7 +4341,7 @@ print_hex (gcry_md_hd_t md, int algo, const char *fname)
if (indent>40)
{
- printf("\n");
+ es_printf ("\n");
indent=0;
}
@@ -4396,24 +4439,22 @@ print_hashline( gcry_md_hd_t md, int algo, const char *fname )
static void
print_mds( const char *fname, int algo )
{
- FILE *fp;
+ estream_t fp;
char buf[1024];
size_t n;
gcry_md_hd_t md;
if (!fname)
{
- fp = stdin;
-#ifdef HAVE_DOSISH_SYSTEM
- setmode ( fileno(fp) , O_BINARY );
-#endif
+ fp = es_stdin;
+ es_set_binary (fp);
}
else
{
- fp = fopen (fname, "rb" );
- if (fp && is_secured_file (fileno (fp)))
+ fp = es_fopen (fname, "rb" );
+ if (fp && is_secured_file (es_fileno (fp)))
{
- fclose (fp);
+ es_fclose (fp);
fp = NULL;
gpg_err_set_errno (EPERM);
}
@@ -4444,10 +4485,10 @@ print_mds( const char *fname, int algo )
gcry_md_enable (md, GCRY_MD_SHA512);
}
- while ((n=fread (buf, 1, DIM(buf), fp)))
+ while ((n=es_fread (buf, 1, DIM(buf), fp)))
gcry_md_write (md, buf, n);
- if (ferror(fp))
+ if (es_ferror(fp))
log_error ("%s: %s\n", fname?fname:"[stdin]", strerror(errno));
else
{
@@ -4497,8 +4538,8 @@ print_mds( const char *fname, int algo )
}
gcry_md_close (md);
- if (fp != stdin)
- fclose (fp);
+ if (fp != es_stdin)
+ es_fclose (fp);
}
diff --git a/g10/keydb.c b/g10/keydb.c
index cf422a8..040ca65 100644
--- a/g10/keydb.c
+++ b/g10/keydb.c
@@ -369,10 +369,18 @@ keydb_add_resource (const char *url, unsigned int flags)
}
#endif /* !HAVE_DRIVE_LETTERS && !__riscos__ */
- if (*resname != DIRSEP_C )
+ if (*resname != DIRSEP_C
+#ifdef HAVE_W32_SYSTEM
+ && *resname != '/' /* Fixme: does not handle drive letters. */
+#endif
+ )
{
/* Do tilde expansion etc. */
- if (strchr(resname, DIRSEP_C) )
+ if (strchr (resname, DIRSEP_C)
+#ifdef HAVE_W32_SYSTEM
+ || strchr (resname, '/') /* Windows also accepts this. */
+#endif
+ )
filename = make_filename (resname, NULL);
else
filename = make_filename (opt.homedir, resname, NULL);
diff --git a/g10/keyedit.c b/g10/keyedit.c
index f283e55..2f9469f 100644
--- a/g10/keyedit.c
+++ b/g10/keyedit.c
@@ -158,23 +158,23 @@ print_and_check_one_sig_colon (KBNODE keyblock, KBNODE node,
if (sigrc != '?' || print_without_key)
{
- printf ("sig:%c::%d:%08lX%08lX:%lu:%lu:",
- sigrc, sig->pubkey_algo, (ulong) sig->keyid[0],
- (ulong) sig->keyid[1], (ulong) sig->timestamp,
- (ulong) sig->expiredate);
+ es_printf ("sig:%c::%d:%08lX%08lX:%lu:%lu:",
+ sigrc, sig->pubkey_algo, (ulong) sig->keyid[0],
+ (ulong) sig->keyid[1], (ulong) sig->timestamp,
+ (ulong) sig->expiredate);
if (sig->trust_depth || sig->trust_value)
- printf ("%d %d", sig->trust_depth, sig->trust_value);
+ es_printf ("%d %d", sig->trust_depth, sig->trust_value);
- printf (":");
+ es_printf (":");
if (sig->trust_regexp)
es_write_sanitized (es_stdout,
sig->trust_regexp, strlen (sig->trust_regexp),
":", NULL);
- printf ("::%02x%c\n", sig->sig_class,
- sig->flags.exportable ? 'x' : 'l');
+ es_printf ("::%02x%c\n", sig->sig_class,
+ sig->flags.exportable ? 'x' : 'l');
if (opt.show_subpackets)
print_subpackets_colon (sig);
@@ -1450,6 +1450,7 @@ keyedit_menu (ctrl_t ctrl, const char *username, strlist_t locusr,
char *answer = NULL;
int redisplay = 1;
int modified = 0;
+ int sec_shadowing = 0;
int run_subkey_warnings = 0;
int toggle;
int have_commands = !!commands;
@@ -1836,8 +1837,7 @@ keyedit_menu (ctrl_t ctrl, const char *username, strlist_t locusr,
if (card_store_subkey (node, xxpk ? xxpk->pubkey_usage : 0))
{
redisplay = 1;
- /* Only the secret key has been modified; thus
- there is no need to set the modified flag. */
+ sec_shadowing = 1;
}
}
}
@@ -1923,7 +1923,7 @@ keyedit_menu (ctrl_t ctrl, const char *username, strlist_t locusr,
if (card_store_subkey (node, 0))
{
redisplay = 1;
- /* FIXME:sec_modified = 1;*/
+ sec_shadowing = 1;
}
}
release_kbnode (node);
@@ -2182,7 +2182,7 @@ keyedit_menu (ctrl_t ctrl, const char *username, strlist_t locusr,
case cmdQUIT:
if (have_commands)
goto leave;
- if (!modified)
+ if (!modified && !sec_shadowing)
goto leave;
if (!cpr_get_answer_is_yes ("keyedit.save.okay",
_("Save changes? (y/N) ")))
@@ -2204,7 +2204,18 @@ keyedit_menu (ctrl_t ctrl, const char *username, strlist_t locusr,
break;
}
}
- else
+
+ if (sec_shadowing)
+ {
+ err = agent_scd_learn (NULL, 1);
+ if (err)
+ {
+ log_error (_("update failed: %s\n"), gpg_strerror (err));
+ break;
+ }
+ }
+
+ if (!modified && !sec_shadowing)
tty_printf (_("Key not changed so no update needed.\n"));
if (update_trust)
@@ -4735,11 +4746,11 @@ ask_revoke_sig (KBNODE keyblock, KBNODE node)
printf ("uat:::::::::%u %lu", uid->numattribs, uid->attrib_len);
else
{
- printf ("uid:::::::::");
+ es_printf ("uid:::::::::");
es_write_sanitized (es_stdout, uid->name, uid->len, ":", NULL);
}
- printf ("\n");
+ es_printf ("\n");
print_and_check_one_sig_colon (keyblock, node, NULL, NULL, NULL, NULL,
1);
diff --git a/g10/keygen.c b/g10/keygen.c
index 11bfbd4..ccd01f9 100644
--- a/g10/keygen.c
+++ b/g10/keygen.c
@@ -44,6 +44,7 @@
#include "pkglue.h"
#include "../common/shareddefs.h"
#include "host2net.h"
+#include "mbox-util.h"
/* The default algorithms. If you change them remember to change them
@@ -4151,7 +4152,7 @@ do_generate_keypair (struct para_data_s *para,
{
tty_printf (_("public and secret key created and signed.\n") );
tty_printf ("\n");
- list_keyblock (pub_root, 0, 1, 1, NULL);
+ list_keyblock_direct (pub_root, 0, 1, 1);
}
@@ -4486,7 +4487,7 @@ gen_card_key (int algo, int keyno, int is_primary, kbnode_t pub_root,
/* Send the learn command so that the agent creates a shadow key for
card key. We need to do that now so that we are able to create
the self-signatures. */
- err = agent_scd_learn (NULL);
+ err = agent_scd_learn (NULL, 0);
if (err)
{
/* Oops: Card removed during generation. */
diff --git a/g10/keyid.c b/g10/keyid.c
index 9f7b70f..a0571b0 100644
--- a/g10/keyid.c
+++ b/g10/keyid.c
@@ -179,7 +179,10 @@ hash_public_key (gcry_md_hd_t md, PKT_public_key *pk)
p = gcry_mpi_get_opaque (pk->pkey[i], &nbits);
pp[i] = xmalloc ((nbits+7)/8);
- memcpy (pp[i], p, (nbits+7)/8);
+ if (p)
+ memcpy (pp[i], p, (nbits+7)/8);
+ else
+ pp[i] = NULL;
nn[i] = (nbits+7)/8;
n += nn[i];
}
@@ -214,14 +217,18 @@ hash_public_key (gcry_md_hd_t md, PKT_public_key *pk)
if(npkey==0 && pk->pkey[0]
&& gcry_mpi_get_flag (pk->pkey[0], GCRYMPI_FLAG_OPAQUE))
{
- gcry_md_write (md, pp[0], nn[0]);
+ if (pp[0])
+ gcry_md_write (md, pp[0], nn[0]);
}
else
- for(i=0; i < npkey; i++ )
- {
- gcry_md_write ( md, pp[i], nn[i] );
- xfree(pp[i]);
- }
+ {
+ for(i=0; i < npkey; i++ )
+ {
+ if (pp[i])
+ gcry_md_write ( md, pp[i], nn[i] );
+ xfree(pp[i]);
+ }
+ }
}
diff --git a/g10/keylist.c b/g10/keylist.c
index 5fd9eb8..d62bc20 100644
--- a/g10/keylist.c
+++ b/g10/keylist.c
@@ -42,23 +42,39 @@
#include "i18n.h"
#include "status.h"
#include "call-agent.h"
+#include "mbox-util.h"
+
static void list_all (int, int);
static void list_one (strlist_t names, int secret, int mark_secret);
static void locate_one (ctrl_t ctrl, strlist_t names);
static void print_card_serialno (const char *serialno);
-struct sig_stats
+struct keylist_context
{
- int inv_sigs;
- int no_key;
- int oth_err;
+ int check_sigs; /* If set signatures shall be verified. */
+ int inv_sigs; /* Counter used if CHECK_SIGS is set. */
+ int no_key; /* Counter used if CHECK_SIGS is set. */
+ int oth_err; /* Counter used if CHECK_SIGS is set. */
};
+
+static void list_keyblock (kbnode_t keyblock, int secret, int has_secret,
+ int fpr, struct keylist_context *listctx);
+
+
/* The stream used to write attribute packets to. */
static estream_t attrib_fp;
+/* Release resources from a keylist context. */
+static void
+keylist_context_release (struct keylist_context *listctx)
+{
+ (void)listctx; /* Nothing to release. */
+}
+
+
/* List the keys. If list is NULL, all available keys are listed.
With LOCATE_MODE set the locate algorithm is used to find a
key. */
@@ -414,9 +430,13 @@ show_notation (PKT_signature * sig, int indent, int mode, int which)
free_notation (notations);
}
+
static void
-print_signature_stats (struct sig_stats *s)
+print_signature_stats (struct keylist_context *s)
{
+ if (!s->check_sigs)
+ return; /* Signature checking was not requested. */
+
if (s->inv_sigs == 1)
tty_printf (_("1 bad signature\n"));
else if (s->inv_sigs)
@@ -444,9 +464,11 @@ list_all (int secret, int mark_secret)
int rc = 0;
int any_secret;
const char *lastresname, *resname;
- struct sig_stats stats;
+ struct keylist_context listctx;
- memset (&stats, 0, sizeof (stats));
+ memset (&listctx, 0, sizeof (listctx));
+ if (opt.check_sigs)
+ listctx.check_sigs = 1;
hd = keydb_new ();
if (!hd)
@@ -497,7 +519,7 @@ list_all (int secret, int mark_secret)
}
merge_keys_and_selfsig (keyblock);
list_keyblock (keyblock, secret, any_secret, opt.fingerprint,
- opt.check_sigs ? &stats : NULL);
+ &listctx);
}
release_kbnode (keyblock);
keyblock = NULL;
@@ -511,9 +533,10 @@ list_all (int secret, int mark_secret)
keydb_get_skipped_counter (hd));
if (opt.check_sigs && !opt.with_colons)
- print_signature_stats (&stats);
+ print_signature_stats (&listctx);
-leave:
+ leave:
+ keylist_context_release (&listctx);
release_kbnode (keyblock);
keydb_release (hd);
}
@@ -528,9 +551,11 @@ list_one (strlist_t names, int secret, int mark_secret)
const char *resname;
const char *keyring_str = _("Keyring");
int i;
- struct sig_stats stats;
+ struct keylist_context listctx;
- memset (&stats, 0, sizeof (stats));
+ memset (&listctx, 0, sizeof (listctx));
+ if (!secret && opt.check_sigs)
+ listctx.check_sigs = 1;
/* fixme: using the bynames function has the disadvantage that we
* don't know wether one of the names given was not found. OTOH,
@@ -559,15 +584,16 @@ list_one (strlist_t names, int secret, int mark_secret)
es_putc ('-', es_stdout);
es_putc ('\n', es_stdout);
}
- list_keyblock (keyblock, secret, mark_secret, opt.fingerprint,
- (!secret && opt.check_sigs)? &stats : NULL);
+ list_keyblock (keyblock, secret, mark_secret, opt.fingerprint, &listctx);
release_kbnode (keyblock);
}
while (!getkey_next (ctx, NULL, &keyblock));
getkey_end (ctx);
if (opt.check_sigs && !opt.with_colons)
- print_signature_stats (&stats);
+ print_signature_stats (&listctx);
+
+ keylist_context_release (&listctx);
}
@@ -578,9 +604,11 @@ locate_one (ctrl_t ctrl, strlist_t names)
strlist_t sl;
GETKEY_CTX ctx = NULL;
KBNODE keyblock = NULL;
- struct sig_stats stats;
+ struct keylist_context listctx;
- memset (&stats, 0, sizeof (stats));
+ memset (&listctx, 0, sizeof (listctx));
+ if (opt.check_sigs)
+ listctx.check_sigs = 1;
for (sl = names; sl; sl = sl->next)
{
@@ -594,8 +622,7 @@ locate_one (ctrl_t ctrl, strlist_t names)
{
do
{
- list_keyblock (keyblock, 0, 0, opt.fingerprint,
- opt.check_sigs ? &stats : NULL);
+ list_keyblock (keyblock, 0, 0, opt.fingerprint, &listctx);
release_kbnode (keyblock);
}
while (ctx && !get_pubkey_next (ctx, NULL, &keyblock));
@@ -605,7 +632,9 @@ locate_one (ctrl_t ctrl, strlist_t names)
}
if (opt.check_sigs && !opt.with_colons)
- print_signature_stats (&stats);
+ print_signature_stats (&listctx);
+
+ keylist_context_release (&listctx);
}
@@ -794,14 +823,86 @@ dump_attribs (const PKT_user_id *uid, PKT_public_key *pk)
}
+/* Print IPGP cert records instead of a standard key listing. */
static void
-list_keyblock_print (KBNODE keyblock, int secret, int fpr, void *opaque)
+list_keyblock_pka (kbnode_t keyblock)
+{
+ kbnode_t kbctx;
+ kbnode_t node;
+ PKT_public_key *pk;
+ char pkstrbuf[PUBKEY_STRING_SIZE];
+ char *hexfpr;
+
+ /* Get the keyid from the keyblock. */
+ node = find_kbnode (keyblock, PKT_PUBLIC_KEY);
+ if (!node)
+ {
+ log_error ("Oops; key lost!\n");
+ dump_kbnode (keyblock);
+ return;
+ }
+
+ pk = node->pkt->pkt.public_key;
+
+ es_fprintf (es_stdout, ";; pub %s/%s %s\n;; ",
+ pubkey_string (pk, pkstrbuf, sizeof pkstrbuf),
+ keystr_from_pk (pk), datestr_from_pk (pk));
+ print_fingerprint (NULL, pk, 10);
+ hexfpr = hexfingerprint (pk);
+
+ for (kbctx = NULL; (node = walk_kbnode (keyblock, &kbctx, 0));)
+ {
+ if (node->pkt->pkttype == PKT_USER_ID)
+ {
+ PKT_user_id *uid = node->pkt->pkt.user_id;
+ char *mbox;
+ char *p;
+
+ if (pk && (uid->is_expired || uid->is_revoked)
+ && !(opt.list_options & LIST_SHOW_UNUSABLE_UIDS))
+ continue;
+
+ es_fputs (";; uid ", es_stdout);
+ print_utf8_buffer (es_stdout, uid->name, uid->len);
+ es_putc ('\n', es_stdout);
+ mbox = mailbox_from_userid (uid->name);
+ if (mbox && (p = strchr (mbox, '@')))
+ {
+ char hashbuf[20];
+ char *hash;
+ unsigned int len;
+
+ *p++ = 0;
+ es_fprintf (es_stdout, "$ORIGIN _pka.%s.\n", p);
+ gcry_md_hash_buffer (GCRY_MD_SHA1, hashbuf, mbox, strlen (mbox));
+ hash = zb32_encode (hashbuf, 8*20);
+ if (hash)
+ {
+ len = strlen (hexfpr)/2;
+ es_fprintf (es_stdout,
+ "%s TYPE37 \\# %u 0006 0000 00 %02X %s\n",
+ hash, 6 + len, len, hexfpr);
+ xfree (hash);
+ }
+ }
+ xfree (mbox);
+ }
+
+ }
+ es_putc ('\n', es_stdout);
+
+ xfree (hexfpr);
+}
+
+
+static void
+list_keyblock_print (KBNODE keyblock, int secret, int fpr,
+ struct keylist_context *listctx)
{
int rc;
KBNODE kbctx;
KBNODE node;
PKT_public_key *pk;
- struct sig_stats *stats = opaque;
int skip_sigs = 0;
int s2k_char;
char *hexgrip = NULL;
@@ -897,11 +998,11 @@ list_keyblock_print (KBNODE keyblock, int secret, int fpr, void *opaque)
for (kbctx = NULL; (node = walk_kbnode (keyblock, &kbctx, 0));)
{
- if (node->pkt->pkttype == PKT_USER_ID && !opt.fast_list_mode)
+ if (node->pkt->pkttype == PKT_USER_ID)
{
PKT_user_id *uid = node->pkt->pkt.user_id;
- if (pk && (uid->is_expired || uid->is_revoked)
+ if ((uid->is_expired || uid->is_revoked)
&& !(opt.list_options & LIST_SHOW_UNUSABLE_UIDS))
{
skip_sigs = 1;
@@ -914,7 +1015,7 @@ list_keyblock_print (KBNODE keyblock, int secret, int fpr, void *opaque)
dump_attribs (uid, pk);
if ((uid->is_revoked || uid->is_expired)
- || ((opt.list_options & LIST_SHOW_UID_VALIDITY) && pk))
+ || (opt.list_options & LIST_SHOW_UID_VALIDITY))
{
const char *validity;
int indent;
@@ -1029,7 +1130,7 @@ list_keyblock_print (KBNODE keyblock, int secret, int fpr, void *opaque)
int sigrc;
char *sigstr;
- if (stats)
+ if (listctx->check_sigs)
{
rc = check_key_signature (keyblock, node, NULL);
switch (gpg_err_code (rc))
@@ -1038,15 +1139,15 @@ list_keyblock_print (KBNODE keyblock, int secret, int fpr, void *opaque)
sigrc = '!';
break;
case GPG_ERR_BAD_SIGNATURE:
- stats->inv_sigs++;
+ listctx->inv_sigs++;
sigrc = '-';
break;
case GPG_ERR_NO_PUBKEY:
case GPG_ERR_UNUSABLE_PUBKEY:
- stats->no_key++;
+ listctx->no_key++;
continue;
default:
- stats->oth_err++;
+ listctx->oth_err++;
sigrc = '%';
break;
}
@@ -1269,7 +1370,7 @@ list_keyblock_colon (KBNODE keyblock, int secret, int has_secret, int fpr)
for (kbctx = NULL; (node = walk_kbnode (keyblock, &kbctx, 0));)
{
- if (node->pkt->pkttype == PKT_USER_ID && !opt.fast_list_mode)
+ if (node->pkt->pkttype == PKT_USER_ID)
{
char *str;
PKT_user_id *uid = node->pkt->pkt.user_id;
@@ -1290,7 +1391,7 @@ list_keyblock_colon (KBNODE keyblock, int secret, int has_secret, int fpr)
{
int uid_validity;
- if (pk && !ulti_hack)
+ if (!ulti_hack)
uid_validity = get_validity_info (pk, uid);
else
uid_validity = 'u';
@@ -1567,25 +1668,54 @@ reorder_keyblock (KBNODE keyblock)
do_reorder_keyblock (keyblock, 0);
}
-void
+static void
list_keyblock (KBNODE keyblock, int secret, int has_secret, int fpr,
- void *opaque)
+ struct keylist_context *listctx)
{
reorder_keyblock (keyblock);
- if (opt.with_colons)
+ if (opt.print_pka_records)
+ list_keyblock_pka (keyblock);
+ else if (opt.with_colons)
list_keyblock_colon (keyblock, secret, has_secret, fpr);
else
- list_keyblock_print (keyblock, secret, fpr, opaque);
+ list_keyblock_print (keyblock, secret, fpr, listctx);
if (secret)
es_fflush (es_stdout);
}
+
+/* Public function used by keygen to list a keyblock. */
+void
+list_keyblock_direct (kbnode_t keyblock, int secret, int has_secret, int fpr)
+{
+ struct keylist_context listctx;
+
+ memset (&listctx, 0, sizeof (listctx));
+ list_keyblock (keyblock, secret, has_secret, fpr, &listctx);
+ keylist_context_release (&listctx);
+}
+
+
+/* Print an hex digit in ICAO spelling. */
+static void
+print_icao_hexdigit (estream_t fp, int c)
+{
+ static const char *list[16] = {
+ "Zero", "One", "Two", "Three", "Four", "Five", "Six", "Seven",
+ "Eight", "Niner", "Alfa", "Bravo", "Charlie", "Delta", "Echo", "Foxtrot"
+ };
+
+ tty_fprintf (fp, "%s", list[c&15]);
+}
+
+
/*
* Function to print the finperprint.
* mode 0: as used in key listings, opt.with_colons is honored
* 1: print using log_info ()
* 2: direct use of tty
* 3: direct use of tty but only primary key.
+ * 10: Same as 0 but with_colons etc is ignored.
*
* Modes 1 and 2 will try and print both subkey and primary key
* fingerprints. A MODE with bit 7 set is used internally. If
@@ -1600,6 +1730,15 @@ print_fingerprint (estream_t override_fp, PKT_public_key *pk, int mode)
estream_t fp;
const char *text;
int primary = 0;
+ int with_colons = opt.with_colons;
+ int with_icao = opt.with_icao_spelling;
+
+ if (mode == 10)
+ {
+ mode = 0;
+ with_colons = 0;
+ with_icao = 0;
+ }
if (pk->main_keyid[0] == pk->keyid[0]
&& pk->main_keyid[1] == pk->keyid[1])
@@ -1653,7 +1792,7 @@ print_fingerprint (estream_t override_fp, PKT_public_key *pk, int mode)
fingerprint_from_pk (pk, array, &n);
p = array;
- if (opt.with_colons && !mode)
+ if (with_colons && !mode)
{
es_fprintf (fp, "fpr:::::::::");
for (i = 0; i < n; i++, p++)
@@ -1675,6 +1814,26 @@ print_fingerprint (estream_t override_fp, PKT_public_key *pk, int mode)
}
}
tty_fprintf (fp, "\n");
+ if (!with_colons && with_icao)
+ {
+ p = array;
+ tty_fprintf (fp, "%*s\"", (int)strlen(text)+1, "");
+ for (i = 0; i < n; i++, p++)
+ {
+ if (!i)
+ ;
+ else if (!(i%4))
+ tty_fprintf (fp, "\n%*s ", (int)strlen(text)+1, "");
+ else if (!(i%2))
+ tty_fprintf (fp, " ");
+ else
+ tty_fprintf (fp, " ");
+ print_icao_hexdigit (fp, *p >> 4);
+ tty_fprintf (fp, " ");
+ print_icao_hexdigit (fp, *p & 15);
+ }
+ tty_fprintf (fp, "\"\n");
+ }
}
/* Print the serial number of an OpenPGP card if available. */
diff --git a/g10/keyserver.c b/g10/keyserver.c
index 035cd03..7cac55e 100644
--- a/g10/keyserver.c
+++ b/g10/keyserver.c
@@ -1488,12 +1488,12 @@ keyserver_search (ctrl_t ctrl, strlist_t tokens)
/* Write global options */
/* for(temp=opt.keyserver_options.other;temp;temp=temp->next) */
- /* fprintf(spawn->tochild,"OPTION %s\n",temp->d); */
+ /* es_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); */
+ /* es_fprintf(spawn->tochild,"OPTION %s\n",temp->d); */
{
membuf_t mb;
@@ -1910,7 +1910,7 @@ keyserver_import_cert (ctrl_t ctrl,
if(domain)
*domain='.';
- err = get_dns_cert (look, &key, fpr, fpr_len, &url);
+ err = get_dns_cert (look, DNS_CERTTYPE_ANY, &key, fpr, fpr_len, &url);
if (err)
;
else if (key)
@@ -1980,7 +1980,7 @@ keyserver_import_pka (ctrl_t ctrl,
*fpr = xmalloc (20);
*fpr_len = 20;
- uri = get_pka_info (name, *fpr);
+ uri = get_pka_info (name, *fpr, 20);
if (uri && *uri)
{
/* An URI is available. Lookup the key. */
@@ -1991,8 +1991,8 @@ keyserver_import_pka (ctrl_t ctrl,
rc = keyserver_import_fprint (ctrl, *fpr, 20, spec);
free_keyserver_spec (spec);
}
- xfree (uri);
}
+ xfree (uri);
if (rc)
{
diff --git a/g10/main.h b/g10/main.h
index d313afb..01eeb7f 100644
--- a/g10/main.h
+++ b/g10/main.h
@@ -162,9 +162,6 @@ char *optsep(char **stringp);
char *argsplit(char *string);
int parse_options(char *str,unsigned int *options,
struct parse_options *opts,int noisy);
-int has_invalid_email_chars (const char *s);
-int is_valid_mailbox (const char *name);
-int is_valid_user_id (const char *uid);
const char *get_libexecdir (void);
int path_access(const char *file,int mode);
@@ -349,8 +346,8 @@ void public_key_list (ctrl_t ctrl, strlist_t list, int locate_mode );
void secret_key_list (ctrl_t ctrl, strlist_t list );
void print_subpackets_colon(PKT_signature *sig);
void reorder_keyblock (KBNODE keyblock);
-void list_keyblock (kbnode_t keyblock, int secret, int has_secret,
- int fpr, void *opaque);
+void list_keyblock_direct (kbnode_t keyblock, int secret, int has_secret,
+ int fpr);
void print_fingerprint (estream_t fp, PKT_public_key *pk, int mode);
void print_revokers (estream_t fp, PKT_public_key *pk);
void show_policy_url(PKT_signature *sig,int indent,int mode);
diff --git a/g10/mainproc.c b/g10/mainproc.c
index 8ff84b7..0f6ba2b 100644
--- a/g10/mainproc.c
+++ b/g10/mainproc.c
@@ -39,6 +39,7 @@
#include "keyserver-internal.h"
#include "photoid.h"
#include "pka.h"
+#include "mbox-util.h"
/* Put an upper limit on nested packets. The 32 is an arbitrary
@@ -930,15 +931,15 @@ print_userid (PACKET *pkt)
if (pkt->pkttype != PKT_USER_ID)
{
- printf ("ERROR: unexpected packet type %d", pkt->pkttype );
+ es_printf ("ERROR: unexpected packet type %d", pkt->pkttype );
return;
}
if (opt.with_colons)
{
if (pkt->pkt.user_id->attrib_data)
- printf("%u %lu",
- pkt->pkt.user_id->numattribs,
- pkt->pkt.user_id->attrib_len);
+ es_printf("%u %lu",
+ pkt->pkt.user_id->numattribs,
+ pkt->pkt.user_id->attrib_len);
else
es_write_sanitized (es_stdout, pkt->pkt.user_id->name,
pkt->pkt.user_id->len, ":", NULL);
@@ -1497,7 +1498,8 @@ pka_uri_from_sig (PKT_signature *sig)
{
char *uri;
- uri = get_pka_info (sig->pka_info->email, sig->pka_info->fpr);
+ uri = get_pka_info (sig->pka_info->email,
+ sig->pka_info->fpr, sizeof sig->pka_info->fpr);
if (uri)
{
sig->pka_info->valid = 1;
@@ -1668,6 +1670,8 @@ check_sig_and_print (CTX c, kbnode_t node)
}
}
+ write_status_text (STATUS_NEWSIG, NULL);
+
astr = openpgp_pk_algo_name ( sig->pubkey_algo );
if (keystrlen () > 8)
{
diff --git a/g10/misc.c b/g10/misc.c
index 37582af..654908d 100644
--- a/g10/misc.c
+++ b/g10/misc.c
@@ -70,18 +70,6 @@
#include <assert.h>
-static int
-string_count_chr (const char *string, int c)
-{
- int count;
-
- for (count=0; *string; string++ )
- if ( *string == c )
- count++;
- return count;
-}
-
-
#ifdef ENABLE_SELINUX_HACKS
/* A object and a global variable to keep track of files marked as
@@ -1394,8 +1382,8 @@ parse_options(char *str,unsigned int *options,
for(i=0;opts[i].name;i++)
if(opts[i].help)
- printf("%s%*s%s\n",opts[i].name,
- maxlen+2-(int)strlen(opts[i].name),"",_(opts[i].help));
+ es_printf("%s%*s%s\n",opts[i].name,
+ maxlen+2-(int)strlen(opts[i].name),"",_(opts[i].help));
g10_exit(0);
}
@@ -1464,69 +1452,6 @@ parse_options(char *str,unsigned int *options,
}
-/* Check whether the string has characters not valid in an RFC-822
- address. To cope with OpenPGP we ignore non-ascii characters
- so that for example umlauts are legal in an email address. An
- OpenPGP user ID must be utf-8 encoded but there is no strict
- requirement for RFC-822. Thus to avoid IDNA encoding we put the
- address verbatim as utf-8 into the user ID under the assumption
- that mail programs handle IDNA at a lower level and take OpenPGP
- user IDs as utf-8. Note that we can't do an utf-8 encoding
- checking here because in keygen.c this function is called with the
- native encoding and native to utf-8 encoding is only done later. */
-int
-has_invalid_email_chars (const char *s)
-{
- int at_seen=0;
- const char *valid_chars=
- "01234567890_-.abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
-
- for ( ; *s; s++ )
- {
- if ( (*s & 0x80) )
- continue; /* We only care about ASCII. */
- if ( *s == '@' )
- at_seen=1;
- else if ( !at_seen && !(strchr (valid_chars, *s)
- || strchr ("!#$%&'*+/=?^`{|}~", *s)))
- return 1;
- else if ( at_seen && !strchr( valid_chars, *s ) )
- return 1;
- }
- return 0;
-}
-
-
-/* Check whether NAME represents a valid mailbox according to
- RFC822. Returns true if so. */
-int
-is_valid_mailbox (const char *name)
-{
- return !( !name
- || !*name
- || has_invalid_email_chars (name)
- || string_count_chr (name,'@') != 1
- || *name == '@'
- || name[strlen(name)-1] == '@'
- || name[strlen(name)-1] == '.'
- || strstr (name, "..") );
-}
-
-
-/* Check whether UID is a valid standard user id of the form
- "Heinrich Heine <heinrichh@duesseldorf.de>"
- and return true if this is the case. */
-int
-is_valid_user_id (const char *uid)
-{
- if (!uid || !*uid)
- return 0;
-
- return 1;
-}
-
-
-
/* Similar to access(2), but uses PATH to find the file. */
int
path_access(const char *file,int mode)
@@ -1711,7 +1636,8 @@ pubkey_nbits( int algo, gcry_mpi_t *key )
int
mpi_print (estream_t fp, gcry_mpi_t a, int mode)
{
- int n=0;
+ int n = 0;
+ size_t nwritten;
if (!a)
return es_fprintf (fp, "[MPI_NULL]");
@@ -1729,19 +1655,19 @@ mpi_print (estream_t fp, gcry_mpi_t a, int mode)
n += es_fprintf (fp, "[invalid opaque value]");
else
{
- nbits = (nbits + 7)/8;
- for (; nbits; nbits--, p++)
- n += es_fprintf (fp, "%02X", *p);
+ if (!es_write_hexstring (fp, p, (nbits + 7)/8, 0, &nwritten))
+ n += nwritten;
}
}
else
{
unsigned char *buffer;
+ size_t buflen;
- if (gcry_mpi_aprint (GCRYMPI_FMT_HEX, &buffer, NULL, a))
+ if (gcry_mpi_aprint (GCRYMPI_FMT_USG, &buffer, &buflen, a))
BUG ();
- es_fputs (buffer, fp);
- n += strlen (buffer);
+ if (!es_write_hexstring (fp, buffer, buflen, 0, &nwritten))
+ n += nwritten;
gcry_free (buffer);
}
return n;
diff --git a/g10/options.h b/g10/options.h
index 7b9f366..6c96d18 100644
--- a/g10/options.h
+++ b/g10/options.h
@@ -67,11 +67,13 @@ struct
int check_sigs; /* check key signatures */
int with_colons;
int with_key_data;
+ int with_icao_spelling; /* Print ICAO spelling with fingerprints. */
int with_fingerprint; /* Option --with-fingerprint active. */
int with_keygrip; /* Option --with-keygrip active. */
int with_secret; /* Option --with-secret active. */
int fingerprint; /* list fingerprints */
int list_sigs; /* list signatures */
+ int print_pka_records;
int no_armor;
int list_packets; /* list-packets mode: 1=normal, 2=invoked by command*/
int def_cipher_algo;
@@ -266,34 +268,34 @@ struct {
#define DBG_PACKET_VALUE 1 /* debug packet reading/writing */
#define DBG_MPI_VALUE 2 /* debug mpi details */
-#define DBG_CIPHER_VALUE 4 /* debug cipher handling */
+#define DBG_CRYPTO_VALUE 4 /* debug crypto handling */
/* (may reveal sensitive data) */
#define DBG_FILTER_VALUE 8 /* debug internal filter handling */
#define DBG_IOBUF_VALUE 16 /* debug iobuf stuff */
#define DBG_MEMORY_VALUE 32 /* debug memory allocation stuff */
-#define DBG_CACHE_VALUE 64 /* debug the cacheing */
+#define DBG_CACHE_VALUE 64 /* debug the caching */
#define DBG_MEMSTAT_VALUE 128 /* show memory statistics */
#define DBG_TRUST_VALUE 256 /* debug the trustdb */
#define DBG_HASHING_VALUE 512 /* debug hashing operations */
-#define DBG_EXTPROG_VALUE 1024 /* debug external program calls */
+#define DBG_IPC_VALUE 1024 /* debug assuan communication */
#define DBG_CARD_IO_VALUE 2048 /* debug smart card I/O. */
#define DBG_CLOCK_VALUE 4096
-
-/* Fixme: For now alias this value. */
-#define DBG_ASSUAN_VALUE DBG_EXTPROG_VALUE
-
+#define DBG_LOOKUP_VALUE 8192 /* debug the kety lookup */
+#define DBG_EXTPROG_VALUE 16384 /* debug external program calls */
/* Tests for the debugging flags. */
#define DBG_PACKET (opt.debug & DBG_PACKET_VALUE)
-#define DBG_CIPHER (opt.debug & DBG_CIPHER_VALUE)
+#define DBG_CRYPTO (opt.debug & DBG_CRYPTO_VALUE)
#define DBG_FILTER (opt.debug & DBG_FILTER_VALUE)
#define DBG_CACHE (opt.debug & DBG_CACHE_VALUE)
#define DBG_TRUST (opt.debug & DBG_TRUST_VALUE)
#define DBG_HASHING (opt.debug & DBG_HASHING_VALUE)
-#define DBG_EXTPROG (opt.debug & DBG_EXTPROG_VALUE)
+#define DBG_IPC (opt.debug & DBG_IPC_VALUE)
#define DBG_CARD_IO (opt.debug & DBG_CARD_IO_VALUE)
-#define DBG_ASSUAN (opt.debug & DBG_ASSUAN_VALUE)
+#define DBG_IPC (opt.debug & DBG_IPC_VALUE)
#define DBG_CLOCK (opt.debug & DBG_CLOCK_VALUE)
+#define DBG_LOOKUP (opt.debug & DBG_LOOKUP_VALUE)
+#define DBG_EXTPROG (opt.debug & DBG_EXTPROG_VALUE)
/* FIXME: We need to check whey we did not put this into opt. */
#define DBG_MEMORY memory_debug_mode
diff --git a/g10/parse-packet.c b/g10/parse-packet.c
index 6232086..c80b7df 100644
--- a/g10/parse-packet.c
+++ b/g10/parse-packet.c
@@ -112,7 +112,7 @@ read_32 (IOBUF inp)
/* Read an external representation of an mpi and return the MPI. The
* external format is a 16 bit unsigned value stored in network byte
* order, giving the number of bits for the following integer. The
- * integer is stored with MSB first (left padded with zeroes to align
+ * integer is stored with MSB first (left padded with zero bits to align
* on a byte boundary). */
static gcry_mpi_t
mpi_read (iobuf_t inp, unsigned int *ret_nread, int secure)
@@ -177,24 +177,38 @@ set_packet_list_mode (int mode)
{
int old = list_mode;
list_mode = mode;
- /* FIXME(gcrypt) mpi_print_mode = DBG_MPI; */
- /* We use stdout print only if invoked by the --list-packets command
+
+ /* We use stdout only if invoked by the --list-packets command
but switch to stderr in all other cases. This breaks the
previous behaviour but that seems to be more of a bug than
intentional. I don't believe that any application makes use of
this long standing annoying way of printing to stdout except when
doing a --list-packets. If this assumption fails, it will be easy
to add an option for the listing stream. Note that we initialize
- it only once; mainly because some code may switch the option
- value later back to 1 and we want to have all output to the same
- stream.
+ it only once; mainly because there is code which switches
+ opt.list_mode back to 1 and we want to have all output to the
+ same stream. The MPI_PRINT_MODE will be enabled if the
+ corresponding debug flag is set or if we are in --list-packets
+ and --verbose is given.
Using stderr is not actually very clean because it bypasses the
logging code but it is a special thing anyway. I am not sure
whether using log_stream() would be better. Perhaps we should
- enable the list mdoe only with a special option. */
+ enable the list mode only with a special option. */
if (!listfp)
- listfp = opt.list_packets == 2 ? es_stdout : es_stderr;
+ {
+ if (opt.list_packets == 2)
+ {
+ listfp = es_stdout;
+ if (opt.verbose)
+ mpi_print_mode = 1;
+ }
+ else
+ listfp = es_stderr;
+
+ if (opt.debug && DBG_MPI_VALUE)
+ mpi_print_mode = 1;
+ }
return old;
}
@@ -2089,6 +2103,12 @@ parse_key (IOBUF inp, int pkttype, unsigned long pktlen,
byte temp[16];
size_t snlen = 0;
+ if (pktlen < 1)
+ {
+ err = gpg_error (GPG_ERR_INV_PACKET);
+ goto leave;
+ }
+
pk->seckey_info = ski = xtrycalloc (1, sizeof *ski);
if (!pk->seckey_info)
{
@@ -2289,6 +2309,12 @@ parse_key (IOBUF inp, int pkttype, unsigned long pktlen,
}
else if (ski->is_protected)
{
+ if (pktlen < 2) /* At least two bytes for the length. */
+ {
+ err = gpg_error (GPG_ERR_INV_PACKET);
+ goto leave;
+ }
+
/* Ugly: The length is encrypted too, so we read all stuff
* up to the end of the packet into the first SKEY
* element. */
@@ -2309,7 +2335,14 @@ parse_key (IOBUF inp, int pkttype, unsigned long pktlen,
/* Not encrypted. */
for (i = npkey; i < nskey; i++)
{
- unsigned int n = pktlen;
+ unsigned int n;
+
+ if (pktlen < 2) /* At least two bytes for the length. */
+ {
+ err = gpg_error (GPG_ERR_INV_PACKET);
+ goto leave;
+ }
+ n = pktlen;
pk->pkey[i] = mpi_read (inp, &n, 0);
pktlen -= n;
if (list_mode)
@@ -2325,6 +2358,11 @@ parse_key (IOBUF inp, int pkttype, unsigned long pktlen,
if (err)
goto leave;
+ if (pktlen < 2)
+ {
+ err = gpg_error (GPG_ERR_INV_PACKET);
+ goto leave;
+ }
ski->csum = read_16 (inp);
pktlen -= 2;
if (list_mode)
diff --git a/g10/pkglue.c b/g10/pkglue.c
index 684ce8a..d72275b 100644
--- a/g10/pkglue.c
+++ b/g10/pkglue.c
@@ -263,7 +263,7 @@ pk_encrypt (pubkey_algo_t algo, gcry_mpi_t *resarr, gcry_mpi_t data,
public = get_mpi_from_sexp (s_ciph, "e", GCRYMPI_FMT_USG);
gcry_sexp_release (s_ciph);
s_ciph = NULL;
- if (DBG_CIPHER)
+ if (DBG_CRYPTO)
{
log_debug ("ECDH ephemeral key:");
gcry_mpi_dump (public);
diff --git a/g10/pubkey-enc.c b/g10/pubkey-enc.c
index 9574769..cb834af 100644
--- a/g10/pubkey-enc.c
+++ b/g10/pubkey-enc.c
@@ -227,7 +227,7 @@ get_it (PKT_pubkey_enc *enc, DEK *dek, PKT_public_key *sk, u32 *keyid)
* DEK is the encryption key (session key) with length k
* CSUM
*/
- if (DBG_CIPHER)
+ if (DBG_CRYPTO)
log_printhex ("DEK frame:", frame, nframe);
n = 0;
@@ -333,7 +333,7 @@ get_it (PKT_pubkey_enc *enc, DEK *dek, PKT_public_key *sk, u32 *keyid)
}
if (DBG_CLOCK)
log_clock ("decryption ready");
- if (DBG_CIPHER)
+ if (DBG_CRYPTO)
log_printhex ("DEK is:", dek->key, dek->keylen);
/* Check that the algo is in the preferences and whether it has expired. */
diff --git a/g10/seskey.c b/g10/seskey.c
index 410f0bf..e79faf8 100644
--- a/g10/seskey.c
+++ b/g10/seskey.c
@@ -82,7 +82,7 @@ encode_session_key (int openpgp_pk_algo, DEK *dek, unsigned int nbits)
u16 csum;
gcry_mpi_t a;
- if (DBG_CIPHER)
+ if (DBG_CRYPTO)
log_debug ("encode_session_key: encoding %d byte DEK", dek->keylen);
csum = 0;
@@ -116,7 +116,7 @@ encode_session_key (int openpgp_pk_algo, DEK *dek, unsigned int nbits)
memset (frame+n, i, i); /* Use it as the value of each padded byte. */
assert (n+i == nframe);
- if (DBG_CIPHER)
+ if (DBG_CRYPTO)
log_debug ("encode_session_key: "
"[%d] %02x %02x %02x ... %02x %02x %02x\n",
(int) nframe, frame[0], frame[1], frame[2],
diff --git a/g10/sig-check.c b/g10/sig-check.c
index 27c51fd..f8ba98b 100644
--- a/g10/sig-check.c
+++ b/g10/sig-check.c
@@ -427,7 +427,7 @@ check_revocation_keys(PKT_public_key *pk,PKT_signature *sig)
busy=1;
- /* printf("looking at %08lX with a sig from %08lX\n",(ulong)pk->keyid[1],
+ /* es_printf("looking at %08lX with a sig from %08lX\n",(ulong)pk->keyid[1],
(ulong)sig->keyid[1]); */
/* is the issuer of the sig one of our revokers? */
diff --git a/g10/sign.c b/g10/sign.c
index d2f4abf..afc117e 100644
--- a/g10/sign.c
+++ b/g10/sign.c
@@ -1021,7 +1021,7 @@ sign_file (ctrl_t ctrl, strlist_t filenames, int detached, strlist_t locusr,
}
handle_progress (pfx, inp, sl->d);
if( opt.verbose )
- fprintf(stderr, " '%s'", sl->d );
+ log_printf (" '%s'", sl->d );
if(opt.textmode)
{
memset( &tfx, 0, sizeof tfx);
@@ -1033,7 +1033,7 @@ sign_file (ctrl_t ctrl, strlist_t filenames, int detached, strlist_t locusr,
iobuf_close(inp); inp = NULL;
}
if( opt.verbose )
- putc( '\n', stderr );
+ log_printf ("\n");
}
else {
/* read, so that the filter can calculate the digest */
diff --git a/g10/tdbdump.c b/g10/tdbdump.c
index c12e9b7..bf9f387 100644
--- a/g10/tdbdump.c
+++ b/g10/tdbdump.c
@@ -78,12 +78,12 @@ list_trustdb( const char *username )
ulong recnum;
int i;
- printf("TrustDB: %s\n", tdbio_get_dbname() );
+ es_printf ("TrustDB: %s\n", tdbio_get_dbname() );
for(i=9+strlen(tdbio_get_dbname()); i > 0; i-- )
- putchar('-');
- putchar('\n');
+ es_putc ('-', es_stdout);
+ es_putc ('\n', es_stdout);
for(recnum=0; !tdbio_read_record( recnum, &rec, 0); recnum++ )
- tdbio_dump_record( &rec, stdout );
+ tdbio_dump_record (&rec, es_stdout);
}
}
@@ -97,23 +97,25 @@ list_trustdb( const char *username )
void
export_ownertrust()
{
- TRUSTREC rec;
- ulong recnum;
- int i;
- byte *p;
+ TRUSTREC rec;
+ ulong recnum;
+ int i;
+ byte *p;
- init_trustdb();
- printf(_("# List of assigned trustvalues, created %s\n"
- "# (Use \"gpg --import-ownertrust\" to restore them)\n"),
- asctimestamp( make_timestamp() ) );
- for(recnum=0; !tdbio_read_record( recnum, &rec, 0); recnum++ ) {
- if( rec.rectype == RECTYPE_TRUST ) {
- if( !rec.r.trust.ownertrust )
- continue;
- p = rec.r.trust.fingerprint;
- for(i=0; i < 20; i++, p++ )
- printf("%02X", *p );
- printf(":%u:\n", (unsigned int)rec.r.trust.ownertrust );
+ init_trustdb();
+ es_printf (_("# List of assigned trustvalues, created %s\n"
+ "# (Use \"gpg --import-ownertrust\" to restore them)\n"),
+ asctimestamp( make_timestamp() ) );
+ for (recnum=0; !tdbio_read_record (recnum, &rec, 0); recnum++ )
+ {
+ if (rec.rectype == RECTYPE_TRUST)
+ {
+ if (!rec.r.trust.ownertrust)
+ continue;
+ p = rec.r.trust.fingerprint;
+ for (i=0; i < 20; i++, p++ )
+ es_printf("%02X", *p );
+ es_printf (":%u:\n", (unsigned int)rec.r.trust.ownertrust );
}
}
}
@@ -122,7 +124,7 @@ export_ownertrust()
void
import_ownertrust( const char *fname )
{
- FILE *fp;
+ estream_t fp;
int is_stdin=0;
char line[256];
char *p;
@@ -134,24 +136,24 @@ import_ownertrust( const char *fname )
init_trustdb();
if( iobuf_is_pipe_filename (fname) ) {
- fp = stdin;
+ fp = es_stdin;
fname = "[stdin]";
is_stdin = 1;
}
- else if( !(fp = fopen( fname, "r" )) ) {
+ else if( !(fp = es_fopen( fname, "r" )) ) {
log_error ( _("can't open '%s': %s\n"), fname, strerror(errno) );
return;
}
- if (is_secured_file (fileno (fp)))
+ if (is_secured_file (es_fileno (fp)))
{
- fclose (fp);
+ es_fclose (fp);
gpg_err_set_errno (EPERM);
log_error (_("can't open '%s': %s\n"), fname, strerror(errno) );
return;
}
- while( fgets( line, DIM(line)-1, fp ) ) {
+ while (es_fgets (line, DIM(line)-1, fp)) {
TRUSTREC rec;
if( !*line || *line == '#' )
@@ -216,10 +218,10 @@ import_ownertrust( const char *fname )
log_error (_("error finding trust record in '%s': %s\n"),
fname, gpg_strerror (rc));
}
- if( ferror(fp) )
+ if (es_ferror (fp))
log_error ( _("read error in '%s': %s\n"), fname, strerror(errno) );
- if( !is_stdin )
- fclose(fp);
+ if (!is_stdin)
+ es_fclose (fp);
if (any)
{
diff --git a/g10/tdbio.c b/g10/tdbio.c
index 91ee3ab..69438b4 100644
--- a/g10/tdbio.c
+++ b/g10/tdbio.c
@@ -1141,59 +1141,62 @@ update_trusthashtbl( TRUSTREC *tr )
void
-tdbio_dump_record( TRUSTREC *rec, FILE *fp )
+tdbio_dump_record (TRUSTREC *rec, estream_t fp)
{
int i;
ulong rnum = rec->recnum;
- fprintf(fp, "rec %5lu, ", rnum );
+ es_fprintf ( fp, "rec %5lu, ", rnum );
switch( rec->rectype ) {
- case 0: fprintf(fp, "blank\n");
+ case 0:
+ es_fprintf (fp, "blank\n");
break;
- case RECTYPE_VER: fprintf(fp,
- "version, td=%lu, f=%lu, m/c/d=%d/%d/%d tm=%d mcl=%d nc=%lu (%s)\n",
- rec->r.ver.trusthashtbl,
- rec->r.ver.firstfree,
- rec->r.ver.marginals,
- rec->r.ver.completes,
- rec->r.ver.cert_depth,
- rec->r.ver.trust_model,
- rec->r.ver.min_cert_level,
- rec->r.ver.nextcheck,
- strtimestamp(rec->r.ver.nextcheck)
- );
+ case RECTYPE_VER:
+ es_fprintf (fp,
+ "version, td=%lu, f=%lu, m/c/d=%d/%d/%d tm=%d mcl=%d nc=%lu (%s)\n",
+ rec->r.ver.trusthashtbl,
+ rec->r.ver.firstfree,
+ rec->r.ver.marginals,
+ rec->r.ver.completes,
+ rec->r.ver.cert_depth,
+ rec->r.ver.trust_model,
+ rec->r.ver.min_cert_level,
+ rec->r.ver.nextcheck,
+ strtimestamp(rec->r.ver.nextcheck)
+ );
break;
- case RECTYPE_FREE: fprintf(fp, "free, next=%lu\n", rec->r.free.next );
+ case RECTYPE_FREE:
+ es_fprintf (fp, "free, next=%lu\n", rec->r.free.next );
break;
case RECTYPE_HTBL:
- fprintf(fp, "htbl,");
+ es_fprintf (fp, "htbl,");
for(i=0; i < ITEMS_PER_HTBL_RECORD; i++ )
- fprintf(fp, " %lu", rec->r.htbl.item[i] );
- putc('\n', fp);
+ es_fprintf (fp, " %lu", rec->r.htbl.item[i] );
+ es_putc ('\n', fp);
break;
case RECTYPE_HLST:
- fprintf(fp, "hlst, next=%lu,", rec->r.hlst.next );
+ es_fprintf (fp, "hlst, next=%lu,", rec->r.hlst.next );
for(i=0; i < ITEMS_PER_HLST_RECORD; i++ )
- fprintf(fp, " %lu", rec->r.hlst.rnum[i] );
- putc('\n', fp);
+ es_fprintf (fp, " %lu", rec->r.hlst.rnum[i] );
+ es_putc ('\n', fp);
break;
case RECTYPE_TRUST:
- fprintf(fp, "trust ");
+ es_fprintf (fp, "trust ");
for(i=0; i < 20; i++ )
- fprintf(fp, "%02X", rec->r.trust.fingerprint[i] );
- fprintf (fp, ", ot=%d, d=%d, vl=%lu\n", rec->r.trust.ownertrust,
- rec->r.trust.depth, rec->r.trust.validlist);
+ es_fprintf (fp, "%02X", rec->r.trust.fingerprint[i] );
+ es_fprintf (fp, ", ot=%d, d=%d, vl=%lu\n", rec->r.trust.ownertrust,
+ rec->r.trust.depth, rec->r.trust.validlist);
break;
case RECTYPE_VALID:
- fprintf(fp, "valid ");
+ es_fprintf (fp, "valid ");
for(i=0; i < 20; i++ )
- fprintf(fp, "%02X", rec->r.valid.namehash[i] );
- fprintf (fp, ", v=%d, next=%lu\n", rec->r.valid.validity,
- rec->r.valid.next);
+ es_fprintf(fp, "%02X", rec->r.valid.namehash[i] );
+ es_fprintf (fp, ", v=%d, next=%lu\n", rec->r.valid.validity,
+ rec->r.valid.next);
break;
default:
- fprintf(fp, "unknown type %d\n", rec->rectype );
+ es_fprintf (fp, "unknown type %d\n", rec->rectype );
break;
}
}
diff --git a/g10/tdbio.h b/g10/tdbio.h
index 4f37de4..d259518 100644
--- a/g10/tdbio.h
+++ b/g10/tdbio.h
@@ -95,7 +95,7 @@ typedef struct trust_record TRUSTREC;
int tdbio_update_version_record(void);
int tdbio_set_dbname( const char *new_dbname, int create, int *r_nofile);
const char *tdbio_get_dbname(void);
-void tdbio_dump_record( TRUSTREC *rec, FILE *fp );
+void tdbio_dump_record( TRUSTREC *rec, estream_t fp );
int tdbio_read_record( ulong recnum, TRUSTREC *rec, int expected );
int tdbio_write_record( TRUSTREC *rec );
int tdbio_db_matches_options(void);
diff --git a/g10/trustdb.c b/g10/trustdb.c
index 08f6cf4..6145cf0 100644
--- a/g10/trustdb.c
+++ b/g10/trustdb.c
@@ -938,11 +938,13 @@ tdb_check_trustdb_stale (void)
if (opt.no_auto_check_trustdb)
{
pending_check_trustdb = 1;
- log_info (_("please do a --check-trustdb\n"));
+ if (!opt.quiet)
+ log_info (_("please do a --check-trustdb\n"));
}
else
{
- log_info (_("checking the trustdb\n"));
+ if (!opt.quiet)
+ log_info (_("checking the trustdb\n"));
validate_keys (0);
}
}
@@ -1068,7 +1070,7 @@ get_validity_counts (PKT_public_key *pk, PKT_user_id *uid)
{
uid->help_marginal_count=vrec.r.valid.marginal_count;
uid->help_full_count=vrec.r.valid.full_count;
- /* printf("Fetched marginal %d, full %d\n",uid->help_marginal_count,uid->help_full_count); */
+ /* es_printf("Fetched marginal %d, full %d\n",uid->help_marginal_count,uid->help_full_count); */
break;
}
@@ -1197,8 +1199,8 @@ dump_key_array (int depth, struct key_array *keys)
u32 kid[2];
keyid_from_pk(node->pkt->pkt.public_key, kid);
- printf ("%d:%08lX%08lX:K::%c::::\n",
- depth, (ulong)kid[0], (ulong)kid[1], '?');
+ es_printf ("%d:%08lX%08lX:K::%c::::\n",
+ depth, (ulong)kid[0], (ulong)kid[1], '?');
for (; node; node = node->next)
{
@@ -1208,15 +1210,15 @@ dump_key_array (int depth, struct key_array *keys)
if (len > 30)
len = 30;
- printf ("%d:%08lX%08lX:U:::%c:::",
- depth, (ulong)kid[0], (ulong)kid[1],
- (node->flag & 4)? 'f':
- (node->flag & 2)? 'm':
- (node->flag & 1)? 'q':'-');
+ es_printf ("%d:%08lX%08lX:U:::%c:::",
+ depth, (ulong)kid[0], (ulong)kid[1],
+ (node->flag & 4)? 'f':
+ (node->flag & 2)? 'm':
+ (node->flag & 1)? 'q':'-');
es_write_sanitized (es_stdout, node->pkt->pkt.user_id->name,
len, ":", NULL);
- putchar (':');
- putchar ('\n');
+ es_putc (':', es_stdout);
+ es_putc ('\n', es_stdout);
}
}
}
diff --git a/g13/Makefile.am b/g13/Makefile.am
index bbffe02..7d627cb 100644
--- a/g13/Makefile.am
+++ b/g13/Makefile.am
@@ -22,7 +22,7 @@ EXTRA_DIST = ChangeLog-2011
bin_PROGRAMS = g13
-AM_CPPFLAGS = -I$(top_srcdir)/gl -I$(top_srcdir)/intl -I$(top_srcdir)/common
+AM_CPPFLAGS = -I$(top_srcdir)/common
include $(top_srcdir)/am/cmacros.am
diff --git a/g13/call-gpg.c b/g13/call-gpg.c
index 54f6056..0bd935c 100644
--- a/g13/call-gpg.c
+++ b/g13/call-gpg.c
@@ -136,7 +136,7 @@ start_gpg (ctrl_t ctrl, int input_fd, int output_fd, assuan_context_t *r_ctx)
*r_ctx = ctx;
- if (DBG_ASSUAN)
+ if (DBG_IPC)
log_debug ("connection to GPG established\n");
return 0;
}
diff --git a/g13/g13.c b/g13/g13.c
index 157e646..2e4e63d 100644
--- a/g13/g13.c
+++ b/g13/g13.c
@@ -260,11 +260,11 @@ set_debug (void)
else if (!strcmp (debug_level, "none") || (numok && numlvl < 1))
opt.debug = 0;
else if (!strcmp (debug_level, "basic") || (numok && numlvl <= 2))
- opt.debug = DBG_ASSUAN_VALUE|DBG_MOUNT_VALUE;
+ opt.debug = DBG_IPC_VALUE|DBG_MOUNT_VALUE;
else if (!strcmp (debug_level, "advanced") || (numok && numlvl <= 5))
- opt.debug = DBG_ASSUAN_VALUE|DBG_MOUNT_VALUE;
+ opt.debug = DBG_IPC_VALUE|DBG_MOUNT_VALUE;
else if (!strcmp (debug_level, "expert") || (numok && numlvl <= 8))
- opt.debug = (DBG_ASSUAN_VALUE|DBG_MOUNT_VALUE|DBG_CRYPTO_VALUE);
+ opt.debug = (DBG_IPC_VALUE|DBG_MOUNT_VALUE|DBG_CRYPTO_VALUE);
else if (!strcmp (debug_level, "guru") || numok)
{
opt.debug = ~0;
@@ -294,7 +294,7 @@ set_debug (void)
(opt.debug & DBG_CRYPTO_VALUE )? " crypto":"",
(opt.debug & DBG_MEMORY_VALUE )? " memory":"",
(opt.debug & DBG_MEMSTAT_VALUE)? " memstat":"",
- (opt.debug & DBG_ASSUAN_VALUE )? " assuan":"");
+ (opt.debug & DBG_IPC_VALUE )? " ipc":"");
}
diff --git a/g13/g13.h b/g13/g13.h
index bdcc02a..371833d 100644
--- a/g13/g13.h
+++ b/g13/g13.h
@@ -70,12 +70,12 @@ struct
#define DBG_CRYPTO_VALUE 4 /* Debug low level crypto. */
#define DBG_MEMORY_VALUE 32 /* Debug memory allocation stuff. */
#define DBG_MEMSTAT_VALUE 128 /* Show memory statistics. */
-#define DBG_ASSUAN_VALUE 1024 /* Debug assuan communication. */
+#define DBG_IPC_VALUE 1024 /* Debug assuan communication. */
#define DBG_MOUNT (opt.debug & DBG_MOUNT_VALUE)
#define DBG_CRYPTO (opt.debug & DBG_CRYPTO_VALUE)
#define DBG_MEMORY (opt.debug & DBG_MEMORY_VALUE)
-#define DBG_ASSUAN (opt.debug & DBG_ASSUAN_VALUE)
+#define DBG_IPC (opt.debug & DBG_IPC_VALUE)
/* Forward declaration for an object defined in server.c. */
struct server_local_s;
diff --git a/g13/utils.c b/g13/utils.c
index 6fe3e5a..4ab4799 100644
--- a/g13/utils.c
+++ b/g13/utils.c
@@ -124,14 +124,16 @@ find_tuple (tupledesc_t tupledesc, unsigned int tag, size_t *r_length)
s_end = s + tupledesc->datalen;
while (s < s_end)
{
- if (s+3 >= s_end || s + 3 < s)
+ /* We use addresses for the overflow check to avoid undefined
+ behaviour. size_t should work with all flat memory models. */
+ if ((size_t)s+3 >= (size_t)s_end || (size_t)s + 3 < (size_t)s)
break;
t = s[0] << 8;
t |= s[1];
n = s[2] << 8;
n |= s[3];
s += 4;
- if (s + n > s_end || s + n < s)
+ if ((size_t)s + n > (size_t)s_end || (size_t)s + n < (size_t)s)
break;
if (t == tag)
{
@@ -159,14 +161,14 @@ next_tuple (tupledesc_t tupledesc, unsigned int *r_tag, size_t *r_length)
s_end = s + tupledesc->datalen;
s += tupledesc->pos;
if (s < s_end
- && !(s+3 >= s_end || s + 3 < s))
+ && !((size_t)s + 3 >= (size_t)s_end || (size_t)s + 3 < (size_t)s))
{
t = s[0] << 8;
t |= s[1];
n = s[2] << 8;
n |= s[3];
s += 4;
- if (!(s + n > s_end || s + n < s))
+ if (!((size_t)s + n > (size_t)s_end || (size_t)s + n < (size_t)s))
{
tupledesc->pos = (s + n) - tupledesc->data;
*r_tag = t;
diff --git a/kbx/Makefile.am b/kbx/Makefile.am
index eb434b6..5df2bba 100644
--- a/kbx/Makefile.am
+++ b/kbx/Makefile.am
@@ -20,8 +20,7 @@
EXTRA_DIST = mkerrors
-AM_CPPFLAGS = -I$(top_srcdir)/gl -I$(top_srcdir)/common \
- -I$(top_srcdir)/intl
+AM_CPPFLAGS = -I$(top_srcdir)/common
include $(top_srcdir)/am/cmacros.am
diff --git a/kbx/keybox-search.c b/kbx/keybox-search.c
index d22ef19..1433591 100644
--- a/kbx/keybox-search.c
+++ b/kbx/keybox-search.c
@@ -30,6 +30,7 @@
#include "keybox-defs.h"
#include <gcrypt.h>
#include "host2net.h"
+#include "mbox-util.h"
#define xtoi_1(p) (*(p) <= '9'? (*(p)- '0'): \
*(p) <= 'F'? (*(p)-'A'+10):(*(p)-'a'+10))
@@ -385,8 +386,8 @@ blob_cmp_name (KEYBOXBLOB blob, int idx,
/* Compare all email addresses of the subject. With SUBSTR given as
- True a substring search is done in the mail address. If X509
- states whether thr search is done on an X.509 blob. */
+ True a substring search is done in the mail address. The X509 flag
+ indicated whether the search is done on an X.509 blob. */
static int
blob_cmp_mail (KEYBOXBLOB blob, const char *name, size_t namelen, int substr,
int x509)
@@ -435,32 +436,62 @@ blob_cmp_mail (KEYBOXBLOB blob, const char *name, size_t namelen, int substr,
for (idx=!!x509 ;idx < nuids; idx++)
{
size_t mypos = pos;
+ size_t mylen;
mypos += idx*uidinfolen;
off = get32 (buffer+mypos);
len = get32 (buffer+mypos+4);
if (off+len > length)
- return 0; /* error: better stop here out of bounds */
- if (!x509)
+ return 0; /* error: better stop here - out of bounds */
+ if (x509)
{
- /* For OpenPGP we need to forward to the mailbox part. */
- for ( ;len && buffer[off] != '<'; len--, off++)
+ if (len < 2 || buffer[off] != '<')
+ continue; /* empty name or trailing 0 not stored */
+ len--; /* one back */
+ if ( len < 3 || buffer[off+len] != '>')
+ continue; /* not a proper email address */
+ off++;
+ len--;
+ }
+ else /* OpenPGP. */
+ {
+ /* We need to forward to the mailbox part. */
+ mypos = off;
+ mylen = len;
+ for ( ; len && buffer[off] != '<'; len--, off++)
;
+ if (len < 2 || buffer[off] != '<')
+ {
+ /* Mailbox not explicitly given or too short. Restore
+ OFF and LEN and check whether the entire string
+ resembles a mailbox without the angle brackets. */
+ off = mypos;
+ len = mylen;
+ if (!is_valid_mailbox_mem (buffer+off, len))
+ continue; /* Not a mail address. */
+ }
+ else /* Seems to be standard user id with mail address. */
+ {
+ off++; /* Point to first char of the mail address. */
+ len--;
+ /* Search closing '>'. */
+ for (mypos=off; len && buffer[mypos] != '>'; len--, mypos++)
+ ;
+ if (!len || buffer[mypos] != '>' || off == mypos)
+ continue; /* Not a proper mail address. */
+ len = mypos - off;
+ }
+
}
- if (len < 2 || buffer[off] != '<')
- continue; /* empty name or trailing 0 not stored */
- len--; /* one back */
- if ( len < 3 || buffer[off+len] != '>')
- continue; /* not a proper email address */
- len--;
+
if (substr)
{
- if (ascii_memcasemem (buffer+off+1, len, name, namelen))
+ if (ascii_memcasemem (buffer+off, len, name, namelen))
return idx+1; /* found */
}
else
{
- if (len == namelen && !ascii_memcasecmp (buffer+off+1, name, len))
+ if (len == namelen && !ascii_memcasecmp (buffer+off, name, len))
return idx+1; /* found */
}
}
diff --git a/po/ru.po b/po/ru.po
index e6f82f7..15ddf27 100644
--- a/po/ru.po
+++ b/po/ru.po
@@ -4,14 +4,14 @@
# !-- no such user (2011-01-11)
# Thanks Pawel I. Shajdo <pshajdo@gmail.com>.
# Thanks Cmecb for the inspiration.
-# Ineiev <ineiev@gnu.org>, 2014
+# Ineiev <ineiev@gnu.org>, 2014, 2015
#
# Designated-Translator: none
msgid ""
msgstr ""
"Project-Id-Version: GnuPG 2.1.0\n"
"Report-Msgid-Bugs-To: translations@gnupg.org\n"
-"PO-Revision-Date: 2014-12-12 17:16+0000\n"
+"PO-Revision-Date: 2015-02-12 17:17+0000\n"
"Last-Translator: Ineiev <ineiev@gnu.org>\n"
"Language-Team: Russian <gnupg-ru@gnupg.org>\n"
"Language: ru\n"
@@ -128,7 +128,7 @@ msgstr "на карте нет основного аутентификацион
#, c-format
msgid "no suitable card key found: %s\n"
-msgstr "в карте не найдено подходящего ключа: %s\n"
+msgstr "на карте не найдено подходящего ключа: %s\n"
#, c-format
msgid "shadowing the key failed: %s\n"
@@ -346,7 +346,7 @@ msgid "allow presetting passphrase"
msgstr "разрешить предустанавливать фразу-пароль"
msgid "allow caller to override the pinentry"
-msgstr ""
+msgstr "разрешить клиентам замещать собой pinentry"
msgid "enable ssh support"
msgstr "включить поддержку ssh"
@@ -1041,13 +1041,13 @@ msgid "armor: %s\n"
msgstr "текстовый формат: %s\n"
msgid "invalid armor header: "
-msgstr "неправильный текстовый заголовок: "
+msgstr "недопустимый текстовый заголовок: "
msgid "armor header: "
msgstr "текстовый заголовок: "
msgid "invalid clearsig header\n"
-msgstr "неправильный заголовок текстовой подписи\n"
+msgstr "недопустимый заголовок текстовой подписи\n"
msgid "unknown armor header: "
msgstr "неизвестный текстовый заголовок: "
@@ -1059,7 +1059,7 @@ msgid "unexpected armor: "
msgstr "неожиданный текстовый формат: "
msgid "invalid dash escaped line: "
-msgstr "неправильная строка, выделенная дефисами: "
+msgstr "недопустимая строка, выделенная дефисами: "
#, c-format
msgid "invalid radix64 character %02X skipped\n"
@@ -1089,7 +1089,7 @@ msgstr "не найдено данных формата OpenPGP.\n"
#, c-format
msgid "invalid armor: line longer than %d characters\n"
-msgstr "неправильный текстовый формат: строка длиннее %d символов\n"
+msgstr "недопустимый текстовый формат: строка длиннее %d символов\n"
msgid ""
"quoted printable character in armor - probably a buggy MTA has been used\n"
@@ -1136,7 +1136,7 @@ msgid "OpenPGP card no. %s detected\n"
msgstr "Обнаружена карта OpenPGP номер %s\n"
msgid "can't do this in batch mode\n"
-msgstr "невозможно сделать это в пакетном режиме\n"
+msgstr "в пакетном режиме это действие невозможно\n"
msgid "This command is only available for version 2 cards\n"
msgstr "Эта команда доступна только для карт версии 2.\n"
@@ -1160,13 +1160,13 @@ msgid "unspecified"
msgstr "не указан"
msgid "not forced"
-msgstr "не принудительно"
+msgstr "не принудительный"
msgid "forced"
-msgstr "принудительно"
+msgstr "принудительный"
msgid "Error: Only plain ASCII is currently allowed.\n"
-msgstr "Ошибка: Допустим только чистый ASCII.\n"
+msgstr "Ошибка: Допустим только простой текст ASCII.\n"
msgid "Error: The \"<\" character may not be used.\n"
msgstr "Ошибка: Нельзя использовать символ \"<\".\n"
@@ -1204,7 +1204,7 @@ msgid "error writing '%s': %s\n"
msgstr "ошибка записи '%s': %s\n"
msgid "Login data (account name): "
-msgstr "Учетная запись (имя):"
+msgstr "Учетная запись (имя): "
#, c-format
msgid "Error: Login data too long (limit is %d characters).\n"
@@ -1237,7 +1237,7 @@ msgid "CA fingerprint: "
msgstr "отпечаток удостоверяющего центра: "
msgid "Error: invalid formatted fingerprint.\n"
-msgstr "Ошибка: неправильный формат отпечатка.\n"
+msgstr "Ошибка: недопустимый формат отпечатка.\n"
#, c-format
msgid "key operation not possible: %s\n"
@@ -1291,7 +1291,7 @@ msgid "error changing size of key %d to %u bits: %s\n"
msgstr "ошибка изменения размера ключа %d до %u бит: %s\n"
msgid "Make off-card backup of encryption key? (Y/n) "
-msgstr "Сделать вне карты архивную копию ключа шифрования? (Y/n)"
+msgstr "Сделать вне карты архивную копию ключа шифрования? (Y/n) "
msgid "Note: keys are already stored on the card!\n"
msgstr "Замечание: ключи уже хранятся на карте!\n"
@@ -1331,23 +1331,17 @@ msgstr "Выберите, где хранить ключ:\n"
msgid "KEYTOCARD failed: %s\n"
msgstr "сбой записи ключа на карту: %s\n"
-#, fuzzy
-#| msgid "This command is not allowed while in %s mode.\n"
msgid "This command is not supported by this card\n"
-msgstr "Данная команда в режиме %s недопустима.\n"
+msgstr "Данная команда этой картой не поддерживается.\n"
-#, fuzzy
-#| msgid "Note: keys are already stored on the card!\n"
msgid "Note: This command destroys all keys stored on the card!\n"
-msgstr "Замечание: ключи уже хранятся на карте!\n"
+msgstr "Замечание: эта команда сотрет с карты все ключи!\n"
-#, fuzzy
-#| msgid "Continue? (Y/n) "
msgid "Continue? (y/N) "
-msgstr "Продолжить? (Y/n) "
+msgstr "Продолжить? (y/N) "
msgid "Really do a factory reset? (enter \"yes\") "
-msgstr ""
+msgstr "Подтвердите сброс к заводским установкам (введите \"yes\") "
msgid "quit this menu"
msgstr "выйти из этого меню"
@@ -1368,7 +1362,7 @@ msgid "change URL to retrieve key"
msgstr "изменить URL получения ключа"
msgid "fetch the key specified in the card URL"
-msgstr "запросить ключ, указанный по заданному картой URL"
+msgstr "запросить ключ по заданному картой URL"
msgid "change the login name"
msgstr "изменить имя учетной записи"
@@ -1398,7 +1392,7 @@ msgid "unblock the PIN using a Reset Code"
msgstr "разблокировать PIN с помощью кода сброса"
msgid "destroy all keys and data"
-msgstr ""
+msgstr "уничтожить все ключи и данные"
msgid "gpg/card> "
msgstr "gpg/card> "
@@ -1437,10 +1431,10 @@ msgid "can't do this in batch mode without \"--yes\"\n"
msgstr "не могу выполнить в пакетном режиме без \"--yes\"\n"
msgid "Delete this key from the keyring? (y/N) "
-msgstr "Удалить данный ключ из таблицы? (y/N)"
+msgstr "Удалить данный ключ из таблицы? (y/N) "
msgid "This is a secret key! - really delete? (y/N) "
-msgstr "Это закрытый ключ! - все равно удалить? (y/N)"
+msgstr "Это закрытый ключ! - все равно удалить? (y/N) "
#, c-format
msgid "deleting secret %s failed: %s\n"
@@ -1457,7 +1451,7 @@ msgid "deleting keyblock failed: %s\n"
msgstr "сбой при удалении блока ключа: %s\n"
msgid "ownertrust information cleared\n"
-msgstr "информация о доверии владельцу стерта\n"
+msgstr "сведения о доверии владельцу сброшены\n"
#, c-format
msgid "there is a secret key for public key \"%s\"!\n"
@@ -1494,20 +1488,19 @@ msgid ""
"WARNING: forcing symmetric cipher %s (%d) violates recipient preferences\n"
msgstr ""
"Внимание: принудительное использование симметричного шифра %s (%d)\n"
-" противоречит предпочтениям получателя\n"
+" нарушает предпочтения получателя\n"
#, c-format
msgid ""
"WARNING: forcing compression algorithm %s (%d) violates recipient "
"preferences\n"
-msgstr ""
-"Внимание: сжатие алгоритмом %s (%d) противоречит предпочтениям получателя\n"
+msgstr "Внимание: сжатие алгоритмом %s (%d) нарушает предпочтения получателя\n"
#, c-format
msgid "forcing symmetric cipher %s (%d) violates recipient preferences\n"
msgstr ""
-"принудительное использование симметричного шифра %s (%d) противоречит "
-"предпочтениям получателя\n"
+"принудительное использование симметричного шифра %s (%d) нарушает "
+"предпочтения получателя\n"
#, c-format
msgid "you may not use %s while in %s mode\n"
@@ -1544,8 +1537,7 @@ msgstr ""
msgid "this platform requires temporary files when calling external programs\n"
msgstr ""
-"на данной платформе требуется использование временных файлов при вызове "
-"внешних программ\n"
+"на данной платформе при вызове внешних программ требуются временные файлы\n"
#, c-format
msgid "unable to execute program '%s': %s\n"
@@ -2299,7 +2291,7 @@ msgstr "пропущен блок типа %d\n"
#, c-format
msgid "%lu keys processed so far\n"
-msgstr "%lu ключей обработано\n"
+msgstr "обработано %lu ключей\n"
#, c-format
msgid "Total number processed: %lu\n"
@@ -2390,14 +2382,12 @@ msgstr "крайне желательно, чтобы Вы обновили св
msgid "re-distribute this key to avoid potential algorithm mismatch problems\n"
msgstr ""
-"распространили этот ключ, чтобы избежать потенциальных проблем несовпадения "
-"алгоритмов\n"
+"распространили этот ключ во избежание возможных нестыковок алгоритмов\n"
#, c-format
msgid "you can update your preferences with: gpg --edit-key %s updpref save\n"
msgstr ""
-"Вы можете обновить список предпочтений командой\n"
-" gpg --edit-key %s updpref save\n"
+"свои предпочтения можно обновить командой gpg --edit-key %s updpref save\n"
#, c-format
msgid "key %s: no user ID\n"
@@ -2423,7 +2413,7 @@ msgid "key %s: no valid user IDs\n"
msgstr "ключ %s: нет действительных ID пользователя\n"
msgid "this may be caused by a missing self-signature\n"
-msgstr "причиной этого может быть отсутствие самоподписи\n"
+msgstr "может быть, из-за отсутствия самоподписи\n"
#, c-format
msgid "key %s: public key not found: %s\n"
@@ -2455,11 +2445,11 @@ msgstr "ключ %s: не совпадает с нашей копией\n"
#, c-format
msgid "key %s: can't locate original keyblock: %s\n"
-msgstr "ключ %s: не нахожу оригинальный блок ключа: %s\n"
+msgstr "ключ %s: оригинальный блок ключей не найден: %s\n"
#, c-format
msgid "key %s: can't read original keyblock: %s\n"
-msgstr "ключ %s: не могу прочитать оригинальный блок ключа: %s\n"
+msgstr "ключ %s: оригинальный блок ключей не читается: %s\n"
#, c-format
msgid "key %s: \"%s\" 1 new user ID\n"
@@ -2522,7 +2512,7 @@ msgid "secret key %s: %s\n"
msgstr "закрытый ключ %s: %s\n"
msgid "importing secret keys not allowed\n"
-msgstr "импорт закрытого ключа не позволен\n"
+msgstr "импорт закрытого ключа не допускается\n"
#, c-format
msgid "key %s: secret key with invalid cipher %d - skipped\n"
@@ -2568,7 +2558,7 @@ msgstr "ключ %s: нет подключа для связывания клю
#, c-format
msgid "key %s: invalid subkey binding\n"
-msgstr "ключ %s: неправильная связь подключей\n"
+msgstr "ключ %s: недопустимая связь подключей\n"
#, c-format
msgid "key %s: removed multiple subkey binding\n"
@@ -2580,7 +2570,7 @@ msgstr "ключ %s: нет подключа для отзыва ключа\n"
#, c-format
msgid "key %s: invalid subkey revocation\n"
-msgstr "ключ %s: недействительный отзыв подключа\n"
+msgstr "ключ %s: неверный отзыв подключа\n"
#, c-format
msgid "key %s: removed multiple subkey revocation\n"
@@ -2628,7 +2618,7 @@ msgstr "Внимание: ключ %s, возможно, отозван: клю
#, c-format
msgid "key %s: \"%s\" revocation certificate added\n"
-msgstr "ключ %s: \"%s\" добавлен сертификат отзыва\n"
+msgstr "ключ %s: добавлен сертификат отзыва \"%s\"\n"
#, c-format
msgid "key %s: direct key signature added\n"
@@ -2791,7 +2781,7 @@ msgid "\"%s\" was already signed by key %s\n"
msgstr "\"%s\" уже подписан ключом %s\n"
msgid "Do you want to sign it again anyway? (y/N) "
-msgstr "Вы все равно хотите снова подписать его? (y/N)"
+msgstr "Вы все равно хотите снова подписать его? (y/N) "
#, c-format
msgid "Nothing to sign with key %s\n"
@@ -2840,7 +2830,7 @@ msgid ""
"Are you sure that you want to sign this key with your\n"
"key \"%s\" (%s)\n"
msgstr ""
-"Уверены ли Вы, что хотите подписать этот ключ\n"
+"Вы уверены, что хотите подписать этот ключ\n"
"своим ключом \"%s\" (%s)?\n"
msgid "This will be a self-signature.\n"
@@ -2868,16 +2858,16 @@ msgid "I have checked this key very carefully.\n"
msgstr "Этот ключ проверен мной очень тщательно.\n"
msgid "Really sign? (y/N) "
-msgstr "Действительно подписать? (y/N)"
+msgstr "Действительно подписать? (y/N) "
#, c-format
msgid "signing failed: %s\n"
-msgstr "не удалось подписать: %s\n"
+msgstr "подписать не удалось: %s\n"
msgid "Key has only stub or on-card key items - no passphrase to change.\n"
msgstr ""
"В ключе только заготовка или элементы для карты -\n"
-"нет фразы-пароля для изменения.\n"
+"фразы-пароля для изменения нет.\n"
#, c-format
msgid "key %s: error changing passphrase: %s\n"
@@ -2987,7 +2977,7 @@ msgid "revoke key or selected subkeys"
msgstr "отозвать ключ или выбранные подключи"
msgid "enable key"
-msgstr "включить ключ"
+msgstr "подключить ключ"
msgid "disable key"
msgstr "отключить ключ"
@@ -3017,7 +3007,7 @@ msgid ""
" a 't' for trust signatures (tsign), an 'nr' for non-revocable signatures\n"
" (nrsign), or any combination thereof (ltsign, tnrsign, etc.).\n"
msgstr ""
-"* Команда 'sign' может иметь префикс 'l' (локальные подписи, lsign),\n"
+"* У команды 'sign' может быть приставка 'l' (локальные подписи, lsign),\n"
" 't' (подписи доверия, tsign), 'nr' (неотзываемые, \n"
" nrsign) или любое их сочетание (ltsign, tnrsign и т.д.).\n"
@@ -3166,11 +3156,11 @@ msgstr "(особо важный)"
#, c-format
msgid "created: %s"
-msgstr "создан: %s"
+msgstr " создан: %s"
#, c-format
msgid "revoked: %s"
-msgstr "отозван: %s"
+msgstr " отозван: %s"
#, c-format
msgid "expired: %s"
@@ -3178,7 +3168,7 @@ msgstr "просрочен с: %s"
#, c-format
msgid "expires: %s"
-msgstr "срок действия истекает: %s"
+msgstr " годен до: %s"
# perhaps this should be somewhere in help/man
# (S - подпись, C - сертификация, E - шифрование, A - аутентификация)
@@ -3340,7 +3330,7 @@ msgid "subkey %s does not sign and so does not need to be cross-certified\n"
msgstr "подключ %s не для подписей, он не нуждается в перекрестном заверении\n"
msgid "Please select exactly one user ID.\n"
-msgstr "Выберите только один ID пользователя.\n"
+msgstr "Выберите ровно один ID пользователя.\n"
#, c-format
msgid "skipping v3 self-signature on user ID \"%s\"\n"
@@ -3504,10 +3494,10 @@ msgstr "11223300"
#, c-format
msgid "Possible actions for a %s key: "
-msgstr "Возможные действия для ключа %s:"
+msgstr "Возможные действия для ключа %s: "
msgid "Current allowed actions: "
-msgstr "Допустимы действия:"
+msgstr "Допустимы действия: "
#, c-format
msgid " (%c) Toggle the sign capability\n"
@@ -3591,7 +3581,7 @@ msgstr "Нет ключа с таким кодом\n"
#, c-format
msgid "%s keys may be between %u and %u bits long.\n"
-msgstr "Ключи %s могут иметь длину от %u до %u бит.\n"
+msgstr "длина ключей %s может быть от %u до %u бит.\n"
#, c-format
msgid "What keysize do you want for the subkey? (%u) "
@@ -3622,10 +3612,10 @@ msgid ""
msgstr ""
"Выберите срок действия ключа.\n"
" 0 = не ограничен\n"
-" <n> = срок действия - n дней\n"
-" <n>w = срок действия - n недель\n"
-" <n>m = срок действия - n месяцев\n"
-" <n>y = срок действия - n лет\n"
+" <n> = срок действия ключа - n дней\n"
+" <n>w = срок действия ключа - n недель\n"
+" <n>m = срок действия ключа - n месяцев\n"
+" <n>y = срок действия ключа - n лет\n"
msgid ""
"Please specify how long the signature should be valid.\n"
@@ -3816,8 +3806,8 @@ msgid ""
"generator a better chance to gain enough entropy.\n"
msgstr ""
"Необходимо получить много случайных чисел. Желательно, чтобы Вы\n"
-"выполняли некоторые другие действия (печать на клавиатуре, движения мыши,\n"
-"обращения к дискам) в процессе генерации; это даст генератору\n"
+"в процессе генерации выполняли какие-то другие действия (печать\n"
+"на клавиатуре, движения мыши, обращения к дискам); это даст генератору\n"
"случайных чисел больше возможностей получить достаточное количество "
"энтропии.\n"
@@ -3920,7 +3910,7 @@ msgid "never "
msgstr "никогда "
msgid "Critical signature policy: "
-msgstr "Критические правила для подписи: "
+msgstr "Критические правила подписи: "
msgid "Signature policy: "
msgstr "Правила подписи: "
@@ -4005,7 +3995,7 @@ msgstr "учитывать набор записей PKA при получени
#, c-format
msgid "WARNING: keyserver option '%s' is not used on this platform\n"
msgstr ""
-"Внимание: параметр сервера ключей '%s' не используется на данной платформе\n"
+"ВНИМАНИЕ: параметр сервера ключей `%s' на данной платформе не используется\n"
msgid "disabled"
msgstr "отключен"
@@ -4045,7 +4035,7 @@ msgstr "ключ не найден на сервере ключей\n"
#, c-format
msgid "requesting key %s from %s server %s\n"
-msgstr "запрашиваю ключ %s с %s сервера %s\n"
+msgstr "запрашиваю ключ %s с сервера %s %s\n"
#, c-format
msgid "requesting key %s from %s\n"
@@ -4057,7 +4047,7 @@ msgstr "пропущено \"%s\": %s\n"
#, c-format
msgid "sending key %s to %s server %s\n"
-msgstr "отправка ключа %s на %s сервер %s\n"
+msgstr "отправка ключа %s на сервер %s %s\n"
#, c-format
msgid "sending key %s to %s\n"
@@ -4236,7 +4226,7 @@ msgstr ""
#, c-format
msgid "standalone signature of class 0x%02x\n"
-msgstr "самостоятельная подпись класса 0x%02x\n"
+msgstr "отдельная подпись класса 0x%02x\n"
msgid "old style (PGP 2.x) signature\n"
msgstr "подпись старого типа (PGP 2.x)\n"
@@ -4396,7 +4386,7 @@ msgstr ""
"создан %s%s.\n"
msgid "Enter passphrase\n"
-msgstr "Введите пароль\n"
+msgstr "Введите фразу-пароль\n"
msgid "cancelled by user\n"
msgstr "прервано пользователем\n"
@@ -4849,7 +4839,7 @@ msgstr "Отмена"
#, c-format
msgid "(Probably you want to select %d here)\n"
-msgstr "(Возможно, Вы здесь выберете %d)\n"
+msgstr "(Скорее всего, Вы здесь выберете %d)\n"
msgid "Enter an optional description; end it with an empty line:\n"
msgstr "Введите необязательное пояснение; завершите пустой строкой:\n"
@@ -4928,7 +4918,7 @@ msgstr "Замечание: ключ для подписей %s отозван\n
#, c-format
msgid "assuming bad signature from key %s due to an unknown critical bit\n"
msgstr ""
-"предполагается плохая подпись ключа %s из-за неизвестного критического бита\n"
+"подпись ключа %s считается плохой из-за неизвестного критического бита\n"
#, c-format
msgid "key %s: no subkey for subkey revocation signature\n"
@@ -5252,7 +5242,7 @@ msgstr ""
#, c-format
msgid "input line %u too long or missing LF\n"
-msgstr "входная строка %u слишком длинная или пропущен перевод строки\n"
+msgstr "слишком длинная входная строка %u или пропущен перевод строки\n"
#, c-format
msgid "can't open fd %d: %s\n"
@@ -5485,7 +5475,7 @@ msgstr ""
#, c-format
msgid "can't access %s - invalid OpenPGP card?\n"
-msgstr "нет доступа к %s - неработоспособная карта OpenPGP?\n"
+msgstr "нет доступа к %s - непригодная карта OpenPGP?\n"
msgid "||Please enter your PIN at the reader's pinpad"
msgstr "||Введите PIN на клавиатуре считывателя"
@@ -5767,8 +5757,8 @@ msgid ""
"S/N %s, ID 0x%08lX,\n"
"created %s, expires %s.\n"
msgstr ""
-"Введите фразу-пароль для доступа к закрытому ключу для сертификата X.509:\"%s"
-"\"\n"
+"Введите фразу-пароль для доступа к закрытому ключу сертификата X.509:\n"
+"\"%s\"\n"
"S/N %s, ID 0x%08lX,\n"
"создан %s, истекает %s.\n"
@@ -7589,7 +7579,7 @@ msgid "|N|set minimal required length for new passphrases to N"
msgstr "|N|установить минимальную длину фразы-пароля равной N"
msgid "|N|require at least N non-alpha characters for a new passphrase"
-msgstr "|n|требовать не менее N неалфавитных символов для новой фразы-пароля"
+msgstr "|n|требовать для новой фразы-пароля не менее N неалфавитных символов"
msgid "|FILE|check new passphrases against pattern in FILE"
msgstr "|FILE|проверять новую фразу-пароль по файлу образцов FILE"
diff --git a/po/uk.po b/po/uk.po
index f04bf0f..2f29aee 100644
--- a/po/uk.po
+++ b/po/uk.po
@@ -2,12 +2,12 @@
# Copyright (C) 2011 Free Software Foundation, Inc.
# This file is distributed under the same license as the GnuPG package.
#
-# Yuri Chornoivan <yurchor@ukr.net>, 2011, 2014.
+# Yuri Chornoivan <yurchor@ukr.net>, 2011, 2014, 2015.
msgid ""
msgstr ""
"Project-Id-Version: GNU gnupg 2.1.0-gitfe8619d\n"
"Report-Msgid-Bugs-To: translations@gnupg.org\n"
-"PO-Revision-Date: 2014-11-07 18:02+0200\n"
+"PO-Revision-Date: 2015-02-18 19:09+0200\n"
"Last-Translator: Yuri Chornoivan <yurchor@ukr.net>\n"
"Language-Team: Ukrainian <kde-i18n-uk@kde.org>\n"
"Language: uk\n"
@@ -339,7 +339,7 @@ msgid "allow presetting passphrase"
msgstr "дозволити попереднє встановлення пароля"
msgid "allow caller to override the pinentry"
-msgstr ""
+msgstr "дозволити функції виклику перевизначати pinentry"
msgid "enable ssh support"
msgstr "увімкнути підтримку ssh"
@@ -779,10 +779,8 @@ msgstr "очікування на працездатність агента… (
msgid "connection to agent established\n"
msgstr "встановлено з’єднання з агентом\n"
-#, fuzzy
-#| msgid "connection to agent established\n"
msgid "connection to agent is in restricted mode\n"
-msgstr "встановлено з’єднання з агентом\n"
+msgstr "з’єднання з агентом відбувається у обмеженому режимі\n"
#, c-format
msgid "no running Dirmngr - starting '%s'\n"
@@ -1337,23 +1335,20 @@ msgstr "Виберіть сховище для зберігання ключа:\
msgid "KEYTOCARD failed: %s\n"
msgstr "Помилка KEYTOCARD: %s\n"
-#, fuzzy
-#| msgid "This command is not allowed while in %s mode.\n"
msgid "This command is not supported by this card\n"
-msgstr "Цією командою не можна користуватися у режимі %s.\n"
+msgstr "Цією карткою не передбачено підтримки вказаної команди\n"
-#, fuzzy
-#| msgid "Note: keys are already stored on the card!\n"
msgid "Note: This command destroys all keys stored on the card!\n"
-msgstr "ЗАУВАЖЕННЯ: ключі вже збережено на картці!\n"
+msgstr ""
+"Зауваження: у результаті виконання цієї команди усі ключі на картці буде "
+"знищено!\n"
-#, fuzzy
-#| msgid "Continue? (Y/n) "
msgid "Continue? (y/N) "
-msgstr "Продовжити? (Y (так)/n (ні)) "
+msgstr "Продовжити? (y (так)/N (ні)) "
msgid "Really do a factory reset? (enter \"yes\") "
msgstr ""
+"Справді хочете скинути усе до типових налаштувань? (введіть «yes» («так»)) "
msgid "quit this menu"
msgstr "вийти з цього меню"
@@ -1404,7 +1399,7 @@ msgid "unblock the PIN using a Reset Code"
msgstr "розблокувати під коду за допомогою коду скидання"
msgid "destroy all keys and data"
-msgstr ""
+msgstr "знищити усі ключі і дані"
msgid "gpg/card> "
msgstr "gpg/картка> "
@@ -2314,10 +2309,8 @@ msgstr "імпортувати підписи, позначені як лише
msgid "repair damage from the pks keyserver during import"
msgstr "відновлювати пошкодження сервером ключів pks під час імпортування"
-#, fuzzy
-#| msgid "do not update the trustdb after import"
msgid "do not clear the ownertrust values during import"
-msgstr "не оновлювати базу даних довіри після імпортування"
+msgstr "не вилучати значень власної довіри під час імпортування"
msgid "do not update the trustdb after import"
msgstr "не оновлювати базу даних довіри після імпортування"
@@ -2343,10 +2336,9 @@ msgstr "оброблено %lu ключів\n"
msgid "Total number processed: %lu\n"
msgstr "Загалом оброблено: %lu\n"
-#, fuzzy, c-format
-#| msgid " skipped new keys: %lu\n"
+#, c-format
msgid " skipped PGP-2 keys: %lu\n"
-msgstr "пропущено нових ключів: %lu\n"
+msgstr " пропущено ключів PGP-2: %lu\n"
#, c-format
msgid " skipped new keys: %lu\n"
@@ -4292,7 +4284,7 @@ msgstr ", алгоритм ключа "
#, c-format
msgid "WARNING: not a detached signature; file '%s' was NOT verified!\n"
-msgstr ""
+msgstr "УВАГА: не відє’днаний підпис; файл «%s» не було перевірено!\n"
#, c-format
msgid "Can't check signature: %s\n"
@@ -5555,10 +5547,8 @@ msgstr ""
msgid "failed to store the key: %s\n"
msgstr "не вдалося зберегти ключ: %s\n"
-#, fuzzy
-#| msgid "unsupported inquiry '%s'\n"
msgid "unsupported curve\n"
-msgstr "непідтримуваний запит «%s»\n"
+msgstr "непідтримувана крива\n"
msgid "please wait while key is being generated ...\n"
msgstr "зачекайте на завершення створення ключа...\n"
@@ -5661,10 +5651,8 @@ msgstr "роботу обробника для дескриптора %d пер
msgid "invalid radix64 character %02x skipped\n"
msgstr "пропущено некоректний символ radix64 %02x\n"
-#, fuzzy
-#| msgid "no gpg-agent running in this session\n"
msgid "no dirmngr running in this session\n"
-msgstr "у цьому сеансі не запущено gpg-agent\n"
+msgstr "у цьому сеансі не запущено dirmngr\n"
#, c-format
msgid "validation model requested by certificate: %s"
diff --git a/scd/Makefile.am b/scd/Makefile.am
index f7217e3..6212e61 100644
--- a/scd/Makefile.am
+++ b/scd/Makefile.am
@@ -21,7 +21,7 @@ EXTRA_DIST = ChangeLog-2011 scdaemon-w32info.rc
libexec_PROGRAMS = scdaemon
-AM_CPPFLAGS = -I$(top_srcdir)/gl -I$(top_srcdir)/intl -I$(top_srcdir)/common
+AM_CPPFLAGS = -I$(top_srcdir)/common
include $(top_srcdir)/am/cmacros.am
diff --git a/scd/apdu.c b/scd/apdu.c
index e5db4f0..53cc4b9 100644
--- a/scd/apdu.c
+++ b/scd/apdu.c
@@ -1307,7 +1307,7 @@ control_pcsc_direct (int slot, pcsc_dword_t ioctl_code,
long err;
err = pcsc_control (reader_table[slot].pcsc.card, ioctl_code,
- cntlbuf, len, buffer, *buflen, buflen);
+ cntlbuf, len, buffer, buflen? *buflen:0, buflen);
if (err)
{
log_error ("pcsc_control failed: %s (0x%lx)\n",
@@ -1375,14 +1375,18 @@ control_pcsc_wrapped (int slot, pcsc_dword_t ioctl_code,
full_len = len;
- n = *buflen < len ? *buflen : len;
+ if (buflen)
+ n = *buflen < len ? *buflen : len;
+ else
+ n = 0;
if ((i=readn (slotp->pcsc.rsp_fd, buffer, n, &len)) || len != n)
{
log_error ("error receiving PC/SC CONTROL response: %s\n",
i? strerror (errno) : "premature EOF");
goto command_failed;
}
- *buflen = n;
+ if (buflen)
+ *buflen = n;
full_len -= len;
if (full_len)
@@ -1851,9 +1855,9 @@ pcsc_vendor_specific_init (int slot)
if (l == 1)
v = p[0];
else if (l == 2)
- v = buf16_to_uint (p);
+ v = (((unsigned int)p[1] << 8) | p[0]);
else if (l == 4)
- v = buf32_to_uint (p);
+ v = (((unsigned int)p[3] << 24) | (p[2] << 16) | (p[1] << 8) | p[0]);
if (tag == PCSCv2_PART10_PROPERTY_bMinPINSize)
reader_table[slot].pcsc.pinmin = v;
diff --git a/scd/app-openpgp.c b/scd/app-openpgp.c
index 6583fb2..10bd64e 100644
--- a/scd/app-openpgp.c
+++ b/scd/app-openpgp.c
@@ -1496,7 +1496,7 @@ get_public_key (app_t app, int keyno)
if (app->app_local->keyattr[keyno].key_type == KEY_TYPE_RSA)
{
err = gcry_sexp_build (&s_pkey, NULL, "(public-key(rsa(n%b)(e%b)))",
- mlen, mbuf, elen, ebuf);
+ (int)mlen, mbuf, (int)elen, ebuf);
if (err)
goto leave;
@@ -1518,7 +1518,7 @@ get_public_key (app_t app, int keyno)
err = gcry_sexp_build (&s_pkey, NULL,
"(public-key(ecc(curve%s)(q%b)))",
- curve_name, mlen, mbuf);
+ curve_name, (int)mlen, mbuf);
if (err)
goto leave;
@@ -1541,7 +1541,7 @@ get_public_key (app_t app, int keyno)
err = gcry_sexp_build (&s_pkey, NULL,
"(public-key(ecc(curve%s)(flags eddsa)(q%b)))",
- curve_name, mlen, mbuf);
+ curve_name, (int)mlen, mbuf);
if (err)
goto leave;
diff --git a/scd/scdaemon.c b/scd/scdaemon.c
index d0777e8..39925ce 100644
--- a/scd/scdaemon.c
+++ b/scd/scdaemon.c
@@ -309,11 +309,11 @@ set_debug (const char *level)
else if (!strcmp (level, "none") || (numok && numlvl < 1))
opt.debug = 0;
else if (!strcmp (level, "basic") || (numok && numlvl <= 2))
- opt.debug = DBG_ASSUAN_VALUE;
+ opt.debug = DBG_IPC_VALUE;
else if (!strcmp (level, "advanced") || (numok && numlvl <= 5))
- opt.debug = DBG_ASSUAN_VALUE|DBG_COMMAND_VALUE;
+ opt.debug = DBG_IPC_VALUE|DBG_COMMAND_VALUE;
else if (!strcmp (level, "expert") || (numok && numlvl <= 8))
- opt.debug = (DBG_ASSUAN_VALUE|DBG_COMMAND_VALUE
+ opt.debug = (DBG_IPC_VALUE|DBG_COMMAND_VALUE
|DBG_CACHE_VALUE|DBG_CARD_IO_VALUE);
else if (!strcmp (level, "guru") || numok)
{
@@ -352,7 +352,7 @@ set_debug (const char *level)
(opt.debug & DBG_CACHE_VALUE )? " cache":"",
(opt.debug & DBG_MEMSTAT_VALUE)? " memstat":"",
(opt.debug & DBG_HASHING_VALUE)? " hashing":"",
- (opt.debug & DBG_ASSUAN_VALUE )? " assuan":"",
+ (opt.debug & DBG_IPC_VALUE )? " ipc":"",
(opt.debug & DBG_CARD_IO_VALUE)? " cardio":"",
(opt.debug & DBG_READER_VALUE )? " reader":"");
}
diff --git a/scd/scdaemon.h b/scd/scdaemon.h
index ab63425..35ada43 100644
--- a/scd/scdaemon.h
+++ b/scd/scdaemon.h
@@ -73,7 +73,7 @@ struct
#define DBG_CACHE_VALUE 64 /* debug the caching */
#define DBG_MEMSTAT_VALUE 128 /* show memory statistics */
#define DBG_HASHING_VALUE 512 /* debug hashing operations */
-#define DBG_ASSUAN_VALUE 1024
+#define DBG_IPC_VALUE 1024
#define DBG_CARD_IO_VALUE 2048
#define DBG_READER_VALUE 4096 /* Trace reader related functions. */
@@ -82,7 +82,7 @@ struct
#define DBG_MEMORY (opt.debug & DBG_MEMORY_VALUE)
#define DBG_CACHE (opt.debug & DBG_CACHE_VALUE)
#define DBG_HASHING (opt.debug & DBG_HASHING_VALUE)
-#define DBG_ASSUAN (opt.debug & DBG_ASSUAN_VALUE)
+#define DBG_IPC (opt.debug & DBG_IPC_VALUE)
#define DBG_CARD_IO (opt.debug & DBG_CARD_IO_VALUE)
#define DBG_READER (opt.debug & DBG_READER_VALUE)
diff --git a/sm/Makefile.am b/sm/Makefile.am
index 7f6df3a..dda3eb8 100644
--- a/sm/Makefile.am
+++ b/sm/Makefile.am
@@ -23,7 +23,7 @@ bin_PROGRAMS = gpgsm
AM_CFLAGS = $(LIBGCRYPT_CFLAGS) $(KSBA_CFLAGS) $(LIBASSUAN_CFLAGS)
-AM_CPPFLAGS = -I$(top_srcdir)/gl -I$(top_srcdir)/common -I$(top_srcdir)/intl
+AM_CPPFLAGS = -I$(top_srcdir)/common
include $(top_srcdir)/am/cmacros.am
if HAVE_W32_SYSTEM
diff --git a/sm/call-agent.c b/sm/call-agent.c
index f579200..4b2ec33 100644
--- a/sm/call-agent.c
+++ b/sm/call-agent.c
@@ -95,7 +95,7 @@ start_agent (ctrl_t ctrl)
opt.agent_program,
opt.lc_ctype, opt.lc_messages,
opt.session_env,
- opt.autostart, opt.verbose, DBG_ASSUAN,
+ opt.autostart, opt.verbose, DBG_IPC,
gpgsm_status2, ctrl);
if (!opt.autostart && gpg_err_code (rc) == GPG_ERR_NO_AGENT)
diff --git a/sm/call-dirmngr.c b/sm/call-dirmngr.c
index f8cfdf8..8e4841b 100644
--- a/sm/call-dirmngr.c
+++ b/sm/call-dirmngr.c
@@ -209,7 +209,7 @@ start_dirmngr_ext (ctrl_t ctrl, assuan_context_t *ctx_r)
err = start_new_dirmngr (&ctx, GPG_ERR_SOURCE_DEFAULT,
opt.homedir, opt.dirmngr_program,
- opt.autostart, opt.verbose, DBG_ASSUAN,
+ opt.autostart, opt.verbose, DBG_IPC,
gpgsm_status2, ctrl);
if (!opt.autostart && gpg_err_code (err) == GPG_ERR_NO_DIRMNGR)
{
@@ -823,7 +823,7 @@ get_cached_cert (assuan_context_t ctx,
*r_cert = NULL;
bin2hex (fpr, 20, hexfpr);
- snprintf (line, DIM(line)-1, "LOOKUP --signle --cache-only 0x%s", hexfpr);
+ snprintf (line, DIM(line)-1, "LOOKUP --single --cache-only 0x%s", hexfpr);
init_membuf (&mb, 4096);
err = assuan_transact (ctx, line, get_cached_cert_data_cb, &mb,
diff --git a/sm/certreqgen.c b/sm/certreqgen.c
index 9720b80..0774591 100644
--- a/sm/certreqgen.c
+++ b/sm/certreqgen.c
@@ -807,7 +807,7 @@ create_request (ctrl_t ctrl,
if (string)
mdalgo = gcry_md_map_name (string);
else
- mdalgo = GCRY_MD_SHA1;
+ mdalgo = GCRY_MD_SHA256;
rc = gcry_md_open (&md, mdalgo, 0);
if (rc)
{
diff --git a/sm/gpgsm.c b/sm/gpgsm.c
index 62e29b8..8cd7e84 100644
--- a/sm/gpgsm.c
+++ b/sm/gpgsm.c
@@ -438,7 +438,7 @@ static int default_include_certs = DEFAULT_INCLUDE_CERTS;
static int default_validation_model;
/* The default cipher algo. */
-#define DEFAULT_CIPHER_ALGO "3DES" /*des-EDE3-CBC*/
+#define DEFAULT_CIPHER_ALGO "AES"
static char *build_list (const char *text,
@@ -670,11 +670,11 @@ set_debug (void)
else if (!strcmp (debug_level, "none") || (numok && numlvl < 1))
opt.debug = 0;
else if (!strcmp (debug_level, "basic") || (numok && numlvl <= 2))
- opt.debug = DBG_ASSUAN_VALUE;
+ opt.debug = DBG_IPC_VALUE;
else if (!strcmp (debug_level, "advanced") || (numok && numlvl <= 5))
- opt.debug = DBG_ASSUAN_VALUE|DBG_X509_VALUE;
+ opt.debug = DBG_IPC_VALUE|DBG_X509_VALUE;
else if (!strcmp (debug_level, "expert") || (numok && numlvl <= 8))
- opt.debug = (DBG_ASSUAN_VALUE|DBG_X509_VALUE
+ opt.debug = (DBG_IPC_VALUE|DBG_X509_VALUE
|DBG_CACHE_VALUE|DBG_CRYPTO_VALUE);
else if (!strcmp (debug_level, "guru") || numok)
{
@@ -714,7 +714,7 @@ set_debug (void)
(opt.debug & DBG_CACHE_VALUE )? " cache":"",
(opt.debug & DBG_MEMSTAT_VALUE)? " memstat":"",
(opt.debug & DBG_HASHING_VALUE)? " hashing":"",
- (opt.debug & DBG_ASSUAN_VALUE )? " assuan":"" );
+ (opt.debug & DBG_IPC_VALUE )? " ipc":"" );
}
diff --git a/sm/gpgsm.h b/sm/gpgsm.h
index 63c9d0b..187ed83 100644
--- a/sm/gpgsm.h
+++ b/sm/gpgsm.h
@@ -153,14 +153,14 @@ struct
#define DBG_CACHE_VALUE 64 /* debug the caching */
#define DBG_MEMSTAT_VALUE 128 /* show memory statistics */
#define DBG_HASHING_VALUE 512 /* debug hashing operations */
-#define DBG_ASSUAN_VALUE 1024 /* debug assuan communication */
+#define DBG_IPC_VALUE 1024 /* debug assuan communication */
#define DBG_X509 (opt.debug & DBG_X509_VALUE)
#define DBG_CRYPTO (opt.debug & DBG_CRYPTO_VALUE)
#define DBG_MEMORY (opt.debug & DBG_MEMORY_VALUE)
#define DBG_CACHE (opt.debug & DBG_CACHE_VALUE)
#define DBG_HASHING (opt.debug & DBG_HASHING_VALUE)
-#define DBG_ASSUAN (opt.debug & DBG_ASSUAN_VALUE)
+#define DBG_IPC (opt.debug & DBG_IPC_VALUE)
/* Forward declaration for an object defined in server.c */
struct server_local_s;
diff --git a/tools/Makefile.am b/tools/Makefile.am
index 1ba0377..5c28954 100644
--- a/tools/Makefile.am
+++ b/tools/Makefile.am
@@ -23,7 +23,7 @@ EXTRA_DIST = \
ccidmon.c ChangeLog-2011 gpg-connect-agent-w32info.rc
-AM_CPPFLAGS = -I$(top_srcdir)/gl -I$(top_srcdir)/intl -I$(top_srcdir)/common
+AM_CPPFLAGS = -I$(top_srcdir)/common
include $(top_srcdir)/am/cmacros.am
if HAVE_W32_SYSTEM
diff --git a/tools/gpgparsemail.c b/tools/gpgparsemail.c
index a8b3dc7..e142f3b 100644
--- a/tools/gpgparsemail.c
+++ b/tools/gpgparsemail.c
@@ -69,7 +69,7 @@ struct parse_info_s {
char *signing_protocol;
int hashing_level; /* The nesting level we are hashing. */
- int hashing;
+ int hashing;
FILE *hash_file;
FILE *sig_file; /* Signature part with MIME or full
@@ -156,7 +156,7 @@ stpcpy (char *a,const char *b)
while (*b)
*a++ = *b++;
*a = 0;
-
+
return (char*)a;
}
#endif
@@ -189,7 +189,7 @@ run_gnupg (int smime, int sig_fd, int data_fd, int *close_list)
if (dup2 (sig_fd, 0) == -1)
die ("dup2 stdin failed: %s", strerror (errno));
}
-
+
/* Keep our data fd and format it for gpg/gpgsm use. */
if (data_fd == -1)
*data_fd_buf = 0;
@@ -205,7 +205,7 @@ run_gnupg (int smime, int sig_fd, int data_fd, int *close_list)
if (dup2 (fd, 1) == -1)
die ("dup2 stderr failed: %s", strerror (errno));
}
-
+
/* Connect stderr to our pipe. */
if (rp[1] != 2)
{
@@ -237,11 +237,11 @@ run_gnupg (int smime, int sig_fd, int data_fd, int *close_list)
"--",
"-", data_fd == -1? NULL : data_fd_buf,
NULL);
-
+
die ("failed to exec the crypto command: %s", strerror (errno));
}
- /* Parent. */
+ /* Parent. */
close (rp[1]);
fp = fdopen (rp[0], "r");
@@ -255,7 +255,7 @@ run_gnupg (int smime, int sig_fd, int data_fd, int *close_list)
{
if (pos < 9)
status_buf[pos] = c;
- else
+ else
{
if (pos == 9)
{
@@ -342,7 +342,7 @@ verify_signature (struct parse_info_s *info)
-/* Prepare for a multipart/signed.
+/* Prepare for a multipart/signed.
FIELD_CTX is the parsed context of the content-type header.*/
static void
mime_signed_begin (struct parse_info_s *info, rfc822parse_t msg,
@@ -387,7 +387,7 @@ mime_signed_begin (struct parse_info_s *info, rfc822parse_t msg,
}
-/* Prepare for a multipart/encrypted.
+/* Prepare for a multipart/encrypted.
FIELD_CTX is the parsed context of the content-type header.*/
static void
mime_encrypted_begin (struct parse_info_s *info, rfc822parse_t msg,
@@ -410,7 +410,7 @@ pkcs7_begin (struct parse_info_s *info, rfc822parse_t msg,
rfc822parse_field_t field_ctx)
{
const char *s;
-
+
(void)msg;
s = rfc822parse_query_parameter (field_ctx, "name", 0);
@@ -509,7 +509,7 @@ message_cb (void *opaque, rfc822parse_event_t event, rfc822parse_t msg)
s1 = rfc822parse_query_media_type (ctx, &s2);
if (s1)
{
- printf ("h media: %*s%s %s\n",
+ printf ("h media: %*s%s %s\n",
info->nesting_level*2, "", s1, s2);
if (info->moss_state == 3)
{
@@ -549,7 +549,7 @@ message_cb (void *opaque, rfc822parse_event_t event, rfc822parse_t msg)
}
else
printf ("h media: %*s none\n", info->nesting_level*2, "");
-
+
rfc822parse_release_field (ctx);
}
else
@@ -573,7 +573,7 @@ message_cb (void *opaque, rfc822parse_event_t event, rfc822parse_t msg)
printf ("b up\n");
if (info->nesting_level)
info->nesting_level--;
- else
+ else
err ("invalid structure (bad nesting level)");
}
else if (event == RFC822PARSE_BOUNDARY || event == RFC822PARSE_LAST_BOUNDARY)
@@ -586,7 +586,7 @@ message_cb (void *opaque, rfc822parse_event_t event, rfc822parse_t msg)
info->skip_show = 1;
printf ("b part\n");
}
- else
+ else
printf ("b last\n");
if (info->moss_state == 2 && info->nesting_level == info->hashing_level)
@@ -648,7 +648,7 @@ parse_message (FILE *fp)
if (rfc822parse_insert (msg, line, length))
die ("parser failed: %s", strerror (errno));
-
+
if (info.hashing)
{
/* Delay hashing of the CR/LF because the last line ending
@@ -689,7 +689,7 @@ parse_message (FILE *fp)
die ("error writing to temporary file: %s", strerror (errno));
}
}
-
+
if (info.show_boundary)
{
if (!opt_no_header)
@@ -727,11 +727,11 @@ parse_message (FILE *fp)
}
-int
+int
main (int argc, char **argv)
{
int last_argc = -1;
-
+
if (argc)
{
argc--; argv++;
@@ -780,8 +780,8 @@ main (int argc, char **argv)
opt_no_header = 1;
argc--; argv++;
}
- }
-
+ }
+
if (argc > 1)
die ("usage: " PGM " [OPTION] [FILE] (try --help for more information)\n");
diff --git a/tools/gpgtar-extract.c b/tools/gpgtar-extract.c
index 1ea3597..6e506d9 100644
--- a/tools/gpgtar-extract.c
+++ b/tools/gpgtar-extract.c
@@ -66,7 +66,11 @@ extract_regular (estream_t stream, const char *dirname,
if (err)
goto leave;
n++;
- nbytes = (n < hdr->nrecords)? RECORDSIZE : (hdr->size % RECORDSIZE);
+ if (n < hdr->nrecords || (hdr->size && !(hdr->size % RECORDSIZE)))
+ nbytes = RECORDSIZE;
+ else
+ nbytes = (hdr->size % RECORDSIZE);
+
nwritten = es_fwrite (record, 1, nbytes, outfp);
if (nwritten != nbytes)
{
diff --git a/tools/rfc822parse.c b/tools/rfc822parse.c
index a70f6a4..285e084 100644
--- a/tools/rfc822parse.c
+++ b/tools/rfc822parse.c
@@ -808,10 +808,12 @@ parse_field (HDR_LINE hdr)
s++; /* Move over the colon. */
for (;;)
{
- if (!*s)
+ while (!*s)
{
if (!hdr->next || !hdr->next->cont)
- break;
+ return tok; /* Ready. */
+
+ /* Next item is a header continuation line. */
hdr = hdr->next;
s = hdr->line;
}
@@ -824,10 +826,11 @@ parse_field (HDR_LINE hdr)
invalid = 0;
for (s++;; s++)
{
- if (!*s)
+ while (!*s)
{
if (!hdr->next || !hdr->next->cont)
- break;
+ goto oparen_out;
+ /* Next item is a header continuation line. */
hdr = hdr->next;
s = hdr->line;
}
@@ -849,6 +852,7 @@ parse_field (HDR_LINE hdr)
else if (*s == '\"')
in_quote = 1;
}
+ oparen_out:
if (!*s)
; /* Actually this is an error, but we don't care about it. */
else
@@ -880,6 +884,7 @@ parse_field (HDR_LINE hdr)
if (*s2 || !hdr->next || !hdr->next->cont)
break;
+ /* Next item is a header continuation line. */
hdr = hdr->next;
s = hdr->line;
}
@@ -931,8 +936,7 @@ parse_field (HDR_LINE hdr)
s++;
}
}
-
- return tok;
+ /*NOTREACHED*/
failure:
{
diff --git a/tools/watchgnupg.c b/tools/watchgnupg.c
index 8ad2a13..9118aa0 100644
--- a/tools/watchgnupg.c
+++ b/tools/watchgnupg.c
@@ -152,7 +152,7 @@ print_fd_and_time (int fd)
/* Print LINE for the client identified by C. Calling this function
- witgh LINE set to NULL, will flush the internal buffer. */
+ with LINE set to NULL, will flush the internal buffer. */
static void
print_line (client_t c, const char *line)
{