Move keytab export to native Heimdal API

pull/1/head
Timothy Pearson 10 years ago
parent e085706825
commit 11869fce63

@ -1140,13 +1140,19 @@ TQString LDAPManager::readFullLineFromPtyProcess(PtyProcess* proc) {
return result;
}
int LDAPManager::bindKAdmin(TQString *errstr) {
int LDAPManager::bindKAdmin(LDAPCredentials *administrativeCredentials, TQString *errstr) {
int retcode = 1;
kadm5_ret_t krb5adm_ret;
kadm5_config_params params;
LDAPCredentials admincreds = currentLDAPCredentials();
LDAPCredentials admincreds;
if (administrativeCredentials) {
admincreds = *administrativeCredentials;
}
else {
admincreds = currentLDAPCredentials();
}
if (admincreds.use_gssapi) {
// FIXME
// Heimdal has issues parsing the keytab file, so for now just prompt for password
@ -1291,7 +1297,14 @@ int LDAPManager::setPasswordForUser(LDAPUserInfo user, TQString *errstr) {
int retcode;
kadm5_ret_t krb5adm_ret;
retcode = bindKAdmin(errstr);
bool kadmin_unbind_needed = false;
if (m_krb5admHandle) {
retcode = 0;
}
else {
retcode = bindKAdmin(NULL, errstr);
kadmin_unbind_needed = true;
}
if (retcode == 0) {
retcode = 1;
krb5_principal user_kadm5_principal;
@ -1313,9 +1326,11 @@ int LDAPManager::setPasswordForUser(LDAPUserInfo user, TQString *errstr) {
krb5_free_principal(m_krb5admContext, user_kadm5_principal);
}
if (kadmin_unbind_needed) {
unbindKAdmin();
unbind(true); // Using kadmin can disrupt our LDAP connection
}
}
return retcode;
}
@ -1843,16 +1858,19 @@ int LDAPManager::addGroupInfo(LDAPGroupInfo group, TQString *errstr) {
}
int LDAPManager::kAdminAddNewPrincipal(TQString principalName, TQString newPassword, TQString *errstr) {
if (bind() < 0) {
return -1;
}
else {
int retcode;
kadm5_ret_t krb5adm_ret;
int i;
char* password = NULL;
retcode = bindKAdmin(errstr);
bool kadmin_unbind_needed = false;
if (m_krb5admHandle) {
retcode = 0;
}
else {
retcode = bindKAdmin(NULL, errstr);
kadmin_unbind_needed = true;
}
if (retcode == 0) {
retcode = 1;
bool generate_password;
@ -1978,12 +1996,13 @@ int LDAPManager::kAdminAddNewPrincipal(TQString principalName, TQString newPassw
free(password);
}
if (kadmin_unbind_needed) {
unbindKAdmin();
unbind(true); // Using kadmin can disrupt our LDAP connection
}
}
return retcode;
}
}
int LDAPManager::addMachineInfo(LDAPMachineInfo machine, TQString *errstr) {
@ -2584,127 +2603,105 @@ LDAPServiceInfoList LDAPManager::machineServices(TQString machine_dn, int* mretc
}
int LDAPManager::exportKeytabForPrincipal(TQString principal, TQString fileName, TQString *errstr) {
if (bind() < 0) {
return -1;
int retcode;
kadm5_ret_t krb5adm_ret;
int i;
bool kadmin_unbind_needed = false;
if (m_krb5admHandle) {
retcode = 0;
}
else {
// Use Kerberos kadmin to export the keytab
LDAPCredentials admincreds = currentLDAPCredentials();
if ((admincreds.username == "") && (admincreds.password == "")) {
// Probably GSSAPI
// Get active ticket principal...
KerberosTicketInfoList tickets = LDAPManager::getKerberosTicketList();
TQStringList principalParts = TQStringList::split("@", tickets[0].cachePrincipal, false);
admincreds.username = principalParts[0];
admincreds.realm = principalParts[1];
admincreds.use_gssapi = true;
retcode = bindKAdmin(NULL, errstr);
kadmin_unbind_needed = true;
}
if (retcode == 0) {
retcode = 1;
TQCString command = "kadmin";
QCStringList args;
if (m_host.startsWith("ldapi://")) {
args << TQCString("-l") << TQCString("-r") << TQCString(admincreds.realm.upper());
krb5_keytab keytab;
if (fileName == "") {
krb5adm_ret = krb5_kt_default(m_krb5admContext, &keytab);
}
else {
if (admincreds.username == "") {
args << TQCString("-r") << TQCString(admincreds.realm.upper());
krb5adm_ret = krb5_kt_resolve(m_krb5admContext, fileName.ascii(), &keytab);
}
else {
args << TQCString("-p") << TQCString(admincreds.username.lower()+"@"+(admincreds.realm.upper())) << TQCString("-r") << TQCString(admincreds.realm.upper());
if (krb5adm_ret) {
if (errstr) *errstr = i18n("%1<p>Details:<br>Failed to open keytab file '%2' (code %3)").arg(krb5_get_error_message(m_krb5admContext, krb5adm_ret)).arg(fileName).arg(krb5adm_ret);
}
else {
kadm5_principal_ent_rec principal_record;
krb5_principal principal_entry = NULL;
memset(&principal_record, 0, sizeof(principal_record));
krb5adm_ret = krb5_parse_name(m_krb5admContext, principal.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);
}
else {
principal_record.principal = principal_entry;
TQString prompt;
PtyProcess kadminProc;
kadminProc.exec(command, args);
prompt = readFullLineFromPtyProcess(&kadminProc);
prompt = prompt.stripWhiteSpace();
if (prompt == "kadmin>") {
if (fileName == "") {
command = TQCString("ext_keytab "+principal);
krb5adm_ret = kadm5_get_principal(m_krb5admHandle, principal_entry, &principal_record, KADM5_PRINCIPAL | KADM5_KVNO | KADM5_KEY_DATA);
if (krb5adm_ret) {
if (errstr) *errstr = i18n("%1<p>Details:<br>Failed to execute kadm5_get_principal (code %2)").arg(krb5_get_error_message(m_krb5admContext, krb5adm_ret)).arg(krb5adm_ret);
retcode = 2;
}
else {
command = TQCString("ext_keytab --keytab=\""+fileName+"\" "+principal);
if (principal_record.n_key_data == 0) {
if (errstr) *errstr = i18n("No keys found!<p>If this principal is known to have valid keys, please check your access permissions and try again");
retcode = 2;
}
kadminProc.enableLocalEcho(false);
kadminProc.writeLine(command, true);
do { // Discard our own input
prompt = readFullLineFromPtyProcess(&kadminProc);
printf("(kadmin) '%s'\n", prompt.ascii());
} while ((prompt == TQString(command)) || (prompt == ""));
prompt = prompt.stripWhiteSpace();
// Use all defaults
while (prompt != "kadmin>") {
if (prompt.endsWith(" Password:")) {
if (admincreds.password == "") {
if (tqApp->type() != TQApplication::Tty) {
TQCString password;
int result = KPasswordDialog::getPassword(password, prompt);
if (result == KPasswordDialog::Accepted) {
admincreds.password = password;
else {
// Extract keys
krb5_keytab_entry *keys = NULL;
keys = (krb5_keytab_entry*)calloc(sizeof(*keys), principal_record.n_key_data);
if (keys == NULL) {
if (errstr) *errstr = i18n("Out of memory");
}
else {
int key_count = 0;
for (i = 0; i < principal_record.n_key_data; i++) {
krb5_key_data *kd = &principal_record.key_data[i];
keys[i].principal = principal_record.principal;
keys[i].vno = kd->key_data_kvno;
keys[i].keyblock.keytype = kd->key_data_type[0];
keys[i].keyblock.keyvalue.length = kd->key_data_length[0];
keys[i].keyblock.keyvalue.data = kd->key_data_contents[0];
keys[i].timestamp = time(NULL);
key_count++;
}
if (key_count < 1) {
if (errstr) *errstr = i18n("No keys found!<p>If this principal is known to have valid keys, please check your access permissions and try again");
}
else {
TQFile file;
file.open(IO_ReadOnly, stdin);
TQTextStream qtin(&file);
admincreds.password = qtin.readLine();
for (i = 0; i < key_count; i++) {
krb5adm_ret = krb5_kt_add_entry(m_krb5admContext, keytab, &keys[i]);
if (krb5adm_ret) {
if (errstr) *errstr = i18n("%1<p>Details:<br>Failed to execute krb5_kt_add_entry (code %2)").arg(krb5_get_error_message(m_krb5admContext, krb5adm_ret)).arg(krb5adm_ret);
}
}
if (admincreds.password != "") {
kadminProc.enableLocalEcho(false);
kadminProc.writeLine(admincreds.password, true);
do { // Discard our own input
prompt = readFullLineFromPtyProcess(&kadminProc);
printf("(kadmin) '%s'\n", prompt.ascii());
} while (prompt == "");
prompt = prompt.stripWhiteSpace();
if (!krb5adm_ret) {
// Success!
retcode = 0;
}
}
if (prompt.contains("authentication failed")) {
if (errstr) *errstr = detailedKAdminErrorMessage(prompt);
kadminProc.enableLocalEcho(false);
kadminProc.writeLine("quit", true);
return 1;
}
else {
// Extract whatever default is in the [brackets] and feed it back to kadmin
TQString defaultParam;
int leftbracket = prompt.find("[");
int rightbracket = prompt.find("]");
if ((leftbracket >= 0) && (rightbracket >= 0)) {
leftbracket++;
defaultParam = prompt.mid(leftbracket, rightbracket-leftbracket);
}
command = TQCString(defaultParam);
kadminProc.enableLocalEcho(false);
kadminProc.writeLine(command, true);
do { // Discard our own input
prompt = readFullLineFromPtyProcess(&kadminProc);
printf("(kadmin) '%s'\n", prompt.ascii());
} while ((prompt == TQString(command)) || (prompt == ""));
prompt = prompt.stripWhiteSpace();
free(keys);
}
kadm5_free_principal_ent(m_krb5admHandle, &principal_record);
}
if (prompt != "kadmin>") {
if (errstr) *errstr = detailedKAdminErrorMessage(prompt);
kadminProc.enableLocalEcho(false);
kadminProc.writeLine("quit", true);
return 1;
}
krb5_kt_close(m_krb5admContext, keytab);
}
// Success!
kadminProc.enableLocalEcho(false);
kadminProc.writeLine("quit", true);
if (kadmin_unbind_needed) {
unbindKAdmin();
unbind(true); // Using kadmin can disrupt our LDAP connection
return 0;
}
if (errstr) *errstr = "Internal error. Verify that kadmin exists and can be executed.";
return 1; // Failure
}
return retcode;
}
int LDAPManager::writeCertificateFileIntoDirectory(TQByteArray cert, TQString attr, TQString* errstr) {
@ -5170,144 +5167,31 @@ int LDAPManager::writeOpenSSLConfigurationFile(LDAPRealmConfig realmcfg, LDAPUse
}
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());
TQString hoststring = "host/"+getMachineFQDN();
TQString prompt;
PtyProcess kadminProc;
kadminProc.exec(command, args);
prompt = readFullLineFromPtyProcess(&kadminProc);
prompt = prompt.stripWhiteSpace();
if (prompt == "kadmin>") {
command = TQCString("ext "+hoststring);
kadminProc.enableLocalEcho(false);
kadminProc.writeLine(command, true);
do { // Discard our own input
prompt = readFullLineFromPtyProcess(&kadminProc);
printf("(kadmin) '%s'\n", prompt.ascii());
} while ((prompt == TQString(command)) || (prompt == ""));
prompt = prompt.stripWhiteSpace();
if (prompt.endsWith(" Password:")) {
kadminProc.enableLocalEcho(false);
kadminProc.writeLine(adminPassword, true);
do { // Discard our own input
prompt = readFullLineFromPtyProcess(&kadminProc);
printf("(kadmin) '%s'\n", prompt.ascii());
} while (prompt == "");
prompt = prompt.stripWhiteSpace();
}
if (prompt.contains("authentication failed")) {
if (errstr) *errstr = prompt;
do { // Wait for command prompt
prompt = readFullLineFromPtyProcess(&kadminProc);
printf("(kadmin) '%s'\n", prompt.ascii());
} while (prompt == "");
kadminProc.enableLocalEcho(false);
kadminProc.writeLine("quit", true);
return 1;
}
else if (prompt.endsWith("Principal does not exist")) {
do { // Wait for command prompt
prompt = readFullLineFromPtyProcess(&kadminProc);
printf("(kadmin) '%s'\n", prompt.ascii());
} while (prompt == "");
command = TQCString("ank --random-key "+hoststring);
kadminProc.enableLocalEcho(false);
kadminProc.writeLine(command, true);
do { // Discard our own input
prompt = readFullLineFromPtyProcess(&kadminProc);
printf("(kadmin) '%s'\n", prompt.ascii());
} while ((prompt == TQString(command)) || (prompt == ""));
prompt = prompt.stripWhiteSpace();
// Use all defaults
while (prompt != "kadmin>") {
if (prompt.endsWith(" Password:")) {
kadminProc.enableLocalEcho(false);
kadminProc.writeLine(adminPassword, true);
do { // Discard our own input
prompt = readFullLineFromPtyProcess(&kadminProc);
printf("(kadmin) '%s'\n", prompt.ascii());
} while (prompt == "");
prompt = prompt.stripWhiteSpace();
}
if (prompt.contains("authentication failed")) {
if (errstr) *errstr = prompt;
do { // Wait for command prompt
prompt = readFullLineFromPtyProcess(&kadminProc);
printf("(kadmin) '%s'\n", prompt.ascii());
} while (prompt == "");
kadminProc.enableLocalEcho(false);
kadminProc.writeLine("quit", true);
return 1;
}
else {
// Extract whatever default is in the [brackets] and feed it back to kadmin
TQString defaultParam;
int leftbracket = prompt.find("[");
int rightbracket = prompt.find("]");
if ((leftbracket >= 0) && (rightbracket >= 0)) {
leftbracket++;
defaultParam = prompt.mid(leftbracket, rightbracket-leftbracket);
}
command = TQCString(defaultParam);
kadminProc.enableLocalEcho(false);
kadminProc.writeLine(command, true);
do { // Discard our own input
prompt = readFullLineFromPtyProcess(&kadminProc);
printf("(kadmin) '%s'\n", prompt.ascii());
} while ((prompt == TQString(command)) || (prompt == ""));
prompt = prompt.stripWhiteSpace();
}
}
command = TQCString("ext "+hoststring);
kadminProc.enableLocalEcho(false);
kadminProc.writeLine(command, true);
do { // Discard our own input
prompt = readFullLineFromPtyProcess(&kadminProc);
printf("(kadmin) '%s'\n", prompt.ascii());
} while ((prompt == TQString(command)) || (prompt == ""));
prompt = prompt.stripWhiteSpace();
if (prompt != "kadmin>") {
if (errstr) *errstr = prompt;
do { // Wait for command prompt
prompt = readFullLineFromPtyProcess(&kadminProc);
printf("(kadmin) '%s'\n", prompt.ascii());
} while (prompt == "");
kadminProc.enableLocalEcho(false);
kadminProc.writeLine("quit", true);
return 1;
}
LDAPCredentials admincreds;
admincreds.username = adminUserName;
admincreds.password = adminPassword;
admincreds.realm = adminRealm;
admincreds.use_gssapi = false;
// Success!
kadminProc.enableLocalEcho(false);
kadminProc.writeLine("quit", true);
TQString hoststring = "host/" + getMachineFQDN();
return 0;
}
else if (prompt == "kadmin>") {
// Success!
kadminProc.enableLocalEcho(false);
kadminProc.writeLine("quit", true);
return 0;
int retcode;
LDAPManager* ldap_mgr = new LDAPManager(adminRealm, TQString::null);
retcode = ldap_mgr->bindKAdmin(&admincreds, errstr);
if (!retcode) {
retcode = ldap_mgr->exportKeytabForPrincipal(hoststring, TQString::null, errstr);
if (retcode == 2) {
// Principal not found, create it
retcode = ldap_mgr->kAdminAddNewPrincipal(hoststring, TQString::null, errstr);
if (!retcode) {
retcode = ldap_mgr->exportKeytabForPrincipal(hoststring, TQString::null, errstr);
}
// Failure
if (errstr) *errstr = prompt;
while (prompt == "") { // Wait for command prompt
prompt = readFullLineFromPtyProcess(&kadminProc);
printf("(kadmin) '%s'\n", prompt.ascii());
}
kadminProc.enableLocalEcho(false);
kadminProc.writeLine("quit", true);
return 1;
ldap_mgr->unbindKAdmin();
}
delete ldap_mgr;
if (errstr) *errstr = "Internal error. Verify that kadmin exists and can be executed.";
return 1; // Failure
return retcode;
}
int LDAPManager::unbondRealm(LDAPRealmConfig realmcfg, TQString adminUserName, const char * adminPassword, TQString adminRealm, TQString *errstr) {

@ -589,7 +589,7 @@ class LDAPManager : public TQObject {
static int unbondRealm(LDAPRealmConfig realmcfg, TQString adminUserName, const char * adminPassword, TQString adminRealm, TQString *errstr=0);
private:
int bindKAdmin(TQString *errstr=0);
int bindKAdmin(LDAPCredentials *administrativeCredentials=NULL, TQString *errstr=0);
int unbindKAdmin(TQString *errstr=0);
int kAdminAddNewPrincipal(TQString principalName, TQString newPassword, TQString *errstr=0);
LDAPUserInfo parseLDAPUserRecord(LDAPMessage* entry);

Loading…
Cancel
Save