diff --git a/src/Makefile.am b/src/Makefile.am index edab92e..4d458e2 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -7,7 +7,7 @@ lib_LTLIBRARIES = libtdeldap.la include_HEADERS = libtdeldap.h ldappasswddlg.h libtdeldap_la_SOURCES = libtdeldap.cpp ldaplogindlgbase.ui ldaplogindlg.cpp ldappasswddlg.cpp -libtdeldap_la_LIBADD = -ltdeio $(LIB_TDEUI) -lldap $(LIB_QT) $(LIB_TDECORE) -ltdesu -llber +libtdeldap_la_LIBADD = -ltdeio $(LIB_TDEUI) -lldap $(LIB_QT) $(LIB_TDECORE) -ltdesu -llber -lkadm5clnt libtdeldap_la_LDFLAGS = -version-info $(lt_current):$(lt_revision):$(lt_age) -no-undefined \ $(all_libraries) diff --git a/src/libtdeldap.cpp b/src/libtdeldap.cpp index 1721bc5..d240428 100644 --- a/src/libtdeldap.cpp +++ b/src/libtdeldap.cpp @@ -108,13 +108,13 @@ bool fileExists(const char* filename) { } } -LDAPManager::LDAPManager(TQString realm, TQString host, TQObject *parent, const char *name) : TQObject(parent, name), m_realm(realm), m_host(host), m_port(0), m_creds(0), m_ldap(0) +LDAPManager::LDAPManager(TQString realm, TQString host, TQObject *parent, const char *name) : TQObject(parent, name), m_realm(realm), m_host(host), m_port(0), m_creds(0), m_ldap(0), m_krb5admHandle(0), m_krb5admKeytabFilename(0) { TQStringList domainChunks = TQStringList::split(".", realm.lower()); m_basedc = "dc=" + domainChunks.join(",dc="); } -LDAPManager::LDAPManager(TQString realm, TQString host, LDAPCredentials* creds, TQObject *parent, const char *name) : TQObject(parent, name), m_realm(realm), m_host(host), m_port(0), m_creds(creds), m_ldap(0) +LDAPManager::LDAPManager(TQString realm, TQString host, LDAPCredentials* creds, TQObject *parent, const char *name) : TQObject(parent, name), m_realm(realm), m_host(host), m_port(0), m_creds(creds), m_ldap(0), m_krb5admHandle(0), m_krb5admKeytabFilename(0) { TQStringList domainChunks = TQStringList::split(".", realm.lower()); m_basedc = "dc=" + domainChunks.join(",dc="); @@ -405,6 +405,10 @@ int LDAPManager::bind(TQString* errstr) { } int LDAPManager::unbind(bool force, TQString* errstr) { + if (m_krb5admHandle) { + unbindKAdmin(); + } + if (!m_ldap) { return 0; } @@ -1094,12 +1098,23 @@ TQString LDAPManager::readFullLineFromPtyProcess(PtyProcess* proc) { return result; } -int LDAPManager::setPasswordForUser(LDAPUserInfo user, TQString *errstr) { - if (user.new_password == "") { - return 0; - } +int LDAPManager::bindKAdmin(LDAPUserInfo user, TQString *errstr) { + int retcode = 1; + + kadm5_ret_t krb5adm_ret; + kadm5_config_params params; LDAPCredentials admincreds = currentLDAPCredentials(); + if (admincreds.use_gssapi) { + // FIXME + // Heimdal has issues parsing the keytab file, so for now just prompt for password + TQCString password; + int result = KPasswordDialog::getPassword(password, i18n("Enter password for %1").arg(admincreds.username)); + if (result == KPasswordDialog::Accepted) { + admincreds.password = password; + admincreds.use_gssapi = false; + } + } if ((admincreds.username == "") && (admincreds.password == "")) { // Probably GSSAPI // Get active ticket principal... @@ -1107,107 +1122,107 @@ int LDAPManager::setPasswordForUser(LDAPUserInfo user, TQString *errstr) { TQStringList principalParts = TQStringList::split("@", tickets[0].cachePrincipal, false); admincreds.username = principalParts[0]; admincreds.realm = principalParts[1]; + admincreds.use_gssapi = true; } - TQCString command = "kadmin"; - QCStringList args; - if (m_host.startsWith("ldapi://")) { - args << TQCString("-l") << TQCString("-r") << TQCString(admincreds.realm.upper()); + TQString ticketFile; + LDAPManager::getKerberosTicketList(TQString::null, &ticketFile); + + memset(¶ms, 0, sizeof(params)); + params.mask |= KADM5_CONFIG_REALM; + params.realm = const_cast(admincreds.realm.upper().ascii()); + + TQString adminPrincipal = TQString::null; + if (admincreds.username != "") { + adminPrincipal = admincreds.username.lower() + "@" + admincreds.realm.upper(); + } + + krb5adm_ret = krb5_init_context(&m_krb5admContext); + if (krb5adm_ret) { + if (errstr) *errstr = TQString("Internal Error

Failed to execute kadm5_init_krb5_context (code %1)").arg(krb5adm_ret); } else { - if (admincreds.username == "") { - args << TQCString("-r") << TQCString(admincreds.realm.upper()); + if (m_host.startsWith("ldapi://")) { + // Local bind + krb5adm_ret = kadm5_init_with_password_ctx(m_krb5admContext, KADM5_ADMIN_SERVICE, admincreds.password.data(), KADM5_ADMIN_SERVICE, ¶ms, KADM5_STRUCT_VERSION, KADM5_API_VERSION_2, &m_krb5admHandle); + if (krb5adm_ret) { + if (errstr) *errstr = TQString("%1

Details:
Failed to execute kadm5_init_with_password (code %2)").arg(krb5_get_error_message(m_krb5admContext, krb5adm_ret)).arg(krb5adm_ret); + } + } + else if (admincreds.use_gssapi) { + // Keytab authentication / bind + if (m_krb5admKeytabFilename) { + free(m_krb5admKeytabFilename); + } + m_krb5admKeytabFilename = strdup(ticketFile.ascii()); + krb5adm_ret = kadm5_init_with_skey_ctx(m_krb5admContext, KADM5_ADMIN_SERVICE, m_krb5admKeytabFilename, KADM5_ADMIN_SERVICE, ¶ms, KADM5_STRUCT_VERSION, KADM5_API_VERSION_2, &m_krb5admHandle); + if (krb5adm_ret) { + if (errstr) *errstr = TQString("%1

Details:
Failed to execute kadm5_init_with_skey (code %2)").arg(krb5_get_error_message(m_krb5admContext, krb5adm_ret)).arg(krb5adm_ret); + } } else { - args << TQCString("-p") << TQCString(admincreds.username.lower()+"@"+(admincreds.realm.upper())) << TQCString("-r") << TQCString(admincreds.realm.upper()); + // Password authentication / bind + krb5adm_ret = kadm5_init_with_password_ctx(m_krb5admContext, adminPrincipal.ascii(), admincreds.password.data(), KADM5_ADMIN_SERVICE, ¶ms, KADM5_STRUCT_VERSION, KADM5_API_VERSION_2, &m_krb5admHandle); + if (krb5adm_ret) { + if (errstr) *errstr = TQString("%1

Details:
Failed to execute kadm5_init_with_password (code %2)").arg(krb5_get_error_message(m_krb5admContext, krb5adm_ret)).arg(krb5adm_ret); + } + } + if (!krb5adm_ret) { + // Success! + retcode = 0; } } - TQString prompt; - PtyProcess kadminProc; - kadminProc.exec(command, args); - prompt = readFullLineFromPtyProcess(&kadminProc); - prompt = prompt.stripWhiteSpace(); - if (prompt == "kadmin>") { - command = TQCString("passwd "+user.name); - kadminProc.enableLocalEcho(false); - kadminProc.writeLine(command, true); - do { // Discard our own input - prompt = readFullLineFromPtyProcess(&kadminProc); - printf("(kadmin) '%s'\n", prompt.ascii()); - } while ((prompt == TQString(command)) || (prompt == "")); - prompt = prompt.stripWhiteSpace(); - if ((prompt.endsWith(" Password:")) && (prompt.startsWith(TQString(user.name + "@")))) { - kadminProc.enableLocalEcho(false); - kadminProc.writeLine(user.new_password, true); - do { // Discard our own input - prompt = readFullLineFromPtyProcess(&kadminProc); - printf("(kadmin) '%s'\n", prompt.ascii()); - } while (prompt == ""); - prompt = prompt.stripWhiteSpace(); - if ((prompt.endsWith(" Password:")) && (prompt.startsWith("Verify"))) { - kadminProc.enableLocalEcho(false); - kadminProc.writeLine(user.new_password, true); - do { // Discard our own input - prompt = readFullLineFromPtyProcess(&kadminProc); - printf("(kadmin) '%s'\n", prompt.ascii()); - } while (prompt == ""); - prompt = prompt.stripWhiteSpace(); - } - if (prompt.endsWith(" Password:")) { - if (admincreds.password == "") { - if (tqApp->type() != TQApplication::Tty) { - TQCString password; - int result = KPasswordDialog::getPassword(password, prompt); - if (result == KPasswordDialog::Accepted) { - admincreds.password = password; - } - } - else { - TQFile file; - file.open(IO_ReadOnly, stdin); - TQTextStream qtin(&file); - admincreds.password = qtin.readLine(); - } - } - if (admincreds.password != "") { - kadminProc.enableLocalEcho(false); - kadminProc.writeLine(admincreds.password, true); - do { // Discard our own input - prompt = readFullLineFromPtyProcess(&kadminProc); - printf("(kadmin) '%s'\n", prompt.ascii()); - } while (prompt == ""); - prompt = prompt.stripWhiteSpace(); - } + return retcode; +} + +int LDAPManager::unbindKAdmin(TQString *errstr) { + if (m_krb5admKeytabFilename) { + free(m_krb5admKeytabFilename); + } + + kadm5_destroy(m_krb5admHandle); + krb5_free_context(m_krb5admContext); + + m_krb5admHandle = NULL; + + return 0; +} + +int LDAPManager::setPasswordForUser(LDAPUserInfo user, TQString *errstr) { + if (user.new_password == "") { + return 0; + } + + int retcode; + kadm5_ret_t krb5adm_ret; + + retcode = bindKAdmin(user, errstr); + if (retcode == 0) { + retcode = 1; + krb5_principal user_kadm5_principal; + krb5adm_ret = krb5_parse_name(m_krb5admContext, user.name.ascii(), &user_kadm5_principal); + if (krb5adm_ret) { + if (errstr) *errstr = TQString("%1

Details:
Failed to execute krb5_parse_name for user '%2' (code %3)").arg(krb5_get_error_message(m_krb5admContext, krb5adm_ret)).arg(user.name).arg(krb5adm_ret); + } + else { + krb5adm_ret = kadm5_chpass_principal(m_krb5admHandle, user_kadm5_principal, user.new_password.data()); + if (krb5adm_ret) { + if (errstr) *errstr = TQString("%1

Details:
Failed to execute kadm5_chpass_principal for user '%2' (code %3)").arg(krb5_get_error_message(m_krb5admContext, krb5adm_ret)).arg(user.name).arg(krb5adm_ret); } - if (prompt != "kadmin>") { - if (errstr) *errstr = detailedKAdminErrorMessage(prompt); - kadminProc.enableLocalEcho(false); - kadminProc.writeLine("quit", true); - return 1; + else { + // Success! + retcode = 0; } - // Success! - kadminProc.enableLocalEcho(false); - kadminProc.writeLine("quit", true); - return 0; - } - else if (prompt == "kadmin>") { - // Success! - kadminProc.enableLocalEcho(false); - kadminProc.writeLine("quit", true); - return 0; + // Clean up + krb5_free_principal(m_krb5admContext, user_kadm5_principal); } - // Failure - if (errstr) *errstr = detailedKAdminErrorMessage(prompt); - kadminProc.enableLocalEcho(false); - kadminProc.writeLine("quit", true); - return 1; + unbindKAdmin(); } - if (errstr) *errstr = "Internal error. Verify that kadmin exists and can be executed."; - return 1; // Failure + return retcode; } TQString klistDateTimeToRFCDateTime(TQString datetime) { @@ -1746,6 +1761,7 @@ int LDAPManager::addMachineInfo(LDAPMachineInfo machine, TQString *errstr) { TQStringList principalParts = TQStringList::split("@", tickets[0].cachePrincipal, false); admincreds.username = principalParts[0]; admincreds.realm = principalParts[1]; + admincreds.use_gssapi = true; } TQCString command = "kadmin"; @@ -1871,6 +1887,7 @@ int LDAPManager::addServiceInfo(LDAPServiceInfo service, TQString *errstr) { TQStringList principalParts = TQStringList::split("@", tickets[0].cachePrincipal, false); admincreds.username = principalParts[0]; admincreds.realm = principalParts[1]; + admincreds.use_gssapi = true; } TQCString command = "kadmin"; @@ -2578,6 +2595,7 @@ int LDAPManager::exportKeytabForPrincipal(TQString principal, TQString fileName, TQStringList principalParts = TQStringList::split("@", tickets[0].cachePrincipal, false); admincreds.username = principalParts[0]; admincreds.realm = principalParts[1]; + admincreds.use_gssapi = true; } TQCString command = "kadmin"; diff --git a/src/libtdeldap.h b/src/libtdeldap.h index ee70ad2..9905eb6 100644 --- a/src/libtdeldap.h +++ b/src/libtdeldap.h @@ -25,6 +25,7 @@ #include #include #include +#include #include #include @@ -588,6 +589,8 @@ class LDAPManager : public TQObject { static int unbondRealm(LDAPRealmConfig realmcfg, TQString adminUserName, const char * adminPassword, TQString adminRealm, TQString *errstr=0); private: + int bindKAdmin(LDAPUserInfo user, TQString *errstr=0); + int unbindKAdmin(TQString *errstr=0); LDAPUserInfo parseLDAPUserRecord(LDAPMessage* entry); LDAPGroupInfo parseLDAPGroupRecord(LDAPMessage* entry); LDAPMachineInfo parseLDAPMachineRecord(LDAPMessage* entry); @@ -604,6 +607,11 @@ class LDAPManager : public TQObject { TQString m_basedc; LDAPCredentials* m_creds; LDAP *m_ldap; + + // kadmin interface + krb5_context m_krb5admContext; + void* m_krb5admHandle; + char* m_krb5admKeytabFilename; }; #endif // _LIBTDELDAP_H_