$NetBSD$

--- lib/scepldap.c.orig	Tue Feb 19 23:40:06 2002
+++ lib/scepldap.c
@@ -7,2 +7,3 @@
  */
+#include <syslog.h>
 #include <config.h>
@@ -41,2 +42,4 @@ char	*x509_to_ldap(scep_t *scep, X509_NA
 			__FILE__, __LINE__, oname);
+		syslog(LOG_DEBUG, "%s:%d: LDAP mapping of %s requested\n",
+			__FILE__, __LINE__, oname);
 	}
@@ -47,2 +50,4 @@ char	*x509_to_ldap(scep_t *scep, X509_NA
 			__FILE__, __LINE__);
+		syslog(LOG_ERR, "%s:%d: unstructuredName not found\n",
+			__FILE__, __LINE__);
 		goto err;
@@ -68,2 +73,4 @@ char	*x509_to_ldap(scep_t *scep, X509_NA
 				" attribute\n", __FILE__, __LINE__);
+			syslog(LOG_ERR, "%s:%d: no data for unstruturedName"
+				" attribute\n", __FILE__, __LINE__);
 			goto err;
@@ -73,3 +80,3 @@ char	*x509_to_ldap(scep_t *scep, X509_NA
 		dn = (char *)malloc(dnl);
-		if (debug)
+		if (debug) {
 			BIO_printf(bio_err, "%s:%d: unstructuredName has type "
@@ -79,2 +86,8 @@ char	*x509_to_ldap(scep_t *scep, X509_NA
 				as->length, as->data, dnl);
+			syslog(LOG_DEBUG, "%s:%d: unstructuredName has type "
+				"%d length %d with value '%*.*s', allocated %d "
+				" bytes\n", __FILE__,
+				__LINE__, as->type, as->length, as->length,
+				as->length, as->data, dnl);
+		}
 		snprintf(dn, dnl, "unstructuredName=%*.*s,%s", as->length,
@@ -103,5 +116,8 @@ char	*x509_to_ldap(scep_t *scep, X509_NA
 reply:
-	if (debug)
+	if (debug) {
 		BIO_printf(bio_err, "%s:%d: X509_NAME '%s' mapped to '%s'\n",
 			__FILE__, __LINE__, oname, dn);
+		syslog(LOG_DEBUG, "%s:%d: X509_NAME '%s' mapped to '%s'\n",
+			__FILE__, __LINE__, oname, dn);
+	}
 	return dn;
@@ -148,2 +164,4 @@ X509_NAME	*ldap_to_x509(char *dn) {
 				__FILE__, __LINE__, name);
+			syslog(LOG_ERR, "%s:%d: no = on dn component %s\n",
+				__FILE__, __LINE__, name);
 			goto err;
@@ -151,3 +169,3 @@ X509_NAME	*ldap_to_x509(char *dn) {
 		*value = '\0'; value++;
-		if (debug)
+		if (debug) {
 			BIO_printf(bio_err, "%s:%d: found name = '%s', "
@@ -155,2 +173,6 @@ X509_NAME	*ldap_to_x509(char *dn) {
 				value);
+			syslog(LOG_DEBUG, "%s:%d: found name = '%s', "
+				"value = '%s'\n", __FILE__, __LINE__, name,
+				value);
+		}
 
@@ -165,2 +187,4 @@ X509_NAME	*ldap_to_x509(char *dn) {
 				"%s=%s\n", __FILE__, __LINE__, name, value);
+			syslog(LOG_ERR, "%s:%d: cannot create name entry "
+				"%s=%s\n", __FILE__, __LINE__, name, value);
 			goto err;
@@ -182,26 +206,45 @@ err:
 int	scep_ldap_init(scep_t *scep) {
+	int version3 = 3, rc;
+
 	/* initialize the LDAP structure				*/
-	if (NULL == (scep->l.ldap = ldap_init(scep->l.ldaphost,
-		scep->l.ldapport))) {
-		BIO_printf(bio_err, "%s:%d: cannot initialize LDAP: %s (%d)\n",
-			__FILE__, __LINE__, strerror(errno), errno);
+	rc = ldap_initialize(&scep->l.ldap, scep->l.ldapuri);
+	if (rc || scep->l.ldap == NULL) {
+		BIO_printf(bio_err, "%s:%d: cannot initialize LDAP connection to %s: %s (%d)\n",
+			__FILE__, __LINE__, scep->l.ldapuri != NULL ? scep->l.ldapuri : "<DEFAULT>", ldap_err2string(rc), rc);
+		syslog(LOG_ERR, "%s:%d: cannot initialize LDAP connection to %s: %s (%d)\n",
+			__FILE__, __LINE__, scep->l.ldapuri != NULL ? scep->l.ldapuri : "<DEFAULT>", ldap_err2string(rc), rc);
 		goto err;
         }
-	if (debug)
-		BIO_printf(bio_err, "%s:%d: LDAP %s:%d initialized\n",
-			__FILE__, __LINE__, scep->l.ldaphost, scep->l.ldapport);
-
+	if (debug) {
+		BIO_printf(bio_err, "%s:%d: LDAP URI %s initialized\n",
+			__FILE__, __LINE__, scep->l.ldapuri != NULL ? scep->l.ldapuri : "<DEFAULT>");
+		syslog(LOG_DEBUG, "%s:%d: LDAP URI %s initialized\n",
+			__FILE__, __LINE__, scep->l.ldapuri != NULL ? scep->l.ldapuri : "<DEFAULT>");
+	}
+	if (ldap_set_option(scep->l.ldap, LDAP_OPT_PROTOCOL_VERSION, &version3) 
+		!= LDAP_OPT_SUCCESS ) {
+		BIO_printf(bio_err, "%s:%d: couldn't set LDAP protocol version 3\n",
+			__FILE__, __LINE__);
+		syslog(LOG_DEBUG, "%s:%d: couldn't set LDAP protocol version 3\n",
+			__FILE__, __LINE__);
+		goto err;
+	}
 	/* perform a bind, if required by the configuration		*/
 	if ((scep->l.binddn) && (scep->l.bindpw)) {
-		if (LDAP_SUCCESS != ldap_simple_bind_s(scep->l.ldap,
-			scep->l.binddn, scep->l.bindpw)) {
-			BIO_printf(bio_err, "%s:%d: bind failed\n", __FILE__,
-				__LINE__);
+		if (LDAP_SUCCESS != (rc = ldap_simple_bind_s(scep->l.ldap,
+			scep->l.binddn, scep->l.bindpw))) {
+			BIO_printf(bio_err, "%s:%d: bind failed: %s\n", __FILE__,
+				__LINE__, ldap_err2string(rc));
+			syslog(LOG_ERR, "%s:%d: bind failed: %s\n", __FILE__,
+				__LINE__, ldap_err2string(rc));
 			goto err;
 		}
-		if (debug)
+		if (debug) {
 			BIO_printf(bio_err, "%s:%d: LDAP bind complete\n",
 				__FILE__, __LINE__);
-	} else
-		if (debug)
+			syslog(LOG_DEBUG, "%s:%d: LDAP bind complete\n",
+				__FILE__, __LINE__);
+		}
+	} else {
+		if (debug) {
 			BIO_printf(bio_err, "%s:%d: LDAP bind not necessary, "
@@ -209,2 +252,7 @@ int	scep_ldap_init(scep_t *scep) {
 				__LINE__);
+			syslog(LOG_DEBUG, "%s:%d: LDAP bind not necessary, "
+				"insufficient parameters\n", __FILE__,
+				__LINE__);
+		}
+	}
 	return 0;
@@ -256,6 +304,7 @@ int	ldap_store_cert(scep_t *scep) {
 	char		*ocvals[3], *idnvals[2], *sdnvals[2], *servals[2],
-			*upvals[2];
-	struct berval	*certvals[2];
+			*upvals[2], *firstdnvals[2], *usnvals[2];
+	struct berval	*certvals[2], *firstdnbvals[2], *usnbvals[2];
 	struct berval	certval;
-	LDAPMod		ocmod, idnmod, sdnmod, sermod, certmod, upmod;
+	LDAPMod		ocmod, idnmod, sdnmod, sermod, certmod, upmod,
+			firstdnmod, usnmod;
 	LDAPMod		*mods[5];
@@ -263,2 +312,3 @@ int	ldap_store_cert(scep_t *scep) {
 	int		rc;
+	LDAPDN		ldapdn;
 
@@ -270,2 +320,4 @@ int	ldap_store_cert(scep_t *scep) {
 				"faked\n", __FILE__, __LINE__);
+			syslog(LOG_DEBUG, "%s:%d: no LDAP, store_cert "
+				"faked\n", __FILE__, __LINE__);
 		return 0;
@@ -285,2 +337,5 @@ int	ldap_store_cert(scep_t *scep) {
 				__LINE__);
+			syslog(LOG_ERR, "%s:%d: cannot get the client "
+				"certificate from the file system\n", __FILE__,
+				__LINE__);
 			goto err;
@@ -296,2 +351,4 @@ int	ldap_store_cert(scep_t *scep) {
 			__FILE__, __LINE__);
+		syslog(LOG_ERR, "%s:%d: cannot convert DN to LDAP form\n",
+			__FILE__, __LINE__);
 		goto err;
@@ -305,3 +362,4 @@ int	ldap_store_cert(scep_t *scep) {
 		ocvals[1] = "sCEPClient";
-		ocvals[2] = NULL;
+		ocvals[2] = "device";
+		ocvals[3] = NULL;
 		ocmod.mod_op = LDAP_MOD_ADD;
@@ -309,12 +367,112 @@ int	ldap_store_cert(scep_t *scep) {
 		ocmod.mod_values = ocvals;
+		rc = ldap_str2dn(dn, &ldapdn, LDAP_DN_FORMAT_LDAPV3);
+		if (rc != LDAP_SUCCESS) {
+			BIO_printf(bio_err, "%s:%d: cannot convert LDAP DN \"%s\" to opaque form: %s\n",
+				__FILE__, __LINE__, dn, ldap_err2string(rc));
+			syslog(LOG_ERR, "%s:%d: cannot convert LDAP DN \"%s\" to opaque form: %s\n",
+				__FILE__, __LINE__, dn, ldap_err2string(rc));
+			goto err;
+		}
+		
+		/*
+		 * in LDAPv3 first element of dn X=y 
+		 * must appear as an attribute-value 
+		 * x: y
+		 * ...apparently.  Whatever.  I could 
+		 * strap on a suit and tie and fly 
+		 * to Leysin for some conference to 
+		 * decide what goes in an X.500 
+		 * object, or I could just keep 
+		 * slapping crap into the object until 
+		 * slapd shuts up.
+		 */
+		firstdnmod.mod_op = LDAP_MOD_ADD;
+		/*
+		 * LDAPv3 DNs can have _RDN components_ separated by , which 
+		 * are each in a different scope and arranged heirarchically, 
+		 * like domain name components.  Then, each RDN can have 
+		 * components which are in the same scope and not 
+		 * heirarchical.  I've never seen that used and don't know 
+		 * what the narrative scenario is for that, but apparently 
+		 * they're separated by + like
+		 *
+		 *  CN=Ada+CN=Lucette,O=WIPO,ST=ASSO,C=FR
+		 * 
+		 * Silly.  next, the ldap_explode_dn man page is wrong.  It 
+		 * has an extra pointer indirection in the 
+		 * typedef **LDAPRDN LDAPDN.  In ldap.h it is just 
+		 * typedef *LDAPRDN LDAPDN, which makes sense because LDAPRDN 
+		 * is not a struct.  Then there is another extra * in the 
+		 * prototype of ldap_str2dn, and another extra star in the 
+		 * 'struct berval *la_attr, *la_value'.  just use the header 
+		 * file.  The man page is so broken.
+		 *
+		 * the (X[0])[0]->y selects the first AVA pair of the 
+		 * first component of the DN, so in this case ldapdn[0] 
+		 * would select CN=Ada+CN=Lucette and (ldapdn[0])[0] would 
+		 * select CN=Ada and (X[0])[0]->la_value would select Ada.
+		 *
+		 * But then you don't know for sure that Ada isn't 
+		 * BER-encoded, and if it's not, how to typecast or reference 
+		 * structure members to get a string out of it.  And in 
+		 * ldap.h, la_attr is a berval also, but there is no flag 
+		 * in an LDAPAVA nor in an LDAPMod to deal with BER-encoded 
+		 * attribute names.  according to libraries/libldap/getdn.c 
+		 * la_attr could actually be binary if attribute names of the 
+		 * form 'oid.1.3.6.1...' are used, and with this API we just 
+		 * pass this into a (char *) like any string.  :(
+		 *
+		 * This is all just a complete motherfucking standardsbloat 
+		 * disaster.
+		 */
+		if ( (ldapdn[0])[0]->la_flags == LDAP_AVA_BINARY) {
+			firstdnmod.mod_op |= LDAP_MOD_BVALUES;
+			firstdnbvals[0] = &(ldapdn[0])[0]->la_value;
+			firstdnbvals[1] = NULL;
+			firstdnmod.mod_bvalues = firstdnbvals;
+		} else {
+			firstdnvals[0] = (ldapdn[0])[0]->la_value.bv_val;
+			firstdnvals[1] = NULL;
+			firstdnmod.mod_values = firstdnvals;
+		}
+		firstdnmod.mod_type = (ldapdn[0])[0]->la_attr.bv_val;
+		/*
+		 * the 'device' structural objectclass says an 
+		 * common name is mandatory, even though we're allowed 
+		 * to use the unstructuredName in the DN.
+		 */
+		if (strcmp(firstdnmod.mod_type, "cn") != 0) {
+			usnmod.mod_op = LDAP_MOD_ADD;
+			if ( (ldapdn[0])[0]->la_flags == LDAP_AVA_BINARY) {
+				usnmod.mod_op |= LDAP_MOD_BVALUES;
+				usnbvals[0] = &(ldapdn[0])[0]->la_value;
+				usnbvals[1] = NULL;
+				usnmod.mod_bvalues = usnbvals;
+			} else {
+				usnvals[0] = (ldapdn[0])[0]->la_value.bv_val;
+				usnvals[1] = NULL;
+				usnmod.mod_values = usnvals;
+			}
+			usnmod.mod_type = "cn";
+			mods[2] = &usnmod;
+		} else
+			mods[2] = NULL;
 		mods[0] = &ocmod;
-		mods[1] = NULL;
+		mods[1] = &firstdnmod;
+		mods[3] = NULL;
 		if (ldap_add_s(scep->l.ldap, dn, mods) != LDAP_SUCCESS) {
+			ldap_memfree(ldapdn);
 			BIO_printf(bio_err, "%s:%d: cannot add new node %s\n",
 				__FILE__, __LINE__, dn);
+			syslog(LOG_ERR, "%s:%d: cannot add new node %s\n",
+				__FILE__, __LINE__, dn);
 			goto err;
 		}
-		if (debug)
-			BIO_printf(bio_err, "%s:%d: adding skeleton node for "
+		ldap_memfree(ldapdn);
+		if (debug) {
+			BIO_printf(bio_err, "%s:%d: added skeleton node for "
 				"%s\n", __FILE__, __LINE__, dn);
+			syslog(LOG_DEBUG, "%s:%d: added skeleton node for "
+				"%s\n", __FILE__, __LINE__, dn);
+		}
 	}
@@ -337,2 +495,10 @@ int	ldap_store_cert(scep_t *scep) {
 			__LINE__, serial);
+		syslog(LOG_DEBUG, "%s:%d: replacing attributes in dn = %s:\n",
+			__FILE__, __LINE__, dn);
+		syslog(LOG_DEBUG, "%s:%d:\tissuerDN=%s\n", __FILE__,
+			__LINE__, issuerDN);
+		syslog(LOG_DEBUG, "%s:%d:\tsubjectDN=%s\n", __FILE__,
+			__LINE__, subjectDN);
+		syslog(LOG_DEBUG, "%s:%d:\tserialNumber=%s\n", __FILE__,
+			__LINE__, serial);
 	}
@@ -341,5 +507,8 @@ int	ldap_store_cert(scep_t *scep) {
 	challenge = get_challenge(scep);
-	if (debug)
+	if (debug) {
 		BIO_printf(bio_err, "%s:%d: got challenge password: %s\n",
 			__FILE__, __LINE__, (challenge) ? challenge: "<null>");
+		syslog(LOG_DEBUG, "%s:%d: got challenge password: %s\n",
+			__FILE__, __LINE__, (challenge) ? "<hidden>" : "<null>");
+	}
 
@@ -376,2 +545,4 @@ int	ldap_store_cert(scep_t *scep) {
 			__FILE__, __LINE__);
+		syslog(LOG_ERR, "%s:%d: cannot write client cert as DER\n",
+			__FILE__, __LINE__);
 		goto err;
@@ -401,7 +572,12 @@ int	ldap_store_cert(scep_t *scep) {
 			"and attributes\n", __FILE__, __LINE__);
+		syslog(LOG_ERR, "%s:%d: cannot update directory with cert "
+			"and attributes\n", __FILE__, __LINE__);
 		goto err;
 	}
-	if (debug)
+	if (debug) {
 		BIO_printf(bio_err, "%s:%d: certificate and attributes for "
-			"%s successfully added\n", __FILE__, __LINE__, dn);
+			"%s successfully modified\n", __FILE__, __LINE__, dn);
+		syslog(LOG_DEBUG, "%s:%d: certificate and attributes for "
+			"%s successfully modified\n", __FILE__, __LINE__, dn);
+	}
 
@@ -439,2 +615,4 @@ static int	ldap_get_cert_common(scep_t *
 			__FILE__, __LINE__);
+		syslog(LOG_ERR, "%s:%d: cannot find certificate\n",
+			__FILE__, __LINE__);
 		goto err;
@@ -446,2 +624,4 @@ static int	ldap_get_cert_common(scep_t *
 			__FILE__, __LINE__);
+		syslog(LOG_ERR, "%s:%d: wrong number of entries returned\n",
+			__FILE__, __LINE__);
 		goto err;
@@ -451,5 +631,8 @@ static int	ldap_get_cert_common(scep_t *
 	e = ldap_first_entry(scep->l.ldap, result);
-	if (debug)
+	if (debug) {
 		BIO_printf(bio_err, "%s:%d: retrieving certificate from %s\n",
 			__FILE__, __LINE__, ldap_get_dn(scep->l.ldap, e));
+		syslog(LOG_DEBUG, "%s:%d: retrieving certificate from %s\n",
+			__FILE__, __LINE__, ldap_get_dn(scep->l.ldap, e));
+	}
 
@@ -461,2 +644,4 @@ static int	ldap_get_cert_common(scep_t *
 			__LINE__);
+		syslog(LOG_ERR, "%s:%d: attribute not found\n", __FILE__,
+			__LINE__);
 		goto err;
@@ -472,2 +657,4 @@ static int	ldap_get_cert_common(scep_t *
 			"retrieved from LDAP directory\n", __FILE__, __LINE__);
+		syslog(LOG_ERR, "%s:%d: cannot decode certificate "
+			"retrieved from LDAP directory\n", __FILE__, __LINE__);
 		goto err;
@@ -503,5 +690,8 @@ int	ldap_get_cert_from_issuer_and_serial
 		issuerDN, serial);
-	if (debug)
+	if (debug) {
 		BIO_printf(bio_err, "%s:%d: search filter: %s\n",
 			__FILE__, __LINE__, filter);
+		syslog(LOG_DEBUG, "%s:%d: search filter: %s\n",
+			__FILE__, __LINE__, filter);
+	}
 
@@ -512,2 +702,4 @@ int	ldap_get_cert_from_issuer_and_serial
 			"failed\n", __FILE__, __LINE__);
+		syslog(LOG_ERR, "%s:%d: certificate retrieval common part "
+			"failed\n", __FILE__, __LINE__);
 		goto err;
@@ -542,5 +734,8 @@ int	ldap_get_cert_from_issuer_and_subjec
 		issuerDN, subjectDN);
-	if (debug)
+	if (debug) {
 		BIO_printf(bio_err, "%s:%d: searching for certificate with "
 			"filter '%s'\n", __FILE__, __LINE__, filter);
+		syslog(LOG_DEBUG, "%s:%d: searching for certificate with "
+			"filter '%s'\n", __FILE__, __LINE__, filter);
+	}
 
@@ -550,2 +745,4 @@ int	ldap_get_cert_from_issuer_and_subjec
 		BIO_printf(bio_err, "%s:%d: cannot get cert common\n", 
+			__FILE__, __LINE__);
+		syslog(LOG_ERR, "%s:%d: cannot get cert common\n", 
 			__FILE__, __LINE__);
