dirmngr: Store all version 2 schema attributes.

* g10/call-dirmngr.c (ks_put_inq_cb): Emit "fpr" records.
* dirmngr/ks-engine-ldap.c (extract_attributes): Add args
extract-state and schemav2.  Add data for the new schema version.
remove the legacy code to handle UIDs in the "pub" line.
(ks_ldap_put): Set new attributes for NTDS use the fingerprint as CN.

Signed-off-by: Werner Koch <wk@gnupg.org>
This commit is contained in:
Werner Koch 2020-12-15 08:55:36 +01:00
parent 2c6bb03cfb
commit a2434ccabd
No known key found for this signature in database
GPG Key ID: E3FDFF218E45B72B
2 changed files with 89 additions and 46 deletions

View File

@ -46,6 +46,7 @@
#include "dirmngr.h" #include "dirmngr.h"
#include "misc.h" #include "misc.h"
#include "../common/userids.h" #include "../common/userids.h"
#include "../common/mbox-util.h"
#include "ks-engine.h" #include "ks-engine.h"
#include "ldap-parse-uri.h" #include "ldap-parse-uri.h"
@ -1629,15 +1630,16 @@ uncescape (char *str)
/* Given one line from an info block (`gpg --list-{keys,sigs} /* Given one line from an info block (`gpg --list-{keys,sigs}
--with-colons KEYID'), pull it apart and fill in the modlist with --with-colons KEYID'), pull it apart and fill in the modlist with
the relevant (for the LDAP schema) attributes. */ the relevant (for the LDAP schema) attributes. EXTRACT_STATE
should initally be set to 0 by the caller. SCHEMAV2 is set if the
server supports the version 2 schema. */
static void static void
extract_attributes (LDAPMod ***modlist, char *line) extract_attributes (LDAPMod ***modlist, int *extract_state,
char *line, int schemav2)
{ {
int field_count; int field_count;
char **fields; char **fields;
char *keyid; char *keyid;
int is_pub, is_sub, is_uid, is_sig; int is_pub, is_sub, is_uid, is_sig;
/* Remove trailing whitespace */ /* Remove trailing whitespace */
@ -1652,24 +1654,42 @@ extract_attributes (LDAPMod ***modlist, char *line)
if (field_count < 7) if (field_count < 7)
goto out; goto out;
is_pub = strcasecmp ("pub", fields[0]) == 0; is_pub = !ascii_strcasecmp ("pub", fields[0]);
is_sub = strcasecmp ("sub", fields[0]) == 0; is_sub = !ascii_strcasecmp ("sub", fields[0]);
is_uid = strcasecmp ("uid", fields[0]) == 0; is_uid = !ascii_strcasecmp ("uid", fields[0]);
is_sig = strcasecmp ("sig", fields[0]) == 0; is_sig = !ascii_strcasecmp ("sig", fields[0]);
if (!ascii_strcasecmp ("fpr", fields[0]))
{
/* Special treatment for a fingerprint. */
if (!(*extract_state & 1))
goto out; /* Stray fingerprint line - ignore. */
*extract_state &= ~1;
if (field_count >= 10 && schemav2)
{
if ((*extract_state & 2))
modlist_add (modlist, "gpgFingerprint", fields[9]);
else
modlist_add (modlist, "gpgSubFingerprint", fields[9]);
}
goto out;
}
*extract_state &= ~(1|2);
if (is_pub)
*extract_state |= (1|2);
else if (is_sub)
*extract_state |= 1;
if (!is_pub && !is_sub && !is_uid && !is_sig) if (!is_pub && !is_sub && !is_uid && !is_sig)
/* Not a relevant line. */ goto out; /* Not a relevant line. */
goto out;
keyid = fields[4]; keyid = fields[4];
if (is_uid && strlen (keyid) == 0) if (is_uid && strlen (keyid) == 0)
/* The uid record type can have an empty keyid. */ ; /* The uid record type can have an empty keyid. */
;
else if (strlen (keyid) == 16 else if (strlen (keyid) == 16
&& strspn (keyid, "0123456789aAbBcCdDeEfF") == 16) && strspn (keyid, "0123456789aAbBcCdDeEfF") == 16)
/* Otherwise, we expect exactly 16 hex characters. */ ; /* Otherwise, we expect exactly 16 hex characters. */
;
else else
{ {
log_error ("malformed record!\n"); log_error ("malformed record!\n");
@ -1748,12 +1768,12 @@ extract_attributes (LDAPMod ***modlist, char *line)
{ {
if (is_pub) if (is_pub)
{ {
modlist_add (modlist, "pgpCertID", keyid); modlist_add (modlist, "pgpCertID", keyid); /* Long keyid(!) */
modlist_add (modlist, "pgpKeyID", &keyid[8]); modlist_add (modlist, "pgpKeyID", &keyid[8]); /* Short keyid */
} }
if (is_sub) if (is_sub)
modlist_add (modlist, "pgpSubKeyID", keyid); modlist_add (modlist, "pgpSubKeyID", keyid); /* Long keyid(!) */
} }
if (is_pub) if (is_pub)
@ -1851,25 +1871,22 @@ extract_attributes (LDAPMod ***modlist, char *line)
} }
} }
if ((is_uid || is_pub) && field_count >= 10) if (is_uid && field_count >= 10)
{ {
char *uid = fields[9]; char *uid = fields[9];
char *mbox;
if (is_pub && strlen (uid) == 0) uncescape (uid);
/* When using gpg --list-keys, the uid is included. When modlist_add (modlist, "pgpUserID", uid);
passed via gpg, it is not. It is important to process it if (schemav2 && (mbox = mailbox_from_userid (uid, 0)))
when it is present, because gpg 1 won't print a UID record {
if there is only one key. */ modlist_add (modlist, "gpgMailbox", mbox);
; xfree (mbox);
else }
{
uncescape (uid);
modlist_add (modlist, "pgpUserID", uid);
}
} }
out: out:
free (fields); xfree (fields);
} }
/* Send the key in {KEY,KEYLEN} with the metadata {INFO,INFOLEN} to /* Send the key in {KEY,KEYLEN} with the metadata {INFO,INFOLEN} to
@ -1888,12 +1905,13 @@ ks_ldap_put (ctrl_t ctrl, parsed_uri_t uri,
LDAPMod **modlist = NULL; LDAPMod **modlist = NULL;
LDAPMod **addlist = NULL; LDAPMod **addlist = NULL;
char *data_armored = NULL; char *data_armored = NULL;
int extract_state;
/* The last byte of the info block. */ /* The last byte of the info block. */
const char *infoend = (const char *) info + infolen - 1; const char *infoend = (const char *) info + infolen - 1;
/* Enable this code to dump the modlist to /tmp/modlist.txt. */ /* Enable this code to dump the modlist to /tmp/modlist.txt. */
#if 0 #if 1
# warning Disable debug code before checking in. # warning Disable debug code before checking in.
const int dump_modlist = 1; const int dump_modlist = 1;
#else #else
@ -1995,9 +2013,15 @@ ks_ldap_put (ctrl_t ctrl, parsed_uri_t uri,
modlist_add (&modlist, "pgpKeySize", NULL); modlist_add (&modlist, "pgpKeySize", NULL);
modlist_add (&modlist, "pgpKeyExpireTime", NULL); modlist_add (&modlist, "pgpKeyExpireTime", NULL);
modlist_add (&modlist, "pgpCertID", NULL); modlist_add (&modlist, "pgpCertID", NULL);
if ((serverinfo & SERVERINFO_SCHEMAV2))
{
modlist_add (&modlist, "gpgFingerprint", NULL);
modlist_add (&modlist, "gpgSubFingerprint", NULL);
modlist_add (&modlist, "gpgMailbox", NULL);
}
/* Assemble the INFO stuff into LDAP attributes */ /* Assemble the INFO stuff into LDAP attributes */
extract_state = 0;
while (infolen > 0) while (infolen > 0)
{ {
char *temp = NULL; char *temp = NULL;
@ -2015,7 +2039,8 @@ ks_ldap_put (ctrl_t ctrl, parsed_uri_t uri,
*newline = '\0'; *newline = '\0';
extract_attributes (&addlist, info); extract_attributes (&addlist, &extract_state, info,
(serverinfo & SERVERINFO_SCHEMAV2));
infolen = infolen - ((uintptr_t) newline - (uintptr_t) info + 1); infolen = infolen - ((uintptr_t) newline - (uintptr_t) info + 1);
info = newline + 1; info = newline + 1;
@ -2061,22 +2086,37 @@ ks_ldap_put (ctrl_t ctrl, parsed_uri_t uri,
keyserver) this does NOT merge signatures, but replaces the whole keyserver) this does NOT merge signatures, but replaces the whole
key. This should make some people very happy. */ key. This should make some people very happy. */
{ {
char **certid; char **attrval;
char *dn; char *dn;
certid = modlist_lookup (addlist, "pgpCertID");
/* We should have exactly one value. */
if (!certid || !(certid[0] && !certid[1]))
{
log_error ("ks-ldap: bad pgpCertID provided\n");
err = GPG_ERR_GENERAL;
goto out;
}
if ((serverinfo & SERVERINFO_NTDS)) if ((serverinfo & SERVERINFO_NTDS))
dn = xtryasprintf ("CN=%s,%s", certid[0], basedn); {
else /* The modern way using a CN RDN with the fingerprint. This
dn = xtryasprintf ("pgpCertID=%s,%s", certid[0], basedn); * has the advantage that we won't have duplicate 64 bit
* keyids in the store. In particular NTDS requires the
* DN to be unique. */
attrval = modlist_lookup (addlist, "gpgFingerprint");
/* We should have exactly one value. */
if (!attrval || !(attrval[0] && !attrval[1]))
{
log_error ("ks-ldap: bad gpgFingerprint provided\n");
err = GPG_ERR_GENERAL;
goto out;
}
dn = xtryasprintf ("CN=%s,%s", attrval[0], basedn);
}
else /* The old style way. */
{
attrval = modlist_lookup (addlist, "pgpCertID");
/* We should have exactly one value. */
if (!attrval || !(attrval[0] && !attrval[1]))
{
log_error ("ks-ldap: bad pgpCertID provided\n");
err = GPG_ERR_GENERAL;
goto out;
}
dn = xtryasprintf ("pgpCertID=%s,%s", attrval[0], basedn);
}
if (!dn) if (!dn)
{ {
err = gpg_error_from_syserror (); err = gpg_error_from_syserror ();

View File

@ -931,6 +931,7 @@ ks_put_inq_cb (void *opaque, const char *line)
{ {
kbnode_t node; kbnode_t node;
estream_t fp; estream_t fp;
char hexfpr[2*MAX_FINGERPRINT_LEN+1];
/* Parse the keyblock and send info lines back to the server. */ /* Parse the keyblock and send info lines back to the server. */
fp = es_fopenmem (0, "rw,samethread"); fp = es_fopenmem (0, "rw,samethread");
@ -988,6 +989,8 @@ ks_put_inq_cb (void *opaque, const char *line)
nbits_from_pk (pk), pk->pubkey_algo, nbits_from_pk (pk), pk->pubkey_algo,
pk->keyid, pk->timestamp, pk->expiredate, pk->keyid, pk->timestamp, pk->expiredate,
NULL); NULL);
es_fprintf (fp, "fpr:::::::::%s:\n",
hexfingerprint (pk, hexfpr, sizeof hexfpr));
} }
break; break;