/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */ /* plugins/kdb/ldap/libkdb_ldap/kdb_ldap.c */ /* * Copyright (c) 2004-2005, Novell, Inc. * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * The copyright holder's name is not used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include "autoconf.h" #if HAVE_UNISTD_H #include #endif #include #include "kdb_ldap.h" #include "ldap_misc.h" #include #include /* * ldap get age */ krb5_error_code krb5_ldap_get_age(context, db_name, age) krb5_context context; char *db_name; time_t *age; { time (age); return 0; } /* * read startup information - kerberos and realm container */ krb5_error_code krb5_ldap_read_startup_information(krb5_context context) { krb5_error_code retval = 0; kdb5_dal_handle *dal_handle=NULL; krb5_ldap_context *ldap_context=NULL; int mask = 0; SETUP_CONTEXT(); if ((retval=krb5_ldap_read_krbcontainer_dn(context, &(ldap_context->container_dn)))) { prepend_err_str(context, _("Unable to read Kerberos container"), retval, retval); goto cleanup; } if ((retval=krb5_ldap_read_realm_params(context, context->default_realm, &(ldap_context->lrparams), &mask))) { prepend_err_str(context, _("Unable to read Realm"), retval, retval); goto cleanup; } if (((mask & LDAP_REALM_MAXTICKETLIFE) == 0) || ((mask & LDAP_REALM_MAXRENEWLIFE) == 0) || ((mask & LDAP_REALM_KRBTICKETFLAGS) == 0)) { kadm5_config_params params_in, params_out; memset(¶ms_in, 0, sizeof(params_in)); memset(¶ms_out, 0, sizeof(params_out)); retval = kadm5_get_config_params(context, 1, ¶ms_in, ¶ms_out); if (retval) { if ((mask & LDAP_REALM_MAXTICKETLIFE) == 0) { ldap_context->lrparams->max_life = 24 * 60 * 60; /* 1 day */ } if ((mask & LDAP_REALM_MAXRENEWLIFE) == 0) { ldap_context->lrparams->max_renewable_life = 0; } if ((mask & LDAP_REALM_KRBTICKETFLAGS) == 0) { ldap_context->lrparams->tktflags = KRB5_KDB_DEF_FLAGS; } retval = 0; goto cleanup; } if ((mask & LDAP_REALM_MAXTICKETLIFE) == 0) { if (params_out.mask & KADM5_CONFIG_MAX_LIFE) ldap_context->lrparams->max_life = params_out.max_life; } if ((mask & LDAP_REALM_MAXRENEWLIFE) == 0) { if (params_out.mask & KADM5_CONFIG_MAX_RLIFE) ldap_context->lrparams->max_renewable_life = params_out.max_rlife; } if ((mask & LDAP_REALM_KRBTICKETFLAGS) == 0) { if (params_out.mask & KADM5_CONFIG_FLAGS) ldap_context->lrparams->tktflags = params_out.flags; } kadm5_free_config_params(context, ¶ms_out); } cleanup: return retval; } /* * Interrogate the root DSE (zero length DN) for an attribute * value assertion. */ static int has_rootdse_ava(krb5_context context, char *ldap_server, char *attribute, char *value) { int i=0, flag=0, ret=0, retval=0; char *attrs[2], **values=NULL; LDAP *ld=NULL; LDAPMessage *msg=NULL, *res=NULL; struct berval cred; attrs[0] = attribute; attrs[1] = NULL; retval = ldap_initialize(&ld, ldap_server); if (retval != LDAP_SUCCESS) { ret = 2; /* Don't know */ goto cleanup; } cred.bv_val = ""; cred.bv_len = 0; /* Anonymous bind */ retval = ldap_sasl_bind_s(ld, "", NULL, &cred, NULL, NULL, NULL); if (retval != LDAP_SUCCESS) { ret = 2; /* Don't know */ goto cleanup; } retval = ldap_search_ext_s(ld, "", LDAP_SCOPE_BASE, NULL, attrs, 0, NULL, NULL, NULL, 0, &res); if (retval != LDAP_SUCCESS) { ret = 2; /* Don't know */ goto cleanup; } msg = ldap_first_message(ld, res); if (msg == NULL) { ret = 2; /* Don't know */ goto cleanup; } values = ldap_get_values(ld, msg, attribute); if (values == NULL) { ret = 1; /* Not supported */ goto cleanup; } for (i = 0; values[i] != NULL; i++) { if (strcmp(values[i], value) == 0) { flag = 1; break; } } if (flag != 1) { ret = 1; /* Not supported */ goto cleanup; } cleanup: if (values != NULL) ldap_value_free(values); if (res != NULL) ldap_msgfree(res); if (ld != NULL) ldap_unbind_ext_s(ld, NULL, NULL); return ret; } #define ERR_MSG1 _("Unable to check if SASL EXTERNAL mechanism is supported by LDAP server. Proceeding anyway ...") #define ERR_MSG2 _("SASL EXTERNAL mechanism not supported by LDAP server. Can't perform certificate-based bind.") /* Function to check if a LDAP server supports the SASL external mechanism *Return values: * 0 => supports * 1 => does not support * 2 => don't know */ int has_sasl_external_mech(krb5_context context, char *ldap_server) { int ret; ret = has_rootdse_ava(context, ldap_server, "supportedSASLMechanisms", "EXTERNAL"); switch (ret) { case 1: /* not supported */ krb5_set_error_message(context, 1, "%s", ERR_MSG2); break; case 2: /* don't know */ krb5_set_error_message(context, 1, "%s", ERR_MSG1); break; default: break; } return ret; } int has_modify_increment(context, ldap_server) krb5_context context; char *ldap_server; { return has_rootdse_ava(context, ldap_server, "supportedFeatures", "1.3.6.1.1.14"); } void * krb5_ldap_alloc(krb5_context context, void *ptr, size_t size) { return realloc(ptr, size); } void krb5_ldap_free(krb5_context context, void *ptr) { free(ptr); } krb5_error_code krb5_ldap_open(krb5_context context, char *conf_section, char **db_args, int mode) { krb5_error_code status = 0; krb5_ldap_context *ldap_context=NULL; /* Clear the global error string */ krb5_clear_error_message(context); ldap_context = k5alloc(sizeof(krb5_ldap_context), &status); if (ldap_context == NULL) goto clean_n_exit; context->dal_handle->db_context = ldap_context; ldap_context->kcontext = context; status = krb5_ldap_parse_db_params(context, db_args); if (status) { prepend_err_str(context, _("Error processing LDAP DB params:"), status, status); goto clean_n_exit; } status = krb5_ldap_read_server_params(context, conf_section, mode & 0x0300); if (status) { prepend_err_str(context, _("Error reading LDAP server params:"), status, status); goto clean_n_exit; } if ((status=krb5_ldap_db_init(context, ldap_context)) != 0) { goto clean_n_exit; } if ((status=krb5_ldap_read_startup_information(context)) != 0) { goto clean_n_exit; } clean_n_exit: /* may be clearing up is not required db_fini might do it for us, check out */ if (status) { krb5_ldap_close(context); } return status; } #include "ldap_err.h" int set_ldap_error(krb5_context ctx, int st, int op) { int translated_st = translate_ldap_error(st, op); krb5_set_error_message(ctx, translated_st, "%s", ldap_err2string(st)); return translated_st; } void prepend_err_str(krb5_context ctx, const char *str, krb5_error_code err, krb5_error_code oerr) { const char *omsg; omsg = krb5_get_error_message(ctx, oerr); krb5_set_error_message(ctx, err, "%s %s", str, omsg); krb5_free_error_message(ctx, omsg); } extern krb5int_access accessor; MAKE_INIT_FUNCTION(kldap_init_fn); int kldap_init_fn(void) { /* Global (per-module) initialization. */ return krb5int_accessor (&accessor, KRB5INT_ACCESS_VERSION); } int kldap_ensure_initialized(void) { return CALL_INIT_FUNCTION (kldap_init_fn); } krb5_error_code krb5_ldap_check_policy_as(krb5_context kcontext, krb5_kdc_req *request, krb5_db_entry *client, krb5_db_entry *server, krb5_timestamp kdc_time, const char **status, krb5_pa_data ***e_data) { krb5_error_code retval; retval = krb5_ldap_lockout_check_policy(kcontext, client, kdc_time); if (retval == KRB5KDC_ERR_CLIENT_REVOKED) *status = "LOCKED_OUT"; return retval; } void krb5_ldap_audit_as_req(krb5_context kcontext, krb5_kdc_req *request, krb5_db_entry *client, krb5_db_entry *server, krb5_timestamp authtime, krb5_error_code error_code) { (void) krb5_ldap_lockout_audit(kcontext, client, authtime, error_code); } krb5_error_code krb5_ldap_check_allowed_to_delegate(krb5_context context, krb5_const_principal client, const krb5_db_entry *server, krb5_const_principal proxy) { krb5_error_code code; krb5_tl_data *tlp; code = KRB5KDC_ERR_POLICY; for (tlp = server->tl_data; tlp != NULL; tlp = tlp->tl_data_next) { krb5_principal acl; if (tlp->tl_data_type != KRB5_TL_CONSTRAINED_DELEGATION_ACL) continue; if (krb5_parse_name(context, (char *)tlp->tl_data_contents, &acl) != 0) continue; if (krb5_principal_compare(context, proxy, acl)) { code = 0; krb5_free_principal(context, acl); break; } krb5_free_principal(context, acl); } return code; }