2N/A/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2N/A/*
2N/A * lib/kdb/kdb_ldap/ldap_tkt_policy.c
2N/A *
2N/A * Copyright (c) 2004-2005, Novell, Inc.
2N/A * All rights reserved.
2N/A *
2N/A * Redistribution and use in source and binary forms, with or without
2N/A * modification, are permitted provided that the following conditions are met:
2N/A *
2N/A * * Redistributions of source code must retain the above copyright notice,
2N/A * this list of conditions and the following disclaimer.
2N/A * * Redistributions in binary form must reproduce the above copyright
2N/A * notice, this list of conditions and the following disclaimer in the
2N/A * documentation and/or other materials provided with the distribution.
2N/A * * The copyright holder's name is not used to endorse or promote products
2N/A * derived from this software without specific prior written permission.
2N/A *
2N/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
2N/A * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2N/A * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2N/A * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
2N/A * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
2N/A * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
2N/A * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2N/A * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
2N/A * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
2N/A * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
2N/A * POSSIBILITY OF SUCH DAMAGE.
2N/A */
2N/A
2N/A#include "ldap_main.h"
2N/A#include "kdb_ldap.h"
2N/A#include "ldap_tkt_policy.h"
2N/A#include "ldap_err.h"
2N/A#include <libintl.h> /* Solaris Kerberos */
2N/A
2N/A/* Ticket policy object management */
2N/A
2N/A/*
2N/A * create the Ticket policy object in Directory.
2N/A */
2N/Akrb5_error_code
2N/Akrb5_ldap_create_policy(krb5_context context, krb5_ldap_policy_params *policy,
2N/A int mask)
2N/A{
2N/A krb5_error_code st=0;
2N/A LDAP *ld=NULL;
2N/A char *strval[3]={NULL}, *policy_dn = NULL;
2N/A LDAPMod **mods=NULL;
2N/A kdb5_dal_handle *dal_handle=NULL;
2N/A krb5_ldap_context *ldap_context=NULL;
2N/A krb5_ldap_server_handle *ldap_server_handle=NULL;
2N/A
2N/A /* validate the input parameters */
2N/A if (policy == NULL || policy->policy == NULL) {
2N/A st = EINVAL;
2N/A krb5_set_error_message (context, st, gettext("Ticket Policy Name missing"));
2N/A goto cleanup;
2N/A }
2N/A
2N/A SETUP_CONTEXT();
2N/A GET_HANDLE();
2N/A
2N/A if ((st = krb5_ldap_name_to_policydn (context, policy->policy, &policy_dn)) != 0)
2N/A goto cleanup;
2N/A
2N/A memset(strval, 0, sizeof(strval));
2N/A strval[0] = policy->policy;
2N/A if ((st=krb5_add_str_mem_ldap_mod(&mods, "cn", LDAP_MOD_ADD, strval)) != 0)
2N/A goto cleanup;
2N/A
2N/A memset(strval, 0, sizeof(strval));
2N/A strval[0] = "krbTicketPolicy";
2N/A strval[1] = "krbTicketPolicyaux";
2N/A if ((st=krb5_add_str_mem_ldap_mod(&mods, "objectclass", LDAP_MOD_ADD, strval)) != 0)
2N/A goto cleanup;
2N/A
2N/A if (mask & LDAP_POLICY_MAXTKTLIFE) {
2N/A if ((st=krb5_add_int_mem_ldap_mod(&mods, "krbmaxticketlife", LDAP_MOD_ADD,
2N/A policy->maxtktlife)) != 0)
2N/A goto cleanup;
2N/A }
2N/A
2N/A if (mask & LDAP_POLICY_MAXRENEWLIFE) {
2N/A if ((st=krb5_add_int_mem_ldap_mod(&mods, "krbmaxrenewableage", LDAP_MOD_ADD,
2N/A policy->maxrenewlife)) != 0)
2N/A goto cleanup;
2N/A }
2N/A
2N/A if (mask & LDAP_POLICY_TKTFLAGS) {
2N/A if ((st=krb5_add_int_mem_ldap_mod(&mods, "krbticketflags", LDAP_MOD_ADD,
2N/A policy->tktflags)) != 0)
2N/A goto cleanup;
2N/A }
2N/A
2N/A /* ldap add operation */
2N/A if ((st=ldap_add_ext_s(ld, policy_dn, mods, NULL, NULL)) != LDAP_SUCCESS) {
2N/A st = set_ldap_error (context, st, OP_ADD);
2N/A goto cleanup;
2N/A }
2N/A
2N/Acleanup:
2N/A if (policy_dn != NULL)
2N/A free(policy_dn);
2N/A
2N/A ldap_mods_free(mods, 1);
2N/A krb5_ldap_put_handle_to_pool(ldap_context, ldap_server_handle);
2N/A return st;
2N/A}
2N/A
2N/A
2N/A/*
2N/A * modify the Ticket policy object in Directory.
2N/A */
2N/A
2N/Akrb5_error_code
2N/Akrb5_ldap_modify_policy(krb5_context context, krb5_ldap_policy_params *policy,
2N/A int mask)
2N/A{
2N/A int objectmask=0;
2N/A krb5_error_code st=0;
2N/A LDAP *ld=NULL;
2N/A char *attrvalues[]={"krbTicketPolicy", "krbTicketPolicyAux", NULL}, *strval[2]={NULL};
2N/A char *policy_dn = NULL;
2N/A LDAPMod **mods=NULL;
2N/A kdb5_dal_handle *dal_handle=NULL;
2N/A krb5_ldap_context *ldap_context=NULL;
2N/A krb5_ldap_server_handle *ldap_server_handle=NULL;
2N/A
2N/A /* validate the input parameters */
2N/A if (policy == NULL || policy->policy==NULL) {
2N/A st = EINVAL;
2N/A krb5_set_error_message (context, st, gettext("Ticket Policy Name missing"));
2N/A goto cleanup;
2N/A }
2N/A
2N/A SETUP_CONTEXT();
2N/A GET_HANDLE();
2N/A
2N/A if ((st = krb5_ldap_name_to_policydn (context, policy->policy, &policy_dn)) != 0)
2N/A goto cleanup;
2N/A
2N/A /* the policydn object should be of the krbTicketPolicy object class */
2N/A st = checkattributevalue(ld, policy_dn, "objectClass", attrvalues, &objectmask);
2N/A CHECK_CLASS_VALIDITY(st, objectmask, "ticket policy object: ");
2N/A
2N/A if ((objectmask & 0x02) == 0) { /* add krbticketpolicyaux to the object class list */
2N/A memset(strval, 0, sizeof(strval));
2N/A strval[0] = "krbTicketPolicyAux";
2N/A if ((st=krb5_add_str_mem_ldap_mod(&mods, "objectclass", LDAP_MOD_ADD, strval)) != 0)
2N/A goto cleanup;
2N/A }
2N/A
2N/A if (mask & LDAP_POLICY_MAXTKTLIFE) {
2N/A if ((st=krb5_add_int_mem_ldap_mod(&mods, "krbmaxticketlife", LDAP_MOD_REPLACE,
2N/A policy->maxtktlife)) != 0)
2N/A goto cleanup;
2N/A }
2N/A
2N/A if (mask & LDAP_POLICY_MAXRENEWLIFE) {
2N/A if ((st=krb5_add_int_mem_ldap_mod(&mods, "krbmaxrenewableage", LDAP_MOD_REPLACE,
2N/A policy->maxrenewlife)) != 0)
2N/A goto cleanup;
2N/A }
2N/A
2N/A if (mask & LDAP_POLICY_TKTFLAGS) {
2N/A if ((st=krb5_add_int_mem_ldap_mod(&mods, "krbticketflags", LDAP_MOD_REPLACE,
2N/A policy->tktflags)) != 0)
2N/A goto cleanup;
2N/A }
2N/A
2N/A if ((st=ldap_modify_ext_s(ld, policy_dn, mods, NULL, NULL)) != LDAP_SUCCESS) {
2N/A st = set_ldap_error (context, st, OP_MOD);
2N/A goto cleanup;
2N/A }
2N/A
2N/Acleanup:
2N/A if (policy_dn != NULL)
2N/A free(policy_dn);
2N/A
2N/A ldap_mods_free(mods, 1);
2N/A krb5_ldap_put_handle_to_pool(ldap_context, ldap_server_handle);
2N/A return st;
2N/A}
2N/A
2N/A
2N/A/*
2N/A * Read the policy object from the Directory and populate the krb5_ldap_policy_params
2N/A * structure.
2N/A */
2N/A
2N/Akrb5_error_code
2N/Akrb5_ldap_read_policy(krb5_context context, char *policyname,
2N/A krb5_ldap_policy_params **policy,
2N/A /* Solaris kerberos: unsigned better for mask */
2N/A unsigned int *omask)
2N/A{
2N/A krb5_error_code st=0, tempst=0;
2N/A int objectmask=0;
2N/A LDAP *ld=NULL;
2N/A LDAPMessage *result=NULL,*ent=NULL;
2N/A char *attributes[] = { "krbMaxTicketLife", "krbMaxRenewableAge", "krbTicketFlags", NULL};
2N/A char *attrvalues[] = { "krbTicketPolicy", NULL}, *policy_dn = NULL;
2N/A krb5_ldap_policy_params *lpolicy=NULL;
2N/A kdb5_dal_handle *dal_handle=NULL;
2N/A krb5_ldap_context *ldap_context=NULL;
2N/A krb5_ldap_server_handle *ldap_server_handle=NULL;
2N/A
2N/A /* validate the input parameters */
2N/A if (policyname == NULL || policy == NULL) {
2N/A st = EINVAL;
2N/A krb5_set_error_message(context, st, gettext("Ticket Policy Object information missing"));
2N/A goto cleanup;
2N/A }
2N/A
2N/A SETUP_CONTEXT();
2N/A GET_HANDLE();
2N/A
2N/A if ((st = krb5_ldap_name_to_policydn (context, policyname, &policy_dn)) != 0)
2N/A goto cleanup;
2N/A
2N/A /* the policydn object should be of the krbTicketPolicy object class */
2N/A st = checkattributevalue(ld, policy_dn, "objectClass", attrvalues, &objectmask);
2N/A CHECK_CLASS_VALIDITY(st, objectmask, "ticket policy object: ");
2N/A
2N/A /* Initialize ticket policy structure */
2N/A lpolicy =(krb5_ldap_policy_params *) malloc(sizeof(krb5_ldap_policy_params));
2N/A CHECK_NULL(lpolicy);
2N/A memset(lpolicy, 0, sizeof(krb5_ldap_policy_params));
2N/A
2N/A if ((lpolicy->policy = strdup (policyname)) == NULL) {
2N/A st = ENOMEM;
2N/A goto cleanup;
2N/A }
2N/A
2N/A lpolicy->tl_data = calloc (1, sizeof(*lpolicy->tl_data));
2N/A CHECK_NULL(lpolicy->tl_data);
2N/A lpolicy->tl_data->tl_data_type = KDB_TL_USER_INFO;
2N/A
2N/A LDAP_SEARCH(policy_dn, LDAP_SCOPE_BASE, "(objectclass=krbTicketPolicy)", attributes);
2N/A
2N/A *omask = 0;
2N/A
2N/A ent=ldap_first_entry(ld, result);
2N/A if (ent != NULL) {
2N/A if (krb5_ldap_get_value(ld, ent, "krbmaxticketlife", (int *) &(lpolicy->maxtktlife)) == 0)
2N/A *omask |= LDAP_POLICY_MAXTKTLIFE;
2N/A
2N/A if (krb5_ldap_get_value(ld, ent, "krbmaxrenewableage", (int *) &(lpolicy->maxrenewlife)) == 0)
2N/A *omask |= LDAP_POLICY_MAXRENEWLIFE;
2N/A
2N/A if (krb5_ldap_get_value(ld, ent, "krbticketflags", (int *) &(lpolicy->tktflags)) == 0)
2N/A *omask |= LDAP_POLICY_TKTFLAGS;
2N/A }
2N/A ldap_msgfree(result);
2N/A
2N/A lpolicy->mask = *omask;
2N/A store_tl_data(lpolicy->tl_data, KDB_TL_MASK, omask);
2N/A *policy = lpolicy;
2N/A
2N/Acleanup:
2N/A if (st != 0) {
2N/A krb5_ldap_free_policy(context, lpolicy);
2N/A *policy = NULL;
2N/A }
2N/A krb5_ldap_put_handle_to_pool(ldap_context, ldap_server_handle);
2N/A return st;
2N/A}
2N/A
2N/A
2N/A/*
2N/A * Function to delete ticket policy object from the directory. Before
2N/A * calling this function krb5_ldap_read_policy should be called to
2N/A * check the existence of the object. This serves one major purpose,
2N/A * i.e., if the object to be is anything other than the ticket policy
2N/A * object then the krb5_ldap_read_policy returns an error and thus is
2N/A * not accidently deleted in this function.
2N/A *
2N/A * NOTE: Other kerberos objects (user/realm object) might be having
2N/A * references to the policy object to be deleted. This situation is
2N/A * not handled here, instead is taken care of at all the places where
2N/A * the deleted policy object is read, to ignore a return status of
2N/A * LDAP_NO_SUCH_OBJECT and continue.
2N/A */
2N/A
2N/Akrb5_error_code
2N/Akrb5_ldap_delete_policy(krb5_context context, char *policyname)
2N/A{
2N/A int refcount = 0;
2N/A char *policy_dn = NULL;
2N/A krb5_error_code st = 0;
2N/A LDAP *ld = NULL;
2N/A kdb5_dal_handle *dal_handle=NULL;
2N/A krb5_ldap_context *ldap_context=NULL;
2N/A krb5_ldap_server_handle *ldap_server_handle=NULL;
2N/A
2N/A if (policyname == NULL) {
2N/A st = EINVAL;
2N/A prepend_err_str (context, gettext("Ticket Policy Object DN missing"),st,st);
2N/A goto cleanup;
2N/A }
2N/A
2N/A
2N/A SETUP_CONTEXT();
2N/A GET_HANDLE();
2N/A
2N/A if ((st = krb5_ldap_name_to_policydn (context, policyname, &policy_dn)) != 0)
2N/A goto cleanup;
2N/A
2N/A /* Checking for policy count for 0 and will not permit delete if
2N/A * it is greater than 0. */
2N/A
2N/A if ((st = krb5_ldap_get_reference_count (context, policy_dn,
2N/A "krbTicketPolicyReference", &refcount, ld)) != 0)
2N/A goto cleanup;
2N/A
2N/A if (refcount == 0) {
2N/A if ((st=ldap_delete_ext_s(ld, policy_dn, NULL, NULL)) != 0) {
2N/A prepend_err_str (context,ldap_err2string(st),st,st);
2N/A
2N/A goto cleanup;
2N/A }
2N/A } else {
2N/A st = EINVAL;
2N/A prepend_err_str (context, gettext("Delete Failed: One or more Principals associated with the Ticket Policy"), st, st);
2N/A goto cleanup;
2N/A }
2N/A
2N/Acleanup:
2N/A if (policy_dn != NULL)
2N/A free (policy_dn);
2N/A krb5_ldap_put_handle_to_pool(ldap_context, ldap_server_handle);
2N/A return st;
2N/A}
2N/A
2N/A
2N/A/*
2N/A * list policy objects from Directory
2N/A */
2N/A
2N/Akrb5_error_code
2N/Akrb5_ldap_list_policy(krb5_context context, char *containerdn, char ***policy)
2N/A{
2N/A int i, j, count;
2N/A char **list = NULL;
2N/A char *policycontainerdn = containerdn;
2N/A kdb5_dal_handle *dal_handle=NULL;
2N/A krb5_ldap_context *ldap_context=NULL;
2N/A krb5_error_code st=0;
2N/A
2N/A SETUP_CONTEXT();
2N/A if (policycontainerdn == NULL) {
2N/A policycontainerdn = ldap_context->lrparams->realmdn;
2N/A }
2N/A
2N/A if ((st = krb5_ldap_list(context, &list, "krbTicketPolicy", policycontainerdn)) != 0)
2N/A goto cleanup;
2N/A
2N/A for (i = 0; list[i] != NULL; i++);
2N/A
2N/A count = i;
2N/A
2N/A *policy = (char **) calloc ((unsigned) count + 1, sizeof(char *));
2N/A if (*policy == NULL) {
2N/A st = ENOMEM;
2N/A goto cleanup;
2N/A }
2N/A
2N/A for (i = 0, j = 0; list[i] != NULL; i++, j++) {
2N/A int ret;
2N/A ret = krb5_ldap_policydn_to_name (context, list[i], &(*policy)[i]);
2N/A if (ret != 0)
2N/A j--;
2N/A }
2N/A
2N/Acleanup:
2N/A return st;
2N/A}
2N/A
2N/A/*
2N/A * Function to free the ticket policy object structure.
2N/A * Note: this function assumes that memory of the policy structure is dynamically allocated and hence the whole
2N/A * structure is freed up. Care should be taken not to call this function on a static structure
2N/A */
2N/A
2N/Akrb5_error_code
2N/Akrb5_ldap_free_policy(krb5_context context, krb5_ldap_policy_params *policy)
2N/A{
2N/A
2N/A krb5_error_code st=0;
2N/A
2N/A if (policy == NULL)
2N/A return st;
2N/A
2N/A if (policy->policy)
2N/A free (policy->policy);
2N/A
2N/A if (policy->tl_data) {
2N/A if (policy->tl_data->tl_data_contents)
2N/A free (policy->tl_data->tl_data_contents);
2N/A free (policy->tl_data);
2N/A }
2N/A free (policy);
2N/A
2N/A return st;
2N/A}
2N/A
2N/A/*
2N/A * This function is general object listing routine. It is currently
2N/A * used for ticket policy object listing.
2N/A */
2N/A
2N/Akrb5_error_code
2N/Akrb5_ldap_list(krb5_context context, char ***list, char *objectclass,
2N/A char *containerdn)
2N/A{
2N/A char *filter=NULL, *dn=NULL;
2N/A krb5_error_code st=0, tempst=0;
2N/A int i=0, count=0, filterlen=0;
2N/A LDAP *ld=NULL;
2N/A LDAPMessage *result=NULL,*ent=NULL;
2N/A kdb5_dal_handle *dal_handle=NULL;
2N/A krb5_ldap_context *ldap_context=NULL;
2N/A krb5_ldap_server_handle *ldap_server_handle=NULL;
2N/A
2N/A SETUP_CONTEXT();
2N/A GET_HANDLE();
2N/A
2N/A /* check if the containerdn exists */
2N/A if (containerdn) {
2N/A if ((st=checkattributevalue(ld, containerdn, NULL, NULL, NULL)) != 0) {
2N/A prepend_err_str (context, "Error reading container object: ", st, st);
2N/A goto cleanup;
2N/A }
2N/A }
2N/A
2N/A /* set the filter for the search operation */
2N/A filterlen = strlen("(objectclass=") + strlen(objectclass) + 1 + 1;
2N/A filter = malloc ((unsigned) filterlen);
2N/A if (filter == NULL) {
2N/A st = ENOMEM;
2N/A goto cleanup;
2N/A }
2N/A snprintf(filter, (unsigned) filterlen,"(objectclass=%s)",objectclass);
2N/A
2N/A LDAP_SEARCH(containerdn, LDAP_SCOPE_SUBTREE, filter, NULL);
2N/A
2N/A count = ldap_count_entries(ld, result);
2N/A if (count == -1) {
2N/A ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, &st);
2N/A st = set_ldap_error(context, st, OP_SEARCH);
2N/A goto cleanup;
2N/A }
2N/A *list = (char **) calloc ((unsigned) count+1, sizeof(char *));
2N/A if (*list == NULL) {
2N/A st = ENOMEM;
2N/A goto cleanup;
2N/A }
2N/A
2N/A for (ent=ldap_first_entry(ld, result), count=0; ent != NULL; ent=ldap_next_entry(ld, ent), ++count) {
2N/A if ((dn=ldap_get_dn(ld, ent)) == NULL)
2N/A continue;
2N/A if (((*list)[count] = strdup(dn)) == NULL) {
2N/A ldap_memfree (dn);
2N/A st = ENOMEM;
2N/A goto cleanup;
2N/A }
2N/A ldap_memfree(dn);
2N/A }
2N/A ldap_msgfree(result);
2N/A
2N/Acleanup:
2N/A if (filter)
2N/A free (filter);
2N/A
2N/A /* some error, free up all the memory */
2N/A if (st != 0) {
2N/A if (*list) {
2N/A for (i=0; (*list)[i]; ++i)
2N/A free ((*list)[i]);
2N/A free (*list);
2N/A *list = NULL;
2N/A }
2N/A }
2N/A krb5_ldap_put_handle_to_pool(ldap_context, ldap_server_handle);
2N/A return st;
2N/A}