From e5a1666d93c1a8ba211a83a7952ea5652dbac558 Mon Sep 17 00:00:00 2001
From: Timothy Pearson <kb9vqf@pearsoncomputing.net>
Date: Sat, 4 Oct 2025 14:30:54 -0500
Subject: Add initial Kerberos password change support

---
 src/CMakeLists.txt        |   3 +
 src/ldapchgpassdlg.cpp    |  46 ++++++++++++
 src/ldapchgpassdlg.h      |  40 +++++++++++
 src/ldapchgpassdlgbase.ui | 145 ++++++++++++++++++++++++++++++++++++++
 src/ldapchgpasswddlg.cpp  |  85 ++++++++++++++++++++++
 src/ldapchgpasswddlg.h    |  50 +++++++++++++
 src/libtdeldap.cpp        | 174 ++++++++++++++++++++++++++++++++++++++++++++++
 src/libtdeldap.h          |   3 +
 8 files changed, 546 insertions(+)
 create mode 100644 src/ldapchgpassdlg.cpp
 create mode 100644 src/ldapchgpassdlg.h
 create mode 100644 src/ldapchgpassdlgbase.ui
 create mode 100644 src/ldapchgpasswddlg.cpp
 create mode 100644 src/ldapchgpasswddlg.h

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..57ec412
--- /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 <tdesimpleconfig.h>
+#include <tdelocale.h>
+#include <kdebug.h>
+#include <tdestandarddirs.h>
+#include <kiconloader.h>
+#include <dcopclient.h>
+#include <tdeprocess.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 62faa34..0e544cf 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
+		TDESimpleConfig* systemconfig = new TDESimpleConfig( 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 d97003b..49f7ec0 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);
 
-- 
cgit v1.2.3

