Branch: master

d9172dad 2015-09-29 12:06:18 Timothy Pearson
Add PKI subject mapping to user principals
Fix long-standing inability to clear user principal attribute fields
M src/libtdeldap.cpp
diff --git a/src/libtdeldap.cpp b/src/libtdeldap.cpp
index 690cee9..37cc76b 100644
--- a/src/libtdeldap.cpp
+++ b/src/libtdeldap.cpp
@@ -51,9 +51,30 @@
 
 extern "C" {
 	#include <hdb.h>
+	#include <hdb_asn1.h>
 	#include <kadm5/admin.h>
 	#include <kadm5/private.h>
 	#include <kadm5/kadm5-private.h>
+
+	// ========================================================================
+	// Taken from asn1-common.h and slightly modified for C++ compilability
+	// ========================================================================
+	#define ASN1_MALLOC_ENCODE_HDB(T, B, BL, S, L, R)              \
+	  do {                                                         \
+	    (BL) = length_##T((S));                                    \
+	    (B) = (unsigned char*)malloc((BL));                        \
+	    if((B) == NULL) {                                          \
+	      (R) = ENOMEM;                                            \
+	    } else {                                                   \
+	      (R) = encode_##T(((unsigned char*)(B)) + (BL) - 1, (BL), \
+	                       (S), (L));                              \
+	      if((R) != 0) {                                           \
+	        free((B));                                             \
+	        (B) = NULL;                                            \
+	      }                                                        \
+	    }                                                          \
+	  } while (0)
+	// ========================================================================
 }
 
 #include "libtdeldap.h"
@@ -930,6 +951,14 @@
 		mods[*i]->mod_values = values;
 		(*i)++;
 	}
+	else {
+		char **values = (char**)malloc(sizeof(char*));
+		values[0] = NULL;
+		mods[*i]->mod_op = LDAP_MOD_REPLACE;
+		mods[*i]->mod_type = strdup(attr.ascii());
+		mods[*i]->mod_values = values;
+		(*i)++;
+	}
 }
 
 void add_single_binary_attribute_operation(LDAPMod **mods, int *i, TQString attr, TQByteArray &ba) {
@@ -1023,9 +1052,68 @@
 		return -1;
 	}
 	else {
+		// Create certificate ACL extension data
+		TQString pkinit_acl_subject = TQString::null;
+		PKICertificateEntryList::Iterator it;
+		for (it = user.pkiCertificates.begin(); it != user.pkiCertificates.end(); ++it) {
+			PKICertificateEntry certificateData = *it;
+
+			TQCString ssldata(certificateData.second);
+			ssldata[certificateData.second.size()] = 0;
+			ssldata.replace("-----BEGIN CERTIFICATE-----", "");
+			ssldata.replace("-----END CERTIFICATE-----", "");
+			ssldata.replace("\n", "");
+			KSSLCertificate* cert = KSSLCertificate::fromString(ssldata);
+			if (cert) {
+				bool expired = false;
+				if (TQDateTime::currentDateTime(Qt::UTC) > cert->getQDTNotAfter()) {
+					expired = true;
+				}
+
+				if ((certificateData.first == PKICertificateStatus::Revoked) || expired) {
+					continue;
+				}
+				else {
+					// NOTE
+					// At this time Heimdal only appears to support one certificate ACL string
+					// Use the last valid certificate subject when creating that string
+					TQStringList reversedSubjectChunks;
+					TQStringList subjectChunks = TQStringList::split("/", cert->getSubject());
+					for (TQStringList::Iterator it = subjectChunks.begin(); it != subjectChunks.end(); it++) {
+						reversedSubjectChunks.prepend(*it);
+					}
+					pkinit_acl_subject = reversedSubjectChunks.join(",");
+				}
+			}
+		}
+		TQByteArray acl_asn1_data;
+		if (pkinit_acl_subject != "") {
+			krb5_error_code krb5_ret;
+			HDB_extension extended_attributes;
+			memset(&extended_attributes, 0, sizeof(extended_attributes));
+			extended_attributes.mandatory = true;
+			extended_attributes.data.element = HDB_extension::HDB_extension_data::choice_HDB_extension_data_pkinit_acl;
+			HDB_Ext_PKINIT_acl* pkinit_acl = &extended_attributes.data.u.pkinit_acl;
+			pkinit_acl->val = (HDB_Ext_PKINIT_acl::HDB_Ext_PKINIT_acl_val*)malloc(sizeof(pkinit_acl->val[0]));
+			pkinit_acl->len = 1;
+			pkinit_acl->val->subject = const_cast<char*>(pkinit_acl_subject.ascii());
+			pkinit_acl->val->issuer = NULL;
+			pkinit_acl->val->anchor = NULL;
+			unsigned char *asn1_encoding_buf;
+			size_t initial_size = 0;
+			size_t resultant_size = 0;
+			ASN1_MALLOC_ENCODE_HDB(HDB_extension, asn1_encoding_buf, initial_size, &extended_attributes, &resultant_size, krb5_ret);
+			if (initial_size == resultant_size) {
+				acl_asn1_data.resize(resultant_size);
+				memcpy(acl_asn1_data.data(), asn1_encoding_buf, resultant_size);
+			}
+			free(pkinit_acl->val);
+			free(asn1_encoding_buf);
+		}
+
 		// Assemble the LDAPMod structure
 		// We will replace any existing attributes with the new values
-		int number_of_parameters = 40;				// 40 primary attributes
+		int number_of_parameters = 49;				// 49 primary attributes
 		LDAPMod *mods[number_of_parameters+1];
 		set_up_attribute_operations(mods, number_of_parameters);
 
@@ -1087,6 +1175,7 @@
 		add_single_attribute_operation(mods, &i, "businessCategory", user.businessCategory);
 		add_single_attribute_operation(mods, &i, "carLicense", user.carLicense);
 		add_single_attribute_operation(mods, &i, "notes", user.notes);
+		add_single_binary_attribute_operation(mods, &i, "krb5ExtendedAttributes", acl_asn1_data);
 		LDAPMod *prevterm = mods[i];
 		mods[i] = NULL;