|
|
|
@ -1,5 +1,5 @@
|
|
|
|
|
/***************************************************************************
|
|
|
|
|
* Copyright (C) 2012 by Timothy Pearson *
|
|
|
|
|
* Copyright (C) 2012-2013 by Timothy Pearson *
|
|
|
|
|
* kb9vqf@pearsoncomputing.net *
|
|
|
|
|
* *
|
|
|
|
|
* This program is free software; you can redistribute it and/or modify *
|
|
|
|
@ -56,12 +56,21 @@
|
|
|
|
|
|
|
|
|
|
// FIXME
|
|
|
|
|
// This assumes Debian!
|
|
|
|
|
#define KRB5_FILE "/etc/krb5.conf"
|
|
|
|
|
|
|
|
|
|
#define NSSWITCH_FILE "/etc/nsswitch.conf"
|
|
|
|
|
|
|
|
|
|
#define PAMD_DIRECTORY "/etc/pam.d/"
|
|
|
|
|
#define PAMD_COMMON_ACCOUNT "common-account"
|
|
|
|
|
#define PAMD_COMMON_AUTH "common-auth"
|
|
|
|
|
|
|
|
|
|
#define LDAP_FILE "/etc/ldap/ldap.conf"
|
|
|
|
|
#define LDAP_SECONDARY_FILE "/etc/ldap.conf"
|
|
|
|
|
#define LDAP_TERTIARY_FILE "/etc/libnss-ldap.conf"
|
|
|
|
|
|
|
|
|
|
#define TDELDAP_SUDO_D_FILE "/etc/sudoers.d/tde-realm-admins"
|
|
|
|
|
#define CRON_UPDATE_NSS_FILE "/etc/cron.daily/upd-local-nss-db"
|
|
|
|
|
|
|
|
|
|
#define CRON_UPDATE_NSS_FILE "/etc/cron.daily/upd-local-nss-db"
|
|
|
|
|
#define CRON_UPDATE_NSS_COMMAND "/usr/sbin/nss_updatedb ldap"
|
|
|
|
|
|
|
|
|
|
int requested_ldap_version = LDAP_VERSION3;
|
|
|
|
@ -2229,7 +2238,7 @@ int LDAPManager::moveKerberosEntries(TQString newSuffix, TQString* errstr) {
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void LDAPManager::writeLDAPConfFile(LDAPRealmConfig realmcfg) {
|
|
|
|
|
int LDAPManager::writeLDAPConfFile(LDAPRealmConfig realmcfg, TQString *errstr) {
|
|
|
|
|
KSimpleConfig* systemconfig;
|
|
|
|
|
TQString m_defaultRealm;
|
|
|
|
|
int m_ldapVersion;
|
|
|
|
@ -2276,37 +2285,39 @@ void LDAPManager::writeLDAPConfFile(LDAPRealmConfig realmcfg) {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (chmod(LDAP_FILE, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH) < 0) {
|
|
|
|
|
printf("ERROR: Unable to change permissions of \"%s\"\n\r", LDAP_FILE);
|
|
|
|
|
return;
|
|
|
|
|
if (errstr) *errstr = TQString("Unable to change permissions of \"%1\"").arg(LDAP_FILE);
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Create symbolic link to secondary LDAP configuration file
|
|
|
|
|
if (fileExists(LDAP_SECONDARY_FILE)) {
|
|
|
|
|
if (unlink(LDAP_SECONDARY_FILE) < 0) {
|
|
|
|
|
printf("ERROR: Unable to unlink \"%s\"\n\r", LDAP_SECONDARY_FILE);
|
|
|
|
|
return;
|
|
|
|
|
if (errstr) *errstr = TQString("Unable to unlink \"%s\"").arg(LDAP_SECONDARY_FILE);
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
command = TQString("ln -s %1 %2").arg(LDAP_FILE).arg(LDAP_SECONDARY_FILE);
|
|
|
|
|
if (system(command) < 0) {
|
|
|
|
|
printf("ERROR: Execution of \"%s\" failed!\n\r", command.ascii());
|
|
|
|
|
return;
|
|
|
|
|
if (errstr) *errstr = TQString("Execution of \"%s\" failed").arg(command.ascii());
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Create symbolic link to tertiary LDAP configuration file
|
|
|
|
|
if (fileExists(LDAP_TERTIARY_FILE)) {
|
|
|
|
|
if (unlink(LDAP_TERTIARY_FILE) < 0) {
|
|
|
|
|
printf("ERROR: Unable to unlink \"%s\"\n\r", LDAP_TERTIARY_FILE);
|
|
|
|
|
return;
|
|
|
|
|
if (errstr) *errstr = TQString("Unable to unlink \"%s\"").arg(LDAP_TERTIARY_FILE);
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
command = TQString("ln -s %1 %2").arg(LDAP_FILE).arg(LDAP_TERTIARY_FILE);
|
|
|
|
|
if (system(command) < 0) {
|
|
|
|
|
printf("ERROR: Execution of \"%s\" failed!\n\r", command.ascii());
|
|
|
|
|
return;
|
|
|
|
|
if (errstr) *errstr = TQString("Execution of \"%s\" failed").arg(command.ascii());
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
delete systemconfig;
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
LDAPTDEBuiltinsInfo LDAPManager::parseLDAPTDEBuiltinsRecord(LDAPMessage* entry) {
|
|
|
|
@ -2486,7 +2497,7 @@ int LDAPManager::writeSudoersConfFile(TQString *errstr) {
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void LDAPManager::writeCronFiles() {
|
|
|
|
|
int LDAPManager::writeClientCronFiles(TQString *errstr) {
|
|
|
|
|
TQFile file(CRON_UPDATE_NSS_FILE);
|
|
|
|
|
if (file.open(IO_WriteOnly)) {
|
|
|
|
|
TQTextStream stream( &file );
|
|
|
|
@ -2501,9 +2512,11 @@ void LDAPManager::writeCronFiles() {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (system(CRON_UPDATE_NSS_COMMAND) < 0) {
|
|
|
|
|
printf("ERROR: Execution of \"%s\" failed!\n\r", CRON_UPDATE_NSS_COMMAND);
|
|
|
|
|
return;
|
|
|
|
|
if (errstr) *errstr = TQString("Execution of \"%s\" failed").arg(CRON_UPDATE_NSS_COMMAND);
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void LDAPManager::writePrimaryRealmCertificateUpdateCronFile() {
|
|
|
|
@ -2565,7 +2578,7 @@ LDAPRealmConfigList LDAPManager::readTDERealmList(KSimpleConfig* config, bool di
|
|
|
|
|
return realms;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void LDAPManager::writeTDERealmList(LDAPRealmConfigList realms, KSimpleConfig* config) {
|
|
|
|
|
int LDAPManager::writeTDERealmList(LDAPRealmConfigList realms, KSimpleConfig* config, TQString *errstr) {
|
|
|
|
|
LDAPRealmConfigList::Iterator it;
|
|
|
|
|
for (it = realms.begin(); it != realms.end(); ++it) {
|
|
|
|
|
LDAPRealmConfig realmcfg = it.data();
|
|
|
|
@ -2599,6 +2612,8 @@ void LDAPManager::writeTDERealmList(LDAPRealmConfigList realms, KSimpleConfig* c
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TQDateTime LDAPManager::getCertificateExpiration(TQString certfile) {
|
|
|
|
@ -2744,7 +2759,170 @@ TQString LDAPManager::getMachineFQDN() {
|
|
|
|
|
return fqdn;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int LDAPManager::bondRealm(LDAPRealmConfig realmcfg, TQString adminUserName, const char * adminPassword, TQString adminRealm, TQString *errstr) {
|
|
|
|
|
LDAPClientRealmConfig LDAPManager::loadClientRealmConfig(KSimpleConfig* config, bool useDefaults) {
|
|
|
|
|
LDAPClientRealmConfig clientRealmConfig;
|
|
|
|
|
|
|
|
|
|
config->setReadDefaults(useDefaults);
|
|
|
|
|
|
|
|
|
|
config->setGroup(NULL);
|
|
|
|
|
clientRealmConfig.enable_bonding = config->readBoolEntry("EnableLDAP", false);
|
|
|
|
|
clientRealmConfig.defaultRealm = config->readEntry("DefaultRealm", TQString::null);
|
|
|
|
|
clientRealmConfig.ticketLifetime = config->readNumEntry("TicketLifetime", 86400);
|
|
|
|
|
clientRealmConfig.ldapRole = config->readEntry("LDAPRole", "Workstation");
|
|
|
|
|
if (LDAPManager::getMachineFQDN() == config->readEntry("HostFQDN", "")) {
|
|
|
|
|
clientRealmConfig.configurationVerifiedForLocalMachine = true;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
clientRealmConfig.configurationVerifiedForLocalMachine = false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
clientRealmConfig.ldapVersion = config->readNumEntry("ConnectionLDAPVersion", 3);
|
|
|
|
|
clientRealmConfig.ldapTimeout = config->readNumEntry("ConnectionLDAPTimeout", 2);
|
|
|
|
|
clientRealmConfig.bindPolicy = config->readEntry("ConnectionBindPolicy", "soft");
|
|
|
|
|
clientRealmConfig.ldapBindTimeout = config->readNumEntry("ConnectionBindTimeout", 2);
|
|
|
|
|
clientRealmConfig.passwordHash = config->readEntry("ConnectionPasswordHash", "exop");
|
|
|
|
|
clientRealmConfig.ignoredUsers = config->readEntry("ConnectionIgnoredUsers", DEFAULT_IGNORED_USERS_LIST);
|
|
|
|
|
|
|
|
|
|
return clientRealmConfig;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int LDAPManager::saveClientRealmConfig(LDAPClientRealmConfig clientRealmConfig, KSimpleConfig* config, TQString *errstr) {
|
|
|
|
|
config->setGroup(NULL);
|
|
|
|
|
config->writeEntry("EnableLDAP", clientRealmConfig.enable_bonding);
|
|
|
|
|
config->writeEntry("HostFQDN", clientRealmConfig.hostFQDN);
|
|
|
|
|
|
|
|
|
|
if (clientRealmConfig.defaultRealm != "") {
|
|
|
|
|
config->writeEntry("DefaultRealm", clientRealmConfig.defaultRealm);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
config->deleteEntry("DefaultRealm");
|
|
|
|
|
}
|
|
|
|
|
config->writeEntry("TicketLifetime", clientRealmConfig.ticketLifetime);
|
|
|
|
|
|
|
|
|
|
config->writeEntry("ConnectionLDAPVersion", clientRealmConfig.ldapVersion);
|
|
|
|
|
config->writeEntry("ConnectionLDAPTimeout", clientRealmConfig.ldapTimeout);
|
|
|
|
|
config->writeEntry("ConnectionBindPolicy", clientRealmConfig.bindPolicy);
|
|
|
|
|
config->writeEntry("ConnectionBindTimeout", clientRealmConfig.ldapBindTimeout);
|
|
|
|
|
config->writeEntry("ConnectionPasswordHash", clientRealmConfig.passwordHash);
|
|
|
|
|
config->writeEntry("ConnectionIgnoredUsers", clientRealmConfig.ignoredUsers);
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int LDAPManager::writeClientKrb5ConfFile(LDAPClientRealmConfig clientRealmConfig, LDAPRealmConfigList realmList, TQString *errstr) {
|
|
|
|
|
TQFile file(KRB5_FILE);
|
|
|
|
|
if (file.open(IO_WriteOnly)) {
|
|
|
|
|
TQTextStream stream( &file );
|
|
|
|
|
|
|
|
|
|
stream << "# This file was automatically generated by TDE\n";
|
|
|
|
|
stream << "# All changes will be lost!\n";
|
|
|
|
|
stream << "\n";
|
|
|
|
|
|
|
|
|
|
// Defaults
|
|
|
|
|
stream << "[libdefaults]\n";
|
|
|
|
|
stream << " ticket_lifetime = " << clientRealmConfig.ticketLifetime << "\n";
|
|
|
|
|
if (clientRealmConfig.defaultRealm != "") {
|
|
|
|
|
stream << " default_realm = " << clientRealmConfig.defaultRealm << "\n";
|
|
|
|
|
}
|
|
|
|
|
stream << "\n";
|
|
|
|
|
|
|
|
|
|
// Realms
|
|
|
|
|
stream << "[realms]\n";
|
|
|
|
|
LDAPRealmConfigList::Iterator it;
|
|
|
|
|
for (it = realmList.begin(); it != realmList.end(); ++it) {
|
|
|
|
|
LDAPRealmConfig realmcfg = it.data();
|
|
|
|
|
stream << " " << realmcfg.name << " = {\n";
|
|
|
|
|
stream << " kdc = " << realmcfg.kdc << ":" << realmcfg.kdc_port << "\n";
|
|
|
|
|
stream << " admin_server = " << realmcfg.admin_server << ":" << realmcfg.admin_server_port << "\n";
|
|
|
|
|
stream << " pkinit_require_eku = " << (realmcfg.pkinit_require_eku?"true":"false") << "\n";
|
|
|
|
|
stream << " pkinit_require_krbtgt_otherName = " << (realmcfg.pkinit_require_krbtgt_otherName?"true":"false") << "\n";
|
|
|
|
|
stream << " win2k_pkinit = " << (realmcfg.win2k_pkinit?"yes":"no") << "\n";
|
|
|
|
|
stream << " win2k_pkinit_require_binding = " << (realmcfg.win2k_pkinit_require_binding?"yes":"no") << "\n";
|
|
|
|
|
stream << " }\n";
|
|
|
|
|
}
|
|
|
|
|
stream << "\n";
|
|
|
|
|
|
|
|
|
|
// Domain aliases
|
|
|
|
|
stream << "[domain_realm]\n";
|
|
|
|
|
LDAPRealmConfigList::Iterator it2;
|
|
|
|
|
for (it2 = realmList.begin(); it2 != realmList.end(); ++it2) {
|
|
|
|
|
LDAPRealmConfig realmcfg = it2.data();
|
|
|
|
|
TQStringList domains = realmcfg.domain_mappings;
|
|
|
|
|
for (TQStringList::Iterator it3 = domains.begin(); it3 != domains.end(); ++it3 ) {
|
|
|
|
|
stream << " " << *it3 << " = " << realmcfg.name << "\n";
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
file.close();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int LDAPManager::writeNSSwitchFile(TQString *errstr) {
|
|
|
|
|
TQFile file(NSSWITCH_FILE);
|
|
|
|
|
if (file.open(IO_WriteOnly)) {
|
|
|
|
|
TQTextStream stream( &file );
|
|
|
|
|
|
|
|
|
|
stream << "# This file was automatically generated by TDE\n";
|
|
|
|
|
stream << "# All changes will be lost!\n";
|
|
|
|
|
stream << "\n";
|
|
|
|
|
stream << "passwd: files ldap [NOTFOUND=return] db" << "\n";
|
|
|
|
|
stream << "group: files ldap [NOTFOUND=return] db" << "\n";
|
|
|
|
|
stream << "shadow: files ldap [NOTFOUND=return] db" << "\n";
|
|
|
|
|
stream << "\n";
|
|
|
|
|
stream << "hosts: files mdns4_minimal [NOTFOUND=return] dns mdns4" << "\n";
|
|
|
|
|
stream << "networks: files" << "\n";
|
|
|
|
|
stream << "\n";
|
|
|
|
|
stream << "protocols: db files" << "\n";
|
|
|
|
|
stream << "services: db files" << "\n";
|
|
|
|
|
stream << "ethers: db files" << "\n";
|
|
|
|
|
stream << "rpc: db files" << "\n";
|
|
|
|
|
stream << "\n";
|
|
|
|
|
stream << "netgroup: nis" << "\n";
|
|
|
|
|
|
|
|
|
|
file.close();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int LDAPManager::writePAMFiles(TQString *errstr) {
|
|
|
|
|
TQFile file(PAMD_DIRECTORY PAMD_COMMON_ACCOUNT);
|
|
|
|
|
if (file.open(IO_WriteOnly)) {
|
|
|
|
|
TQTextStream stream( &file );
|
|
|
|
|
|
|
|
|
|
stream << "# This file was automatically generated by TDE\n";
|
|
|
|
|
stream << "# All changes will be lost!\n";
|
|
|
|
|
stream << "\n";
|
|
|
|
|
stream << "account sufficient pam_unix.so nullok_secure" << "\n";
|
|
|
|
|
stream << "account sufficient pam_ldap.so" << "\n";
|
|
|
|
|
stream << "account required pam_permit.so" << "\n";
|
|
|
|
|
|
|
|
|
|
file.close();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TQFile file2(PAMD_DIRECTORY PAMD_COMMON_AUTH);
|
|
|
|
|
if (file2.open(IO_WriteOnly)) {
|
|
|
|
|
TQTextStream stream( &file2 );
|
|
|
|
|
|
|
|
|
|
stream << "# This file was automatically generated by TDE\n";
|
|
|
|
|
stream << "# All changes will be lost!\n";
|
|
|
|
|
stream << "\n";
|
|
|
|
|
stream << "auth [default=ignore success=ignore] pam_mount.so" << "\n";
|
|
|
|
|
stream << "auth sufficient pam_unix.so nullok try_first_pass" << "\n";
|
|
|
|
|
stream << "auth [default=ignore success=1 service_err=reset] pam_krb5.so ccache=/tmp/krb5cc_%u use_first_pass" << "\n";
|
|
|
|
|
stream << "auth [default=die success=done] pam_ccreds.so action=validate use_first_pass" << "\n";
|
|
|
|
|
stream << "auth sufficient pam_ccreds.so action=store use_first_pass" << "\n";
|
|
|
|
|
stream << "auth required pam_deny.so" << "\n";
|
|
|
|
|
|
|
|
|
|
file2.close();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int LDAPManager::bondRealm(TQString adminUserName, const char * adminPassword, TQString adminRealm, TQString *errstr) {
|
|
|
|
|
TQCString command = "kadmin";
|
|
|
|
|
QCStringList args;
|
|
|
|
|
args << TQCString("-p") << TQCString(adminUserName+"@"+(adminRealm.upper())) << TQCString("-r") << TQCString(adminRealm.upper());
|
|
|
|
@ -2778,6 +2956,10 @@ int LDAPManager::bondRealm(LDAPRealmConfig realmcfg, TQString adminUserName, con
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
else if (prompt.endsWith("Principal does not exist")) {
|
|
|
|
|
do { // Wait for command prompt
|
|
|
|
|
prompt = readFullLineFromPtyProcess(&kadminProc);
|
|
|
|
|
printf("(kadmin) '%s'\n\r", prompt.ascii());
|
|
|
|
|
} while (prompt == "");
|
|
|
|
|
command = TQCString("ank --random-key "+hoststring);
|
|
|
|
|
kadminProc.writeLine(command, true);
|
|
|
|
|
do { // Discard our own input
|
|
|
|
@ -2834,14 +3016,12 @@ int LDAPManager::bondRealm(LDAPRealmConfig realmcfg, TQString adminUserName, con
|
|
|
|
|
// Success!
|
|
|
|
|
kadminProc.writeLine("quit", true);
|
|
|
|
|
|
|
|
|
|
realmcfg.bonded = true;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
else if (prompt == "kadmin>") {
|
|
|
|
|
// Success!
|
|
|
|
|
kadminProc.writeLine("quit", true);
|
|
|
|
|
|
|
|
|
|
realmcfg.bonded = true;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -2898,7 +3078,7 @@ int LDAPManager::unbondRealm(LDAPRealmConfig realmcfg, TQString adminUserName, c
|
|
|
|
|
kadminProc.writeLine("quit", true);
|
|
|
|
|
|
|
|
|
|
// Delete keys from keytab
|
|
|
|
|
command = TQString("ktutil remove -p %1").arg(hostprinc);
|
|
|
|
|
command = TQString("ktutil remove -p %1").arg(hoststring+"@"+adminRealm.upper());
|
|
|
|
|
if (system(command) < 0) {
|
|
|
|
|
printf("ERROR: Execution of \"%s\" failed!\n\r", command.data());
|
|
|
|
|
return 1; // Failure
|
|
|
|
|