aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWerner Koch <[email protected]>2025-07-25 13:06:38 +0000
committerWerner Koch <[email protected]>2025-07-25 13:30:40 +0000
commit7f51955301273d11911924f4a1fde241f84669f8 (patch)
tree226dd4ef8f19c993d81f00f543c1c8f0be4143b8
parentgpgsm: Fix caching of the trustlist's flags. (diff)
downloadgnupg-7f51955301273d11911924f4a1fde241f84669f8.tar.gz
gnupg-7f51955301273d11911924f4a1fde241f84669f8.zip
dirmngr: Implement command KS_DEL for ldap servers.STABLE-BRANCH-2-2
* dirmngr/server.c (cmd_ks_del): New. (percentplus_line_to_strlist): New. * dirmngr/ks-action.c (ks_action_del): New. * dirmngr/ks-engine-ldap.c (ks_ldap_del): New. -- GnuPG-bug-id: 5447 Backported-from-master: 9d356a172e7cc492707a6466d30ede8eb0dcf92d
-rw-r--r--NEWS12
-rw-r--r--dirmngr/ks-action.c33
-rw-r--r--dirmngr/ks-action.h2
-rw-r--r--dirmngr/ks-engine-ldap.c110
-rw-r--r--dirmngr/ks-engine.h1
-rw-r--r--dirmngr/server.c86
6 files changed, 244 insertions, 0 deletions
diff --git a/NEWS b/NEWS
index cedda3727..20c48afc6 100644
--- a/NEWS
+++ b/NEWS
@@ -1,6 +1,18 @@
Noteworthy changes in version 2.2.48 (unreleased)
-------------------------------------------------
+ * scd:p15: Accept P15 cards with a zero-length label. [rG84229829b5]
+
+ * scd:p15: Make signing work for Nexus cards. [rGe1576eee04]
+
+ * gpg: Fully implement the group key flag. [rG924f09d1f3]
+
+ * gpgsm: Make use of the de-vs flag in the trustlist.txt. [rG14383ff052]
+
+ * gpgsm: Fix caching of the trustlist's flags. [T7738]
+
+ * dirmngr: Implement command KS_DEL for LDAP. [T5447]
+
Noteworthy changes in version 2.2.47 (2025-04-09)
-------------------------------------------------
diff --git a/dirmngr/ks-action.c b/dirmngr/ks-action.c
index ad200ece6..81582f206 100644
--- a/dirmngr/ks-action.c
+++ b/dirmngr/ks-action.c
@@ -543,6 +543,39 @@ ks_action_put (ctrl_t ctrl, uri_item_t keyservers,
}
+/* Delete an OpenPGP key from all KEYSERVERS which use LDAP. The key
+ * is specifified by PATTERNS. */
+gpg_error_t
+ks_action_del (ctrl_t ctrl, uri_item_t keyservers, strlist_t fprlist)
+{
+ gpg_error_t err = 0;
+ gpg_error_t first_err = 0;
+ int any_server = 0;
+ uri_item_t uri;
+
+ for (uri = keyservers; uri; uri = uri->next)
+ {
+#if USE_LDAP
+ if ( !strcmp (uri->parsed_uri->scheme, "ldap")
+ || !strcmp (uri->parsed_uri->scheme, "ldaps")
+ || !strcmp (uri->parsed_uri->scheme, "ldapi")
+ || uri->parsed_uri->opaque )
+ {
+ any_server = 1;
+ err = ks_ldap_del (ctrl, uri->parsed_uri, fprlist);
+ if (err && !first_err)
+ first_err = err;
+ }
+#endif
+ }
+
+ if (!any_server)
+ err = gpg_error (GPG_ERR_NO_KEYSERVER); /* No LDAP keyserver */
+ else if (!err && first_err)
+ err = first_err;
+ return err;
+}
+
/* Query the default LDAP server or the one given by URL using
* the filter expression FILTER. Write the result to OUTFP. */
diff --git a/dirmngr/ks-action.h b/dirmngr/ks-action.h
index 223aae2da..0df497266 100644
--- a/dirmngr/ks-action.h
+++ b/dirmngr/ks-action.h
@@ -33,6 +33,8 @@ 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,
void *data, size_t datalen,
void *info, size_t infolen);
+gpg_error_t ks_action_del (ctrl_t ctrl, uri_item_t keyservers,
+ strlist_t fprlist);
gpg_error_t ks_action_query (ctrl_t ctrl, const char *ldapserver,
unsigned int ks_get_flags,
const char *filter, char **attr,
diff --git a/dirmngr/ks-engine-ldap.c b/dirmngr/ks-engine-ldap.c
index b416ac004..e1b0b6caa 100644
--- a/dirmngr/ks-engine-ldap.c
+++ b/dirmngr/ks-engine-ldap.c
@@ -2988,6 +2988,116 @@ ks_ldap_put (ctrl_t ctrl, parsed_uri_t uri,
}
+/* Delete the keys given by the list of fingerprints in FPRLIST from
+ * the keyserver identified by URI. The function stops at the first
+ * error encountered. */
+gpg_error_t
+ks_ldap_del (ctrl_t ctrl, parsed_uri_t uri, strlist_t fprlist)
+{
+ gpg_error_t err = 0;
+ int ldap_err;
+ unsigned int serverinfo;
+ LDAP *ldap_conn = NULL;
+ char *basedn = NULL;
+ char *dn = NULL;
+ strlist_t fpr;
+ unsigned int count = 0;
+ unsigned int totalcount = 0;
+
+ if (dirmngr_use_tor ())
+ {
+ return no_ldap_due_to_tor (ctrl);
+ }
+
+ for (fpr = fprlist; fpr; fpr = fpr->next)
+ totalcount++;
+
+ err = my_ldap_connect (uri, 0, &ldap_conn, &basedn, NULL, NULL, &serverinfo);
+ if (err || !basedn)
+ {
+ if(opt.verbose)
+ log_info ("%s: connecting to server failed\n", __func__);
+ if (!err)
+ err = gpg_error (GPG_ERR_GENERAL); /* (no baseDN) */
+ goto leave;
+ }
+
+ if (!(serverinfo & SERVERINFO_REALLDAP))
+ {
+ if(opt.verbose)
+ log_info ("%s: The PGP.com keyserver is not supported\n", __func__);
+ err = gpg_error (GPG_ERR_NOT_SUPPORTED);
+ goto leave;
+ }
+
+ if (!(serverinfo & SERVERINFO_SCHEMAV2))
+ {
+ if(opt.verbose)
+ log_info ("%s: The keyserver does not support the v2 schema\n",
+ __func__);
+ err = gpg_error (GPG_ERR_NOT_SUPPORTED);
+ goto leave;
+ }
+
+ if (opt.verbose)
+ log_info ("%s: Using DN: %s,%s\n", __func__,
+ (serverinfo & SERVERINFO_NTDS)? "CN=<fingerprint>"
+ /* */ : "pgpCertID=<keyid>",
+ basedn);
+ for (fpr = fprlist; fpr; fpr = fpr->next)
+ {
+ if ((serverinfo & SERVERINFO_NTDS))
+ {
+ xfree (dn);
+ dn = xtryasprintf ("CN=%s,%s", fpr->d, basedn);
+ }
+ else
+ {
+ unsigned int off;
+
+ /* Simle method to get the keyID. Note that a v5 key
+ * (len>40) has the keyid at the left. If the length is
+ * less than 17 we assume a keyid has been given. */
+ off = strlen (fpr->d);
+ if (off <= 40 && off > 16)
+ off = off - 16;
+ else
+ off = 0;
+
+ xfree (dn);
+ dn = xtryasprintf ("pgpCertID=%.16s,%s", fpr->d+off, basedn);
+ }
+
+ npth_unprotect ();
+ ldap_err = ldap_delete_ext_s (ldap_conn, dn, NULL, NULL);
+ npth_protect ();
+ if (ldap_err == LDAP_SUCCESS)
+ {
+ if (opt.verbose)
+ log_info ("%s: key %s deleted\n", __func__, fpr->d);
+ count++;
+ }
+ else
+ {
+ log_error ("%s: error deleting key %s: %s\n",
+ __func__, fpr->d, ldap_err2string (ldap_err));
+ err = ldap_err_to_gpg_err (ldap_err);
+ break; /* Stop at the first failed deletion. */
+ }
+ }
+ log_info ("%s: number of keys deleted: %u of %u\n",
+ __func__, count, totalcount);
+
+
+ leave:
+ if (ldap_conn)
+ ldap_unbind (ldap_conn);
+ xfree (dn);
+ xfree (basedn);
+ return err;
+}
+
+
/* Get the data described by FILTER_ARG from URI. On success R_FP has
* an open stream to read the data. KS_GET_FLAGS conveys flags from
diff --git a/dirmngr/ks-engine.h b/dirmngr/ks-engine.h
index 6de77ccb2..005d07490 100644
--- a/dirmngr/ks-engine.h
+++ b/dirmngr/ks-engine.h
@@ -82,6 +82,7 @@ gpg_error_t ks_ldap_get (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 *info, size_t infolen);
+gpg_error_t ks_ldap_del (ctrl_t ctrl, parsed_uri_t uri, strlist_t fprlist);
gpg_error_t ks_ldap_query (ctrl_t ctrl, parsed_uri_t uri,
unsigned int ks_get_flags,
const char *filter, char **attrs,
diff --git a/dirmngr/server.c b/dirmngr/server.c
index bf4e891f3..b43390be0 100644
--- a/dirmngr/server.c
+++ b/dirmngr/server.c
@@ -324,6 +324,46 @@ strcpy_escaped_plus (char *d, const unsigned char *s)
}
+/* Break the LINE into space delimited tokens, put them into a new
+ * strlist and return it at R_LIST. On error an erro code is
+ * returned. If no tokens are found the list is set to NULL.
+ * Percent-plus encoding is removed from each token. Note that the
+ * function will modify LINE. */
+static gpg_error_t
+percentplus_line_to_strlist (char *line, strlist_t *r_list)
+{
+ strlist_t list = NULL;
+ strlist_t sl;
+ char *p;
+
+ for (p=line; *p; line = p)
+ {
+ while (*p && *p != ' ')
+ p++;
+ if (*p)
+ *p++ = 0;
+ if (*line)
+ {
+ sl = xtrymalloc (sizeof *sl + strlen (line));
+ if (!sl)
+ {
+ gpg_error_t err = gpg_error_from_syserror ();
+ free_strlist (list);
+ *r_list = NULL;
+ return err;
+ }
+ sl->flags = 0;
+ strcpy_escaped_plus (sl->d, line);
+ sl->next = list;
+ list = sl;
+ }
+ }
+
+ *r_list = list;
+ return 0;
+}
+
+
/* This function returns true if a Tor server is running. The status
* is cached for the current connection. */
static int
@@ -2702,6 +2742,51 @@ cmd_ks_put (assuan_context_t ctx, char *line)
}
+static const char hlp_ks_del[] =
+ "KS_DEL --ldap {<fingerprints>}\n"
+ "\n"
+ "Delete the keys specified by primary keys FINGERPRINTS from the\n"
+ "configured OpenPGP LDAP server. The option --ldap is mandatory.";
+static gpg_error_t
+cmd_ks_del (assuan_context_t ctx, char *line)
+{
+ ctrl_t ctrl = assuan_get_pointer (ctx);
+ gpg_error_t err;
+ strlist_t list = NULL;
+ unsigned int flags = 0;
+
+ if (has_option (line, "--ldap"))
+ flags |= KS_GET_FLAG_ONLY_LDAP;
+ line = skip_options (line);
+
+ err = percentplus_line_to_strlist (line, &list);
+ if (err)
+ goto leave;
+
+ if (!(flags & KS_GET_FLAG_ONLY_LDAP))
+ {
+ err = set_error (GPG_ERR_SYNTAX, "option --ldap is mandatory");
+ goto leave;
+ }
+
+ if (!list)
+ {
+ err = set_error (GPG_ERR_SYNTAX, "no fingerprints given");
+ goto leave;
+ }
+
+ err = ensure_keyserver (ctrl);
+ if (err)
+ goto leave;
+
+ err = ks_action_del (ctrl, ctrl->server_local->keyservers, list);
+
+ leave:
+ free_strlist (list);
+ return leave_cmd (ctx, err);
+}
+
+
static const char hlp_ad_query[] =
"AD_QUERY [--first|--next] [--] <filter> \n"
@@ -3035,6 +3120,7 @@ register_commands (assuan_context_t ctx)
{ "KS_GET", cmd_ks_get, hlp_ks_get },
{ "KS_FETCH", cmd_ks_fetch, hlp_ks_fetch },
{ "KS_PUT", cmd_ks_put, hlp_ks_put },
+ { "KS_DEL", cmd_ks_del, hlp_ks_del },
{ "AD_QUERY", cmd_ad_query, hlp_ad_query },
{ "GETINFO", cmd_getinfo, hlp_getinfo },
{ "LOADSWDB", cmd_loadswdb, hlp_loadswdb },