mirror of
git://git.gnupg.org/gnupg.git
synced 2024-12-22 10:19:57 +01:00
dirmngr: New options --first and --next for KS_GET.
* dirmngr/server.c (cmd_ks_get): Add option --first and --next. (start_command_handler): Free that new ldap state. * dirmngr/ks-engine-ldap.c (struct ks_engine_ldap_local_s): New. (ks_ldap_new_state, ks_ldap_clear_state): New. (ks_ldap_free_state): New. (return_one_keyblock): New. Mostly factored out from .... (ks_ldap_get): here. Implement --first/--next feature. * dirmngr/ks-action.c (ks_action_get): Rename arg ldap_only to ks_get_flags. * dirmngr/ks-engine.h (KS_GET_FLAG_ONLY_LDAP): New. (KS_GET_FLAG_FIRST): New. (KS_GET_FLAG_NEXT): New. * dirmngr/dirmngr.h (struct server_control_s): Add member ks_get_state. (struct ks_engine_ldap_local_s): New forward reference. -- This feature allows to fetch keyblock by keyblock from an LDAP server. This way tools can process and maybe filter each keyblock in a more flexible way. Here is an example where two keyblocks for one mail address are returned: $ gpg-connect-agent --dirmngr > ks_get --ldap --first <foo@example.org> [... First keyblock is returned ] OK > ks_get --next [ ... Next keyblock is returned ] OK > ks_get --next ERR 167772218 No data <Dirmngr> GnuPG_bug_id: 6224
This commit is contained in:
parent
3390951ffd
commit
4de98d4468
@ -187,8 +187,10 @@ struct cert_ref_s
|
|||||||
};
|
};
|
||||||
typedef struct cert_ref_s *cert_ref_t;
|
typedef struct cert_ref_s *cert_ref_t;
|
||||||
|
|
||||||
|
/* Forward reference; access only via ks-engine-ldap.c. */
|
||||||
|
struct ks_engine_ldap_local_s;
|
||||||
|
|
||||||
/* Forward references; access only through server.c. */
|
/* Forward reference; access only through server.c. */
|
||||||
struct server_local_s;
|
struct server_local_s;
|
||||||
|
|
||||||
#if SIZEOF_UNSIGNED_LONG == 8
|
#if SIZEOF_UNSIGNED_LONG == 8
|
||||||
@ -205,6 +207,7 @@ struct server_control_s
|
|||||||
int no_server; /* We are not running under server control. */
|
int no_server; /* We are not running under server control. */
|
||||||
int status_fd; /* Only for non-server mode. */
|
int status_fd; /* Only for non-server mode. */
|
||||||
struct server_local_s *server_local;
|
struct server_local_s *server_local;
|
||||||
|
struct ks_engine_ldap_local_s *ks_get_state;
|
||||||
int force_crl_refresh; /* Always load a fresh CRL. */
|
int force_crl_refresh; /* Always load a fresh CRL. */
|
||||||
|
|
||||||
int check_revocations_nest_level; /* Internal to check_revovations. */
|
int check_revocations_nest_level; /* Internal to check_revovations. */
|
||||||
|
@ -243,7 +243,7 @@ ks_action_search (ctrl_t ctrl, uri_item_t keyservers,
|
|||||||
keyservers and write the result to the provided output stream. */
|
keyservers and write the result to the provided output stream. */
|
||||||
gpg_error_t
|
gpg_error_t
|
||||||
ks_action_get (ctrl_t ctrl, uri_item_t keyservers,
|
ks_action_get (ctrl_t ctrl, uri_item_t keyservers,
|
||||||
strlist_t patterns, int ldap_only, estream_t outfp)
|
strlist_t patterns, unsigned int ks_get_flags, estream_t outfp)
|
||||||
{
|
{
|
||||||
gpg_error_t err = 0;
|
gpg_error_t err = 0;
|
||||||
gpg_error_t first_err = 0;
|
gpg_error_t first_err = 0;
|
||||||
@ -270,7 +270,7 @@ ks_action_get (ctrl_t ctrl, uri_item_t keyservers,
|
|||||||
|| strcmp (uri->parsed_uri->scheme, "https") == 0);
|
|| strcmp (uri->parsed_uri->scheme, "https") == 0);
|
||||||
int is_ldap = 0;
|
int is_ldap = 0;
|
||||||
|
|
||||||
if (ldap_only)
|
if ((ks_get_flags & KS_GET_FLAG_ONLY_LDAP))
|
||||||
is_hkp_s = is_http_s = 0;
|
is_hkp_s = is_http_s = 0;
|
||||||
|
|
||||||
#if USE_LDAP
|
#if USE_LDAP
|
||||||
@ -287,7 +287,8 @@ ks_action_get (ctrl_t ctrl, uri_item_t keyservers,
|
|||||||
{
|
{
|
||||||
#if USE_LDAP
|
#if USE_LDAP
|
||||||
if (is_ldap)
|
if (is_ldap)
|
||||||
err = ks_ldap_get (ctrl, uri->parsed_uri, sl->d, &infp);
|
err = ks_ldap_get (ctrl, uri->parsed_uri, sl->d, ks_get_flags,
|
||||||
|
&infp);
|
||||||
else
|
else
|
||||||
#endif
|
#endif
|
||||||
if (is_hkp_s)
|
if (is_hkp_s)
|
||||||
|
@ -26,7 +26,8 @@ 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,
|
gpg_error_t ks_action_search (ctrl_t ctrl, uri_item_t keyservers,
|
||||||
strlist_t patterns, estream_t outfp);
|
strlist_t patterns, estream_t outfp);
|
||||||
gpg_error_t ks_action_get (ctrl_t ctrl, uri_item_t keyservers,
|
gpg_error_t ks_action_get (ctrl_t ctrl, uri_item_t keyservers,
|
||||||
strlist_t patterns, int ldap_only, estream_t outfp);
|
strlist_t patterns, unsigned int ks_get_flags,
|
||||||
|
estream_t outfp);
|
||||||
gpg_error_t ks_action_fetch (ctrl_t ctrl, const char *url, 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, uri_item_t keyservers,
|
gpg_error_t ks_action_put (ctrl_t ctrl, uri_item_t keyservers,
|
||||||
void *data, size_t datalen,
|
void *data, size_t datalen,
|
||||||
|
@ -40,7 +40,7 @@
|
|||||||
|
|
||||||
/* Flags with infos from the connected server. */
|
/* Flags with infos from the connected server. */
|
||||||
#define SERVERINFO_REALLDAP 1 /* This is not the PGP keyserver. */
|
#define SERVERINFO_REALLDAP 1 /* This is not the PGP keyserver. */
|
||||||
#define SERVERINFO_PGPKEYV2 2 /* Needs "pgpeyV2" instead of "pgpKey" */
|
#define SERVERINFO_PGPKEYV2 2 /* Needs "pgpKeyV2" instead of "pgpKey"*/
|
||||||
#define SERVERINFO_SCHEMAV2 4 /* Version 2 of the Schema. */
|
#define SERVERINFO_SCHEMAV2 4 /* Version 2 of the Schema. */
|
||||||
#define SERVERINFO_NTDS 8 /* Server is an Active Directory. */
|
#define SERVERINFO_NTDS 8 /* Server is an Active Directory. */
|
||||||
|
|
||||||
@ -50,6 +50,17 @@ time_t timegm(struct tm *tm);
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/* Object to keep state pertaining to this module. */
|
||||||
|
struct ks_engine_ldap_local_s
|
||||||
|
{
|
||||||
|
LDAP *ldap_conn;
|
||||||
|
LDAPMessage *message;
|
||||||
|
LDAPMessage *msg_iter; /* Iterator for message. */
|
||||||
|
unsigned int serverinfo;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static time_t
|
static time_t
|
||||||
ldap2epochtime (const char *timestr)
|
ldap2epochtime (const char *timestr)
|
||||||
@ -165,6 +176,45 @@ ks_ldap_help (ctrl_t ctrl, parsed_uri_t uri)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* Create a new empty state object. Returns NULL on error */
|
||||||
|
static struct ks_engine_ldap_local_s *
|
||||||
|
ks_ldap_new_state (void)
|
||||||
|
{
|
||||||
|
return xtrycalloc (1, sizeof(struct ks_engine_ldap_local_s));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Clear the state object STATE. Returns the STATE object. */
|
||||||
|
static struct ks_engine_ldap_local_s *
|
||||||
|
ks_ldap_clear_state (struct ks_engine_ldap_local_s *state)
|
||||||
|
{
|
||||||
|
if (state->ldap_conn)
|
||||||
|
{
|
||||||
|
ldap_unbind (state->ldap_conn);
|
||||||
|
state->ldap_conn = NULL;
|
||||||
|
}
|
||||||
|
if (state->message)
|
||||||
|
{
|
||||||
|
ldap_msgfree (state->message);
|
||||||
|
state->message = NULL;
|
||||||
|
}
|
||||||
|
state->serverinfo = 0;
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Release a state object. */
|
||||||
|
void
|
||||||
|
ks_ldap_free_state (struct ks_engine_ldap_local_s *state)
|
||||||
|
{
|
||||||
|
if (!state)
|
||||||
|
return;
|
||||||
|
ks_ldap_clear_state (state);
|
||||||
|
xfree (state);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* Convert a keyspec to a filter. Return an error if the keyspec is
|
/* 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
|
bad or is not supported. The filter is escaped and returned in
|
||||||
@ -288,6 +338,8 @@ keyspec_to_ldap_filter (const char *keyspec, char **filter, int only_exact,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* Helper for my_ldap_connect. */
|
||||||
static char *
|
static char *
|
||||||
interrogate_ldap_dn (LDAP *ldap_conn, const char *basedn_search,
|
interrogate_ldap_dn (LDAP *ldap_conn, const char *basedn_search,
|
||||||
unsigned int *r_serverinfo)
|
unsigned int *r_serverinfo)
|
||||||
@ -874,12 +926,90 @@ no_ldap_due_to_tor (ctrl_t ctrl)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Helper for ks_ldap_get. Returns 0 if a key was fetched and printed
|
||||||
|
* to FP. The error code GPG_ERR_NO_DATA is returned if no key was
|
||||||
|
* printed. Note that FP is updated by this function. */
|
||||||
|
static gpg_error_t
|
||||||
|
return_one_keyblock (LDAP *ldap_conn, LDAPMessage *msg, unsigned int serverinfo,
|
||||||
|
estream_t *fp, strlist_t *seenp)
|
||||||
|
{
|
||||||
|
gpg_error_t err;
|
||||||
|
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
|
||||||
|
*
|
||||||
|
* Note that in --first/--next mode we don't do any duplicate
|
||||||
|
* detection.
|
||||||
|
*/
|
||||||
|
|
||||||
|
certid = ldap_get_values (ldap_conn, msg, "pgpcertid");
|
||||||
|
if (certid && certid[0])
|
||||||
|
{
|
||||||
|
if (!seenp || !strlist_find (*seenp, certid[0]))
|
||||||
|
{
|
||||||
|
/* It's not a duplicate, add it */
|
||||||
|
if (seenp)
|
||||||
|
add_to_strlist (seenp, certid[0]);
|
||||||
|
|
||||||
|
if (!*fp)
|
||||||
|
{
|
||||||
|
*fp = es_fopenmem(0, "rw");
|
||||||
|
if (!*fp)
|
||||||
|
{
|
||||||
|
err = gpg_error_from_syserror ();
|
||||||
|
goto leave;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extract_keys (*fp, ldap_conn, certid[0], msg);
|
||||||
|
|
||||||
|
vals = ldap_get_values (ldap_conn, msg,
|
||||||
|
(serverinfo & SERVERINFO_PGPKEYV2)?
|
||||||
|
"pgpKeyV2" : "pgpKey");
|
||||||
|
if (!vals)
|
||||||
|
{
|
||||||
|
err = ldap_to_gpg_err (ldap_conn);
|
||||||
|
log_error("ks-ldap: unable to retrieve key %s "
|
||||||
|
"from keyserver\n", certid[0]);
|
||||||
|
}
|
||||||
|
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);
|
||||||
|
err = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else /* Duplicate. */
|
||||||
|
err = gpg_error (GPG_ERR_NO_DATA);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
err = gpg_error (GPG_ERR_NO_DATA);
|
||||||
|
|
||||||
|
leave:
|
||||||
|
my_ldap_value_free (certid);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* Get the key described key the KEYSPEC string from the keyserver
|
/* 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
|
* identified by URI. On success R_FP has an open stream to read the
|
||||||
data. */
|
* data. KS_GET_FLAGS conveys flags from the client. */
|
||||||
gpg_error_t
|
gpg_error_t
|
||||||
ks_ldap_get (ctrl_t ctrl, parsed_uri_t uri, const char *keyspec,
|
ks_ldap_get (ctrl_t ctrl, parsed_uri_t uri, const char *keyspec,
|
||||||
estream_t *r_fp)
|
unsigned int ks_get_flags, estream_t *r_fp)
|
||||||
{
|
{
|
||||||
gpg_error_t err = 0;
|
gpg_error_t err = 0;
|
||||||
int ldap_err;
|
int ldap_err;
|
||||||
@ -890,7 +1020,24 @@ ks_ldap_get (ctrl_t ctrl, parsed_uri_t uri, const char *keyspec,
|
|||||||
LDAP *ldap_conn = NULL;
|
LDAP *ldap_conn = NULL;
|
||||||
char *basedn = NULL;
|
char *basedn = NULL;
|
||||||
estream_t fp = NULL;
|
estream_t fp = NULL;
|
||||||
|
int count;
|
||||||
LDAPMessage *message = NULL;
|
LDAPMessage *message = NULL;
|
||||||
|
LDAPMessage *msg;
|
||||||
|
int anykey = 0;
|
||||||
|
int first_mode = 0;
|
||||||
|
int next_mode = 0;
|
||||||
|
strlist_t seen = NULL; /* The set of entries that we've seen. */
|
||||||
|
/* The ordering is significant. Specifically, "pgpcertid" needs to
|
||||||
|
* be the second item in the list, since everything after it may be
|
||||||
|
* discarded if we aren't in verbose mode. */
|
||||||
|
char *attrs[] =
|
||||||
|
{
|
||||||
|
"dummy", /* (to be be replaced.) */
|
||||||
|
"pgpcertid", "pgpuserid", "pgpkeyid", "pgprevoked", "pgpdisabled",
|
||||||
|
"pgpkeycreatetime", "modifytimestamp", "pgpkeysize", "pgpkeytype",
|
||||||
|
"gpgfingerprint",
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
|
||||||
(void) ctrl;
|
(void) ctrl;
|
||||||
|
|
||||||
@ -899,143 +1046,138 @@ ks_ldap_get (ctrl_t ctrl, parsed_uri_t uri, const char *keyspec,
|
|||||||
return no_ldap_due_to_tor (ctrl);
|
return no_ldap_due_to_tor (ctrl);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Make sure we are talking to an OpenPGP LDAP server. */
|
/* Make sure we got a state. */
|
||||||
err = my_ldap_connect (uri, &ldap_conn,
|
if ((ks_get_flags & KS_GET_FLAG_FIRST))
|
||||||
&basedn, &host, &use_tls, &serverinfo);
|
|
||||||
if (err || !basedn)
|
|
||||||
{
|
{
|
||||||
if (!err)
|
if (ctrl->ks_get_state)
|
||||||
err = gpg_error (GPG_ERR_GENERAL);
|
ks_ldap_clear_state (ctrl->ks_get_state);
|
||||||
goto out;
|
else if (!(ctrl->ks_get_state = ks_ldap_new_state ()))
|
||||||
|
return gpg_error_from_syserror ();
|
||||||
|
first_mode = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Now that we have information about the server we can construct a
|
if ((ks_get_flags & KS_GET_FLAG_NEXT))
|
||||||
* query best suited for the capabilities of the server. */
|
|
||||||
err = keyspec_to_ldap_filter (keyspec, &filter, 1, serverinfo);
|
|
||||||
if (err)
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
if (opt.debug)
|
|
||||||
log_debug ("ks-ldap: using filter: %s\n", filter);
|
|
||||||
|
|
||||||
{
|
|
||||||
/* The ordering is significant. Specifically, "pgpcertid" needs
|
|
||||||
to be the second item in the list, since everything after it
|
|
||||||
may be discarded if we aren't in verbose mode. */
|
|
||||||
char *attrs[] =
|
|
||||||
{
|
|
||||||
"dummy",
|
|
||||||
"pgpcertid", "pgpuserid", "pgpkeyid", "pgprevoked", "pgpdisabled",
|
|
||||||
"pgpkeycreatetime", "modifytimestamp", "pgpkeysize", "pgpkeytype",
|
|
||||||
"gpgfingerprint",
|
|
||||||
NULL
|
|
||||||
};
|
|
||||||
/* 1 if we want just attribute types; 0 if we want both attribute
|
|
||||||
* types and values. */
|
|
||||||
int attrsonly = 0;
|
|
||||||
int count;
|
|
||||||
|
|
||||||
/* Replace "dummy". */
|
|
||||||
attrs[0] = (serverinfo & SERVERINFO_PGPKEYV2)? "pgpKeyV2" : "pgpKey";
|
|
||||||
|
|
||||||
npth_unprotect ();
|
|
||||||
ldap_err = ldap_search_s (ldap_conn, basedn, LDAP_SCOPE_SUBTREE,
|
|
||||||
filter, attrs, attrsonly, &message);
|
|
||||||
npth_protect ();
|
|
||||||
if (ldap_err)
|
|
||||||
{
|
|
||||||
err = ldap_err_to_gpg_err (ldap_err);
|
|
||||||
|
|
||||||
log_error ("ks-ldap: LDAP search error: %s\n",
|
|
||||||
ldap_err2string (ldap_err));
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
count = ldap_count_entries (ldap_conn, message);
|
|
||||||
if (count < 1)
|
|
||||||
{
|
|
||||||
log_info ("ks-ldap: 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,
|
if (!ctrl->ks_get_state || !ctrl->ks_get_state->ldap_conn
|
||||||
so we should fetch them all (test this by fetching short key
|
|| !ctrl->ks_get_state->message)
|
||||||
id 0xDEADBEEF). */
|
{
|
||||||
|
log_error ("ks_ldap: --next requested but no state\n");
|
||||||
|
return gpg_error (GPG_ERR_INV_STATE);
|
||||||
|
}
|
||||||
|
next_mode = 1;
|
||||||
|
}
|
||||||
|
|
||||||
/* The set of entries that we've seen. */
|
/* Do not keep an old state around if not needed. */
|
||||||
strlist_t seen = NULL;
|
if (!(first_mode || next_mode))
|
||||||
LDAPMessage *each;
|
{
|
||||||
int anykey = 0;
|
ks_ldap_free_state (ctrl->ks_get_state);
|
||||||
|
ctrl->ks_get_state = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (next_mode)
|
||||||
|
{
|
||||||
|
while (ctrl->ks_get_state->msg_iter)
|
||||||
|
{
|
||||||
|
npth_unprotect ();
|
||||||
|
ctrl->ks_get_state->msg_iter
|
||||||
|
= ldap_next_entry (ctrl->ks_get_state->ldap_conn,
|
||||||
|
ctrl->ks_get_state->msg_iter);
|
||||||
|
npth_protect ();
|
||||||
|
if (ctrl->ks_get_state->msg_iter)
|
||||||
|
{
|
||||||
|
err = return_one_keyblock (ctrl->ks_get_state->ldap_conn,
|
||||||
|
ctrl->ks_get_state->msg_iter,
|
||||||
|
ctrl->ks_get_state->serverinfo,
|
||||||
|
&fp, NULL);
|
||||||
|
if (!err)
|
||||||
|
break; /* Found. */
|
||||||
|
else if (gpg_err_code (err) == GPG_ERR_NO_DATA)
|
||||||
|
err = 0; /* Skip empty/duplicate attributes. */
|
||||||
|
else
|
||||||
|
goto leave;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!ctrl->ks_get_state->msg_iter || !fp)
|
||||||
|
err = gpg_error (GPG_ERR_NO_DATA);
|
||||||
|
|
||||||
|
}
|
||||||
|
else /* Not in --next mode. */
|
||||||
|
{
|
||||||
|
/* Make sure we are talking to an OpenPGP LDAP server. */
|
||||||
|
err = my_ldap_connect (uri, &ldap_conn,
|
||||||
|
&basedn, &host, &use_tls, &serverinfo);
|
||||||
|
if (err || !basedn)
|
||||||
|
{
|
||||||
|
if (!err)
|
||||||
|
err = gpg_error (GPG_ERR_GENERAL);
|
||||||
|
goto leave;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Now that we have information about the server we can construct a
|
||||||
|
* query best suited for the capabilities of the server. */
|
||||||
|
err = keyspec_to_ldap_filter (keyspec, &filter, 1, serverinfo);
|
||||||
|
if (err)
|
||||||
|
goto leave;
|
||||||
|
|
||||||
|
if (opt.debug)
|
||||||
|
log_debug ("ks-ldap: using filter: %s\n", filter);
|
||||||
|
|
||||||
|
/* Replace "dummy". */
|
||||||
|
attrs[0] = (serverinfo & SERVERINFO_PGPKEYV2)? "pgpKeyV2" : "pgpKey";
|
||||||
|
|
||||||
|
npth_unprotect ();
|
||||||
|
ldap_err = ldap_search_s (ldap_conn, basedn, LDAP_SCOPE_SUBTREE,
|
||||||
|
filter, attrs, 0, &message);
|
||||||
|
npth_protect ();
|
||||||
|
if (ldap_err)
|
||||||
|
{
|
||||||
|
err = ldap_err_to_gpg_err (ldap_err);
|
||||||
|
|
||||||
|
log_error ("ks-ldap: LDAP search error: %s\n",
|
||||||
|
ldap_err2string (ldap_err));
|
||||||
|
goto leave;
|
||||||
|
}
|
||||||
|
|
||||||
|
count = ldap_count_entries (ldap_conn, message);
|
||||||
|
if (count < 1)
|
||||||
|
{
|
||||||
|
log_info ("ks-ldap: 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 leave;
|
||||||
|
}
|
||||||
|
|
||||||
for (npth_unprotect (),
|
for (npth_unprotect (),
|
||||||
each = ldap_first_entry (ldap_conn, message),
|
msg = ldap_first_entry (ldap_conn, message),
|
||||||
npth_protect ();
|
npth_protect ();
|
||||||
each;
|
msg;
|
||||||
npth_unprotect (),
|
npth_unprotect (),
|
||||||
each = ldap_next_entry (ldap_conn, each),
|
msg = ldap_next_entry (ldap_conn, msg),
|
||||||
npth_protect ())
|
npth_protect ())
|
||||||
{
|
{
|
||||||
char **vals;
|
err = return_one_keyblock (ldap_conn, msg, serverinfo,
|
||||||
char **certid;
|
&fp, first_mode? NULL : &seen);
|
||||||
|
if (!err)
|
||||||
/* Use the long keyid to remove duplicates. The LDAP
|
{
|
||||||
server returns the same keyid more than once if there
|
anykey = 1;
|
||||||
are multiple user IDs on the key. Note that this does
|
if (first_mode)
|
||||||
NOT mean that a keyid that exists multiple times on the
|
break;
|
||||||
keyserver will not be fetched. It means that each KEY,
|
}
|
||||||
no matter how many user IDs share its keyid, will be
|
else if (gpg_err_code (err) == GPG_ERR_NO_DATA)
|
||||||
fetched only once. If a keyid that belongs to more
|
err = 0; /* Skip empty/duplicate attributes. */
|
||||||
than one key is fetched, the server quite properly
|
else
|
||||||
responds with all matching keys. -ds */
|
goto leave;
|
||||||
|
|
||||||
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, attrs[0]);
|
|
||||||
if (! vals)
|
|
||||||
{
|
|
||||||
err = ldap_to_gpg_err (ldap_conn);
|
|
||||||
log_error("ks-ldap: 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);
|
|
||||||
anykey = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
my_ldap_value_free (certid);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
free_strlist (seen);
|
if (ctrl->ks_get_state) /* Save the iterator. */
|
||||||
|
ctrl->ks_get_state->msg_iter = msg;
|
||||||
|
|
||||||
if (! fp)
|
if (!fp) /* Nothing was found. */
|
||||||
err = gpg_error (GPG_ERR_NO_DATA);
|
err = gpg_error (GPG_ERR_NO_DATA);
|
||||||
|
|
||||||
if (!err && anykey)
|
if (!err && anykey)
|
||||||
@ -1043,9 +1185,27 @@ ks_ldap_get (ctrl_t ctrl, parsed_uri_t uri, const char *keyspec,
|
|||||||
use_tls? "ldaps" : "ldap",
|
use_tls? "ldaps" : "ldap",
|
||||||
host? host:"");
|
host? host:"");
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
out:
|
|
||||||
|
leave:
|
||||||
|
/* Store our state if needed. */
|
||||||
|
if (!err && (ks_get_flags & KS_GET_FLAG_FIRST))
|
||||||
|
{
|
||||||
|
log_assert (!ctrl->ks_get_state->ldap_conn);
|
||||||
|
ctrl->ks_get_state->ldap_conn = ldap_conn;
|
||||||
|
ldap_conn = NULL;
|
||||||
|
log_assert (!ctrl->ks_get_state->message);
|
||||||
|
ctrl->ks_get_state->message = message;
|
||||||
|
message = NULL;
|
||||||
|
ctrl->ks_get_state->serverinfo = serverinfo;
|
||||||
|
}
|
||||||
|
if ((ks_get_flags & KS_GET_FLAG_NEXT))
|
||||||
|
{
|
||||||
|
/* Keep the state in --next mode even with errors. */
|
||||||
|
ldap_conn = NULL;
|
||||||
|
message = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
if (message)
|
if (message)
|
||||||
ldap_msgfree (message);
|
ldap_msgfree (message);
|
||||||
|
|
||||||
@ -1062,6 +1222,7 @@ ks_ldap_get (ctrl_t ctrl, parsed_uri_t uri, const char *keyspec,
|
|||||||
*r_fp = fp;
|
*r_fp = fp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
free_strlist (seen);
|
||||||
xfree (basedn);
|
xfree (basedn);
|
||||||
xfree (host);
|
xfree (host);
|
||||||
|
|
||||||
|
@ -23,6 +23,12 @@
|
|||||||
|
|
||||||
#include "http.h"
|
#include "http.h"
|
||||||
|
|
||||||
|
/* Flags for engine functions. */
|
||||||
|
#define KS_GET_FLAG_ONLY_LDAP 1
|
||||||
|
#define KS_GET_FLAG_FIRST 2
|
||||||
|
#define KS_GET_FLAG_NEXT 4
|
||||||
|
|
||||||
|
|
||||||
/*-- ks-action.c --*/
|
/*-- ks-action.c --*/
|
||||||
gpg_error_t ks_print_help (ctrl_t ctrl, const char *text);
|
gpg_error_t ks_print_help (ctrl_t ctrl, const char *text);
|
||||||
gpg_error_t ks_printf_help (ctrl_t ctrl, const char *format,
|
gpg_error_t ks_printf_help (ctrl_t ctrl, const char *format,
|
||||||
@ -63,10 +69,12 @@ gpg_error_t ks_kdns_fetch (ctrl_t ctrl, parsed_uri_t uri, estream_t *r_fp);
|
|||||||
|
|
||||||
/*-- ks-engine-ldap.c --*/
|
/*-- ks-engine-ldap.c --*/
|
||||||
gpg_error_t ks_ldap_help (ctrl_t ctrl, parsed_uri_t uri);
|
gpg_error_t ks_ldap_help (ctrl_t ctrl, parsed_uri_t uri);
|
||||||
|
void ks_ldap_free_state (struct ks_engine_ldap_local_s *state);
|
||||||
gpg_error_t ks_ldap_search (ctrl_t ctrl, parsed_uri_t uri, const char *pattern,
|
gpg_error_t ks_ldap_search (ctrl_t ctrl, parsed_uri_t uri, const char *pattern,
|
||||||
estream_t *r_fp);
|
estream_t *r_fp);
|
||||||
gpg_error_t ks_ldap_get (ctrl_t ctrl, parsed_uri_t uri,
|
gpg_error_t ks_ldap_get (ctrl_t ctrl, parsed_uri_t uri,
|
||||||
const char *keyspec, estream_t *r_fp);
|
const char *keyspec, unsigned int ks_get_flags,
|
||||||
|
estream_t *r_fp);
|
||||||
gpg_error_t ks_ldap_put (ctrl_t ctrl, parsed_uri_t uri,
|
gpg_error_t ks_ldap_put (ctrl_t ctrl, parsed_uri_t uri,
|
||||||
void *data, size_t datalen,
|
void *data, size_t datalen,
|
||||||
void *info, size_t infolen);
|
void *info, size_t infolen);
|
||||||
|
@ -49,7 +49,7 @@
|
|||||||
# include "ldap-wrapper.h"
|
# include "ldap-wrapper.h"
|
||||||
#endif
|
#endif
|
||||||
#include "ks-action.h"
|
#include "ks-action.h"
|
||||||
#include "ks-engine.h" /* (ks_hkp_print_hosttable) */
|
#include "ks-engine.h"
|
||||||
#if USE_LDAP
|
#if USE_LDAP
|
||||||
# include "ldap-parse-uri.h"
|
# include "ldap-parse-uri.h"
|
||||||
#endif
|
#endif
|
||||||
@ -2518,12 +2518,13 @@ cmd_ks_search (assuan_context_t ctx, char *line)
|
|||||||
|
|
||||||
|
|
||||||
static const char hlp_ks_get[] =
|
static const char hlp_ks_get[] =
|
||||||
"KS_GET [--quick] [--ldap] {<pattern>}\n"
|
"KS_GET [--quick] [--ldap] [--first|--next] {<pattern>}\n"
|
||||||
"\n"
|
"\n"
|
||||||
"Get the keys matching PATTERN from the configured OpenPGP keyservers\n"
|
"Get the keys matching PATTERN from the configured OpenPGP keyservers\n"
|
||||||
"(see command KEYSERVER). Each pattern should be a keyid, a fingerprint,\n"
|
"(see command KEYSERVER). Each pattern should be a keyid, a fingerprint,\n"
|
||||||
"or an exact name indicated by the '=' prefix. Option --quick uses a\n"
|
"or an exact name indicated by the '=' prefix. Option --quick uses a\n"
|
||||||
"shorter timeout; --ldap will use only ldap servers";
|
"shorter timeout; --ldap will use only ldap servers. With --first only\n"
|
||||||
|
"the first item is returned; --next is used to return the next item";
|
||||||
static gpg_error_t
|
static gpg_error_t
|
||||||
cmd_ks_get (assuan_context_t ctx, char *line)
|
cmd_ks_get (assuan_context_t ctx, char *line)
|
||||||
{
|
{
|
||||||
@ -2532,11 +2533,16 @@ cmd_ks_get (assuan_context_t ctx, char *line)
|
|||||||
strlist_t list, sl;
|
strlist_t list, sl;
|
||||||
char *p;
|
char *p;
|
||||||
estream_t outfp;
|
estream_t outfp;
|
||||||
int ldap_only;
|
unsigned int flags = 0;
|
||||||
|
|
||||||
if (has_option (line, "--quick"))
|
if (has_option (line, "--quick"))
|
||||||
ctrl->timeout = opt.connect_quick_timeout;
|
ctrl->timeout = opt.connect_quick_timeout;
|
||||||
ldap_only = has_option (line, "--ldap");
|
if (has_option (line, "--ldap"))
|
||||||
|
flags |= KS_GET_FLAG_ONLY_LDAP;
|
||||||
|
if (has_option (line, "--first"))
|
||||||
|
flags |= KS_GET_FLAG_FIRST;
|
||||||
|
if (has_option (line, "--next"))
|
||||||
|
flags |= KS_GET_FLAG_NEXT;
|
||||||
line = skip_options (line);
|
line = skip_options (line);
|
||||||
|
|
||||||
/* Break the line into a strlist. Each pattern is by
|
/* Break the line into a strlist. Each pattern is by
|
||||||
@ -2565,6 +2571,36 @@ cmd_ks_get (assuan_context_t ctx, char *line)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ((flags & KS_GET_FLAG_FIRST) && !(flags & KS_GET_FLAG_ONLY_LDAP))
|
||||||
|
{
|
||||||
|
err = PARM_ERROR ("--first is only supported with --ldap");
|
||||||
|
goto leave;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (list && list->next && (flags & KS_GET_FLAG_FIRST))
|
||||||
|
{
|
||||||
|
/* ks_action_get loops over the pattern and we can't easily keep
|
||||||
|
* this state. */
|
||||||
|
err = PARM_ERROR ("Only one pattern allowed with --first");
|
||||||
|
goto leave;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((flags & KS_GET_FLAG_NEXT))
|
||||||
|
{
|
||||||
|
if (list || (flags & ~KS_GET_FLAG_NEXT))
|
||||||
|
{
|
||||||
|
err = PARM_ERROR ("No pattern or other options allowed with --next");
|
||||||
|
goto leave;
|
||||||
|
}
|
||||||
|
/* Add a dummy pattern. */
|
||||||
|
if (!add_to_strlist_try (&list, ""))
|
||||||
|
{
|
||||||
|
err = gpg_error_from_syserror ();
|
||||||
|
goto leave;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
err = ensure_keyserver (ctrl);
|
err = ensure_keyserver (ctrl);
|
||||||
if (err)
|
if (err)
|
||||||
goto leave;
|
goto leave;
|
||||||
@ -2579,7 +2615,7 @@ cmd_ks_get (assuan_context_t ctx, char *line)
|
|||||||
ctrl->server_local->inhibit_data_logging_now = 0;
|
ctrl->server_local->inhibit_data_logging_now = 0;
|
||||||
ctrl->server_local->inhibit_data_logging_count = 0;
|
ctrl->server_local->inhibit_data_logging_count = 0;
|
||||||
err = ks_action_get (ctrl, ctrl->server_local->keyservers,
|
err = ks_action_get (ctrl, ctrl->server_local->keyservers,
|
||||||
list, ldap_only, outfp);
|
list, flags, outfp);
|
||||||
es_fclose (outfp);
|
es_fclose (outfp);
|
||||||
ctrl->server_local->inhibit_data_logging = 0;
|
ctrl->server_local->inhibit_data_logging = 0;
|
||||||
}
|
}
|
||||||
@ -3090,6 +3126,8 @@ start_command_handler (assuan_fd_t fd, unsigned int session_id)
|
|||||||
ctrl->refcount);
|
ctrl->refcount);
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
ks_ldap_free_state (ctrl->ks_get_state);
|
||||||
|
ctrl->ks_get_state = NULL;
|
||||||
release_ctrl_ocsp_certs (ctrl);
|
release_ctrl_ocsp_certs (ctrl);
|
||||||
xfree (ctrl->server_local);
|
xfree (ctrl->server_local);
|
||||||
dirmngr_deinit_default_ctrl (ctrl);
|
dirmngr_deinit_default_ctrl (ctrl);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user