#include "autoconf.h"
#if HAVE_UNISTD_H
#include <unistd.h>
#endif
#include "ldap_main.h"
#include "ldap_service_stash.h"
#include <kdb5.h>
static krb5_error_code
krb5_validate_ldap_context(krb5_context context, krb5_ldap_context *ldap_context)
{
krb5_error_code st=0;
unsigned char *password=NULL;
if (ldap_context->bind_dn == NULL) {
st = EINVAL;
krb5_set_error_message(context, st, "LDAP bind dn value missing ");
goto err_out;
}
if (ldap_context->bind_pwd == NULL && ldap_context->service_password_file == NULL) {
st = EINVAL;
krb5_set_error_message(context, st, "LDAP bind password value missing ");
goto err_out;
}
if (ldap_context->bind_pwd == NULL && ldap_context->service_password_file !=
NULL && ldap_context->service_cert_path == NULL) {
if ((st=krb5_ldap_readpassword(context, ldap_context, &password)) != 0) {
prepend_err_str(context, "Error reading password from stash: ", st, st);
goto err_out;
}
if (!strncmp("{FILE}", (char *)password, 6)) {
ldap_context->service_cert_path = strdup((char *)password + strlen("{FILE}"));
if (password[strlen((char *)password) + 1] == '\0')
ldap_context->service_cert_pass = NULL;
else
ldap_context->service_cert_pass = strdup((char *)password +
strlen((char *)password) + 1);
free(password);
} else {
ldap_context->bind_pwd = (char *)password;
if (ldap_context->bind_pwd == NULL) {
st = EINVAL;
krb5_set_error_message(context, st, "Error reading password from stash");
goto err_out;
}
}
}
if (ldap_context->bind_pwd != NULL && strlen(ldap_context->bind_pwd) == 0) {
st = EINVAL;
krb5_set_error_message(context, st, "Service password length is zero");
goto err_out;
}
err_out:
return st;
}
static krb5_error_code
krb5_ldap_bind(ldap_context, ldap_server_handle)
krb5_ldap_context *ldap_context;
krb5_ldap_server_handle *ldap_server_handle;
{
krb5_error_code st=0;
struct berval bv={0, NULL}, *servercreds=NULL;
if (ldap_context->service_cert_path != NULL) {
st = ldap_sasl_bind_s(ldap_server_handle->ldap_handle,
NULL,
"EXTERNAL",
&bv,
NULL,
NULL,
&servercreds);
if (st == LDAP_SASL_BIND_IN_PROGRESS) {
st = ldap_sasl_bind_s(ldap_server_handle->ldap_handle,
NULL,
"EXTERNAL",
servercreds,
NULL,
NULL,
&servercreds);
}
} else {
bv.bv_val = ldap_context->bind_pwd;
bv.bv_len = strlen(ldap_context->bind_pwd);
st = ldap_sasl_bind_s(ldap_server_handle->ldap_handle,
ldap_context->bind_dn,
NULL, &bv, NULL,
NULL, NULL);
}
return st;
}
static krb5_error_code
krb5_ldap_initialize(ldap_context, server_info)
krb5_ldap_context *ldap_context;
krb5_ldap_server_info *server_info;
{
krb5_error_code st=0;
krb5_ldap_server_handle *ldap_server_handle=NULL;
ldap_server_handle = calloc(1, sizeof(krb5_ldap_server_handle));
if (ldap_server_handle == NULL) {
st = ENOMEM;
goto err_out;
}
if ((st = ldap_initialize(&ldap_server_handle->ldap_handle, server_info->server_name)) != 0) {
if (ldap_context->kcontext)
krb5_set_error_message (ldap_context->kcontext, KRB5_KDB_ACCESS_ERROR, "%s",
ldap_err2string(st));
st = KRB5_KDB_ACCESS_ERROR;
goto err_out;
}
if ((st=krb5_ldap_bind(ldap_context, ldap_server_handle)) == 0) {
ldap_server_handle->server_info_update_pending = FALSE;
server_info->server_status = ON;
krb5_update_ldap_handle(ldap_server_handle, server_info);
} else {
if (ldap_context->kcontext)
krb5_set_error_message (ldap_context->kcontext,
KRB5_KDB_ACCESS_ERROR, "%s",
ldap_err2string(st));
st = KRB5_KDB_ACCESS_ERROR;
server_info->server_status = OFF;
time(&server_info->downtime);
free(ldap_server_handle);
}
err_out:
return st;
}
krb5_error_code
krb5_ldap_db_init(krb5_context context, krb5_ldap_context *ldap_context)
{
krb5_error_code st=0;
krb5_boolean sasl_mech_supported=TRUE;
int cnt=0, version=LDAP_VERSION3;
struct timeval local_timelimit = {10,0};
if ((st=krb5_validate_ldap_context(context, ldap_context)) != 0)
goto err_out;
ldap_set_option(NULL, LDAP_OPT_PROTOCOL_VERSION, &version);
#ifdef LDAP_OPT_NETWORK_TIMEOUT
ldap_set_option(NULL, LDAP_OPT_NETWORK_TIMEOUT, &local_timelimit);
#elif defined LDAP_X_OPT_CONNECT_TIMEOUT
ldap_set_option(NULL, LDAP_X_OPT_CONNECT_TIMEOUT, &local_timelimit);
#endif
HNDL_LOCK(ldap_context);
while (ldap_context->server_info_list[cnt] != NULL) {
krb5_ldap_server_info *server_info=NULL;
server_info = ldap_context->server_info_list[cnt];
if (server_info->server_status == NOTSET) {
int conns=0;
if (ldap_context->service_cert_path != NULL) {
if (has_sasl_external_mech(context, server_info->server_name) == 1) {
cnt++;
sasl_mech_supported = FALSE;
continue;
}
sasl_mech_supported = TRUE;
}
krb5_clear_error_message(context);
for (conns=0; conns < ldap_context->max_server_conns; ++conns) {
if ((st=krb5_ldap_initialize(ldap_context, server_info)) != 0)
break;
}
if (server_info->server_status == ON)
break;
}
++cnt;
}
HNDL_UNLOCK(ldap_context);
err_out:
if (sasl_mech_supported == FALSE) {
st = KRB5_KDB_ACCESS_ERROR;
krb5_set_error_message (context, st,
"Certificate based authentication requested but "
"not supported by LDAP servers");
}
return (st);
}
krb5_error_code
krb5_ldap_db_single_init(krb5_ldap_context *ldap_context)
{
krb5_error_code st=0;
int cnt=0;
krb5_ldap_server_info *server_info=NULL;
while (ldap_context->server_info_list[cnt] != NULL) {
server_info = ldap_context->server_info_list[cnt];
if ((server_info->server_status == NOTSET || server_info->server_status == ON)) {
if (server_info->num_conns < ldap_context->max_server_conns-1) {
st = krb5_ldap_initialize(ldap_context, server_info);
if (st == LDAP_SUCCESS)
goto cleanup;
}
}
++cnt;
}
cnt = 0;
while (ldap_context->server_info_list[cnt] != NULL) {
server_info = ldap_context->server_info_list[cnt];
st = krb5_ldap_initialize(ldap_context, server_info);
if (st == LDAP_SUCCESS)
goto cleanup;
++cnt;
}
cleanup:
return (st);
}
krb5_error_code
krb5_ldap_rebind(ldap_context, ldap_server_handle)
krb5_ldap_context *ldap_context;
krb5_ldap_server_handle **ldap_server_handle;
{
krb5_ldap_server_handle *handle = *ldap_server_handle;
if ((ldap_initialize(&handle->ldap_handle, handle->server_info->server_name) != LDAP_SUCCESS)
|| (krb5_ldap_bind(ldap_context, handle) != LDAP_SUCCESS))
return krb5_ldap_request_next_handle_from_pool(ldap_context, ldap_server_handle);
return LDAP_SUCCESS;
}
krb5_error_code krb5_ldap_lib_init()
{
return 0;
}
krb5_error_code krb5_ldap_lib_cleanup()
{
return 0;
}
krb5_error_code
krb5_ldap_free_ldap_context(krb5_ldap_context *ldap_context)
{
if (ldap_context == NULL)
return 0;
krb5_ldap_free_krbcontainer_params(ldap_context->krbcontainer);
ldap_context->krbcontainer = NULL;
krb5_ldap_free_realm_params(ldap_context->lrparams);
ldap_context->lrparams = NULL;
krb5_ldap_free_server_params(ldap_context);
return 0;
}
krb5_error_code
krb5_ldap_close(krb5_context context)
{
kdb5_dal_handle *dal_handle=NULL;
krb5_ldap_context *ldap_context=NULL;
if (context == NULL ||
context->db_context == NULL ||
((kdb5_dal_handle *)context->db_context)->db_context == NULL)
return 0;
dal_handle = (kdb5_dal_handle *) context->db_context;
ldap_context = (krb5_ldap_context *) dal_handle->db_context;
dal_handle->db_context = NULL;
krb5_ldap_free_ldap_context(ldap_context);
return 0;
}