|
|
|
@ -46,34 +46,15 @@
|
|
|
|
|
#include <sys/time.h>
|
|
|
|
|
#include <errno.h>
|
|
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
|
#include <sys/socket.h>
|
|
|
|
|
#include <sys/un.h>
|
|
|
|
|
#include <sys/socket.h>
|
|
|
|
|
#include <sys/un.h>
|
|
|
|
|
|
|
|
|
|
extern "C" {
|
|
|
|
|
#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"
|
|
|
|
@ -90,6 +71,9 @@
|
|
|
|
|
// This assumes Debian!
|
|
|
|
|
#define KRB5_FILE "/etc/krb5.conf"
|
|
|
|
|
|
|
|
|
|
//#define KRB5_ANK_RANDOM_PASSWORD_LENGTH 1024
|
|
|
|
|
#define KRB5_ANK_RANDOM_PASSWORD_LENGTH 512
|
|
|
|
|
|
|
|
|
|
#define NSSWITCH_FILE "/etc/nsswitch.conf"
|
|
|
|
|
|
|
|
|
|
#define PAMD_DIRECTORY "/etc/pam.d/"
|
|
|
|
@ -137,6 +121,19 @@ bool fileExists(const char* filename) {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static kadm5_ret_t kadm5_get_default_principal_info(krb5_context context, void* handle, krb5_principal princ, kadm5_principal_ent_t def) {
|
|
|
|
|
kadm5_ret_t ret;
|
|
|
|
|
krb5_principal def_principal;
|
|
|
|
|
krb5_const_realm realm = krb5_principal_get_realm(context, princ);
|
|
|
|
|
ret = krb5_make_principal(context, &def_principal, realm, "default", NULL);
|
|
|
|
|
if (ret) {
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
ret = kadm5_get_principal(handle, def_principal, def, KADM5_PRINCIPAL_NORMAL_MASK);
|
|
|
|
|
krb5_free_principal(context, def_principal);
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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());
|
|
|
|
@ -196,10 +193,25 @@ TQString LDAPManager::realm() {
|
|
|
|
|
return m_realm;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
LDAPCredentials LDAPManager::currentLDAPCredentials() {
|
|
|
|
|
LDAPCredentials LDAPManager::currentLDAPCredentials(bool inferGSSAPIData) {
|
|
|
|
|
if (m_creds) {
|
|
|
|
|
if (inferGSSAPIData) {
|
|
|
|
|
LDAPCredentials credentials = *m_creds;
|
|
|
|
|
if ((credentials.username == "") && (credentials.password == "")) {
|
|
|
|
|
// Probably GSSAPI
|
|
|
|
|
// Get active ticket principal...
|
|
|
|
|
KerberosTicketInfoList tickets = LDAPManager::getKerberosTicketList();
|
|
|
|
|
TQStringList principalParts = TQStringList::split("@", tickets[0].cachePrincipal, false);
|
|
|
|
|
credentials.username = principalParts[0];
|
|
|
|
|
credentials.realm = principalParts[1];
|
|
|
|
|
credentials.use_gssapi = true;
|
|
|
|
|
}
|
|
|
|
|
return credentials;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
return *m_creds;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
return LDAPCredentials();
|
|
|
|
|
}
|
|
|
|
@ -346,8 +358,9 @@ int LDAPManager::bind(TQString* errstr) {
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
struct berval anoncred;
|
|
|
|
|
anoncred.bv_val = "";
|
|
|
|
|
anoncred.bv_len = strlen("");
|
|
|
|
|
TQCString anonpass = "";
|
|
|
|
|
anoncred.bv_val = anonpass.data();
|
|
|
|
|
anoncred.bv_len = anonpass.length();
|
|
|
|
|
retcode = ldap_sasl_bind_s(ldapconn, "", mechanism, &anoncred, NULL, NULL, NULL);
|
|
|
|
|
if (retcode == LDAP_SUCCESS ) {
|
|
|
|
|
// Look for the DN for the specified user
|
|
|
|
@ -1127,7 +1140,7 @@ TQString LDAPManager::readFullLineFromPtyProcess(PtyProcess* proc) {
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int LDAPManager::bindKAdmin(LDAPUserInfo user, TQString *errstr) {
|
|
|
|
|
int LDAPManager::bindKAdmin(TQString *errstr) {
|
|
|
|
|
int retcode = 1;
|
|
|
|
|
|
|
|
|
|
kadm5_ret_t krb5adm_ret;
|
|
|
|
@ -1186,7 +1199,7 @@ int LDAPManager::bindKAdmin(LDAPUserInfo user, TQString *errstr) {
|
|
|
|
|
|
|
|
|
|
krb5adm_ret = krb5_init_context(&m_krb5admContext);
|
|
|
|
|
if (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);
|
|
|
|
|
if (errstr) *errstr = i18n("%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 (use_local_socket) {
|
|
|
|
@ -1278,7 +1291,7 @@ int LDAPManager::setPasswordForUser(LDAPUserInfo user, TQString *errstr) {
|
|
|
|
|
int retcode;
|
|
|
|
|
kadm5_ret_t krb5adm_ret;
|
|
|
|
|
|
|
|
|
|
retcode = bindKAdmin(user, errstr);
|
|
|
|
|
retcode = bindKAdmin(errstr);
|
|
|
|
|
if (retcode == 0) {
|
|
|
|
|
retcode = 1;
|
|
|
|
|
krb5_principal user_kadm5_principal;
|
|
|
|
@ -1301,6 +1314,7 @@ int LDAPManager::setPasswordForUser(LDAPUserInfo user, TQString *errstr) {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
unbindKAdmin();
|
|
|
|
|
unbind(true); // Using kadmin can disrupt our LDAP connection
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return retcode;
|
|
|
|
@ -1833,6 +1847,147 @@ int LDAPManager::addMachineInfo(LDAPMachineInfo machine, TQString *errstr) {
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
int retcode;
|
|
|
|
|
kadm5_ret_t krb5adm_ret;
|
|
|
|
|
int i;
|
|
|
|
|
char* password = NULL;
|
|
|
|
|
|
|
|
|
|
retcode = bindKAdmin(errstr);
|
|
|
|
|
if (retcode == 0) {
|
|
|
|
|
retcode = 1;
|
|
|
|
|
bool generate_password;
|
|
|
|
|
if (machine.newPassword == "") {
|
|
|
|
|
generate_password = true;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
generate_password = false;
|
|
|
|
|
password = strdup(machine.newPassword.data());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
LDAPCredentials admincreds = currentLDAPCredentials(true);
|
|
|
|
|
TQString hoststring = "host/" + machine.name + "." + admincreds.realm.lower();
|
|
|
|
|
|
|
|
|
|
// Construct and add new principal record
|
|
|
|
|
kadm5_principal_ent_rec principal_record;
|
|
|
|
|
kadm5_principal_ent_rec default_record;
|
|
|
|
|
kadm5_principal_ent_rec *default_entry = NULL;
|
|
|
|
|
krb5_principal principal_entry = NULL;
|
|
|
|
|
int mask = 0;
|
|
|
|
|
|
|
|
|
|
memset(&principal_record, 0, sizeof(principal_record));
|
|
|
|
|
krb5adm_ret = krb5_parse_name(m_krb5admContext, hoststring.ascii(), &principal_entry);
|
|
|
|
|
if (krb5adm_ret) {
|
|
|
|
|
if (errstr) *errstr = i18n("%1<p>Details:<br>Failed to execute krb5_parse_name (code %2)").arg(krb5_get_error_message(m_krb5admContext, krb5adm_ret)).arg(krb5adm_ret);
|
|
|
|
|
}
|
|
|
|
|
principal_record.principal = principal_entry;
|
|
|
|
|
mask |= KADM5_PRINCIPAL;
|
|
|
|
|
|
|
|
|
|
default_entry = &default_record;
|
|
|
|
|
krb5adm_ret = kadm5_get_default_principal_info(m_krb5admContext, m_krb5admHandle, principal_entry, default_entry);
|
|
|
|
|
if (krb5adm_ret) {
|
|
|
|
|
default_entry = NULL;
|
|
|
|
|
if (errstr) *errstr = i18n("%1<p>Details:<br>Failed to execute kadm5_get_default_principal_info (code %2)").arg(krb5_get_error_message(m_krb5admContext, krb5adm_ret)).arg(krb5adm_ret);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
// Use defaults
|
|
|
|
|
principal_record.max_life = default_entry->max_life;
|
|
|
|
|
principal_record.max_renewable_life = default_entry->max_renewable_life;
|
|
|
|
|
principal_record.princ_expire_time = default_entry->princ_expire_time;
|
|
|
|
|
principal_record.pw_expiration = default_entry->pw_expiration;
|
|
|
|
|
principal_record.attributes = default_entry->attributes & ~KRB5_KDB_DISALLOW_ALL_TIX;
|
|
|
|
|
principal_record.policy = strdup(default_entry->policy);
|
|
|
|
|
|
|
|
|
|
if (generate_password) {
|
|
|
|
|
const char charset[] =
|
|
|
|
|
"@$%&*()-+=:,/<>?0123456789"
|
|
|
|
|
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
|
|
|
|
"abcdefghijklmnopqrstuvwxyz";
|
|
|
|
|
const size_t max_index = (sizeof(charset) - 2);
|
|
|
|
|
|
|
|
|
|
TQFile randomNode("/dev/urandom");
|
|
|
|
|
if (randomNode.open(IO_ReadOnly)) {
|
|
|
|
|
password = (char*)malloc(sizeof(char) * KRB5_ANK_RANDOM_PASSWORD_LENGTH);
|
|
|
|
|
if (password) {
|
|
|
|
|
if (randomNode.readBlock(password, KRB5_ANK_RANDOM_PASSWORD_LENGTH) < KRB5_ANK_RANDOM_PASSWORD_LENGTH) {
|
|
|
|
|
free(password);
|
|
|
|
|
password = NULL;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
for (i = 0; i < KRB5_ANK_RANDOM_PASSWORD_LENGTH - 1; i++) {
|
|
|
|
|
while ((unsigned char)password[i] > max_index) {
|
|
|
|
|
password[i] -= max_index;
|
|
|
|
|
}
|
|
|
|
|
password[i] = charset[(int)password[i]];
|
|
|
|
|
}
|
|
|
|
|
password[i] = 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
randomNode.close();
|
|
|
|
|
}
|
|
|
|
|
if (password) {
|
|
|
|
|
principal_record.attributes |= KRB5_KDB_DISALLOW_ALL_TIX;
|
|
|
|
|
mask |= KADM5_ATTRIBUTES;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
if (errstr) *errstr = i18n("Unable to generate random password");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (password) {
|
|
|
|
|
krb5adm_ret = kadm5_create_principal(m_krb5admHandle, &principal_record, mask, password);
|
|
|
|
|
if (krb5adm_ret) {
|
|
|
|
|
if (errstr) *errstr = i18n("%1<p>Details:<br>Failed to execute kadm5_create_principal (code %2)").arg(krb5_get_error_message(m_krb5admContext, krb5adm_ret)).arg(krb5adm_ret);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
if (generate_password) {
|
|
|
|
|
krb5_keyblock *new_keys;
|
|
|
|
|
int key_count;
|
|
|
|
|
krb5adm_ret = kadm5_randkey_principal(m_krb5admHandle, principal_entry, &new_keys, &key_count);
|
|
|
|
|
if (krb5adm_ret) {
|
|
|
|
|
key_count = 0;
|
|
|
|
|
}
|
|
|
|
|
for (i = 0; i < key_count; i++) {
|
|
|
|
|
krb5_free_keyblock_contents(m_krb5admContext, &new_keys[i]);
|
|
|
|
|
}
|
|
|
|
|
if (key_count > 0) {
|
|
|
|
|
free(new_keys);
|
|
|
|
|
}
|
|
|
|
|
kadm5_get_principal(m_krb5admHandle, principal_entry, &principal_record, KADM5_PRINCIPAL | KADM5_KVNO | KADM5_ATTRIBUTES);
|
|
|
|
|
krb5_free_principal(m_krb5admContext, principal_entry);
|
|
|
|
|
principal_entry = principal_record.principal;
|
|
|
|
|
principal_record.attributes &= (~KRB5_KDB_DISALLOW_ALL_TIX);
|
|
|
|
|
principal_record.kvno = 1;
|
|
|
|
|
krb5adm_ret = kadm5_modify_principal(m_krb5admHandle, &principal_record, KADM5_ATTRIBUTES | KADM5_KVNO);
|
|
|
|
|
if (krb5adm_ret) {
|
|
|
|
|
if (errstr) *errstr = i18n("%1<p>Details:<br>Failed to execute kadm5_modify_principal (code %2)").arg(krb5_get_error_message(m_krb5admContext, krb5adm_ret)).arg(krb5adm_ret);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
retcode = 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
retcode = 0;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
kadm5_free_principal_ent(m_krb5admHandle, &principal_record);
|
|
|
|
|
if (default_entry) {
|
|
|
|
|
kadm5_free_principal_ent(m_krb5admHandle, default_entry);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (password) {
|
|
|
|
|
free(password);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
unbindKAdmin();
|
|
|
|
|
unbind(true); // Using kadmin can disrupt our LDAP connection
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return retcode;
|
|
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
|
// Use Kerberos kadmin to actually add the machine
|
|
|
|
|
LDAPCredentials admincreds = currentLDAPCredentials();
|
|
|
|
|
if ((admincreds.username == "") && (admincreds.password == "")) {
|
|
|
|
@ -1950,6 +2105,7 @@ int LDAPManager::addMachineInfo(LDAPMachineInfo machine, TQString *errstr) {
|
|
|
|
|
|
|
|
|
|
if (errstr) *errstr = "Internal error. Verify that kadmin exists and can be executed.";
|
|
|
|
|
return 1; // Failure
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|