From 8a439f8521d78dc4c3ebcca248bc60f540e83acb Mon Sep 17 00:00:00 2001 From: Timothy Pearson Date: Thu, 27 Jun 2013 23:03:24 +0000 Subject: [PATCH] Add a number of methods to enable multi-master replication --- src/libtdeldap.cpp | 696 ++++++++++++++++++++++++++++++++++++++------- src/libtdeldap.h | 35 +++ 2 files changed, 626 insertions(+), 105 deletions(-) diff --git a/src/libtdeldap.cpp b/src/libtdeldap.cpp index 8209501..8aac29f 100644 --- a/src/libtdeldap.cpp +++ b/src/libtdeldap.cpp @@ -876,6 +876,40 @@ void add_multiple_attributes_operation(LDAPMod **mods, int *i, TQString attr, TQ (*i)++; } +void delete_single_attribute_operation(LDAPMod **mods, int *i, TQString attr) { + mods[*i]->mod_op = LDAP_MOD_DELETE; + mods[*i]->mod_type = strdup(attr.ascii()); + (*i)++; +} + +void set_up_attribute_operations(LDAPMod **mods, int number_of_parameters) { + int i; + for (i=0;imod_type = NULL; + mods[i]->mod_values = NULL; + } + mods[number_of_parameters] = NULL; +} + +void clean_up_attribute_operations(int i, LDAPMod **mods, LDAPMod *prevterm, int number_of_parameters) { + mods[i] = prevterm; + for (i=0;imod_type != NULL) { + free(mods[i]->mod_type); + } + if (mods[i]->mod_values != NULL) { + int j = 0; + while (mods[i]->mod_values[j] != NULL) { + free(mods[i]->mod_values[j]); + j++; + } + free(mods[i]->mod_values); + } + delete mods[i]; + } +} + int LDAPManager::updateUserInfo(LDAPUserInfo user, TQString *errstr) { int retcode; int i; @@ -889,12 +923,7 @@ int LDAPManager::updateUserInfo(LDAPUserInfo user, TQString *errstr) { // We will replace any existing attributes with the new values int number_of_parameters = 40; // 40 primary attributes LDAPMod *mods[number_of_parameters+1]; - for (i=0;imod_type = NULL; - mods[i]->mod_values = NULL; - } - mods[number_of_parameters] = NULL; + set_up_attribute_operations(mods, number_of_parameters); // Load LDAP modification requests from provided data structure i=0; @@ -961,21 +990,7 @@ int LDAPManager::updateUserInfo(LDAPUserInfo user, TQString *errstr) { retcode = ldap_modify_ext_s(m_ldap, user.distinguishedName.ascii(), mods, NULL, NULL); // Clean up - mods[i] = prevterm; - for (i=0;imod_type != NULL) { - free(mods[i]->mod_type); - } - if (mods[i]->mod_values != NULL) { - int j = 0; - while (mods[i]->mod_values[j] != NULL) { - free(mods[i]->mod_values[j]); - j++; - } - free(mods[i]->mod_values); - } - delete mods[i]; - } + clean_up_attribute_operations(i, mods, prevterm, number_of_parameters); if (retcode != LDAP_SUCCESS) { if (errstr) { @@ -1485,12 +1500,7 @@ int LDAPManager::updateGroupInfo(LDAPGroupInfo group, TQString *errstr) { // We will replace any existing attributes with the new values int number_of_parameters = 3; // 3 primary attributes LDAPMod *mods[number_of_parameters+1]; - for (i=0;imod_type = NULL; - mods[i]->mod_values = NULL; - } - mods[number_of_parameters] = NULL; + set_up_attribute_operations(mods, number_of_parameters); // Load LDAP modification requests from provided data structure i=0; @@ -1520,21 +1530,7 @@ int LDAPManager::updateGroupInfo(LDAPGroupInfo group, TQString *errstr) { retcode = ldap_modify_ext_s(m_ldap, group.distinguishedName.ascii(), mods, NULL, NULL); // Clean up - mods[i] = prevterm; - for (i=0;imod_type != NULL) { - free(mods[i]->mod_type); - } - if (mods[i]->mod_values != NULL) { - int j = 0; - while (mods[i]->mod_values[j] != NULL) { - free(mods[i]->mod_values[j]); - j++; - } - free(mods[i]->mod_values); - } - delete mods[i]; - } + clean_up_attribute_operations(i, mods, prevterm, number_of_parameters); if (retcode != LDAP_SUCCESS) { if (errstr) { @@ -1575,12 +1571,7 @@ int LDAPManager::addUserInfo(LDAPUserInfo user, TQString *errstr) { // Create the base DN entry int number_of_parameters = 14; // 14 primary attributes LDAPMod *mods[number_of_parameters+1]; - for (i=0;imod_type = NULL; - mods[i]->mod_values = NULL; - } - mods[number_of_parameters] = NULL; + set_up_attribute_operations(mods, number_of_parameters); // Load initial required LDAP object attributes i=0; @@ -1607,21 +1598,7 @@ int LDAPManager::addUserInfo(LDAPUserInfo user, TQString *errstr) { retcode = ldap_add_ext_s(m_ldap, user.distinguishedName.ascii(), mods, NULL, NULL); // Clean up - mods[i] = prevterm; - for (i=0;imod_type != NULL) { - free(mods[i]->mod_type); - } - if (mods[i]->mod_values != NULL) { - int j = 0; - while (mods[i]->mod_values[j] != NULL) { - free(mods[i]->mod_values[j]); - j++; - } - free(mods[i]->mod_values); - } - delete mods[i]; - } + clean_up_attribute_operations(i, mods, prevterm, number_of_parameters); if (retcode != LDAP_SUCCESS) { if (errstr) { @@ -1650,12 +1627,7 @@ int LDAPManager::addGroupInfo(LDAPGroupInfo group, TQString *errstr) { // Create the base DN entry int number_of_parameters = 6; // 6 primary attributes LDAPMod *mods[number_of_parameters+1]; - for (i=0;imod_type = NULL; - mods[i]->mod_values = NULL; - } - mods[number_of_parameters] = NULL; + set_up_attribute_operations(mods, number_of_parameters); TQString placeholderGroup = "cn=placeholder," + m_basedc; @@ -1675,21 +1647,7 @@ int LDAPManager::addGroupInfo(LDAPGroupInfo group, TQString *errstr) { retcode = ldap_add_ext_s(m_ldap, group.distinguishedName.ascii(), mods, NULL, NULL); // Clean up - mods[i] = prevterm; - for (i=0;imod_type != NULL) { - free(mods[i]->mod_type); - } - if (mods[i]->mod_values != NULL) { - int j = 0; - while (mods[i]->mod_values[j] != NULL) { - free(mods[i]->mod_values[j]); - j++; - } - free(mods[i]->mod_values); - } - delete mods[i]; - } + clean_up_attribute_operations(i, mods, prevterm, number_of_parameters); if (retcode != LDAP_SUCCESS) { if (errstr) { @@ -2673,12 +2631,7 @@ int LDAPManager::writeCertificateFileIntoDirectory(TQByteArray cert, TQString at // We will replace any existing attributes with the new values int number_of_parameters = 1; // 1 primary attribute LDAPMod *mods[number_of_parameters+1]; - for (i=0;imod_type = NULL; - mods[i]->mod_values = NULL; - } - mods[number_of_parameters] = NULL; + set_up_attribute_operations(mods, number_of_parameters); // Load LDAP modification requests from provided data structure i=0; @@ -2690,21 +2643,7 @@ int LDAPManager::writeCertificateFileIntoDirectory(TQByteArray cert, TQString at retcode = ldap_modify_ext_s(m_ldap, TQString("cn=certificate store,o=tde,cn=tde realm data,ou=master services,ou=core,ou=realm,%1").arg(m_basedc).ascii(), mods, NULL, NULL); // Clean up - mods[i] = prevterm; - for (i=0;imod_type != NULL) { - free(mods[i]->mod_type); - } - if (mods[i]->mod_values != NULL) { - int j = 0; - while (mods[i]->mod_values[j] != NULL) { - delete mods[i]->mod_values[j]; - j++; - } - free(mods[i]->mod_values); - } - delete mods[i]; - } + clean_up_attribute_operations(i, mods, prevterm, number_of_parameters); if (retcode != LDAP_SUCCESS) { if (errstr) *errstr = i18n("LDAP certificate upload failure

Reason: [%3] %4").arg(retcode).arg(ldap_err2string(retcode)); @@ -2885,6 +2824,94 @@ LDAPTDEBuiltinsInfo LDAPManager::parseLDAPTDEBuiltinsRecord(LDAPMessage* entry) return builtininfo; } +LDAPMasterReplicationInfo LDAPManager::parseLDAPMasterReplicationRecord(LDAPMasterReplicationInfo replicationinfo, LDAPMessage* entry) { + char* dn = NULL; + char* attr; + struct berval **vals; + BerElement* ber; + int i; + + if((dn = ldap_get_dn(m_ldap, entry)) != NULL) { + ldap_memfree(dn); + } + + for( attr = ldap_first_attribute(m_ldap, entry, &ber); attr != NULL; attr = ldap_next_attribute(m_ldap, entry, ber)) { + if ((vals = ldap_get_values_len(m_ldap, entry, attr)) != NULL) { + TQString ldap_field = attr; + if (ldap_field == "olcServerID") { + i=0; + while (vals[i] != NULL) { + TQStringList serverIDMapping = TQStringList::split(" ", TQString(vals[i]->bv_val), FALSE); + LDAPMasterReplicationMapping mapping; + mapping.id = serverIDMapping[0].toInt(); + mapping.fqdn = serverIDMapping[1]; + mapping.fqdn.replace("ldap:", ""); + mapping.fqdn.replace("ldaps:", ""); + mapping.fqdn.replace("/", ""); + replicationinfo.serverIDs.append(mapping); + i++; + } + replicationinfo.informationValid = true; + } + else if (ldap_field == "olcMirrorMode") { + i=0; + TQString mirrorModeEnabled(vals[i]->bv_val); + if (mirrorModeEnabled == "TRUE") { + replicationinfo.enabled = true; + } + else { + replicationinfo.enabled = false; + } + } + ldap_value_free_len(vals); + } + ldap_memfree(attr); + } + + if (ber != NULL) { + ber_free(ber, 0); + } + + return replicationinfo; +} + +TQString LDAPManager::parseLDAPSyncProvOverlayConfigRecord(LDAPMessage* entry) { + char* dn = NULL; + char* attr; + struct berval **vals; + BerElement* ber; + int i; + TQString syncProvEntry; + + if((dn = ldap_get_dn(m_ldap, entry)) != NULL) { + ldap_memfree(dn); + } + + for( attr = ldap_first_attribute(m_ldap, entry, &ber); attr != NULL; attr = ldap_next_attribute(m_ldap, entry, ber)) { + if ((vals = ldap_get_values_len(m_ldap, entry, attr)) != NULL) { + TQString ldap_field = attr; + if (ldap_field == "olcOverlay") { + i=0; + while (vals[i] != NULL) { + TQString value(vals[i]->bv_val); + if (value.endsWith("}syncprov")) { + syncProvEntry = value; + } + i++; + } + } + ldap_value_free_len(vals); + } + ldap_memfree(attr); + } + + if (ber != NULL) { + ber_free(ber, 0); + } + + return syncProvEntry; +} + LDAPTDEBuiltinsInfo LDAPManager::getTDEBuiltinMappings(TQString *errstr) { int retcode; LDAPTDEBuiltinsInfo builtininfo; @@ -2918,6 +2945,441 @@ LDAPTDEBuiltinsInfo LDAPManager::getTDEBuiltinMappings(TQString *errstr) { return LDAPTDEBuiltinsInfo(); } +LDAPMasterReplicationInfo LDAPManager::getLDAPMasterReplicationSettings(TQString *errstr) { + int retcode; + LDAPMasterReplicationInfo replicationinfo; + + if (bind(errstr) < 0) { + return LDAPMasterReplicationInfo(); + } + else { + // Check cn=config settings + LDAPMessage* msg; + retcode = ldap_search_ext_s(m_ldap, "cn=config", LDAP_SCOPE_SUBTREE, NULL, ldap_user_and_operational_attributes, 0, NULL, NULL, NULL, 0, &msg); + if (retcode != LDAP_SUCCESS) { + if (errstr) *errstr = i18n("LDAP search failure

Reason: [%3] %4").arg(retcode).arg(ldap_err2string(retcode)); + else KMessageBox::error(0, i18n("LDAP search failure

Reason: [%3] %4").arg(retcode).arg(ldap_err2string(retcode)), i18n("LDAP Error")); + return LDAPMasterReplicationInfo(); + } + + // Iterate through the returned entries + LDAPMessage* entry; + for(entry = ldap_first_entry(m_ldap, msg); entry != NULL; entry = ldap_next_entry(m_ldap, entry)) { + LDAPMasterReplicationInfo potentialReplicationInfo; + potentialReplicationInfo = parseLDAPMasterReplicationRecord(LDAPMasterReplicationInfo(), entry); + if (potentialReplicationInfo.informationValid) { + replicationinfo = potentialReplicationInfo; + } + } + + // clean up + ldap_msgfree(msg); + + // Set OpenLDAP defaults + replicationinfo.enabled = false; + + // Check olcDatabase 0 configuration settings + retcode = ldap_search_ext_s(m_ldap, "olcDatabase={0}config,cn=config", LDAP_SCOPE_SUBTREE, NULL, ldap_user_and_operational_attributes, 0, NULL, NULL, NULL, 0, &msg); + if (retcode != LDAP_SUCCESS) { + if (errstr) *errstr = i18n("LDAP search failure

Reason: [%3] %4").arg(retcode).arg(ldap_err2string(retcode)); + else KMessageBox::error(0, i18n("LDAP search failure

Reason: [%3] %4").arg(retcode).arg(ldap_err2string(retcode)), i18n("LDAP Error")); + return LDAPMasterReplicationInfo(); + } + + // Iterate through the returned entries + for(entry = ldap_first_entry(m_ldap, msg); entry != NULL; entry = ldap_next_entry(m_ldap, entry)) { + replicationinfo = parseLDAPMasterReplicationRecord(replicationinfo, entry); + } + + // clean up + ldap_msgfree(msg); + + return replicationinfo; + } + + return LDAPMasterReplicationInfo(); +} + +int LDAPManager::setLDAPMasterReplicationSettings(LDAPMasterReplicationInfo replicationinfo, TQString *errstr) { + int retcode; + int i; + + if (bind(errstr) < 0) { + return -1; + } + else { + if (replicationinfo.enabled) { + if (!errstr && (replicationinfo.syncDN == "")) { + replicationinfo.syncDN = "cn=admin," + m_basedc; + } + if (!errstr && replicationinfo.syncPassword.isNull()) { + LDAPPasswordDialog passdlg(0, 0, false); + passdlg.m_base->ldapAdminRealm->setEnabled(false); + passdlg.m_base->ldapAdminRealm->insertItem(m_realm); + passdlg.m_base->ldapUseTLS->hide(); + passdlg.m_base->ldapAdminUsername->setEnabled(false); + passdlg.m_base->ldapAdminUsername->setText(replicationinfo.syncDN); + if (passdlg.exec() == TQDialog::Accepted) { + replicationinfo.syncPassword = passdlg.m_base->ldapAdminPassword->password(); + } + } + + if ((replicationinfo.syncDN == "") || (replicationinfo.syncPassword.isNull())) { + if (errstr) *errstr = i18n("LDAP modification failure

Reason: Invalid multi-master synchronization credentials provided"); + else KMessageBox::error(0, i18n("LDAP modification failure

Reason: Invalid multi-master synchronization credentials provided"), i18n("User Error")); + return -1; + } + + // Test credentials before continuing + LDAPCredentials* credentials = new LDAPCredentials; + credentials->username = replicationinfo.syncDN; + credentials->password = replicationinfo.syncPassword; + credentials->realm = m_realm; + LDAPManager* ldap_mgr = new LDAPManager(m_realm, "ldapi://", credentials); + TQString errorstring; + if (ldap_mgr->bind(&errorstring) != 0) { + delete ldap_mgr; + if (errstr) *errstr = i18n("LDAP modification failure

Reason: Invalid multi-master synchronization credentials provided"); + else KMessageBox::error(0, i18n("LDAP modification failure

Reason: Invalid multi-master synchronization credentials provided"), i18n("User Error")); + return -1; + } + delete ldap_mgr; + } + + if (replicationinfo.serverIDs.count() <= 0) { + replicationinfo.enabled = false; + } + + if (replicationinfo.serverIDs.count() > 0) { + // Assemble the LDAPMod structure + // We will replace any existing attributes with the new values + int number_of_parameters = 1; // 1 primary attribute + LDAPMod *mods[number_of_parameters+1]; + set_up_attribute_operations(mods, number_of_parameters); + + // Load LDAP modification requests from provided data structure + i=0; + TQStringList serverMappingList; + LDAPMasterReplicationMap::iterator it; + for (it = replicationinfo.serverIDs.begin(); it != replicationinfo.serverIDs.end(); ++it) { + serverMappingList.append(TQString("%1 ldaps://%2/").arg((*it).id).arg((*it).fqdn)); + } + add_multiple_attributes_operation(mods, &i, "olcServerID", serverMappingList); + LDAPMod *prevterm = mods[i]; + mods[i] = NULL; + + // Perform LDAP update + retcode = ldap_modify_ext_s(m_ldap, "cn=config", mods, NULL, NULL); + + // Clean up + clean_up_attribute_operations(i, mods, prevterm, number_of_parameters); + + if (retcode == LDAP_NO_SUCH_ATTRIBUTE) { + // Add new object instead + // Assemble the LDAPMod structure + // We will replace any existing attributes with the new values + int number_of_parameters = 1; // 1 primary attribute + LDAPMod *mods[number_of_parameters+1]; + set_up_attribute_operations(mods, number_of_parameters); + + // Load LDAP modification requests from provided data structure + i=0; + TQStringList serverMappingList; + LDAPMasterReplicationMap::iterator it; + for (it = replicationinfo.serverIDs.begin(); it != replicationinfo.serverIDs.end(); ++it) { + serverMappingList.append(TQString("%1 ldaps://%2/").arg((*it).id).arg((*it).fqdn)); + } + create_multiple_attributes_operation(mods, &i, "olcServerID", serverMappingList); + LDAPMod *prevterm = mods[i]; + mods[i] = NULL; + + // Perform LDAP update + retcode = ldap_add_ext_s(m_ldap, "cn=config", mods, NULL, NULL); + + // Clean up + clean_up_attribute_operations(i, mods, prevterm, number_of_parameters); + } + + if (retcode != LDAP_SUCCESS) { + if (errstr) *errstr = i18n("LDAP modification failure

Reason: [%3] %4").arg(retcode).arg(ldap_err2string(retcode)); + else KMessageBox::error(0, i18n("LDAP modification failure

Reason: [%3] %4").arg(retcode).arg(ldap_err2string(retcode)), i18n("LDAP Error")); + return -2; + } + } + else { + // Delete the olcServerID entry + // Assemble the LDAPMod structure + int number_of_parameters = 1; // 1 primary attribute + LDAPMod *mods[number_of_parameters+1]; + set_up_attribute_operations(mods, number_of_parameters); + + // Load LDAP delete request + i=0; + delete_single_attribute_operation(mods, &i, "olcServerID"); + LDAPMod *prevterm = mods[i]; + mods[i] = NULL; + + // Perform LDAP update + retcode = ldap_modify_ext_s(m_ldap, "cn=config", mods, NULL, NULL); + + // Clean up + clean_up_attribute_operations(i, mods, prevterm, number_of_parameters); + + if ((retcode != LDAP_SUCCESS) && (retcode != LDAP_NO_SUCH_ATTRIBUTE)) { + if (errstr) *errstr = i18n("LDAP modification failure

Reason: [%3] %4").arg(retcode).arg(ldap_err2string(retcode)); + else KMessageBox::error(0, i18n("LDAP modification failure

Reason: [%3] %4").arg(retcode).arg(ldap_err2string(retcode)), i18n("LDAP Error")); + return -2; + } + } + + { + if (replicationinfo.enabled) { + // Config Database + { + // Assemble the LDAPMod structure + // We will replace any existing attributes with the new values + int number_of_parameters = 2; // 2 primary attributes + LDAPMod *mods[number_of_parameters+1]; + set_up_attribute_operations(mods, number_of_parameters); + + // Load LDAP modification requests from provided data structure + i=0; + TQStringList syncReplServerList; + LDAPMasterReplicationMap::iterator it; + int rid = 1; + for (it = replicationinfo.serverIDs.begin(); it != replicationinfo.serverIDs.end(); ++it) { + TQString ridString; + TQString serverSyncReplString; + TQString databaseDN; + ridString.sprintf("%03d", rid); + databaseDN = "cn=config"; + serverSyncReplString = TQString("rid=%1 provider=ldaps://%2/ binddn=\"%3\" bindmethod=simple credentials=\"%4\" searchbase=\"%5\" type=refreshAndPersist retry=\"%5\" timeout=%6").arg(ridString).arg((*it).fqdn).arg(replicationinfo.syncDN).arg(replicationinfo.syncPassword).arg(databaseDN).arg(replicationinfo.retryMethod).arg(replicationinfo.timeout); + syncReplServerList.append(serverSyncReplString); + rid++; + } + add_multiple_attributes_operation(mods, &i, "olcSyncRepl", syncReplServerList); + add_single_attribute_operation(mods, &i, "olcMirrorMode", "TRUE"); + LDAPMod *prevterm = mods[i]; + mods[i] = NULL; + + // Perform LDAP update + retcode = ldap_modify_ext_s(m_ldap, "olcDatabase={0}config,cn=config", mods, NULL, NULL); + + // Clean up + clean_up_attribute_operations(i, mods, prevterm, number_of_parameters); + + if (retcode != LDAP_SUCCESS) { + if (errstr) *errstr = i18n("LDAP modification failure

Reason: [%3] %4").arg(retcode).arg(ldap_err2string(retcode)); + else KMessageBox::error(0, i18n("LDAP modification failure

Reason: [%3] %4").arg(retcode).arg(ldap_err2string(retcode)), i18n("LDAP Error")); + return -2; + } + } + + // Main Database + { + // Assemble the LDAPMod structure + // We will replace any existing attributes with the new values + int number_of_parameters = 2; // 2 primary attributes + LDAPMod *mods[number_of_parameters+1]; + set_up_attribute_operations(mods, number_of_parameters); + + // Load LDAP modification requests from provided data structure + i=0; + TQStringList syncReplServerList; + LDAPMasterReplicationMap::iterator it; + int rid = 1; + for (it = replicationinfo.serverIDs.begin(); it != replicationinfo.serverIDs.end(); ++it) { + TQString ridString; + TQString serverSyncReplString; + TQString databaseDN; + ridString.sprintf("%03d", rid); + databaseDN = m_basedc; + serverSyncReplString = TQString("rid=%1 provider=ldaps://%2/ binddn=\"%3\" bindmethod=simple credentials=\"%4\" searchbase=\"%5\" type=refreshAndPersist retry=\"%5\" timeout=%6").arg(ridString).arg((*it).fqdn).arg(replicationinfo.syncDN).arg(replicationinfo.syncPassword).arg(databaseDN).arg(replicationinfo.retryMethod).arg(replicationinfo.timeout); + syncReplServerList.append(serverSyncReplString); + rid++; + } + add_multiple_attributes_operation(mods, &i, "olcSyncRepl", syncReplServerList); + add_single_attribute_operation(mods, &i, "olcMirrorMode", "TRUE"); + LDAPMod *prevterm = mods[i]; + mods[i] = NULL; + + // Perform LDAP update + retcode = ldap_modify_ext_s(m_ldap, "olcDatabase={1}hdb,cn=config", mods, NULL, NULL); + + // Clean up + clean_up_attribute_operations(i, mods, prevterm, number_of_parameters); + + if (retcode != LDAP_SUCCESS) { + if (errstr) *errstr = i18n("LDAP modification failure

Reason: [%3] %4").arg(retcode).arg(ldap_err2string(retcode)); + else KMessageBox::error(0, i18n("LDAP modification failure

Reason: [%3] %4").arg(retcode).arg(ldap_err2string(retcode)), i18n("LDAP Error")); + return -2; + } + } + } + else { + // Delete the olcSyncRepl and olcMirrorMode entries + + // Main Database + { + // Assemble the LDAPMod structure + int number_of_parameters = 2; // 2 primary attributes + LDAPMod *mods[number_of_parameters+1]; + set_up_attribute_operations(mods, number_of_parameters); + + // Load LDAP delete request + i=0; + delete_single_attribute_operation(mods, &i, "olcSyncRepl"); + delete_single_attribute_operation(mods, &i, "olcMirrorMode"); + LDAPMod *prevterm = mods[i]; + mods[i] = NULL; + + // Perform LDAP update + retcode = ldap_modify_ext_s(m_ldap, "olcDatabase={1}hdb,cn=config", mods, NULL, NULL); + + // Clean up + clean_up_attribute_operations(i, mods, prevterm, number_of_parameters); + + if ((retcode != LDAP_SUCCESS) && (retcode != LDAP_NO_SUCH_ATTRIBUTE)) { + if (errstr) *errstr = i18n("LDAP modification failure

Reason: [%3] %4").arg(retcode).arg(ldap_err2string(retcode)); + else KMessageBox::error(0, i18n("LDAP modification failure

Reason: [%3] %4").arg(retcode).arg(ldap_err2string(retcode)), i18n("LDAP Error")); + return -2; + } + } + + // Config Database + { + // Assemble the LDAPMod structure + int number_of_parameters = 2; // 2 primary attributes + LDAPMod *mods[number_of_parameters+1]; + set_up_attribute_operations(mods, number_of_parameters); + + // Load LDAP delete request + i=0; + delete_single_attribute_operation(mods, &i, "olcSyncRepl"); + delete_single_attribute_operation(mods, &i, "olcMirrorMode"); + LDAPMod *prevterm = mods[i]; + mods[i] = NULL; + + // Perform LDAP update + retcode = ldap_modify_ext_s(m_ldap, "olcDatabase={0}config,cn=config", mods, NULL, NULL); + + // Clean up + clean_up_attribute_operations(i, mods, prevterm, number_of_parameters); + + if ((retcode != LDAP_SUCCESS) && (retcode != LDAP_NO_SUCH_ATTRIBUTE)) { + if (errstr) *errstr = i18n("LDAP modification failure

Reason: [%3] %4").arg(retcode).arg(ldap_err2string(retcode)); + else KMessageBox::error(0, i18n("LDAP modification failure

Reason: [%3] %4").arg(retcode).arg(ldap_err2string(retcode)), i18n("LDAP Error")); + return -2; + } + } + } + + // Get current active replication settings + TQString* readOnlyErrorString = NULL; + LDAPMasterReplicationInfo currentReplicationInfo = getLDAPMasterReplicationSettings(readOnlyErrorString); + if (readOnlyErrorString) { + // Uh oh + if (errstr) *errstr = *readOnlyErrorString; + else KMessageBox::error(0, *readOnlyErrorString, i18n("LDAP Error")); + return -2; + } + if (currentReplicationInfo.enabled != replicationinfo.enabled) { + if (replicationinfo.enabled) { + // Set up replication + // NOTE: The syncprov module itself is already loaded by the stock TDE LDAP configuration + + // Check to see if the syncprov overlay entries already exist + bool haveOlcOverlaySyncProv = false; + LDAPMessage* msg; + retcode = ldap_search_ext_s(m_ldap, "olcDatabase={0}config,cn=config", LDAP_SCOPE_SUBTREE, NULL, ldap_user_and_operational_attributes, 0, NULL, NULL, NULL, 0, &msg); + if (retcode != LDAP_SUCCESS) { + if (errstr) *errstr = i18n("LDAP search failure

Reason: [%3] %4").arg(retcode).arg(ldap_err2string(retcode)); + else KMessageBox::error(0, i18n("LDAP search failure

Reason: [%3] %4").arg(retcode).arg(ldap_err2string(retcode)), i18n("LDAP Error")); + return -2; + } + + // Iterate through the returned entries + LDAPMessage* entry; + for(entry = ldap_first_entry(m_ldap, msg); entry != NULL; entry = ldap_next_entry(m_ldap, entry)) { + if (parseLDAPSyncProvOverlayConfigRecord(entry) != "") { + haveOlcOverlaySyncProv = true; + } + } + + // clean up + ldap_msgfree(msg); + + if (!haveOlcOverlaySyncProv) { + // Create the base DN entry + int number_of_parameters = 1; // 1 primary attribute + LDAPMod *mods[number_of_parameters+1]; + set_up_attribute_operations(mods, number_of_parameters); + + // Load initial required LDAP object attributes + i=0; + TQStringList objectClassList; + objectClassList.append("olcOverlayConfig"); + objectClassList.append("olcSyncProvConfig"); + create_multiple_attributes_operation(mods, &i, "objectClass", objectClassList); + LDAPMod *prevterm = mods[i]; + mods[i] = NULL; + + // Add new object + retcode = ldap_add_ext_s(m_ldap, "olcOverlay=syncprov,olcDatabase={0}config,cn=config", mods, NULL, NULL); + + // Clean up + clean_up_attribute_operations(i, mods, prevterm, number_of_parameters); + + if (retcode != LDAP_SUCCESS) { + if (errstr) { + *errstr = i18n("LDAP overlay configuration failure

Reason: [%3] %4").arg(retcode).arg(ldap_err2string(retcode)); + } + else { + KMessageBox::error(0, i18n("LDAP overlay configuration failure

Reason: [%3] %4").arg(retcode).arg(ldap_err2string(retcode)), i18n("LDAP Error")); + } + return -2; + } + } + } + else { + // Check to see if the syncprov overlay entries exist + TQString olcOverlaySyncProvAttr; + LDAPMessage* msg; + retcode = ldap_search_ext_s(m_ldap, "olcDatabase={0}config,cn=config", LDAP_SCOPE_SUBTREE, NULL, ldap_user_and_operational_attributes, 0, NULL, NULL, NULL, 0, &msg); + if (retcode != LDAP_SUCCESS) { + if (errstr) *errstr = i18n("LDAP search failure

Reason: [%3] %4").arg(retcode).arg(ldap_err2string(retcode)); + else KMessageBox::error(0, i18n("LDAP search failure

Reason: [%3] %4").arg(retcode).arg(ldap_err2string(retcode)), i18n("LDAP Error")); + return -2; + } + + // Iterate through the returned entries + LDAPMessage* entry; + for(entry = ldap_first_entry(m_ldap, msg); entry != NULL; entry = ldap_next_entry(m_ldap, entry)) { + olcOverlaySyncProvAttr = parseLDAPSyncProvOverlayConfigRecord(entry); + if (olcOverlaySyncProvAttr != "") { + break; + } + } + + // clean up + ldap_msgfree(msg); + + if (olcOverlaySyncProvAttr != "") { + // FIXME + // OpenLDAP does not support removing overlays from the cn=config interface (i.e., once they are enabled above, they stay unless manually deleted from the config files) + // See http://www.openldap.org/lists/openldap-software/200811/msg00103.html + // If it were possible, the code would look something like this: + // retcode = ldap_delete_ext_s(m_ldap, olcOverlaySyncProvAttr + ",olcDatabase={0}config,cn=config", NULL, NULL); + } + } + } + return 0; + } + } + + return -1; +} + int LDAPManager::getTDECertificate(TQString certificateName, TQString fileName, TQString *errstr) { int retcode; int returncode; @@ -3774,6 +4236,30 @@ LDAPTDEBuiltinsInfo::~LDAPTDEBuiltinsInfo() { // } +LDAPMasterReplicationInfo::LDAPMasterReplicationInfo() { + // TQStrings are always initialized to TQString::null, so they don't need initialization here... + informationValid = false; + enabled = false; + // FIXME + // Retry method and timeout should be user configurable + // See http://www.openldap.org/doc/admin24/slapdconfig.html for syntax + retryMethod = "5 5 300 5"; + timeout = 1; +} + +LDAPMasterReplicationInfo::~LDAPMasterReplicationInfo() { + // +} + + +LDAPMasterReplicationMapping::LDAPMasterReplicationMapping() { + id = -1; +} + +LDAPMasterReplicationMapping::~LDAPMasterReplicationMapping() { + // +} + KerberosTicketInfo::KerberosTicketInfo() { // TQStrings are always initialized to TQString::null, so they don't need initialization here... informationValid = false; diff --git a/src/libtdeldap.h b/src/libtdeldap.h index 2c73967..ee60b94 100644 --- a/src/libtdeldap.h +++ b/src/libtdeldap.h @@ -374,6 +374,37 @@ class LDAPTDEBuiltinsInfo TQString builtinStandardUserGroup; }; +class LDAPMasterReplicationMapping +{ + public: + LDAPMasterReplicationMapping(); + ~LDAPMasterReplicationMapping(); + + public: + int id; + TQString fqdn; +}; + +typedef TQValueList LDAPMasterReplicationMap; + +class LDAPMasterReplicationInfo +{ + public: + LDAPMasterReplicationInfo(); + ~LDAPMasterReplicationInfo(); + + public: + bool informationValid; + bool enabled; + LDAPMasterReplicationMap serverIDs; + TQString retryMethod; + int timeout; + int syncMethod; + TQString syncDN; + TQCString syncPassword; + TQString certificateFile; +}; + class KerberosTicketInfo { public: @@ -446,6 +477,8 @@ class LDAPManager : public TQObject { int writeCertificateFileIntoDirectory(TQByteArray cert, TQString attr, TQString* errstr=0); LDAPTDEBuiltinsInfo getTDEBuiltinMappings(TQString *errstr=0); + LDAPMasterReplicationInfo getLDAPMasterReplicationSettings(TQString *errstr=0); + int setLDAPMasterReplicationSettings(LDAPMasterReplicationInfo replicationinfo, TQString *errstr=0); int writeSudoersConfFile(TQString *errstr=0); int getTDECertificate(TQString certificateName, TQString fileName, TQString *errstr=0); int setPasswordForUser(LDAPUserInfo user, TQString *errstr); @@ -489,6 +522,8 @@ class LDAPManager : public TQObject { LDAPMachineInfo parseLDAPMachineRecord(LDAPMessage* entry); LDAPServiceInfo parseLDAPMachineServiceRecord(LDAPMessage* entry); LDAPTDEBuiltinsInfo parseLDAPTDEBuiltinsRecord(LDAPMessage* entry); + LDAPMasterReplicationInfo parseLDAPMasterReplicationRecord(LDAPMasterReplicationInfo replicationinfo, LDAPMessage* entry); + TQString parseLDAPSyncProvOverlayConfigRecord(LDAPMessage* entry); private: TQString m_realm;