/* * lib/kdb/kdb_ldap/ldap_tkt_policy.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 "ldap_main.h" #include "kdb_ldap.h" #include "ldap_tkt_policy.h" #include "ldap_err.h" #include /* Ticket policy object management */ /* * create the Ticket policy object in Directory. */ krb5_error_code krb5_ldap_create_policy(context, policy, mask) krb5_context context; krb5_ldap_policy_params *policy; int mask; { krb5_error_code st=0; LDAP *ld=NULL; char *strval[3]={NULL}, *policy_dn = NULL; LDAPMod **mods=NULL; kdb5_dal_handle *dal_handle=NULL; krb5_ldap_context *ldap_context=NULL; krb5_ldap_server_handle *ldap_server_handle=NULL; /* validate the input parameters */ if (policy == NULL || policy->policy == NULL) { st = EINVAL; krb5_set_error_message (context, st, gettext("Ticket Policy Name missing")); goto cleanup; } SETUP_CONTEXT(); GET_HANDLE(); if ((st = krb5_ldap_name_to_policydn (context, policy->policy, &policy_dn)) != 0) goto cleanup; memset(strval, 0, sizeof(strval)); strval[0] = policy->policy; if ((st=krb5_add_str_mem_ldap_mod(&mods, "cn", LDAP_MOD_ADD, strval)) != 0) goto cleanup; memset(strval, 0, sizeof(strval)); strval[0] = "krbTicketPolicy"; strval[1] = "krbTicketPolicyaux"; if ((st=krb5_add_str_mem_ldap_mod(&mods, "objectclass", LDAP_MOD_ADD, strval)) != 0) goto cleanup; if (mask & LDAP_POLICY_MAXTKTLIFE) { if ((st=krb5_add_int_mem_ldap_mod(&mods, "krbmaxticketlife", LDAP_MOD_ADD, policy->maxtktlife)) != 0) goto cleanup; } if (mask & LDAP_POLICY_MAXRENEWLIFE) { if ((st=krb5_add_int_mem_ldap_mod(&mods, "krbmaxrenewableage", LDAP_MOD_ADD, policy->maxrenewlife)) != 0) goto cleanup; } if (mask & LDAP_POLICY_TKTFLAGS) { if ((st=krb5_add_int_mem_ldap_mod(&mods, "krbticketflags", LDAP_MOD_ADD, policy->tktflags)) != 0) goto cleanup; } /* ldap add operation */ if ((st=ldap_add_ext_s(ld, policy_dn, mods, NULL, NULL)) != LDAP_SUCCESS) { st = set_ldap_error (context, st, OP_ADD); goto cleanup; } cleanup: if (policy_dn != NULL) free(policy_dn); ldap_mods_free(mods, 1); krb5_ldap_put_handle_to_pool(ldap_context, ldap_server_handle); return st; } /* * modify the Ticket policy object in Directory. */ krb5_error_code krb5_ldap_modify_policy(context, policy, mask) krb5_context context; krb5_ldap_policy_params *policy; int mask; { int objectmask=0; krb5_error_code st=0; LDAP *ld=NULL; char *attrvalues[]={"krbTicketPolicy", "krbTicketPolicyAux", NULL}, *strval[2]={NULL}; char *policy_dn = NULL; LDAPMod **mods=NULL; kdb5_dal_handle *dal_handle=NULL; krb5_ldap_context *ldap_context=NULL; krb5_ldap_server_handle *ldap_server_handle=NULL; /* validate the input parameters */ if (policy == NULL || policy->policy==NULL) { st = EINVAL; krb5_set_error_message (context, st, gettext("Ticket Policy Name missing")); goto cleanup; } SETUP_CONTEXT(); GET_HANDLE(); if ((st = krb5_ldap_name_to_policydn (context, policy->policy, &policy_dn)) != 0) goto cleanup; /* the policydn object should be of the krbTicketPolicy object class */ st = checkattributevalue(ld, policy_dn, "objectClass", attrvalues, &objectmask); CHECK_CLASS_VALIDITY(st, objectmask, "ticket policy object: "); if ((objectmask & 0x02) == 0) { /* add krbticketpolicyaux to the object class list */ memset(strval, 0, sizeof(strval)); strval[0] = "krbTicketPolicyAux"; if ((st=krb5_add_str_mem_ldap_mod(&mods, "objectclass", LDAP_MOD_ADD, strval)) != 0) goto cleanup; } if (mask & LDAP_POLICY_MAXTKTLIFE) { if ((st=krb5_add_int_mem_ldap_mod(&mods, "krbmaxticketlife", LDAP_MOD_REPLACE, policy->maxtktlife)) != 0) goto cleanup; } if (mask & LDAP_POLICY_MAXRENEWLIFE) { if ((st=krb5_add_int_mem_ldap_mod(&mods, "krbmaxrenewableage", LDAP_MOD_REPLACE, policy->maxrenewlife)) != 0) goto cleanup; } if (mask & LDAP_POLICY_TKTFLAGS) { if ((st=krb5_add_int_mem_ldap_mod(&mods, "krbticketflags", LDAP_MOD_REPLACE, policy->tktflags)) != 0) goto cleanup; } if ((st=ldap_modify_ext_s(ld, policy_dn, mods, NULL, NULL)) != LDAP_SUCCESS) { st = set_ldap_error (context, st, OP_MOD); goto cleanup; } cleanup: if (policy_dn != NULL) free(policy_dn); ldap_mods_free(mods, 1); krb5_ldap_put_handle_to_pool(ldap_context, ldap_server_handle); return st; } /* * Read the policy object from the Directory and populate the krb5_ldap_policy_params * structure. */ krb5_error_code krb5_ldap_read_policy(context, policyname, policy, omask) krb5_context context; char *policyname; krb5_ldap_policy_params **policy; unsigned int *omask; /* Solaris kerberos: unsigned better for mask */ { krb5_error_code st=0, tempst=0; int objectmask=0; LDAP *ld=NULL; LDAPMessage *result=NULL,*ent=NULL; char *attributes[] = { "krbMaxTicketLife", "krbMaxRenewableAge", "krbTicketFlags", NULL}; char *attrvalues[] = { "krbTicketPolicy", NULL}, *policy_dn = NULL; krb5_ldap_policy_params *lpolicy=NULL; kdb5_dal_handle *dal_handle=NULL; krb5_ldap_context *ldap_context=NULL; krb5_ldap_server_handle *ldap_server_handle=NULL; /* validate the input parameters */ if (policyname == NULL || policy == NULL) { st = EINVAL; krb5_set_error_message(context, st, gettext("Ticket Policy Object information missing")); goto cleanup; } SETUP_CONTEXT(); GET_HANDLE(); if ((st = krb5_ldap_name_to_policydn (context, policyname, &policy_dn)) != 0) goto cleanup; /* the policydn object should be of the krbTicketPolicy object class */ st = checkattributevalue(ld, policy_dn, "objectClass", attrvalues, &objectmask); CHECK_CLASS_VALIDITY(st, objectmask, "ticket policy object: "); /* Initialize ticket policy structure */ lpolicy =(krb5_ldap_policy_params *) malloc(sizeof(krb5_ldap_policy_params)); CHECK_NULL(lpolicy); memset(lpolicy, 0, sizeof(krb5_ldap_policy_params)); if ((lpolicy->policy = strdup (policyname)) == NULL) { st = ENOMEM; goto cleanup; } lpolicy->tl_data = calloc (1, sizeof(*lpolicy->tl_data)); CHECK_NULL(lpolicy->tl_data); lpolicy->tl_data->tl_data_type = KDB_TL_USER_INFO; LDAP_SEARCH(policy_dn, LDAP_SCOPE_BASE, "(objectclass=krbTicketPolicy)", attributes); *omask = 0; ent=ldap_first_entry(ld, result); if (ent != NULL) { if (krb5_ldap_get_value(ld, ent, "krbmaxticketlife", (int *) &(lpolicy->maxtktlife)) == 0) *omask |= LDAP_POLICY_MAXTKTLIFE; if (krb5_ldap_get_value(ld, ent, "krbmaxrenewableage", (int *) &(lpolicy->maxrenewlife)) == 0) *omask |= LDAP_POLICY_MAXRENEWLIFE; if (krb5_ldap_get_value(ld, ent, "krbticketflags", (int *) &(lpolicy->tktflags)) == 0) *omask |= LDAP_POLICY_TKTFLAGS; } ldap_msgfree(result); lpolicy->mask = *omask; store_tl_data(lpolicy->tl_data, KDB_TL_MASK, omask); *policy = lpolicy; cleanup: if (st != 0) { krb5_ldap_free_policy(context, lpolicy); *policy = NULL; } krb5_ldap_put_handle_to_pool(ldap_context, ldap_server_handle); return st; } /* * Function to delete ticket policy object from the directory. Before * calling this function krb5_ldap_read_policy should be called to * check the existence of the object. This serves one major purpose, * i.e., if the object to be is anything other than the ticket policy * object then the krb5_ldap_read_policy returns an error and thus is * not accidently deleted in this function. * * NOTE: Other kerberos objects (user/realm object) might be having * references to the policy object to be deleted. This situation is * not handled here, instead is taken care of at all the places where * the deleted policy object is read, to ignore a return status of * LDAP_NO_SUCH_OBJECT and continue. */ krb5_error_code krb5_ldap_delete_policy(context, policyname) krb5_context context; char *policyname; { int refcount = 0; char *policy_dn = NULL; krb5_error_code st = 0; LDAP *ld = NULL; kdb5_dal_handle *dal_handle=NULL; krb5_ldap_context *ldap_context=NULL; krb5_ldap_server_handle *ldap_server_handle=NULL; if (policyname == NULL) { st = EINVAL; prepend_err_str (context, gettext("Ticket Policy Object DN missing"),st,st); goto cleanup; } SETUP_CONTEXT(); GET_HANDLE(); if ((st = krb5_ldap_name_to_policydn (context, policyname, &policy_dn)) != 0) goto cleanup; /* Checking for policy count for 0 and will not permit delete if * it is greater than 0. */ if ((st = krb5_ldap_get_reference_count (context, policy_dn, "krbTicketPolicyReference", &refcount, ld)) != 0) goto cleanup; if (refcount == 0) { if ((st=ldap_delete_ext_s(ld, policy_dn, NULL, NULL)) != 0) { prepend_err_str (context,ldap_err2string(st),st,st); goto cleanup; } } else { st = EINVAL; prepend_err_str (context, gettext("Delete Failed: One or more Principals associated with the Ticket Policy"),st,st); goto cleanup; } cleanup: if (policy_dn != NULL) free (policy_dn); krb5_ldap_put_handle_to_pool(ldap_context, ldap_server_handle); return st; } /* * list policy objects from Directory */ krb5_error_code krb5_ldap_list_policy(context, containerdn, policy) krb5_context context; char *containerdn; char ***policy; { int i, j, count; char **list = NULL; char *policycontainerdn = containerdn; kdb5_dal_handle *dal_handle=NULL; krb5_ldap_context *ldap_context=NULL; krb5_error_code st=0; SETUP_CONTEXT(); if (policycontainerdn == NULL) { policycontainerdn = ldap_context->lrparams->realmdn; } if ((st = krb5_ldap_list(context, &list, "krbTicketPolicy", policycontainerdn)) != 0) goto cleanup; for (i = 0; list[i] != NULL; i++); count = i; *policy = (char **) calloc ((unsigned) count + 1, sizeof(char *)); if (*policy == NULL) { st = ENOMEM; goto cleanup; } for (i = 0, j = 0; list[i] != NULL; i++, j++) { int ret; ret = krb5_ldap_policydn_to_name (context, list[i], &(*policy)[i]); if (ret != 0) j--; } cleanup: return st; } /* * Function to free the ticket policy object structure. * Note: this function assumes that memory of the policy structure is dynamically allocated and hence the whole * structure is freed up. Care should be taken not to call this function on a static structure */ krb5_error_code krb5_ldap_free_policy(context, policy) krb5_context context; krb5_ldap_policy_params *policy; { krb5_error_code st=0; if (policy == NULL) return st; if (policy->policy) free (policy->policy); if (policy->tl_data) { if (policy->tl_data->tl_data_contents) free (policy->tl_data->tl_data_contents); free (policy->tl_data); } free (policy); return st; } /* * This function is general object listing routine. It is currently * used for ticket policy object listing. */ krb5_error_code krb5_ldap_list(context, list, objectclass, containerdn) krb5_context context; char ***list; char *objectclass; char *containerdn; { char *filter=NULL, *dn=NULL; krb5_error_code st=0, tempst=0; int i=0, count=0, filterlen=0; LDAP *ld=NULL; LDAPMessage *result=NULL,*ent=NULL; kdb5_dal_handle *dal_handle=NULL; krb5_ldap_context *ldap_context=NULL; krb5_ldap_server_handle *ldap_server_handle=NULL; SETUP_CONTEXT(); GET_HANDLE(); /* check if the containerdn exists */ if (containerdn) { if ((st=checkattributevalue(ld, containerdn, NULL, NULL, NULL)) != 0) { prepend_err_str (context, gettext("Error reading container object: "), st, st); goto cleanup; } } /* set the filter for the search operation */ filterlen = strlen("(objectclass=") + strlen(objectclass) + 1 + 1; filter = malloc ((unsigned) filterlen); if (filter == NULL) { st = ENOMEM; goto cleanup; } snprintf(filter, (unsigned) filterlen,"(objectclass=%s)",objectclass); LDAP_SEARCH(containerdn, LDAP_SCOPE_SUBTREE, filter, NULL); count = ldap_count_entries(ld, result); if (count == -1) { ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, &st); st = set_ldap_error(context, st, OP_SEARCH); goto cleanup; } *list = (char **) calloc ((unsigned) count+1, sizeof(char *)); if (*list == NULL) { st = ENOMEM; goto cleanup; } for (ent=ldap_first_entry(ld, result), count=0; ent != NULL; ent=ldap_next_entry(ld, ent), ++count) { if ((dn=ldap_get_dn(ld, ent)) == NULL) continue; if (((*list)[count] = strdup(dn)) == NULL) { ldap_memfree (dn); st = ENOMEM; goto cleanup; } ldap_memfree(dn); } ldap_msgfree(result); cleanup: if (filter) free (filter); /* some error, free up all the memory */ if (st != 0) { if (*list) { for (i=0; (*list)[i]; ++i) free ((*list)[i]); free (*list); *list = NULL; } } krb5_ldap_put_handle_to_pool(ldap_context, ldap_server_handle); return st; }