diff options
| author | Timothy Pearson <kb9vqf@pearsoncomputing.net> | 2025-10-04 14:30:54 -0500 |
|---|---|---|
| committer | Timothy Pearson <kb9vqf@pearsoncomputing.net> | 2025-10-22 19:18:20 -0500 |
| commit | 01f0efc9b043ed5f528cf659002c6325b6d114e4 (patch) | |
| tree | df05b561bdb84f138c7a2f40a899daf039b33fd2 | |
| parent | ad930c33b27d9c669c9ecb7172beb3e50e24e2e9 (diff) | |
| download | libtdeldap-01f0efc9.tar.gz libtdeldap-01f0efc9.zip | |
Add initial Kerberos password change support
| -rw-r--r-- | src/CMakeLists.txt | 3 | ||||
| -rw-r--r-- | src/ldapchgpassdlg.cpp | 46 | ||||
| -rw-r--r-- | src/ldapchgpassdlg.h | 40 | ||||
| -rw-r--r-- | src/ldapchgpassdlgbase.ui | 145 | ||||
| -rw-r--r-- | src/ldapchgpasswddlg.cpp | 85 | ||||
| -rw-r--r-- | src/ldapchgpasswddlg.h | 50 | ||||
| -rw-r--r-- | src/libtdeldap.cpp | 174 | ||||
| -rw-r--r-- | src/libtdeldap.h | 3 |
8 files changed, 546 insertions, 0 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 4c5715b..e46eb88 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -24,6 +24,9 @@ tde_add_library( tdeldap SHARED AUTOMOC ldaplogindlgbase.ui ldaplogindlg.cpp ldappasswddlg.cpp + ldapchgpassdlgbase.ui + ldapchgpassdlg.cpp + ldapchgpasswddlg.cpp LINK tdeui-shared tdecore-shared diff --git a/src/ldapchgpassdlg.cpp b/src/ldapchgpassdlg.cpp new file mode 100644 index 0000000..f07bce4 --- /dev/null +++ b/src/ldapchgpassdlg.cpp @@ -0,0 +1,46 @@ +/*************************************************************************** + * Copyright (C) 2012 by Timothy Pearson * + * kb9vqf@pearsoncomputing.net * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ + +#include <tqstringlist.h> +#include <tqlabel.h> +#include <tqmap.h> + +#include <tdeapplication.h> +#include <ksimpleconfig.h> +#include <tdelocale.h> +#include <kdebug.h> +#include <kstandarddirs.h> +#include <kiconloader.h> +#include <dcopclient.h> +#include <kprocess.h> +#include <kcombobox.h> + +#include "ldapchgpassdlg.h" + +LDAPChangePassword::LDAPChangePassword(TQWidget *parent, const char *name ) : LDAPChangePasswordDlg(parent,name) { + px_icon->setPixmap(SmallIcon("password.png")); + ldapAdminRealm->setEditable(true); +} + +LDAPChangePassword::~LDAPChangePassword(){ + // +} + +#include "ldapchgpassdlg.moc" diff --git a/src/ldapchgpassdlg.h b/src/ldapchgpassdlg.h new file mode 100644 index 0000000..c2c672b --- /dev/null +++ b/src/ldapchgpassdlg.h @@ -0,0 +1,40 @@ +/*************************************************************************** + * Copyright (C) 2012 by Timothy Pearson * + * kb9vqf@pearsoncomputing.net * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ + +#ifndef LDAPCHANGEPASSWORD_H +#define LDAPCHANGEPASSWORD_H + +#include "ldapchgpassdlgbase.h" + +class TQStringList; + +/**LDAP login dialog + *@author Timothy Pearson + */ + +class LDAPChangePassword : public LDAPChangePasswordDlg { + TQ_OBJECT +public: + LDAPChangePassword(TQWidget *parent=0, const char *name=0); + ~LDAPChangePassword(); +}; + +#endif + diff --git a/src/ldapchgpassdlgbase.ui b/src/ldapchgpassdlgbase.ui new file mode 100644 index 0000000..1b07d11 --- /dev/null +++ b/src/ldapchgpassdlgbase.ui @@ -0,0 +1,145 @@ +<!DOCTYPE UI><UI version="3.0" stdsetdef="1"> +<class>LDAPChangePasswordDlg</class> +<widget class="TQWidget"> + <property name="name"> + <cstring>LDAPChangePasswordDlg</cstring> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="TQLabel" row="1" column="0" rowspan="1" colspan="1"> + <property name="name"> + <cstring>px_icon</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>0</hsizetype> + <vsizetype>0</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="frameShape"> + <enum>NoFrame</enum> + </property> + <property name="frameShadow"> + <enum>Plain</enum> + </property> + <property name="scaledContents"> + <bool>true</bool> + </property> + <property name="indent"> + <number>0</number> + </property> + </widget> + <widget class="TQLabel" row="1" column="1" colspan="2"> + <property name="name"> + <cstring>passprompt</cstring> + </property> + <property name="text"> + <string>Please provide current and new LDAP credentials below</string> + </property> + </widget> + <widget class="TQLabel" row="2" column="0" colspan="2"> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="text"> + <string>Username</string> + </property> + </widget> + <widget class="KLineEdit" row="2" column="2"> + <property name="name"> + <cstring>ldapUsername</cstring> + </property> + </widget> + <widget class="TQLabel" row="3" column="0" colspan="2"> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="text"> + <string>Current Password</string> + </property> + </widget> + <widget class="KPasswordEdit" row="3" column="2"> + <property name="name"> + <cstring>ldapCurrentPassword</cstring> + </property> + </widget> + <widget class="TQLabel" row="4" column="0" colspan="2"> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="text"> + <string>New Password</string> + </property> + </widget> + <widget class="KPasswordEdit" row="4" column="2"> + <property name="name"> + <cstring>ldapNewPassword</cstring> + </property> + </widget> + <widget class="TQLabel" row="5" column="0" colspan="2"> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="text"> + <string>Confirm New Password</string> + </property> + </widget> + <widget class="KPasswordEdit" row="5" column="2"> + <property name="name"> + <cstring>ldapConfirmNewPassword</cstring> + </property> + </widget> + <widget class="TQLabel" row="7" column="0" colspan="2"> + <property name="name"> + <cstring>kerberosOtherInfoString</cstring> + </property> + <property name="text"> + <string>Service Principal</string> + </property> + <property name="hidden"> + <cstring>true</cstring> + </property> + </widget> + <widget class="KLineEdit" row="7" column="2"> + <property name="name"> + <cstring>kerberosServicePrincipal</cstring> + </property> + <property name="hidden"> + <cstring>true</cstring> + </property> + </widget> + <widget class="TQLabel" row="7" column="0" colspan="2"> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="text"> + <string>LDAP Realm</string> + </property> + </widget> + <widget class="KComboBox" row="7" column="2"> + <property name="name"> + <cstring>ldapAdminRealm</cstring> + </property> + </widget> + <widget class="TQCheckBox" row="7" column="0" colspan="3"> + <property name="name"> + <cstring>ldapUseTLS</cstring> + </property> + <property name="text"> + <string>Use LDAP TLS to encrypt this connection (recommended)</string> + </property> + </widget> + </grid> +</widget> +<layoutdefaults spacing="3" margin="6"/> +<layoutfunctions spacing="KDialog::spacingHint" margin="KDialog::marginHint"/> +<includes> + <include location="global" impldecl="in implementation">kcombobox.h</include> + <include location="global" impldecl="in implementation">klineedit.h</include> + <include location="global" impldecl="in implementation">kpassdlg.h</include> +</includes> +</UI> diff --git a/src/ldapchgpasswddlg.cpp b/src/ldapchgpasswddlg.cpp new file mode 100644 index 0000000..3314761 --- /dev/null +++ b/src/ldapchgpasswddlg.cpp @@ -0,0 +1,85 @@ +/*************************************************************************** + * Copyright (C) 2012 by Timothy Pearson * + * kb9vqf@pearsoncomputing.net * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ + +#include <tdelocale.h> +#include <klineedit.h> +#include <ktextedit.h> +#include <knuminput.h> +#include <tdeactionselector.h> +#include <tqlistbox.h> +#include <kpushbutton.h> +#include <tqpixmap.h> +#include <tqiconset.h> +#include <tqlabel.h> +#include <kpassdlg.h> + +#include "ldapchgpassdlg.h" +#include "ldapchgpasswddlg.h" + +LDAPChangePasswordDialog::LDAPChangePasswordDialog(TQWidget* parent, const char* name, bool allowGSSAPI, bool allowSmartCard) + : KDialogBase(parent, name, true, i18n("LDAP Authentication"), Ok|Cancel|((allowGSSAPI)?User1:0)|((allowSmartCard)?User2:0), Ok, true, i18n("Authenticate with SASL/GSSAPI"), i18n("Authenticate with cryptographic card")) +{ + m_base = new LDAPChangePassword(this); + + connect(m_base->ldapUsername, TQ_SIGNAL(textChanged(const TQString&)), this, TQ_SLOT(processLockouts())); + connect(m_base->ldapCurrentPassword, TQ_SIGNAL(textChanged(const TQString&)), this, TQ_SLOT(processLockouts())); + connect(m_base->ldapNewPassword, TQ_SIGNAL(textChanged(const TQString&)), this, TQ_SLOT(processLockouts())); + connect(m_base->ldapConfirmNewPassword, TQ_SIGNAL(textChanged(const TQString&)), this, TQ_SLOT(processLockouts())); + + setMainWidget(m_base); + processLockouts(); +} + +void LDAPChangePasswordDialog::slotOk() { + use_gssapi = false; + use_smartcard = false; + accept(); +} + +void LDAPChangePasswordDialog::slotUser1() { + use_gssapi = true; + use_smartcard = false; + accept(); +} + +void LDAPChangePasswordDialog::slotUser2() { + use_gssapi = false; + use_smartcard = true; + accept(); +} + +void LDAPChangePasswordDialog::processLockouts() { + bool dataValid = true; + + if (m_base->ldapUsername->text().length() < 1) + dataValid = false; + if (m_base->ldapCurrentPassword->password().length() < 1) + dataValid = false; + if (m_base->ldapNewPassword->password().length() < 1) + dataValid = false; + if (m_base->ldapNewPassword->password() == m_base->ldapCurrentPassword->password()) + dataValid = false; + if (m_base->ldapNewPassword->password() != m_base->ldapConfirmNewPassword->password()) + dataValid = false; + + enableButtonOK(dataValid); +} + +#include "ldapchgpasswddlg.moc" diff --git a/src/ldapchgpasswddlg.h b/src/ldapchgpasswddlg.h new file mode 100644 index 0000000..d0d6bdc --- /dev/null +++ b/src/ldapchgpasswddlg.h @@ -0,0 +1,50 @@ +/*************************************************************************** + * Copyright (C) 2012 by Timothy Pearson * + * kb9vqf@pearsoncomputing.net * + * * + * This program is free software; you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation; either version 2 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program; if not, write to the * + * Free Software Foundation, Inc., * + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + ***************************************************************************/ + +#ifndef _LDAPCHANGEPASSWORDDIALOG_H_ +#define _LDAPCHANGEPASSWORDDIALOG_H_ + +#include <kdialogbase.h> +#include <kcombobox.h> + +class LDAPChangePassword; + +class TDE_EXPORT LDAPChangePasswordDialog : public KDialogBase +{ + TQ_OBJECT + +public: + LDAPChangePasswordDialog(TQWidget* parent = 0, const char* name = 0, bool allowGSSAPI = true, bool allowSmartCard = false); + +public slots: + void slotOk(); + void slotUser1(); + void slotUser2(); + +public: + LDAPChangePassword *m_base; + bool use_gssapi; + bool use_smartcard; + +private slots: + void processLockouts(); +}; + +#endif diff --git a/src/libtdeldap.cpp b/src/libtdeldap.cpp index 5a7424c..0d8784e 100644 --- a/src/libtdeldap.cpp +++ b/src/libtdeldap.cpp @@ -84,6 +84,8 @@ extern "C" { #include "libtdeldap.h" #include "ldaplogindlg.h" #include "ldappasswddlg.h" +#include "ldapchgpassdlg.h" +#include "ldapchgpasswddlg.h" #define LDAP_INSECURE_PORT 389 #define LDAP_SECURE_PORT 636 @@ -1738,6 +1740,53 @@ int LDAPManager::getKerberosPassword(LDAPCredentials &creds, TQString prompt, bo return ret; } +int LDAPManager::getNewKerberosPassword(LDAPCredentials &oldCreds, LDAPCredentials &newCreds, TQString prompt, bool allowSmartCard, TQWidget* parent) +{ + int i; + + TQString defaultRealm; + LDAPRealmConfigList realms = fetchAndReadTDERealmList(&defaultRealm); + + if (oldCreds.realm != "") { + defaultRealm = oldCreds.realm; + } + LDAPChangePasswordDialog passdlg(parent, 0, false, allowSmartCard); + passdlg.m_base->ldapAdminRealm->setEnabled(true); + LDAPRealmConfigList::Iterator it; + i=0; + for (it = realms.begin(); it != realms.end(); ++it) { + passdlg.m_base->ldapAdminRealm->insertItem((*it).name); + if ((*it).name == defaultRealm) { + passdlg.m_base->ldapAdminRealm->setCurrentItem(i); + } + i++; + } + passdlg.m_base->passprompt->setText(prompt); + passdlg.m_base->ldapUseTLS->hide(); + if (oldCreds.username != "") { + passdlg.m_base->ldapUsername->setText(oldCreds.username); + passdlg.m_base->ldapCurrentPassword->setFocus(); + } + const int ret = passdlg.exec(); + if (ret == KDialog::Accepted) { + oldCreds.username = passdlg.m_base->ldapUsername->text(); + oldCreds.password = passdlg.m_base->ldapCurrentPassword->password(); + oldCreds.realm = passdlg.m_base->ldapAdminRealm->currentText(); + oldCreds.service = passdlg.m_base->kerberosServicePrincipal->text(); + oldCreds.use_tls = passdlg.m_base->ldapUseTLS->isOn(); + oldCreds.use_gssapi = false; + if (allowSmartCard) { + oldCreds.use_smartcard = passdlg.use_smartcard; + } + else { + oldCreds.use_smartcard = false; + } + newCreds = oldCreds; + newCreds.password = passdlg.m_base->ldapNewPassword->password(); + } + return ret; +} + int LDAPManager::obtainKerberosTicket(LDAPCredentials creds, TQString principal, TQString *errstr) { TQCString command = "kinit"; QCStringList args; @@ -1869,6 +1918,131 @@ int LDAPManager::destroyKerberosTicket(TQString principal, TQString *errstr) { return 0; } +int LDAPManager::changeKerberosPassword(LDAPCredentials oldCreds, LDAPCredentials newCreds, TQString principal, TQString *errstr) { + TQCString command = "kpasswd"; + QCStringList args; + if (oldCreds.use_smartcard) { + // Get PKCS#11 slot number from the LDAP configuration file + KSimpleConfig* systemconfig = new KSimpleConfig( TQString::fromLatin1( KDE_CONFDIR "/ldap/ldapconfigrc" )); + systemconfig->setGroup(NULL); + int pkcs11_login_card_slot = systemconfig->readNumEntry("PKCS11LoginCardSlot", 0); + delete systemconfig; + + TQString pkcsProviderString = "PKCS11:" + TDECryptographicCardDevice::pkcsProviderLibrary(); + if (pkcs11_login_card_slot != 0) { + pkcsProviderString.append(TQString(",slot=%1").arg(pkcs11_login_card_slot)); + } + args << TQCString("-C") << pkcsProviderString.local8Bit(); + + // Find certificate on card and set credentials to match + TDEGenericDevice *hwdevice; + TDEHardwareDevices *hwdevices = TDEGlobal::hardwareDevices(); + TDEGenericHardwareList cardReaderList = hwdevices->listByDeviceClass(TDEGenericDeviceType::CryptographicCard); + for (hwdevice = cardReaderList.first(); hwdevice; hwdevice = cardReaderList.next()) { + TDECryptographicCardDevice* cdevice = static_cast<TDECryptographicCardDevice*>(hwdevice); + TQString username = TQString::null; + TQString realm = TQString::null; + X509CertificatePtrList certList = cdevice->cardX509Certificates(); + if (certList.count() > 0) { + TQStringList::Iterator it; + KSSLCertificate* card_cert = NULL; + card_cert = KSSLCertificate::fromX509(certList[0]); + TQStringList cert_subject_parts = TQStringList::split("/", card_cert->getSubject(), false); + TQStringList reversed_cert_subject_parts; + for (it = cert_subject_parts.begin(); it != cert_subject_parts.end(); it++) { + reversed_cert_subject_parts.prepend(*it); + } + for (it = reversed_cert_subject_parts.begin(); it != reversed_cert_subject_parts.end(); ++it ) { + TQString lcpart = (*it).lower(); + if (lcpart.startsWith("cn=")) { + username = lcpart.right(lcpart.length() - strlen("cn=")); + } + else if (lcpart.startsWith("dc=")) { + realm.append(lcpart.right(lcpart.length() - strlen("dc=")) + "."); + } + } + if (realm.endsWith(".")) { + realm.truncate(realm.length() - 1); + } + delete card_cert; + } + if (username != "") { + oldCreds.username = username; + oldCreds.realm = realm; + break; + } + } + } + if (principal == "") { + args << TQString("%1@%2").arg(oldCreds.username).arg(oldCreds.realm.upper()).local8Bit(); + } + else { + args << TQCString("-S") << principal.local8Bit() << TQString("%1@%2").arg(oldCreds.username).arg(oldCreds.realm.upper()).local8Bit(); + } + + TQString prompt; + PtyProcess kinitProc; + kinitProc.exec(command, args); + prompt = readFullLineFromPtyProcess(&kinitProc); + prompt = prompt.stripWhiteSpace(); + while (prompt.endsWith(" Password:") || (oldCreds.use_smartcard && prompt.contains("PIN"))) { + if (oldCreds.use_smartcard) { + TQString password; + int result = KPasswordDialog::getPassword(password, prompt); + if (result == KPasswordDialog::Accepted) { + oldCreds.password = password; + } + else { + return 0; + } + } + kinitProc.enableLocalEcho(false); + kinitProc.writeLine(oldCreds.password.utf8(), true); + do { // Discard our own input + prompt = readFullLineFromPtyProcess(&kinitProc); + printf("(kpasswd) '%s'\n", prompt.ascii()); + } while (prompt == ""); + prompt = prompt.stripWhiteSpace(); + } + if (!prompt.startsWith(TQString("New password for %1@%2:").arg(oldCreds.username).arg(oldCreds.realm.upper()))) { + if (errstr) *errstr = detailedKAdminErrorMessage(prompt); + return 1; + } + else { + kinitProc.enableLocalEcho(false); + kinitProc.writeLine(newCreds.password.utf8(), true); + do { // Discard our own input + prompt = readFullLineFromPtyProcess(&kinitProc); + printf("(kpasswd) '%s'\n", prompt.ascii()); + } while (prompt == ""); + prompt = prompt.stripWhiteSpace(); + } + if (!prompt.startsWith(TQString("Verify password - "))) { + if (errstr) *errstr = detailedKAdminErrorMessage(prompt); + return 1; + } + else { + kinitProc.enableLocalEcho(false); + kinitProc.writeLine(newCreds.password.utf8(), true); + do { // Discard our own input + prompt = readFullLineFromPtyProcess(&kinitProc); + printf("(kpasswd) '%s'\n", prompt.ascii()); + } while (prompt == ""); + prompt = prompt.stripWhiteSpace(); + } + if (prompt.startsWith("Success")) { + // Success! + return 0; + } + else if ((prompt != "") && (prompt != "TDE process terminated")) { + if (errstr) *errstr = detailedKAdminErrorMessage(prompt); + return 1; + } + + // Presumed success! + return 0; +} + int LDAPManager::updateGroupInfo(LDAPGroupInfo group, TQString *errstr) { int retcode; int i; diff --git a/src/libtdeldap.h b/src/libtdeldap.h index d281404..881c2fb 100644 --- a/src/libtdeldap.h +++ b/src/libtdeldap.h @@ -571,10 +571,13 @@ class TDE_EXPORT LDAPManager : public TQObject { static KerberosTicketInfoList getKerberosTicketList(TQString cache=TQString::null, TQString *cacheFileName=0); static int getKerberosPassword(LDAPCredentials &creds, TQString prompt, bool requestServicePrincipal=false, bool allowSmartCard=false, TQWidget* parent=0); + static int getNewKerberosPassword(LDAPCredentials &oldCreds, LDAPCredentials &newCreds, TQString prompt, bool allowSmartCard=false, TQWidget* parent=0); static int obtainKerberosTicket(LDAPCredentials creds, TQString principal, TQString *errstr=0); static int obtainKerberosServiceTicket(TQString principal, TQString *errstr=0); static int destroyKerberosTicket(TQString principal, TQString *errstr=0); + static int changeKerberosPassword(LDAPCredentials oldCreds, LDAPCredentials newCreds, TQString principal, TQString *errstr=0); + static TQString detailedKAdminErrorMessage(TQString initialMessage); static TQString readFullLineFromPtyProcess(PtyProcess* proc); |
