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; } /* Check if the returned 'password' is actually the path of a certificate */ if (!strncmp("{FILE}", (char *)password, 6)) { /* 'password' format: <path>\0<password> */ 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; } } } /* NULL password not allowed */ 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; }
krb5_error_code krb5_read_tkt_policy(krb5_context context, krb5_ldap_context *ldap_context, krb5_db_entry *entries, char *policy) { krb5_error_code st=0; unsigned int mask=0, omask=0; int tkt_mask=(KDB_MAX_LIFE_ATTR | KDB_MAX_RLIFE_ATTR | KDB_TKT_FLAGS_ATTR); krb5_ldap_policy_params *tktpoldnparam=NULL; if ((st=krb5_get_attributes_mask(context, entries, &mask)) != 0) goto cleanup; if ((mask & tkt_mask) == tkt_mask) goto cleanup; if (policy != NULL) { st = krb5_ldap_read_policy(context, policy, &tktpoldnparam, &omask); if (st && st != KRB5_KDB_NOENTRY) { prepend_err_str(context, _("Error reading ticket policy. "), st, st); goto cleanup; } st = 0; /* reset the return status */ } if ((mask & KDB_MAX_LIFE_ATTR) == 0) { if ((omask & KDB_MAX_LIFE_ATTR) == KDB_MAX_LIFE_ATTR) entries->max_life = tktpoldnparam->maxtktlife; else if (ldap_context->lrparams->max_life) entries->max_life = ldap_context->lrparams->max_life; } if ((mask & KDB_MAX_RLIFE_ATTR) == 0) { if ((omask & KDB_MAX_RLIFE_ATTR) == KDB_MAX_RLIFE_ATTR) entries->max_renewable_life = tktpoldnparam->maxrenewlife; else if (ldap_context->lrparams->max_renewable_life) entries->max_renewable_life = ldap_context->lrparams->max_renewable_life; } if ((mask & KDB_TKT_FLAGS_ATTR) == 0) { if ((omask & KDB_TKT_FLAGS_ATTR) == KDB_TKT_FLAGS_ATTR) entries->attributes = tktpoldnparam->tktflags; else if (ldap_context->lrparams->tktflags) entries->attributes |= ldap_context->lrparams->tktflags; } krb5_ldap_free_policy(context, tktpoldnparam); cleanup: return st; }
/* Ensure that we have the parameters we need to authenticate to the LDAP * server. Read the password if necessary. */ static krb5_error_code validate_context(krb5_context context, krb5_ldap_context *ctx) { krb5_error_code ret; if (ctx->sasl_mech != NULL) { /* Read the password for use as the SASL secret if we can, but do not * require one as not all mechanisms need it. */ if (ctx->bind_pwd == NULL && ctx->sasl_authcid != NULL && ctx->service_password_file != NULL) { (void)krb5_ldap_readpassword(context, ctx->service_password_file, ctx->sasl_authcid, &ctx->bind_pwd); } return 0; } /* For a simple bind, a DN and password are required. */ if (ctx->bind_dn == NULL) { k5_setmsg(context, EINVAL, _("LDAP bind dn value missing")); return EINVAL; } if (ctx->bind_pwd == NULL && ctx->service_password_file == NULL) { k5_setmsg(context, EINVAL, _("LDAP bind password value missing")); return EINVAL; } if (ctx->bind_pwd == NULL && ctx->service_password_file != NULL) { ret = krb5_ldap_readpassword(context, ctx->service_password_file, ctx->bind_dn, &ctx->bind_pwd); if (ret) { prepend_err_str(context, _("Error reading password from stash: "), ret, ret); return ret; } } /* An empty password is not allowed. */ if (*ctx->bind_pwd == '\0') { k5_setmsg(context, EINVAL, _("Service password length is zero")); return EINVAL; } return 0; }
/* * This function will create a krbcontainer and realm on the LDAP Server, with * the specified attributes. */ krb5_error_code krb5_ldap_create(krb5_context context, char *conf_section, char **db_args) { krb5_error_code status = 0; char **t_ptr = db_args; krb5_ldap_realm_params *rparams = NULL; kdb5_dal_handle *dal_handle = NULL; krb5_ldap_context *ldap_context=NULL; krb5_boolean realm_obj_created = FALSE; krb5_boolean krbcontainer_obj_created = FALSE; krb5_ldap_krbcontainer_params kparams = {0}; int srv_cnt = 0; int mask = 0; /* Clear the global error string */ krb5_clear_error_message(context); ldap_context = malloc(sizeof(krb5_ldap_context)); if (ldap_context == NULL) { status = ENOMEM; goto cleanup; } memset(ldap_context, 0, sizeof(*ldap_context)); ldap_context->kcontext = context; /* populate ldap_context with ldap specific options */ while (t_ptr && *t_ptr) { char *opt = NULL, *val = NULL; if ((status = krb5_ldap_get_db_opt(*t_ptr, &opt, &val)) != 0) { goto cleanup; } if (opt && !strcmp(opt, "binddn")) { if (ldap_context->bind_dn) { free (opt); free (val); status = EINVAL; krb5_set_error_message (context, status, "'binddn' missing"); goto cleanup; } if (val == NULL) { status = EINVAL; krb5_set_error_message (context, status, "'binddn' value missing"); free(opt); goto cleanup; } ldap_context->bind_dn = strdup(val); if (ldap_context->bind_dn == NULL) { free (opt); free (val); status = ENOMEM; goto cleanup; } } else if (opt && !strcmp(opt, "nconns")) { if (ldap_context->max_server_conns) { free (opt); free (val); status = EINVAL; krb5_set_error_message (context, status, "'nconns' missing"); goto cleanup; } if (val == NULL) { status = EINVAL; krb5_set_error_message (context, status, "'nconns' value missing"); free(opt); goto cleanup; } ldap_context->max_server_conns = atoi(val) ? atoi(val) : DEFAULT_CONNS_PER_SERVER; } else if (opt && !strcmp(opt, "bindpwd")) { if (ldap_context->bind_pwd) { free (opt); free (val); status = EINVAL; krb5_set_error_message (context, status, "'bindpwd' missing"); goto cleanup; } if (val == NULL) { status = EINVAL; krb5_set_error_message (context, status, "'bindpwd' value missing"); free(opt); goto cleanup; } ldap_context->bind_pwd = strdup(val); if (ldap_context->bind_pwd == NULL) { free (opt); free (val); status = ENOMEM; goto cleanup; } } else if (opt && !strcmp(opt, "host")) { if (val == NULL) { status = EINVAL; krb5_set_error_message (context, status, "'host' value missing"); free(opt); goto cleanup; } if (ldap_context->server_info_list == NULL) ldap_context->server_info_list = (krb5_ldap_server_info **) calloc(SERV_COUNT+1, sizeof(krb5_ldap_server_info *)); if (ldap_context->server_info_list == NULL) { free (opt); free (val); status = ENOMEM; goto cleanup; } ldap_context->server_info_list[srv_cnt] = (krb5_ldap_server_info *) calloc(1, sizeof(krb5_ldap_server_info)); if (ldap_context->server_info_list[srv_cnt] == NULL) { free (opt); free (val); status = ENOMEM; goto cleanup; } ldap_context->server_info_list[srv_cnt]->server_status = NOTSET; ldap_context->server_info_list[srv_cnt]->server_name = strdup(val); if (ldap_context->server_info_list[srv_cnt]->server_name == NULL) { free (opt); free (val); status = ENOMEM; goto cleanup; } srv_cnt++; } else { /* ignore hash argument. Might have been passed from create */ status = EINVAL; if (opt && !strcmp(opt, "temporary")) { /* * temporary is passed in when kdb5_util load without -update is done. * This is unsupported by the LDAP plugin. */ krb5_set_error_message(context, status, _("creation of LDAP entries aborted, " "plugin requires -update argument")); } else { krb5_set_error_message(context, status, _("unknown option \'%s\'"), opt?opt:val); } free(opt); free(val); goto cleanup; } free(opt); free(val); t_ptr++; } dal_handle = context->dal_handle; dal_handle->db_context = (kdb5_dal_handle *) ldap_context; status = krb5_ldap_read_server_params(context, conf_section, KRB5_KDB_SRV_TYPE_ADMIN); if (status) { dal_handle->db_context = NULL; prepend_err_str (context, "Error reading LDAP server params: ", status, status); goto cleanup; } status = krb5_ldap_db_init(context, ldap_context); if (status) { goto cleanup; } /* read the kerberos container */ if ((status = krb5_ldap_read_krbcontainer_params(context, &(ldap_context->krbcontainer))) == KRB5_KDB_NOENTRY) { /* Read the kerberos container location from configuration file */ if (ldap_context->conf_section) { if ((status = profile_get_string(context->profile, KDB_MODULE_SECTION, ldap_context->conf_section, KRB5_CONF_LDAP_KERBEROS_CONTAINER_DN, NULL, &kparams.DN)) != 0) { goto cleanup; } } if (kparams.DN == NULL) { if ((status = profile_get_string(context->profile, KDB_MODULE_DEF_SECTION, KRB5_CONF_LDAP_KERBEROS_CONTAINER_DN, NULL, NULL, &kparams.DN)) != 0) { goto cleanup; } } /* create the kerberos container */ status = krb5_ldap_create_krbcontainer(context, ((kparams.DN != NULL) ? &kparams : NULL)); if (status) goto cleanup; krbcontainer_obj_created = TRUE; status = krb5_ldap_read_krbcontainer_params(context, &(ldap_context->krbcontainer)); if (status) goto cleanup; } else if (status) { goto cleanup; } rparams = (krb5_ldap_realm_params *) malloc(sizeof(krb5_ldap_realm_params)); if (rparams == NULL) { status = ENOMEM; goto cleanup; } memset(rparams, 0, sizeof(*rparams)); rparams->realm_name = strdup(context->default_realm); if (rparams->realm_name == NULL) { status = ENOMEM; goto cleanup; } if ((status = krb5_ldap_create_realm(context, rparams, mask))) goto cleanup; /* We just created the Realm container. Here starts our transaction tracking */ realm_obj_created = TRUE; /* verify realm object */ if ((status = krb5_ldap_read_realm_params(context, rparams->realm_name, &(ldap_context->lrparams), &mask))) goto cleanup; cleanup: /* If the krbcontainer/realm creation is not complete, do the roll-back here */ if ((krbcontainer_obj_created) && (!realm_obj_created)) { int rc; rc = krb5_ldap_delete_krbcontainer(context, ((kparams.DN != NULL) ? &kparams : NULL)); krb5_set_error_message(context, rc, _("could not complete roll-back, error " "deleting Kerberos Container")); } /* should call krb5_ldap_free_krbcontainer_params() but can't */ if (kparams.DN != NULL) krb5_xfree(kparams.DN); if (rparams) krb5_ldap_free_realm_params(rparams); return(status); }
/* * This function will create a krbcontainer and realm on the LDAP Server, with * the specified attributes. */ krb5_error_code krb5_ldap_create (krb5_context context, char *conf_section, char **db_args) { krb5_error_code status = 0; char **t_ptr = db_args; krb5_ldap_realm_params *rparams = NULL; kdb5_dal_handle *dal_handle = NULL; krb5_ldap_context *ldap_context=NULL; krb5_boolean realm_obj_created = FALSE; krb5_boolean krbcontainer_obj_created = FALSE; krb5_ldap_krbcontainer_params kparams = {0}; int srv_cnt = 0; int mask = 0; #ifdef HAVE_EDIRECTORY int i = 0, rightsmask = 0; #endif /* Clear the global error string */ krb5_clear_error_message(context); ldap_context = malloc(sizeof(krb5_ldap_context)); if (ldap_context == NULL) { status = ENOMEM; goto cleanup; } memset(ldap_context, 0, sizeof(*ldap_context)); ldap_context->kcontext = context; /* populate ldap_context with ldap specific options */ while (t_ptr && *t_ptr) { char *opt = NULL, *val = NULL; if ((status = krb5_ldap_get_db_opt(*t_ptr, &opt, &val)) != 0) { goto cleanup; } if (opt && !strcmp(opt, "binddn")) { if (ldap_context->bind_dn) { free (opt); free (val); status = EINVAL; krb5_set_error_message (context, status, gettext("'binddn' missing")); goto cleanup; } if (val == NULL) { status = EINVAL; krb5_set_error_message (context, status, gettext("'binddn' value missing")); free(opt); goto cleanup; } ldap_context->bind_dn = strdup(val); if (ldap_context->bind_dn == NULL) { free (opt); free (val); status = ENOMEM; goto cleanup; } } else if (opt && !strcmp(opt, "nconns")) { if (ldap_context->max_server_conns) { free (opt); free (val); status = EINVAL; krb5_set_error_message (context, status, gettext("'nconns' missing")); goto cleanup; } if (val == NULL) { status = EINVAL; krb5_set_error_message (context, status, gettext("'nconns' value missing")); free(opt); goto cleanup; } ldap_context->max_server_conns = atoi(val) ? atoi(val) : DEFAULT_CONNS_PER_SERVER; } else if (opt && !strcmp(opt, "bindpwd")) { if (ldap_context->bind_pwd) { free (opt); free (val); status = EINVAL; krb5_set_error_message (context, status, gettext("'bindpwd' missing")); goto cleanup; } if (val == NULL) { status = EINVAL; krb5_set_error_message (context, status, gettext("'bindpwd' value missing")); free(opt); goto cleanup; } ldap_context->bind_pwd = strdup(val); if (ldap_context->bind_pwd == NULL) { free (opt); free (val); status = ENOMEM; goto cleanup; } } else if (opt && !strcmp(opt, "host")) { if (val == NULL) { status = EINVAL; krb5_set_error_message (context, status, gettext("'host' value missing")); free(opt); goto cleanup; } if (ldap_context->server_info_list == NULL) ldap_context->server_info_list = (krb5_ldap_server_info **) calloc(SERV_COUNT+1, sizeof(krb5_ldap_server_info *)); if (ldap_context->server_info_list == NULL) { free (opt); free (val); status = ENOMEM; goto cleanup; } ldap_context->server_info_list[srv_cnt] = (krb5_ldap_server_info *) calloc(1, sizeof(krb5_ldap_server_info)); if (ldap_context->server_info_list[srv_cnt] == NULL) { free (opt); free (val); status = ENOMEM; goto cleanup; } ldap_context->server_info_list[srv_cnt]->server_status = NOTSET; ldap_context->server_info_list[srv_cnt]->server_name = strdup(val); if (ldap_context->server_info_list[srv_cnt]->server_name == NULL) { free (opt); free (val); status = ENOMEM; goto cleanup; } srv_cnt++; #ifdef HAVE_EDIRECTORY } else if (opt && !strcmp(opt, "cert")) { if (val == NULL) { status = EINVAL; krb5_set_error_message (context, status, gettext("'cert' value missing")); free(opt); goto cleanup; } if (ldap_context->root_certificate_file == NULL) { ldap_context->root_certificate_file = strdup(val); if (ldap_context->root_certificate_file == NULL) { free (opt); free (val); status = ENOMEM; goto cleanup; } } else { void *tmp=NULL; char *oldstr = NULL; unsigned int len=0; oldstr = strdup(ldap_context->root_certificate_file); if (oldstr == NULL) { free (opt); free (val); status = ENOMEM; goto cleanup; } tmp = ldap_context->root_certificate_file; len = strlen(ldap_context->root_certificate_file) + 2 + strlen(val); ldap_context->root_certificate_file = realloc(ldap_context->root_certificate_file, len); if (ldap_context->root_certificate_file == NULL) { free (tmp); free (opt); free (val); status = ENOMEM; goto cleanup; } memset(ldap_context->root_certificate_file, 0, len); sprintf(ldap_context->root_certificate_file,"%s %s", oldstr, val); free (oldstr); } #endif } else { /* ignore hash argument. Might have been passed from create */ status = EINVAL; if (opt && !strcmp(opt, "temporary")) { /* * temporary is passed in when kdb5_util load without -update is done. * This is unsupported by the LDAP plugin. */ krb5_set_error_message (context, status, gettext("creation of LDAP entries aborted, plugin requires -update argument")); } else { krb5_set_error_message (context, status, gettext("unknown option \'%s\'"), opt?opt:val); } free(opt); free(val); goto cleanup; } free(opt); free(val); t_ptr++; } dal_handle = (kdb5_dal_handle *) context->db_context; dal_handle->db_context = (kdb5_dal_handle *) ldap_context; status = krb5_ldap_read_server_params(context, conf_section, KRB5_KDB_SRV_TYPE_ADMIN); if (status) { dal_handle->db_context = NULL; prepend_err_str (context, gettext("Error reading LDAP server params: "), status, status); goto cleanup; } status = krb5_ldap_db_init(context, ldap_context); if (status) { goto cleanup; } /* read the kerberos container */ if ((status = krb5_ldap_read_krbcontainer_params(context, &(ldap_context->krbcontainer))) == KRB5_KDB_NOENTRY) { /* Read the kerberos container location from configuration file */ if (ldap_context->conf_section) { if ((status = profile_get_string(context->profile, KDB_MODULE_SECTION, ldap_context->conf_section, "ldap_kerberos_container_dn", NULL, &kparams.DN)) != 0) { goto cleanup; } } if (kparams.DN == NULL) { if ((status = profile_get_string(context->profile, KDB_MODULE_DEF_SECTION, "ldap_kerberos_container_dn", NULL, NULL, &kparams.DN)) != 0) { goto cleanup; } } /* create the kerberos container */ status = krb5_ldap_create_krbcontainer(context, ((kparams.DN != NULL) ? &kparams : NULL)); if (status) goto cleanup; krbcontainer_obj_created = TRUE; status = krb5_ldap_read_krbcontainer_params(context, &(ldap_context->krbcontainer)); if (status) { krb5_set_error_message(context, status, gettext("while reading kerberos container information")); goto cleanup; } } else if (status) { krb5_set_error_message(context, status, gettext("while reading kerberos container information")); goto cleanup; } rparams = (krb5_ldap_realm_params *) malloc(sizeof(krb5_ldap_realm_params)); if (rparams == NULL) { status = ENOMEM; goto cleanup; } memset(rparams, 0, sizeof(*rparams)); rparams->realm_name = strdup(context->default_realm); if (rparams->realm_name == NULL) { status = ENOMEM; goto cleanup; } if ((status = krb5_ldap_create_realm(context, rparams, mask))) { krb5_set_error_message(context, status, gettext("while creating realm object entry")); goto cleanup; } /* We just created the Realm container. Here starts our transaction tracking */ realm_obj_created = TRUE; /* verify realm object */ if ((status = krb5_ldap_read_realm_params(context, rparams->realm_name, &(ldap_context->lrparams), &mask))) { krb5_set_error_message(context, status, gettext("while reading realm object entry")); goto cleanup; } #ifdef HAVE_EDIRECTORY if ((mask & LDAP_REALM_KDCSERVERS) || (mask & LDAP_REALM_ADMINSERVERS) || (mask & LDAP_REALM_PASSWDSERVERS)) { rightsmask =0; rightsmask |= LDAP_REALM_RIGHTS; rightsmask |= LDAP_SUBTREE_RIGHTS; if ((rparams != NULL) && (rparams->kdcservers != NULL)) { for (i=0; (rparams->kdcservers[i] != NULL); i++) { if ((status=krb5_ldap_add_service_rights(context, LDAP_KDC_SERVICE, rparams->kdcservers[i], rparams->realm_name, rparams->subtree, rightsmask)) != 0) { goto cleanup; } } } rightsmask = 0; rightsmask |= LDAP_REALM_RIGHTS; rightsmask |= LDAP_SUBTREE_RIGHTS; if ((rparams != NULL) && (rparams->adminservers != NULL)) { for (i=0; (rparams->adminservers[i] != NULL); i++) { if ((status=krb5_ldap_add_service_rights(context, LDAP_ADMIN_SERVICE, rparams->adminservers[i], rparams->realm_name, rparams->subtree, rightsmask)) != 0) { goto cleanup; } } } rightsmask = 0; rightsmask |= LDAP_REALM_RIGHTS; rightsmask |= LDAP_SUBTREE_RIGHTS; if ((rparams != NULL) && (rparams->passwdservers != NULL)) { for (i=0; (rparams->passwdservers[i] != NULL); i++) { if ((status=krb5_ldap_add_service_rights(context, LDAP_PASSWD_SERVICE, rparams->passwdservers[i], rparams->realm_name, rparams->subtree, rightsmask)) != 0) { goto cleanup; } } } } #endif cleanup: /* If the krbcontainer/realm creation is not complete, do the roll-back here */ if ((krbcontainer_obj_created) && (!realm_obj_created)) { int rc; rc = krb5_ldap_delete_krbcontainer(context, ((kparams.DN != NULL) ? &kparams : NULL)); krb5_set_error_message(context, rc, gettext("could not complete roll-back, error deleting Kerberos Container")); } /* should call krb5_ldap_free_krbcontainer_params() but can't */ if (kparams.DN != NULL) krb5_xfree(kparams.DN); if (rparams) krb5_ldap_free_realm_params(rparams); return(status); }
krb5_error_code krb5_ldap_put_principal(krb5_context context, krb5_db_entry *entry, char **db_args) { int l=0, kerberos_principal_object_type=0; krb5_error_code st=0, tempst=0; LDAP *ld=NULL; LDAPMessage *result=NULL, *ent=NULL; char *user=NULL, *subtree=NULL, *principal_dn=NULL; char **values=NULL, *strval[10]= {NULL}, errbuf[1024]; struct berval **bersecretkey=NULL; LDAPMod **mods=NULL; krb5_boolean create_standalone_prinicipal=FALSE; krb5_boolean krb_identity_exists=FALSE, establish_links=FALSE; char *standalone_principal_dn=NULL; krb5_tl_data *tl_data=NULL; krb5_key_data **keys=NULL; kdb5_dal_handle *dal_handle=NULL; krb5_ldap_context *ldap_context=NULL; krb5_ldap_server_handle *ldap_server_handle=NULL; osa_princ_ent_rec princ_ent; xargs_t xargs = {0}; char *polname = NULL; OPERATION optype; krb5_boolean found_entry = FALSE; /* Clear the global error string */ krb5_clear_error_message(context); SETUP_CONTEXT(); if (ldap_context->lrparams == NULL || ldap_context->krbcontainer == NULL) return EINVAL; /* get ldap handle */ GET_HANDLE(); if (is_principal_in_realm(ldap_context, entry->princ) != 0) { st = EINVAL; krb5_set_error_message(context, st, _("Principal does not belong to " "the default realm")); goto cleanup; } /* get the principal information to act on */ if (entry->princ) { if (((st=krb5_unparse_name(context, entry->princ, &user)) != 0) || ((st=krb5_ldap_unparse_principal_name(user)) != 0)) goto cleanup; } /* Identity the type of operation, it can be * add principal or modify principal. * hack if the entry->mask has KRB_PRINCIPAL flag set * then it is a add operation */ if (entry->mask & KADM5_PRINCIPAL) optype = ADD_PRINCIPAL; else optype = MODIFY_PRINCIPAL; if (((st=krb5_get_princ_type(context, entry, &kerberos_principal_object_type)) != 0) || ((st=krb5_get_userdn(context, entry, &principal_dn)) != 0)) goto cleanup; if ((st=process_db_args(context, db_args, &xargs, optype)) != 0) goto cleanup; if (entry->mask & KADM5_LOAD) { int tree = 0, ntrees = 0, princlen = 0, numlentries = 0; char **subtreelist = NULL, *filter = NULL; /* A load operation is special, will do a mix-in (add krbprinc * attrs to a non-krb object entry) if an object exists with a * matching krbprincipalname attribute so try to find existing * object and set principal_dn. This assumes that the * krbprincipalname attribute is unique (only one object entry has * a particular krbprincipalname attribute). */ if (user == NULL) { /* must have principal name for search */ st = EINVAL; krb5_set_error_message(context, st, _("operation can not continue, principal " "name not found")); goto cleanup; } princlen = strlen(FILTER) + strlen(user) + 2 + 1; /* 2 for closing brackets */ if ((filter = malloc(princlen)) == NULL) { st = ENOMEM; goto cleanup; } snprintf(filter, princlen, FILTER"%s))", user); /* get the current subtree list */ if ((st = krb5_get_subtree_info(ldap_context, &subtreelist, &ntrees)) != 0) goto cleanup; found_entry = FALSE; /* search for entry with matching krbprincipalname attribute */ for (tree = 0; found_entry == FALSE && tree < ntrees; ++tree) { result = NULL; if (principal_dn == NULL) { LDAP_SEARCH_1(subtreelist[tree], ldap_context->lrparams->search_scope, filter, principal_attributes, IGNORE_STATUS); } else { /* just look for entry with principal_dn */ LDAP_SEARCH_1(principal_dn, LDAP_SCOPE_BASE, filter, principal_attributes, IGNORE_STATUS); } if (st == LDAP_SUCCESS) { numlentries = ldap_count_entries(ld, result); if (numlentries > 1) { ldap_msgfree(result); free(filter); st = EINVAL; krb5_set_error_message(context, st, _("operation can not continue, " "more than one entry with " "principal name \"%s\" found"), user); goto cleanup; } else if (numlentries == 1) { found_entry = TRUE; if (principal_dn == NULL) { ent = ldap_first_entry(ld, result); if (ent != NULL) { /* setting principal_dn will cause that entry to be modified further down */ if ((principal_dn = ldap_get_dn(ld, ent)) == NULL) { ldap_get_option (ld, LDAP_OPT_RESULT_CODE, &st); st = set_ldap_error (context, st, 0); ldap_msgfree(result); free(filter); goto cleanup; } } } } if (result) ldap_msgfree(result); } else if (st != LDAP_NO_SUCH_OBJECT) { /* could not perform search, return with failure */ st = set_ldap_error (context, st, 0); free(filter); goto cleanup; } /* * If it isn't found then assume a standalone princ entry is to * be created. */ } /* end for (tree = 0; principal_dn == ... */ free(filter); if (found_entry == FALSE && principal_dn != NULL) { /* * if principal_dn is null then there is code further down to * deal with setting standalone_principal_dn. Also note that * this will set create_standalone_prinicipal true for * non-mix-in entries which is okay if loading from a dump. */ create_standalone_prinicipal = TRUE; standalone_principal_dn = strdup(principal_dn); CHECK_NULL(standalone_principal_dn); } } /* end if (entry->mask & KADM5_LOAD */ /* time to generate the DN information with the help of * containerdn, principalcontainerreference or * realmcontainerdn information */ if (principal_dn == NULL && xargs.dn == NULL) { /* creation of standalone principal */ /* get the subtree information */ if (entry->princ->length == 2 && entry->princ->data[0].length == strlen("krbtgt") && strncmp(entry->princ->data[0].data, "krbtgt", entry->princ->data[0].length) == 0) { /* if the principal is a inter-realm principal, always created in the realm container */ subtree = strdup(ldap_context->lrparams->realmdn); } else if (xargs.containerdn) { if ((st=checkattributevalue(ld, xargs.containerdn, NULL, NULL, NULL)) != 0) { if (st == KRB5_KDB_NOENTRY || st == KRB5_KDB_CONSTRAINT_VIOLATION) { int ost = st; st = EINVAL; snprintf(errbuf, sizeof(errbuf), _("'%s' not found: "), xargs.containerdn); prepend_err_str(context, errbuf, st, ost); } goto cleanup; } subtree = strdup(xargs.containerdn); } else if (ldap_context->lrparams->containerref && strlen(ldap_context->lrparams->containerref) != 0) { /* * Here the subtree should be changed with * principalcontainerreference attribute value */ subtree = strdup(ldap_context->lrparams->containerref); } else { subtree = strdup(ldap_context->lrparams->realmdn); } CHECK_NULL(subtree); if (asprintf(&standalone_principal_dn, "krbprincipalname=%s,%s", user, subtree) < 0) standalone_principal_dn = NULL; CHECK_NULL(standalone_principal_dn); /* * free subtree when you are done using the subtree * set the boolean create_standalone_prinicipal to TRUE */ create_standalone_prinicipal = TRUE; free(subtree); subtree = NULL; } /* * If the DN information is presented by the user, time to * validate the input to ensure that the DN falls under * any of the subtrees */ if (xargs.dn_from_kbd == TRUE) { /* make sure the DN falls in the subtree */ int tre=0, dnlen=0, subtreelen=0, ntrees=0; char **subtreelist=NULL; char *dn=NULL; krb5_boolean outofsubtree=TRUE; if (xargs.dn != NULL) { dn = xargs.dn; } else if (xargs.linkdn != NULL) { dn = xargs.linkdn; } else if (standalone_principal_dn != NULL) { /* * Even though the standalone_principal_dn is constructed * within this function, there is the containerdn input * from the user that can become part of the it. */ dn = standalone_principal_dn; } /* get the current subtree list */ if ((st = krb5_get_subtree_info(ldap_context, &subtreelist, &ntrees)) != 0) goto cleanup; for (tre=0; tre<ntrees; ++tre) { if (subtreelist[tre] == NULL || strlen(subtreelist[tre]) == 0) { outofsubtree = FALSE; break; } else { dnlen = strlen (dn); subtreelen = strlen(subtreelist[tre]); if ((dnlen >= subtreelen) && (strcasecmp((dn + dnlen - subtreelen), subtreelist[tre]) == 0)) { outofsubtree = FALSE; break; } } } for (tre=0; tre < ntrees; ++tre) { free(subtreelist[tre]); } if (outofsubtree == TRUE) { st = EINVAL; krb5_set_error_message(context, st, _("DN is out of the realm subtree")); goto cleanup; } /* * dn value will be set either by dn, linkdn or the standalone_principal_dn * In the first 2 cases, the dn should be existing and in the last case we * are supposed to create the ldap object. so the below should not be * executed for the last case. */ if (standalone_principal_dn == NULL) { /* * If the ldap object is missing, this results in an error. */ /* * Search for krbprincipalname attribute here. * This is to find if a kerberos identity is already present * on the ldap object, in which case adding a kerberos identity * on the ldap object should result in an error. */ char *attributes[]= {"krbticketpolicyreference", "krbprincipalname", NULL}; LDAP_SEARCH_1(dn, LDAP_SCOPE_BASE, 0, attributes, IGNORE_STATUS); if (st == LDAP_SUCCESS) { ent = ldap_first_entry(ld, result); if (ent != NULL) { if ((values=ldap_get_values(ld, ent, "krbticketpolicyreference")) != NULL) { ldap_value_free(values); } if ((values=ldap_get_values(ld, ent, "krbprincipalname")) != NULL) { krb_identity_exists = TRUE; ldap_value_free(values); } } ldap_msgfree(result); } else { st = set_ldap_error(context, st, OP_SEARCH); goto cleanup; } } } /* * If xargs.dn is set then the request is to add a * kerberos principal on a ldap object, but if * there is one already on the ldap object this * should result in an error. */ if (xargs.dn != NULL && krb_identity_exists == TRUE) { st = EINVAL; snprintf(errbuf, sizeof(errbuf), _("ldap object is already kerberized")); krb5_set_error_message(context, st, "%s", errbuf); goto cleanup; } if (xargs.linkdn != NULL) { /* * link information can be changed using modprinc. * However, link information can be changed only on the * standalone kerberos principal objects. A standalone * kerberos principal object is of type krbprincipal * structural objectclass. * * NOTE: kerberos principals on an ldap object can't be * linked to other ldap objects. */ if (optype == MODIFY_PRINCIPAL && kerberos_principal_object_type != KDB_STANDALONE_PRINCIPAL_OBJECT) { st = EINVAL; snprintf(errbuf, sizeof(errbuf), _("link information can not be set/updated as the " "kerberos principal belongs to an ldap object")); krb5_set_error_message(context, st, "%s", errbuf); goto cleanup; } /* * Check the link information. If there is already a link * existing then this operation is not allowed. */ { char **linkdns=NULL; int j=0; if ((st=krb5_get_linkdn(context, entry, &linkdns)) != 0) { snprintf(errbuf, sizeof(errbuf), _("Failed getting object references")); krb5_set_error_message(context, st, "%s", errbuf); goto cleanup; } if (linkdns != NULL) { st = EINVAL; snprintf(errbuf, sizeof(errbuf), _("kerberos principal is already linked to a ldap " "object")); krb5_set_error_message(context, st, "%s", errbuf); for (j=0; linkdns[j] != NULL; ++j) free (linkdns[j]); free (linkdns); goto cleanup; } } establish_links = TRUE; } if (entry->mask & KADM5_LAST_SUCCESS) { memset(strval, 0, sizeof(strval)); if ((strval[0]=getstringtime(entry->last_success)) == NULL) goto cleanup; if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbLastSuccessfulAuth", LDAP_MOD_REPLACE, strval)) != 0) { free (strval[0]); goto cleanup; } free (strval[0]); } if (entry->mask & KADM5_LAST_FAILED) { memset(strval, 0, sizeof(strval)); if ((strval[0]=getstringtime(entry->last_failed)) == NULL) goto cleanup; if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbLastFailedAuth", LDAP_MOD_REPLACE, strval)) != 0) { free (strval[0]); goto cleanup; } free(strval[0]); } if (entry->mask & KADM5_FAIL_AUTH_COUNT) { krb5_kvno fail_auth_count; fail_auth_count = entry->fail_auth_count; if (entry->mask & KADM5_FAIL_AUTH_COUNT_INCREMENT) fail_auth_count++; st = krb5_add_int_mem_ldap_mod(&mods, "krbLoginFailedCount", LDAP_MOD_REPLACE, fail_auth_count); if (st != 0) goto cleanup; } else if (entry->mask & KADM5_FAIL_AUTH_COUNT_INCREMENT) { int attr_mask = 0; krb5_boolean has_fail_count; /* Check if the krbLoginFailedCount attribute exists. (Through * krb5 1.8.1, it wasn't set in new entries.) */ st = krb5_get_attributes_mask(context, entry, &attr_mask); if (st != 0) goto cleanup; has_fail_count = ((attr_mask & KDB_FAIL_AUTH_COUNT_ATTR) != 0); /* * If the client library and server supports RFC 4525, * then use it to increment by one the value of the * krbLoginFailedCount attribute. Otherwise, assert the * (provided) old value by deleting it before adding. */ #ifdef LDAP_MOD_INCREMENT if (ldap_server_handle->server_info->modify_increment && has_fail_count) { st = krb5_add_int_mem_ldap_mod(&mods, "krbLoginFailedCount", LDAP_MOD_INCREMENT, 1); if (st != 0) goto cleanup; } else { #endif /* LDAP_MOD_INCREMENT */ if (has_fail_count) { st = krb5_add_int_mem_ldap_mod(&mods, "krbLoginFailedCount", LDAP_MOD_DELETE, entry->fail_auth_count); if (st != 0) goto cleanup; } st = krb5_add_int_mem_ldap_mod(&mods, "krbLoginFailedCount", LDAP_MOD_ADD, entry->fail_auth_count + 1); if (st != 0) goto cleanup; #ifdef LDAP_MOD_INCREMENT } #endif } else if (optype == ADD_PRINCIPAL) { /* Initialize krbLoginFailedCount in new entries to help avoid a * race during the first failed login. */ st = krb5_add_int_mem_ldap_mod(&mods, "krbLoginFailedCount", LDAP_MOD_ADD, 0); } if (entry->mask & KADM5_MAX_LIFE) { if ((st=krb5_add_int_mem_ldap_mod(&mods, "krbmaxticketlife", LDAP_MOD_REPLACE, entry->max_life)) != 0) goto cleanup; } if (entry->mask & KADM5_MAX_RLIFE) { if ((st=krb5_add_int_mem_ldap_mod(&mods, "krbmaxrenewableage", LDAP_MOD_REPLACE, entry->max_renewable_life)) != 0) goto cleanup; } if (entry->mask & KADM5_ATTRIBUTES) { if ((st=krb5_add_int_mem_ldap_mod(&mods, "krbticketflags", LDAP_MOD_REPLACE, entry->attributes)) != 0) goto cleanup; } if (entry->mask & KADM5_PRINCIPAL) { memset(strval, 0, sizeof(strval)); strval[0] = user; if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbprincipalname", LDAP_MOD_REPLACE, strval)) != 0) goto cleanup; } if (entry->mask & KADM5_PRINC_EXPIRE_TIME) { memset(strval, 0, sizeof(strval)); if ((strval[0]=getstringtime(entry->expiration)) == NULL) goto cleanup; if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbprincipalexpiration", LDAP_MOD_REPLACE, strval)) != 0) { free (strval[0]); goto cleanup; } free (strval[0]); } if (entry->mask & KADM5_PW_EXPIRATION) { memset(strval, 0, sizeof(strval)); if ((strval[0]=getstringtime(entry->pw_expiration)) == NULL) goto cleanup; if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbpasswordexpiration", LDAP_MOD_REPLACE, strval)) != 0) { free (strval[0]); goto cleanup; } free (strval[0]); } if (entry->mask & KADM5_POLICY) { memset(&princ_ent, 0, sizeof(princ_ent)); for (tl_data=entry->tl_data; tl_data; tl_data=tl_data->tl_data_next) { if (tl_data->tl_data_type == KRB5_TL_KADM_DATA) { /* FIX ME: I guess the princ_ent should be freed after this call */ if ((st = krb5_lookup_tl_kadm_data(tl_data, &princ_ent)) != 0) { goto cleanup; } } } if (princ_ent.aux_attributes & KADM5_POLICY) { memset(strval, 0, sizeof(strval)); if ((st = krb5_ldap_name_to_policydn (context, princ_ent.policy, &polname)) != 0) goto cleanup; strval[0] = polname; if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbpwdpolicyreference", LDAP_MOD_REPLACE, strval)) != 0) goto cleanup; } else { st = EINVAL; krb5_set_error_message(context, st, "Password policy value null"); goto cleanup; } } else if (entry->mask & KADM5_LOAD && found_entry == TRUE) { /* * a load is special in that existing entries must have attrs that * removed. */ if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbpwdpolicyreference", LDAP_MOD_REPLACE, NULL)) != 0) goto cleanup; } if (entry->mask & KADM5_POLICY_CLR) { if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbpwdpolicyreference", LDAP_MOD_DELETE, NULL)) != 0) goto cleanup; } if (entry->mask & KADM5_KEY_DATA || entry->mask & KADM5_KVNO) { krb5_kvno mkvno; if ((st=krb5_dbe_lookup_mkvno(context, entry, &mkvno)) != 0) goto cleanup; bersecretkey = krb5_encode_krbsecretkey (entry->key_data, entry->n_key_data, mkvno); if ((st=krb5_add_ber_mem_ldap_mod(&mods, "krbprincipalkey", LDAP_MOD_REPLACE | LDAP_MOD_BVALUES, bersecretkey)) != 0) goto cleanup; if (!(entry->mask & KADM5_PRINCIPAL)) { memset(strval, 0, sizeof(strval)); if ((strval[0]=getstringtime(entry->pw_expiration)) == NULL) goto cleanup; if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbpasswordexpiration", LDAP_MOD_REPLACE, strval)) != 0) { free (strval[0]); goto cleanup; } free (strval[0]); } /* Update last password change whenever a new key is set */ { krb5_timestamp last_pw_changed; if ((st=krb5_dbe_lookup_last_pwd_change(context, entry, &last_pw_changed)) != 0) goto cleanup; memset(strval, 0, sizeof(strval)); if ((strval[0] = getstringtime(last_pw_changed)) == NULL) goto cleanup; if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbLastPwdChange", LDAP_MOD_REPLACE, strval)) != 0) { free (strval[0]); goto cleanup; } free (strval[0]); } } /* Modify Key data ends here */ /* Set tl_data */ if (entry->tl_data != NULL) { int count = 0; struct berval **ber_tl_data = NULL; krb5_tl_data *ptr; krb5_timestamp unlock_time; for (ptr = entry->tl_data; ptr != NULL; ptr = ptr->tl_data_next) { if (ptr->tl_data_type == KRB5_TL_LAST_PWD_CHANGE #ifdef SECURID || ptr->tl_data_type == KRB5_TL_DB_ARGS #endif || ptr->tl_data_type == KRB5_TL_KADM_DATA || ptr->tl_data_type == KDB_TL_USER_INFO || ptr->tl_data_type == KRB5_TL_CONSTRAINED_DELEGATION_ACL || ptr->tl_data_type == KRB5_TL_LAST_ADMIN_UNLOCK) continue; count++; } if (count != 0) { int j; ber_tl_data = (struct berval **) calloc (count + 1, sizeof (struct berval*)); if (ber_tl_data == NULL) { st = ENOMEM; goto cleanup; } for (j = 0, ptr = entry->tl_data; ptr != NULL; ptr = ptr->tl_data_next) { /* Ignore tl_data that are stored in separate directory * attributes */ if (ptr->tl_data_type == KRB5_TL_LAST_PWD_CHANGE #ifdef SECURID || ptr->tl_data_type == KRB5_TL_DB_ARGS #endif || ptr->tl_data_type == KRB5_TL_KADM_DATA || ptr->tl_data_type == KDB_TL_USER_INFO || ptr->tl_data_type == KRB5_TL_CONSTRAINED_DELEGATION_ACL || ptr->tl_data_type == KRB5_TL_LAST_ADMIN_UNLOCK) continue; if ((st = tl_data2berval (ptr, &ber_tl_data[j])) != 0) break; j++; } if (st == 0) { ber_tl_data[count] = NULL; st=krb5_add_ber_mem_ldap_mod(&mods, "krbExtraData", LDAP_MOD_REPLACE | LDAP_MOD_BVALUES, ber_tl_data); } for (j = 0; ber_tl_data[j] != NULL; j++) { free(ber_tl_data[j]->bv_val); free(ber_tl_data[j]); } free(ber_tl_data); if (st != 0) goto cleanup; } if ((st=krb5_dbe_lookup_last_admin_unlock(context, entry, &unlock_time)) != 0) goto cleanup; if (unlock_time != 0) { /* Update last admin unlock */ memset(strval, 0, sizeof(strval)); if ((strval[0] = getstringtime(unlock_time)) == NULL) goto cleanup; if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbLastAdminUnlock", LDAP_MOD_REPLACE, strval)) != 0) { free (strval[0]); goto cleanup; } free (strval[0]); } } /* Directory specific attribute */ if (xargs.tktpolicydn != NULL) { int tmask=0; if (strlen(xargs.tktpolicydn) != 0) { st = checkattributevalue(ld, xargs.tktpolicydn, "objectclass", policyclass, &tmask); CHECK_CLASS_VALIDITY(st, tmask, _("ticket policy object value: ")); strval[0] = xargs.tktpolicydn; strval[1] = NULL; if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbticketpolicyreference", LDAP_MOD_REPLACE, strval)) != 0) goto cleanup; } else { /* if xargs.tktpolicydn is a empty string, then delete * already existing krbticketpolicyreference attr */ if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbticketpolicyreference", LDAP_MOD_DELETE, NULL)) != 0) goto cleanup; } } if (establish_links == TRUE) { memset(strval, 0, sizeof(strval)); strval[0] = xargs.linkdn; if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbObjectReferences", LDAP_MOD_REPLACE, strval)) != 0) goto cleanup; } /* * in case mods is NULL then return * not sure but can happen in a modprinc * so no need to return an error * addprinc will at least have the principal name * and the keys passed in */ if (mods == NULL) goto cleanup; if (create_standalone_prinicipal == TRUE) { memset(strval, 0, sizeof(strval)); strval[0] = "krbprincipal"; strval[1] = "krbprincipalaux"; strval[2] = "krbTicketPolicyAux"; if ((st=krb5_add_str_mem_ldap_mod(&mods, "objectclass", LDAP_MOD_ADD, strval)) != 0) goto cleanup; st = ldap_add_ext_s(ld, standalone_principal_dn, mods, NULL, NULL); if (st == LDAP_ALREADY_EXISTS && entry->mask & KADM5_LOAD) { /* a load operation must replace an existing entry */ st = ldap_delete_ext_s(ld, standalone_principal_dn, NULL, NULL); if (st != LDAP_SUCCESS) { snprintf(errbuf, sizeof(errbuf), _("Principal delete failed (trying to replace " "entry): %s"), ldap_err2string(st)); st = translate_ldap_error (st, OP_ADD); krb5_set_error_message(context, st, "%s", errbuf); goto cleanup; } else { st = ldap_add_ext_s(ld, standalone_principal_dn, mods, NULL, NULL); } } if (st != LDAP_SUCCESS) { snprintf(errbuf, sizeof(errbuf), _("Principal add failed: %s"), ldap_err2string(st)); st = translate_ldap_error (st, OP_ADD); krb5_set_error_message(context, st, "%s", errbuf); goto cleanup; } } else { /* * Here existing ldap object is modified and can be related * to any attribute, so always ensure that the ldap * object is extended with all the kerberos related * objectclasses so that there are no constraint * violations. */ { char *attrvalues[] = {"krbprincipalaux", "krbTicketPolicyAux", NULL}; int p, q, r=0, amask=0; if ((st=checkattributevalue(ld, (xargs.dn) ? xargs.dn : principal_dn, "objectclass", attrvalues, &amask)) != 0) goto cleanup; memset(strval, 0, sizeof(strval)); for (p=1, q=0; p<=2; p<<=1, ++q) { if ((p & amask) == 0) strval[r++] = attrvalues[q]; } if (r != 0) { if ((st=krb5_add_str_mem_ldap_mod(&mods, "objectclass", LDAP_MOD_ADD, strval)) != 0) goto cleanup; } } if (xargs.dn != NULL) st=ldap_modify_ext_s(ld, xargs.dn, mods, NULL, NULL); else st = ldap_modify_ext_s(ld, principal_dn, mods, NULL, NULL); if (st != LDAP_SUCCESS) { snprintf(errbuf, sizeof(errbuf), _("User modification failed: %s"), ldap_err2string(st)); st = translate_ldap_error (st, OP_MOD); krb5_set_error_message(context, st, "%s", errbuf); goto cleanup; } if (entry->mask & KADM5_FAIL_AUTH_COUNT_INCREMENT) entry->fail_auth_count++; } cleanup: if (user) free(user); free_xargs(xargs); if (standalone_principal_dn) free(standalone_principal_dn); if (principal_dn) free (principal_dn); if (polname != NULL) free(polname); if (subtree) free (subtree); if (bersecretkey) { for (l=0; bersecretkey[l]; ++l) { if (bersecretkey[l]->bv_val) free (bersecretkey[l]->bv_val); free (bersecretkey[l]); } free (bersecretkey); } if (keys) free (keys); ldap_mods_free(mods, 1); krb5_ldap_put_handle_to_pool(ldap_context, ldap_server_handle); return(st); }
krb5_error_code krb5_ldap_delete_realm (krb5_context context, char *lrealm) { LDAP *ld = NULL; krb5_error_code st = 0, tempst=0; char **values=NULL, **subtrees=NULL, **policy=NULL; LDAPMessage **result_arr=NULL, *result = NULL, *ent = NULL; krb5_principal principal; unsigned int l=0, ntree=0; int i=0, j=0, mask=0; kdb5_dal_handle *dal_handle = NULL; krb5_ldap_context *ldap_context = NULL; krb5_ldap_server_handle *ldap_server_handle = NULL; krb5_ldap_realm_params *rparam=NULL; SETUP_CONTEXT (); if (lrealm == NULL) { st = EINVAL; k5_setmsg(context, st, _("Realm information not available")); goto cleanup; } if ((st=krb5_ldap_read_realm_params(context, lrealm, &rparam, &mask)) != 0) goto cleanup; /* get ldap handle */ GET_HANDLE (); /* delete all the principals belonging to the realm in the tree */ { char *attr[] = {"krbprincipalname", NULL}, *realm=NULL, filter[256]; krb5_ldap_context lcontext; realm = ldap_filter_correct (lrealm); assert (sizeof (filter) >= sizeof ("(krbprincipalname=)") + strlen (realm) + 2 /* "*@" */ + 1); snprintf (filter, sizeof(filter), "(krbprincipalname=*@%s)", realm); free (realm); /* LDAP_SEARCH(NULL, LDAP_SCOPE_SUBTREE, filter, attr); */ memset(&lcontext, 0, sizeof(krb5_ldap_context)); lcontext.lrparams = rparam; if ((st=krb5_get_subtree_info(&lcontext, &subtrees, &ntree)) != 0) goto cleanup; result_arr = (LDAPMessage **) calloc((unsigned int)ntree+1, sizeof(LDAPMessage *)); if (result_arr == NULL) { st = ENOMEM; goto cleanup; } for (l=0; l < ntree; ++l) { LDAP_SEARCH(subtrees[l], rparam->search_scope, filter, attr); result_arr[l] = result; } } /* NOTE: Here all the principals should be cached and the ldap handle should be freed, * as a DAL-LDAP interface is called right down here. Caching might be constrained by * availability of the memory. The caching is not done, however there would be limit * on the minimum number of handles for a server and it is 2. As the DAL-LDAP is not * thread-safe this should suffice. */ for (j=0; (result=result_arr[j]) != NULL; ++j) { for (ent = ldap_first_entry (ld, result); ent != NULL; ent = ldap_next_entry (ld, ent)) { if ((values = ldap_get_values(ld, ent, "krbPrincipalName")) != NULL) { for (i = 0; values[i] != NULL; ++i) { krb5_parse_name(context, values[i], &principal); if (principal_in_realm_2(principal, lrealm) == 0) { st=krb5_ldap_delete_principal(context, principal); if (st && st != KRB5_KDB_NOENTRY) goto cleanup; } krb5_free_principal(context, principal); } ldap_value_free(values); } } } /* Delete all password policies */ krb5_ldap_iterate_password_policy (context, "*", delete_password_policy, context); /* Delete all ticket policies */ { if ((st = krb5_ldap_list_policy (context, ldap_context->lrparams->realmdn, &policy)) != 0) { prepend_err_str(context, _("Error reading ticket policy: "), st, st); goto cleanup; } for (i = 0; policy [i] != NULL; i++) krb5_ldap_delete_policy(context, policy[i]); } /* Delete the realm object */ if ((st=ldap_delete_ext_s(ld, ldap_context->lrparams->realmdn, NULL, NULL)) != LDAP_SUCCESS) { int ost = st; st = translate_ldap_error (st, OP_DEL); k5_setmsg(context, st, _("Realm Delete FAILED: %s"), ldap_err2string(ost)); } cleanup: if (subtrees) { for (l=0; l < ntree; ++l) { if (subtrees[l]) free (subtrees[l]); } free (subtrees); } if (result_arr != NULL) { for (l = 0; l < ntree; l++) ldap_msgfree(result_arr[l]); free(result_arr); } if (policy != NULL) { for (i = 0; policy[i] != NULL; i++) free (policy[i]); free (policy); } krb5_ldap_free_realm_params(rparam); krb5_ldap_put_handle_to_pool(ldap_context, ldap_server_handle); return st; }