Branch: master

3d6055df 2015-09-28 02:49:20 Timothy Pearson
Fix local kadmin access
M src/Makefile.am
M src/libtdeldap.cpp
M src/libtdeldap.h
diff --git a/src/Makefile.am b/src/Makefile.am
index 4d458e2..5d5b855 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -7,7 +7,7 @@
 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 -lkadm5clnt
+libtdeldap_la_LIBADD = -ltdeio $(LIB_TDEUI) -lldap $(LIB_QT) $(LIB_TDECORE) -ltdesu -llber -lkadm5clnt -lkadm5srv
 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 d240428..9f5f9a5 100644
--- a/src/libtdeldap.cpp
+++ b/src/libtdeldap.cpp
@@ -46,6 +46,35 @@
 #include <sys/time.h>
 #include <errno.h>
 
+#if 0
+	#include <sys/socket.h>
+	#include <sys/un.h>
+	#include <hdb.h>
+	#include <kadm5/admin.h>
+	#include <kadm5/private.h>
+	#include <kadm5/kadm5-private.h>
+#else
+	#include <kadm5/admin.h>
+
+	extern "C" {
+		// The following declaration was taken from hdb-protos.h
+		const char *
+		hdb_db_dir (krb5_context /*context*/);
+
+		// The following declaration was taken from kadm5-private.h
+		kadm5_ret_t
+		kadm5_s_init_with_password_ctx (
+			krb5_context /*context*/,
+			const char */*client_name*/,
+			const char */*password*/,
+			const char */*service_name*/,
+			kadm5_config_params */*realm_params*/,
+			unsigned long /*struct_version*/,
+			unsigned long /*api_version*/,
+			void **/*server_handle*/);
+	}
+#endif
+
 #include "libtdeldap.h"
 #include "ldaplogindlg.h"
 #include "ldappasswddlg.h"
@@ -108,13 +137,13 @@
 	}
 }
 
-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)
+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), m_krb5admRealmName(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), m_krb5admHandle(0), m_krb5admKeytabFilename(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), m_krb5admRealmName(0)
 {
 	TQStringList domainChunks = TQStringList::split(".", realm.lower());
 	m_basedc = "dc=" + domainChunks.join(",dc=");
@@ -1125,13 +1154,31 @@
 		admincreds.use_gssapi = true;
 	}
 
+	bool use_local_socket = false;
+	if (m_host.startsWith("ldapi://")) {
+		use_local_socket = true;
+	}
+
 	TQString ticketFile;
 	LDAPManager::getKerberosTicketList(TQString::null, &ticketFile);
 
 	memset(&params, 0, sizeof(params));
-	params.mask |= KADM5_CONFIG_REALM;
-	params.realm = const_cast<char *>(admincreds.realm.upper().ascii());
-	
+	if (!use_local_socket) {
+		params.mask |= KADM5_CONFIG_REALM;
+		if (m_krb5admRealmName) {
+			free(m_krb5admRealmName);
+		}
+		if (admincreds.realm != "") {
+			m_krb5admRealmName = strdup(admincreds.realm.upper().ascii());
+		}
+		else {
+			TQString defaultRealm;
+			fetchAndReadTDERealmList(&defaultRealm);
+			m_krb5admRealmName = strdup(defaultRealm.ascii());
+		}
+		params.realm = m_krb5admRealmName;
+	}
+
 	TQString adminPrincipal = TQString::null;
 	if (admincreds.username != "") {
 		adminPrincipal = admincreds.username.lower() + "@" + admincreds.realm.upper();
@@ -1139,14 +1186,43 @@
 
 	krb5adm_ret = krb5_init_context(&m_krb5admContext);
 	if (krb5adm_ret) {
-		if (errstr) *errstr = TQString("Internal Error<p>Failed to execute kadm5_init_krb5_context (code %1)").arg(krb5adm_ret);
+		if (errstr) *errstr = TQString("%1<p>Details:<br>Failed to execute kadm5_init_krb5_context (code %2)").arg(krb5_get_error_message(m_krb5admContext, krb5adm_ret)).arg(krb5adm_ret);
 	}
 	else {
-		if (m_host.startsWith("ldapi://")) {
+		if (use_local_socket) {
 			// Local bind
-			krb5adm_ret = kadm5_init_with_password_ctx(m_krb5admContext, KADM5_ADMIN_SERVICE, admincreds.password.data(), KADM5_ADMIN_SERVICE, &params, KADM5_STRUCT_VERSION, KADM5_API_VERSION_2, &m_krb5admHandle);
+
+			// Read KDC configuration files
+			int temp_ret;
+			char **files;
+			char* config_file;
+			temp_ret = asprintf(&config_file, "%s/kdc.conf", hdb_db_dir(m_krb5admContext));
+			if (temp_ret == -1) {
+				if (errstr) *errstr = i18n("Out of memory");
+			}
+
+			krb5adm_ret = krb5_prepend_config_files_default(config_file, &files);
 			if (krb5adm_ret) {
-				if (errstr) *errstr = TQString("%1<p>Details:<br>Failed to execute kadm5_init_with_password (code %2)").arg(krb5_get_error_message(m_krb5admContext, krb5adm_ret)).arg(krb5adm_ret);
+				if (errstr) *errstr = i18n("%1<p>Details:<br>Failed to execute krb5_prepend_config_files_default (code %2)").arg(krb5_get_error_message(m_krb5admContext, krb5adm_ret)).arg(krb5adm_ret);
+			}
+			
+			krb5adm_ret = krb5_set_config_files(m_krb5admContext, files);
+			krb5_free_config_files(files);
+			if(krb5adm_ret) {
+				if (errstr) *errstr = i18n("%1<p>Details:<br>Failed to execute krb5_set_config_files (code %2)").arg(krb5_get_error_message(m_krb5admContext, krb5adm_ret)).arg(krb5adm_ret);
+			}
+
+			// Bypass password quality checks
+			kadm5_setup_passwd_quality_check(m_krb5admContext, NULL, NULL);
+			krb5adm_ret = kadm5_add_passwd_quality_verifier(m_krb5admContext, NULL);
+			if (krb5adm_ret) {
+				if (errstr) *errstr = i18n("%1<p>Details:<br>Failed to execute kadm5_add_passwd_quality_verifier (code %2)").arg(krb5_get_error_message(m_krb5admContext, krb5adm_ret)).arg(krb5adm_ret);
+			}
+
+			// Initialize context
+			krb5adm_ret = kadm5_s_init_with_password_ctx(m_krb5admContext, KADM5_ADMIN_SERVICE, NULL, KADM5_ADMIN_SERVICE, &params, KADM5_STRUCT_VERSION, KADM5_API_VERSION_2, &m_krb5admHandle);
+			if (krb5adm_ret) {
+				if (errstr) *errstr = i18n("%1<p>Details:<br>Failed to execute kadm5_s_init_with_password_ctx (code %2)").arg(krb5_get_error_message(m_krb5admContext, krb5adm_ret)).arg(krb5adm_ret);
 			}
 		}
 		else if (admincreds.use_gssapi) {
@@ -1157,14 +1233,14 @@
 			m_krb5admKeytabFilename = strdup(ticketFile.ascii());
 			krb5adm_ret = kadm5_init_with_skey_ctx(m_krb5admContext, KADM5_ADMIN_SERVICE, m_krb5admKeytabFilename, KADM5_ADMIN_SERVICE, &params, KADM5_STRUCT_VERSION, KADM5_API_VERSION_2, &m_krb5admHandle);
 			if (krb5adm_ret) {
-				if (errstr) *errstr = TQString("%1<p>Details:<br>Failed to execute kadm5_init_with_skey (code %2)").arg(krb5_get_error_message(m_krb5admContext, krb5adm_ret)).arg(krb5adm_ret);
+				if (errstr) *errstr = i18n("%1<p>Details:<br>Failed to execute kadm5_init_with_skey (code %2)").arg(krb5_get_error_message(m_krb5admContext, krb5adm_ret)).arg(krb5adm_ret);
 			}
 		}
 		else {
 			// Password authentication / bind
-			krb5adm_ret = kadm5_init_with_password_ctx(m_krb5admContext, adminPrincipal.ascii(), admincreds.password.data(), KADM5_ADMIN_SERVICE, &params, KADM5_STRUCT_VERSION, KADM5_API_VERSION_2, &m_krb5admHandle);
+ 			krb5adm_ret = kadm5_init_with_password_ctx(m_krb5admContext, adminPrincipal.ascii(), admincreds.password.data(), KADM5_ADMIN_SERVICE, &params, KADM5_STRUCT_VERSION, KADM5_API_VERSION_2, &m_krb5admHandle);
 			if (krb5adm_ret) {
-				if (errstr) *errstr = TQString("%1<p>Details:<br>Failed to execute kadm5_init_with_password (code %2)").arg(krb5_get_error_message(m_krb5admContext, krb5adm_ret)).arg(krb5adm_ret);
+				if (errstr) *errstr = i18n("%1<p>Details:<br>Failed to execute kadm5_init_with_password (code %2)").arg(krb5_get_error_message(m_krb5admContext, krb5adm_ret)).arg(krb5adm_ret);
 			}
 		}
 		if (!krb5adm_ret) {
@@ -1179,6 +1255,11 @@
 int LDAPManager::unbindKAdmin(TQString *errstr) {
 	if (m_krb5admKeytabFilename) {
 		free(m_krb5admKeytabFilename);
+		m_krb5admKeytabFilename = NULL;
+	}
+	if (m_krb5admRealmName) {
+		free(m_krb5admRealmName);
+		m_krb5admRealmName = NULL;
 	}
 
 	kadm5_destroy(m_krb5admHandle);
@@ -1203,12 +1284,12 @@
 		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<p>Details:<br>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);
+			if (errstr) *errstr = i18n("%1<p>Details:<br>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<p>Details:<br>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 (errstr) *errstr = i18n("%1<p>Details:<br>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);
 			}
 			else {
 				// Success!
diff --git a/src/libtdeldap.h b/src/libtdeldap.h
index 9905eb6..ee685b4 100644
--- a/src/libtdeldap.h
+++ b/src/libtdeldap.h
@@ -612,6 +612,7 @@
 		krb5_context m_krb5admContext;
 		void* m_krb5admHandle;
 		char* m_krb5admKeytabFilename;
+		char* m_krb5admRealmName;
 };
 
 #endif // _LIBTDELDAP_H_