From 3ba9d6e8524284bd52d302682575fba68a74ad17 Mon Sep 17 00:00:00 2001 From: Timothy Pearson Date: Wed, 13 Jun 2012 20:56:24 -0500 Subject: [PATCH] Add service handling routines --- src/libtdeldap.cpp | 272 ++++++++++++++++++++++++++++++++++++++++++++- src/libtdeldap.h | 28 ++++- 2 files changed, 293 insertions(+), 7 deletions(-) diff --git a/src/libtdeldap.cpp b/src/libtdeldap.cpp index 1d5486b..86bd60e 100644 --- a/src/libtdeldap.cpp +++ b/src/libtdeldap.cpp @@ -156,7 +156,6 @@ int LDAPManager::bind(TQString* errstr) { KerberosTicketInfoList m_krbTickets = LDAPManager::getKerberosTicketList(); bool using_ldapi = false; - bool using_gssapi = false; if (m_host.startsWith("ldapi://")) { using_ldapi = true; } @@ -177,9 +176,7 @@ int LDAPManager::bind(TQString* errstr) { m_creds->password = passdlg.m_base->ldapAdminPassword->password(); m_creds->realm = passdlg.m_base->ldapAdminRealm->currentText(); m_creds->use_tls = passdlg.m_base->ldapUseTLS->isOn(); - } - if (passdlg.use_gssapi) { - using_gssapi = true; + m_creds->use_gssapi = passdlg.use_gssapi; } } else { @@ -229,7 +226,7 @@ int LDAPManager::bind(TQString* errstr) { TQCString pass = m_creds->password; cred.bv_val = pass.data(); cred.bv_len = pass.length(); - if ((!using_ldapi && !using_gssapi)) { + if ((!using_ldapi && !m_creds->use_gssapi)) { if (!ldap_dn.contains(",")) { // Look for a POSIX account with anonymous bind and the specified account name TQString uri; @@ -293,7 +290,7 @@ int LDAPManager::bind(TQString* errstr) { } } - if (using_gssapi) { + if (m_creds->use_gssapi) { retcode = ldap_sasl_interactive_bind_s(m_ldap, "", "GSSAPI", NULL, NULL, LDAP_SASL_AUTOMATIC, sasl_bind_interact_callback, NULL); } else { @@ -1468,6 +1465,109 @@ int LDAPManager::addGroupInfo(LDAPGroupInfo group) { } } +int LDAPManager::addServiceInfo(LDAPServiceInfo service, TQString *errstr) { + int retcode; + int i; + LDAPGroupInfo serviceinfo; + + if (bind() < 0) { + return -1; + } + else { + // Use Kerberos kadmin to actually add the service + LDAPCredentials admincreds = currentLDAPCredentials(); + if ((admincreds.username == "") && (admincreds.password == "")) { + // Probably GSSAPI + // Get active ticket principal... + KerberosTicketInfoList tickets = LDAPManager::getKerberosTicketList(); + TQStringList principalParts = TQStringList::split("@", tickets[0].cachePrincipal, false); + admincreds.username = principalParts[0]; + admincreds.realm = principalParts[1]; + } + + TQCString command = "kadmin"; + QCStringList args; + if (m_host.startsWith("ldapi://")) { + args << TQCString("-l") << TQCString("-r") << TQCString(admincreds.realm.upper()); + } + else { + if (admincreds.username == "") { + args << TQCString("-r") << TQCString(admincreds.realm.upper()); + } + else { + args << TQCString("-p") << TQCString(admincreds.username.lower()+"@"+(admincreds.realm.upper())) << TQCString("-r") << TQCString(admincreds.realm.upper()); + } + } + + TQString hoststring = service.name+"/"+service.machine; + + TQString prompt; + PtyProcess kadminProc; + kadminProc.exec(command, args); + prompt = kadminProc.readLine(true); + prompt = prompt.stripWhiteSpace(); + if (prompt == "kadmin>") { + kadminProc.writeLine(TQCString("ank --random-key "+hoststring), true); + prompt = kadminProc.readLine(true); // Discard our own input + prompt = readFullLineFromPtyProcess(&kadminProc); + prompt = prompt.stripWhiteSpace(); + // Use all defaults + while (prompt != "kadmin>") { + if (prompt.endsWith(" Password:")) { + if (admincreds.password == "") { + TQCString password; + int result = KPasswordDialog::getPassword(password, prompt); + if (result == KPasswordDialog::Accepted) { + admincreds.password = password; + } + } + if (admincreds.password != "") { + kadminProc.writeLine(admincreds.password, true); + prompt = kadminProc.readLine(true); // Discard our own input + prompt = kadminProc.readLine(true); + prompt = prompt.stripWhiteSpace(); + } + } + if (prompt.contains("authentication failed")) { + if (errstr) *errstr = prompt; + kadminProc.writeLine("quit", true); + return 1; + } + else { + // Extract whatever default is in the [brackets] and feed it back to kadmin + TQString defaultParam; + int leftbracket = prompt.find("["); + int rightbracket = prompt.find("]"); + if ((leftbracket >= 0) && (rightbracket >= 0)) { + leftbracket++; + defaultParam = prompt.mid(leftbracket, rightbracket-leftbracket); + } + kadminProc.writeLine(TQCString(defaultParam), true); + prompt = kadminProc.readLine(true); // Discard our own input + prompt = kadminProc.readLine(true); + prompt = prompt.stripWhiteSpace(); + } + } + if (prompt != "kadmin>") { + if (errstr) *errstr = prompt; + kadminProc.writeLine("quit", true); + return 1; + } + + // Success! + kadminProc.writeLine("quit", true); + unbind(true); // Using kadmin can disrupt our LDAP connection + + // Move Kerberos entries + return moveKerberosEntries("o=kerberos,cn=kerberos control,ou=master services,ou=core,ou=realm," + m_basedc, errstr); + } + + if (errstr) *errstr = "Internal error. Verify that kadmin exists and can be executed."; + return 1; // Failure + + } +} + int LDAPManager::deleteUserInfo(LDAPUserInfo user) { int retcode; LDAPUserInfo userinfo; @@ -1528,6 +1628,26 @@ int LDAPManager::deleteMachineInfo(LDAPMachineInfo machine) { } } +int LDAPManager::deleteServiceInfo(LDAPServiceInfo service) { + int retcode; + LDAPServiceInfo serviceinfo; + + if (bind() < 0) { + return -1; + } + else { + // Delete the base DN entry + retcode = ldap_delete_ext_s(m_ldap, service.distinguishedName.ascii(), NULL, NULL); + if (retcode != LDAP_SUCCESS) { + KMessageBox::error(0, i18n("LDAP deletion failure

Reason: [%3] %4").arg(retcode).arg(ldap_err2string(retcode)), i18n("LDAP Error")); + return -2; + } + else { + return 0; + } + } +} + LDAPGroupInfo LDAPManager::parseLDAPGroupRecord(LDAPMessage* entry) { char* dn = NULL; char* attr; @@ -1632,6 +1752,52 @@ LDAPMachineInfo LDAPManager::parseLDAPMachineRecord(LDAPMessage* entry) { return machineinfo; } +LDAPServiceInfo LDAPManager::parseLDAPMachineServiceRecord(LDAPMessage* entry) { + char* dn = NULL; + char* attr; + struct berval **vals; + BerElement* ber; + int i; + + LDAPServiceInfo machineserviceinfo; + + if((dn = ldap_get_dn(m_ldap, entry)) != NULL) { + machineserviceinfo.distinguishedName = dn; + TQStringList dnParts = TQStringList::split(",", dn); + TQString id = dnParts[0]; + dnParts = TQStringList::split("/", id); + id = dnParts[0]; + dnParts = TQStringList::split("=", id); + machineserviceinfo.name = dnParts[1]; + 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) { + machineserviceinfo.informationValid = true; + TQString ldap_field = attr; + i=0; + if (ldap_field == "creatorsName") { + machineserviceinfo.creatorsName = vals[i]->bv_val; + } + else if (ldap_field == "tdeBuiltinAccount") { + machineserviceinfo.tde_builtin_account = (TQString(vals[i]->bv_val).upper() == "TRUE")?true:false; + } + else if (ldap_field == "krb5KDCFlags") { + machineserviceinfo.status = (LDAPKRB5Flags)(atoi(vals[i]->bv_val)); + } + ldap_value_free_len(vals); + } + ldap_memfree(attr); + } + + if (ber != NULL) { + ber_free(ber, 0); + } + + return machineserviceinfo; +} + LDAPGroupInfoList LDAPManager::groups(int* mretcode) { int retcode; LDAPGroupInfoList groups; @@ -1702,6 +1868,87 @@ LDAPMachineInfoList LDAPManager::machines(int* mretcode) { return LDAPMachineInfoList(); } +LDAPServiceInfoList LDAPManager::services(int* mretcode) { + int retcode; + LDAPServiceInfoList services; + + if (bind() < 0) { + if (mretcode) *mretcode = -1; + return LDAPServiceInfoList(); + } + else { + int machineSearchRet; + LDAPMachineInfoList machineList = machines(&machineSearchRet); + if (machineSearchRet != 0) { + if (mretcode) *mretcode = -1; + return LDAPServiceInfoList(); + } + + LDAPMachineInfoList::Iterator it; + for (it = machineList.begin(); it != machineList.end(); ++it) { + LDAPMachineInfo machine = *it; + LDAPServiceInfoList thisMachineServiceList = machineServices(machine.distinguishedName); + LDAPServiceInfoList::Iterator it2; + for (it2 = thisMachineServiceList.begin(); it2 != thisMachineServiceList.end(); ++it2) { + services.append(*it2); + } + } + + if (mretcode) *mretcode = 0; + return services; + } + + return LDAPServiceInfoList(); +} + +LDAPServiceInfoList LDAPManager::machineServices(TQString machine_dn, int* mretcode) { + int retcode; + LDAPServiceInfoList services; + + if (bind() < 0) { + if (mretcode) *mretcode = -1; + return LDAPServiceInfoList(); + } + else { + LDAPMessage* msg; + TQString ldap_base_dn = m_basedc; + + TQStringList machinednParts = TQStringList::split(",", machine_dn); + TQString machine_name = machinednParts[0]; + if (machine_name.startsWith("krb5PrincipalName=host/")) { + machine_name = machine_name.remove(0, 23); + machine_name.replace("@"+m_realm, ""); + } + + TQString ldap_filter = TQString("(&(objectClass=krb5Principal)(uid=*/%1))").arg(machine_name); + retcode = ldap_search_ext_s(m_ldap, ldap_base_dn.ascii(), LDAP_SCOPE_SUBTREE, ldap_filter.ascii(), ldap_user_and_operational_attributes, 0, NULL, NULL, NULL, 0, &msg); + if (retcode != LDAP_SUCCESS) { + KMessageBox::error(0, i18n("LDAP search failure

Reason: [%3] %4").arg(retcode).arg(ldap_err2string(retcode)), i18n("LDAP Error")); + if (mretcode) *mretcode = -1; + return LDAPServiceInfoList(); + } + + // Iterate through the returned entries + LDAPMessage* entry; + for(entry = ldap_first_entry(m_ldap, msg); entry != NULL; entry = ldap_next_entry(m_ldap, entry)) { + LDAPServiceInfo sinfo = parseLDAPMachineServiceRecord(entry); + sinfo.machine_dn = machine_dn; + sinfo.machine = machine_name; + if (sinfo.name != "host") { + services.append(sinfo); + } + } + + // clean up + ldap_msgfree(msg); + + if (mretcode) *mretcode = 0; + return services; + } + + return LDAPServiceInfoList(); +} + int LDAPManager::writeCertificateFileIntoDirectory(TQByteArray cert, TQString attr, TQString* errstr) { int retcode; int i; @@ -2245,6 +2492,7 @@ TQString LDAPManager::getMachineFQDN() { LDAPCredentials::LDAPCredentials() { // TQStrings are always initialized to TQString::null, so they don't need initialization here... use_tls = true; + use_gssapi = false; } LDAPCredentials::~LDAPCredentials() { @@ -2301,6 +2549,18 @@ LDAPMachineInfo::~LDAPMachineInfo() { // } +LDAPServiceInfo::LDAPServiceInfo() { + // TQStrings are always initialized to TQString::null, so they don't need initialization here... + informationValid = false; + + tde_builtin_account = false; + status = (LDAPKRB5Flags)0; +} + +LDAPServiceInfo::~LDAPServiceInfo() { + // +} + LDAPTDEBuiltinsInfo::LDAPTDEBuiltinsInfo() { // 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 35d3c27..341dff9 100644 --- a/src/libtdeldap.h +++ b/src/libtdeldap.h @@ -81,6 +81,7 @@ enum LDAPKRB5Flags { KRB5_ACTIVE_DEFAULT = KRB5_FORWARDABLE | KRB5_RENEWABLE | KRB5_CLIENT | KRB5_CHANGE_PW, KRB5_DISABLED_ACCOUNT = KRB5_FORWARDABLE | KRB5_SERVER | KRB5_INVALID | KRB5_REQUIRE_PREAUTH | KRB5_REQUIRE_HWAUTH | KRB5_OK_AS_DELEGATE | KRB5_USER_TO_USER, KRB5_MACHINE_ACCOUNT_DEFAULT = KRB5_FORWARDABLE | KRB5_PROXIABLE | KRB5_RENEWABLE | KRB5_POSTDATE | KRB5_SERVER | KRB5_CLIENT, + KRB5_SERVICE_PRINCIPAL_DEFAULT = KRB5_FORWARDABLE | KRB5_PROXIABLE | KRB5_RENEWABLE | KRB5_POSTDATE | KRB5_SERVER | KRB5_CLIENT, KRB5_FLAG_MAX = 0x80000000 }; @@ -140,6 +141,7 @@ class LDAPCredentials TQCString password; TQString realm; bool use_tls; + bool use_gssapi; TQString service; }; @@ -295,7 +297,25 @@ class LDAPMachineInfo TQString name; bool tde_builtin_account; - LDAPKRB5Flags status; + LDAPKRB5Flags status; // Default is 126 [KRB5_MACHINE_ACCOUNT_DEFAULT] +}; + +class LDAPServiceInfo +{ + public: + LDAPServiceInfo(); + ~LDAPServiceInfo(); + + public: + bool informationValid; + TQString distinguishedName; + TQString creatorsName; + + TQString name; + TQString machine; + TQString machine_dn; + bool tde_builtin_account; + LDAPKRB5Flags status; // Default is 126 [KRB5_SERVICE_PRINCIPAL_DEFAULT] }; class LDAPTDEBuiltinsInfo @@ -338,6 +358,7 @@ class KerberosTicketInfo typedef TQValueList LDAPUserInfoList; typedef TQValueList LDAPGroupInfoList; typedef TQValueList LDAPMachineInfoList; +typedef TQValueList LDAPServiceInfoList; typedef TQValueList KerberosTicketInfoList; class LDAPManager : public TQObject { @@ -355,15 +376,19 @@ class LDAPManager : public TQObject { LDAPUserInfoList users(int* retcode=0); LDAPGroupInfoList groups(int* retcode=0); LDAPMachineInfoList machines(int* retcode=0); + LDAPServiceInfoList machineServices(TQString machine_dn, int* retcode=0); + LDAPServiceInfoList services(int* retcode=0); LDAPUserInfo getUserByDistinguishedName(TQString dn); LDAPGroupInfo getGroupByDistinguishedName(TQString dn, TQString *errstr=0); int updateUserInfo(LDAPUserInfo user); int updateGroupInfo(LDAPGroupInfo group); int addUserInfo(LDAPUserInfo user); int addGroupInfo(LDAPGroupInfo group); + int addServiceInfo(LDAPServiceInfo service, TQString *errstr=0); int deleteUserInfo(LDAPUserInfo user); int deleteGroupInfo(LDAPGroupInfo group); int deleteMachineInfo(LDAPMachineInfo machine); + int deleteServiceInfo(LDAPServiceInfo service); LDAPCredentials currentLDAPCredentials(); @@ -400,6 +425,7 @@ class LDAPManager : public TQObject { LDAPUserInfo parseLDAPUserRecord(LDAPMessage* entry); LDAPGroupInfo parseLDAPGroupRecord(LDAPMessage* entry); LDAPMachineInfo parseLDAPMachineRecord(LDAPMessage* entry); + LDAPServiceInfo parseLDAPMachineServiceRecord(LDAPMessage* entry); LDAPTDEBuiltinsInfo parseLDAPTDEBuiltinsRecord(LDAPMessage* entry); private: