From d9172dad3c94e373c944d6f4e7a06262ed0329a1 Mon Sep 17 00:00:00 2001 From: Timothy Pearson Date: Tue, 29 Sep 2015 12:06:18 -0500 Subject: [PATCH] Add PKI subject mapping to user principals Fix long-standing inability to clear user principal attribute fields --- src/libtdeldap.cpp | 91 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 90 insertions(+), 1 deletion(-) 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 + #include #include #include #include + + // ======================================================================== + // 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 @@ void add_single_attribute_operation(LDAPMod **mods, int *i, TQString attr, TQStr 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 @@ int LDAPManager::updateUserInfo(LDAPUserInfo user, TQString *errstr) { 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(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 @@ int LDAPManager::updateUserInfo(LDAPUserInfo user, TQString *errstr) { 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;