/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
/* plugins/kdb/ldap/ldap_util/kdb5_ldap_realm.c */
/*
 * Copyright 1990,1991,2001, 2002, 2008 by the Massachusetts Institute of Technology.
 * All Rights Reserved.
 *
 * Export of this software from the United States of America may
 *   require a specific license from the United States Government.
 *   It is the responsibility of any person or organization contemplating
 *   export to obtain such a license before exporting.
 *
 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
 * distribute this software and its documentation for any purpose and
 * without fee is hereby granted, provided that the above copyright
 * notice appear in all copies and that both that copyright notice and
 * this permission notice appear in supporting documentation, and that
 * the name of M.I.T. not be used in advertising or publicity pertaining
 * to distribution of the software without specific, written prior
 * permission.  Furthermore if you modify this software you must label
 * your software as modified software and not distribute it in such a
 * fashion that it might be confused with the original M.I.T. software.
 * M.I.T. makes no representations about the suitability of
 * this software for any purpose.  It is provided "as is" without express
 * or implied warranty.
 */

/*
 * Copyright (C) 1998 by the FundsXpress, INC.
 *
 * All rights reserved.
 *
 * Export of this software from the United States of America may require
 * a specific license from the United States Government.  It is the
 * responsibility of any person or organization contemplating export to
 * obtain such a license before exporting.
 *
 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
 * distribute this software and its documentation for any purpose and
 * without fee is hereby granted, provided that the above copyright
 * notice appear in all copies and that both that copyright notice and
 * this permission notice appear in supporting documentation, and that
 * the name of FundsXpress. not be used in advertising or publicity pertaining
 * to distribution of the software without specific, written prior
 * permission.  FundsXpress makes no representations about the suitability of
 * this software for any purpose.  It is provided "as is" without express
 * or implied warranty.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 */

/* 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.
 */

/*
 * Create / Modify / Destroy / View / List realm(s)
 */

#include <stdio.h>
#include <k5-int.h>
#include <kadm5/admin.h>
#include <adm_proto.h>
#include "kdb5_ldap_util.h"
#include "kdb5_ldap_list.h"
#include <ldap_principal.h>
#include <ldap_krbcontainer.h>
extern time_t get_date(char *); /* kadmin/cli/getdate.o */

char *yes = "yes\n"; /* \n to compare against result of fgets */
krb5_key_salt_tuple def_kslist = {ENCTYPE_DES_CBC_CRC, KRB5_KDB_SALTTYPE_NORMAL};

struct realm_info rblock = {
    KRB5_KDB_MAX_LIFE,
    KRB5_KDB_MAX_RLIFE,
    KRB5_KDB_EXPIRATION,
    KRB5_KDB_DEF_FLAGS,
    (krb5_keyblock *) NULL,
    1,
    &def_kslist
};

krb5_data tgt_princ_entries[] = {
    {0, KRB5_TGS_NAME_SIZE, KRB5_TGS_NAME},
    {0, 0, 0} };

krb5_data db_creator_entries[] = {
    {0, sizeof("db_creation")-1, "db_creation"} };


static krb5_principal_data db_create_princ = {
    0,                                  /* magic number */
    {0, 0, 0},                          /* krb5_data realm */
    db_creator_entries,                 /* krb5_data *data */
    1,                                  /* int length */
    KRB5_NT_SRV_INST                    /* int type */
};

extern char *mkey_password;
extern char *progname;
extern kadm5_config_params global_params;

static void print_realm_params(krb5_ldap_realm_params *rparams, int mask);
static int kdb_ldap_create_principal (krb5_context context, krb5_principal
                                      princ, enum ap_op op,
                                      struct realm_info *pblock,
                                      const krb5_keyblock *master_keyblock);


static char *strdur(time_t duration);
static int get_ticket_policy(krb5_ldap_realm_params *rparams, int *i, char *argv[],int argc);
static krb5_error_code krb5_dbe_update_mod_princ_data_new (krb5_context context, krb5_db_entry *entry, krb5_timestamp mod_date, krb5_const_principal mod_princ);
static krb5_error_code krb5_dbe_update_tl_data_new ( krb5_context context, krb5_db_entry *entry, krb5_tl_data *new_tl_data);

#define ADMIN_LIFETIME 60*60*3 /* 3 hours */
#define CHANGEPW_LIFETIME 60*5 /* 5 minutes */

#ifdef HAVE_EDIRECTORY
#define FREE_DN_LIST(dnlist)    if (dnlist != NULL) {   \
        for (idx=0; dnlist[idx] != NULL; idx++)         \
            free(dnlist[idx]);                          \
        free(dnlist);                                   \
    }
#endif

static int
get_ticket_policy(krb5_ldap_realm_params *rparams, int *i, char *argv[],
                  int argc)
{
    time_t date;
    time_t now;
    int mask = 0;
    krb5_error_code retval = 0;
    krb5_boolean no_msg = FALSE;

    krb5_boolean print_usage = FALSE;
    char *me = progname;

    time(&now);
    if (!strcmp(argv[*i], "-maxtktlife")) {
        if (++(*i) > argc-1)
            goto err_usage;
        date = get_date(argv[*i]);
        if (date == (time_t)(-1)) {
            retval = EINVAL;
            com_err(me, retval, _("while providing time specification"));
            goto err_nomsg;
        }
        rparams->max_life = date-now;
        mask |= LDAP_REALM_MAXTICKETLIFE;
    }


    else if (!strcmp(argv[*i], "-maxrenewlife")) {
        if (++(*i) > argc-1)
            goto err_usage;

        date = get_date(argv[*i]);
        if (date == (time_t)(-1)) {
            retval = EINVAL;
            com_err(me, retval, _("while providing time specification"));
            goto err_nomsg;
        }
        rparams->max_renewable_life = date-now;
        mask |= LDAP_REALM_MAXRENEWLIFE;
    } else if (!strcmp((argv[*i] + 1), "allow_postdated")) {
        if (*(argv[*i]) == '+')
            rparams->tktflags &= (int)(~KRB5_KDB_DISALLOW_POSTDATED);
        else if (*(argv[*i]) == '-')
            rparams->tktflags |= KRB5_KDB_DISALLOW_POSTDATED;
        else
            goto err_usage;

        mask |= LDAP_REALM_KRBTICKETFLAGS;
    } else if (!strcmp((argv[*i] + 1), "allow_forwardable")) {
        if (*(argv[*i]) == '+')
            rparams->tktflags &= (int)(~KRB5_KDB_DISALLOW_FORWARDABLE);

        else if (*(argv[*i]) == '-')
            rparams->tktflags |= KRB5_KDB_DISALLOW_FORWARDABLE;
        else
            goto err_usage;

        mask |= LDAP_REALM_KRBTICKETFLAGS;
    } else if (!strcmp((argv[*i] + 1), "allow_renewable")) {
        if (*(argv[*i]) == '+')
            rparams->tktflags &= (int)(~KRB5_KDB_DISALLOW_RENEWABLE);
        else if (*(argv[*i]) == '-')
            rparams->tktflags |= KRB5_KDB_DISALLOW_RENEWABLE;
        else
            goto err_usage;

        mask |= LDAP_REALM_KRBTICKETFLAGS;
    } else if (!strcmp((argv[*i] + 1), "allow_proxiable")) {
        if (*(argv[*i]) == '+')
            rparams->tktflags &= (int)(~KRB5_KDB_DISALLOW_PROXIABLE);
        else if (*(argv[*i]) == '-')
            rparams->tktflags |= KRB5_KDB_DISALLOW_PROXIABLE;
        else
            goto err_usage;

        mask |= LDAP_REALM_KRBTICKETFLAGS;
    } else if (!strcmp((argv[*i] + 1), "allow_dup_skey")) {
        if (*(argv[*i]) == '+')
            rparams->tktflags &= (int)(~KRB5_KDB_DISALLOW_DUP_SKEY);
        else if (*(argv[*i]) == '-')
            rparams->tktflags |= KRB5_KDB_DISALLOW_DUP_SKEY;
        else
            goto err_usage;

        mask |= LDAP_REALM_KRBTICKETFLAGS;
    }

    else if (!strcmp((argv[*i] + 1), "requires_preauth")) {
        if (*(argv[*i]) == '+')
            rparams->tktflags |= KRB5_KDB_REQUIRES_PRE_AUTH;
        else if (*(argv[*i]) == '-')
            rparams->tktflags &= (int)(~KRB5_KDB_REQUIRES_PRE_AUTH);
        else
            goto err_usage;

        mask |= LDAP_REALM_KRBTICKETFLAGS;
    } else if (!strcmp((argv[*i] + 1), "requires_hwauth")) {
        if (*(argv[*i]) == '+')
            rparams->tktflags |= KRB5_KDB_REQUIRES_HW_AUTH;
        else if (*(argv[*i]) == '-')
            rparams->tktflags &= (int)(~KRB5_KDB_REQUIRES_HW_AUTH);
        else
            goto err_usage;

        mask |= LDAP_REALM_KRBTICKETFLAGS;
    } else if (!strcmp((argv[*i] + 1), "allow_svr")) {
        if (*(argv[*i]) == '+')
            rparams->tktflags &= (int)(~KRB5_KDB_DISALLOW_SVR);
        else if (*(argv[*i]) == '-')
            rparams->tktflags |= KRB5_KDB_DISALLOW_SVR;
        else
            goto err_usage;

        mask |= LDAP_REALM_KRBTICKETFLAGS;
    } else if (!strcmp((argv[*i] + 1), "allow_tgs_req")) {
        if (*(argv[*i]) == '+')
            rparams->tktflags &= (int)(~KRB5_KDB_DISALLOW_TGT_BASED);
        else if (*(argv[*i]) == '-')
            rparams->tktflags |= KRB5_KDB_DISALLOW_TGT_BASED;
        else
            goto err_usage;

        mask |= LDAP_REALM_KRBTICKETFLAGS;
    } else if (!strcmp((argv[*i] + 1), "allow_tix")) {
        if (*(argv[*i]) == '+')
            rparams->tktflags &= (int)(~KRB5_KDB_DISALLOW_ALL_TIX);
        else if (*(argv[*i]) == '-')
            rparams->tktflags |= KRB5_KDB_DISALLOW_ALL_TIX;
        else
            goto err_usage;

        mask |= LDAP_REALM_KRBTICKETFLAGS;
    } else if (!strcmp((argv[*i] + 1), "needchange")) {
        if (*(argv[*i]) == '+')
            rparams->tktflags |= KRB5_KDB_REQUIRES_PWCHANGE;
        else if (*(argv[*i]) == '-')
            rparams->tktflags &= (int)(~KRB5_KDB_REQUIRES_PWCHANGE);
        else
            goto err_usage;

        mask |= LDAP_REALM_KRBTICKETFLAGS;
    } else if (!strcmp((argv[*i] + 1), "password_changing_service")) {
        if (*(argv[*i]) == '+')
            rparams->tktflags |= KRB5_KDB_PWCHANGE_SERVICE;
        else if (*(argv[*i]) == '-')
            rparams->tktflags &= (int)(~KRB5_KDB_PWCHANGE_SERVICE);
        else
            goto err_usage;

        mask |=LDAP_REALM_KRBTICKETFLAGS;
    }
err_usage:
    print_usage = TRUE;

err_nomsg:
    no_msg = TRUE;

    return mask;
}

/*
 * This function will create a realm on the LDAP Server, with
 * the specified attributes.
 */
void
kdb5_ldap_create(int argc, char *argv[])
{
    krb5_error_code retval = 0;
    krb5_keyblock master_keyblock;
    krb5_ldap_realm_params *rparams = NULL;
    krb5_principal master_princ = NULL;
    kdb5_dal_handle *dal_handle = NULL;
    krb5_ldap_context *ldap_context=NULL;
    krb5_boolean realm_obj_created = FALSE;
    krb5_boolean create_complete = FALSE;
    krb5_boolean print_usage = FALSE;
    krb5_boolean no_msg = FALSE;
    char *oldcontainerref=NULL;
    char pw_str[1024];
    int do_stash = 0;
    int i = 0;
    int mask = 0, ret_mask = 0;
    char **list = NULL;
#ifdef HAVE_EDIRECTORY
    int rightsmask = 0;
#endif

    memset(&master_keyblock, 0, sizeof(master_keyblock));

    rparams = (krb5_ldap_realm_params *)malloc(
        sizeof(krb5_ldap_realm_params));
    if (rparams == NULL) {
        retval = ENOMEM;
        goto cleanup;
    }
    memset(rparams, 0, sizeof(krb5_ldap_realm_params));

    /* Parse the arguments */
    for (i = 1; i < argc; i++) {
        if (!strcmp(argv[i], "-subtrees")) {
            if (++i > argc-1)
                goto err_usage;

            if (strncmp(argv[i], "", strlen(argv[i]))!=0) {
                list = (char **) calloc(MAX_LIST_ENTRIES, sizeof(char *));
                if (list == NULL) {
                    retval = ENOMEM;
                    goto cleanup;
                }
                if ((retval = krb5_parse_list(argv[i], LIST_DELIMITER, list))) {
                    free(list);
                    list = NULL;
                    goto cleanup;
                }

                rparams->subtreecount=0;
                while (list[rparams->subtreecount]!=NULL)
                    (rparams->subtreecount)++;
                rparams->subtree = list;
            } else if (strncmp(argv[i], "", strlen(argv[i]))==0) {
                /* dont allow subtree value to be set at the root(NULL, "") of the tree */
                com_err(progname, EINVAL,
                        _("for subtree while creating realm '%s'"),
                        global_params.realm);
                goto err_nomsg;
            }
            rparams->subtree[rparams->subtreecount] = NULL;
            mask |= LDAP_REALM_SUBTREE;
        } else if (!strcmp(argv[i], "-containerref")) {
            if (++i > argc-1)
                goto err_usage;
            if (strncmp(argv[i], "", strlen(argv[i]))==0) {
                /* dont allow containerref value to be set at the root(NULL, "") of the tree */
                com_err(progname, EINVAL,
                        _("for container reference while creating realm '%s'"),
                        global_params.realm);
                goto err_nomsg;
            }
            rparams->containerref = strdup(argv[i]);
            if (rparams->containerref == NULL) {
                retval = ENOMEM;
                goto cleanup;
            }
            mask |= LDAP_REALM_CONTREF;
        } else if (!strcmp(argv[i], "-sscope")) {
            if (++i > argc-1)
                goto err_usage;
            /* Possible values for search scope are
             * one (or 1) and sub (or 2)
             */
            if (!strcasecmp(argv[i], "one")) {
                rparams->search_scope = 1;
            } else if (!strcasecmp(argv[i], "sub")) {
                rparams->search_scope = 2;
            } else {
                rparams->search_scope = atoi(argv[i]);
                if ((rparams->search_scope != 1) &&
                    (rparams->search_scope != 2)) {
                    com_err(progname, EINVAL, _("invalid search scope while "
                                                "creating realm '%s'"),
                            global_params.realm);
                    goto err_nomsg;
                }
            }
            mask |= LDAP_REALM_SEARCHSCOPE;
        }
#ifdef HAVE_EDIRECTORY
        else if (!strcmp(argv[i], "-kdcdn")) {
            if (++i > argc-1)
                goto err_usage;
            rparams->kdcservers = (char **)malloc(
                sizeof(char *) * MAX_LIST_ENTRIES);
            if (rparams->kdcservers == NULL) {
                retval = ENOMEM;
                goto cleanup;
            }
            memset(rparams->kdcservers, 0, sizeof(char*)*MAX_LIST_ENTRIES);
            if ((retval = krb5_parse_list(argv[i], LIST_DELIMITER,
                                          rparams->kdcservers))) {
                goto cleanup;
            }
            mask |= LDAP_REALM_KDCSERVERS;
        } else if (!strcmp(argv[i], "-admindn")) {
            if (++i > argc-1)
                goto err_usage;
            rparams->adminservers = (char **)malloc(
                sizeof(char *) * MAX_LIST_ENTRIES);
            if (rparams->adminservers == NULL) {
                retval = ENOMEM;
                goto cleanup;
            }
            memset(rparams->adminservers, 0, sizeof(char*)*MAX_LIST_ENTRIES);
            if ((retval = krb5_parse_list(argv[i], LIST_DELIMITER,
                                          rparams->adminservers))) {
                goto cleanup;
            }
            mask |= LDAP_REALM_ADMINSERVERS;
        } else if (!strcmp(argv[i], "-pwddn")) {
            if (++i > argc-1)
                goto err_usage;
            rparams->passwdservers = (char **)malloc(
                sizeof(char *) * MAX_LIST_ENTRIES);
            if (rparams->passwdservers == NULL) {
                retval = ENOMEM;
                goto cleanup;
            }
            memset(rparams->passwdservers, 0, sizeof(char*)*MAX_LIST_ENTRIES);
            if ((retval = krb5_parse_list(argv[i], LIST_DELIMITER,
                                          rparams->passwdservers))) {
                goto cleanup;
            }
            mask |= LDAP_REALM_PASSWDSERVERS;
        }
#endif
        else if (!strcmp(argv[i], "-s")) {
            do_stash = 1;
        } else if ((ret_mask= get_ticket_policy(rparams,&i,argv,argc)) !=0) {
            mask|=ret_mask;
        }

        else {
            printf(_("'%s' is an invalid option\n"), argv[i]);
            goto err_usage;
        }
    }

    /* If the default enctype/salttype is not provided, use the
     * default values and also add to the list of supported
     * enctypes/salttype
     */

    rblock.max_life = global_params.max_life;
    rblock.max_rlife = global_params.max_rlife;
    rblock.expiration = global_params.expiration;
    rblock.flags = global_params.flags;
    rblock.nkslist = global_params.num_keysalts;
    rblock.kslist = global_params.keysalts;

    krb5_princ_set_realm_data(util_context, &db_create_princ, global_params.realm);
    krb5_princ_set_realm_length(util_context, &db_create_princ, strlen(global_params.realm));

    printf(_("Initializing database for realm '%s'\n"), global_params.realm);

    if (!mkey_password) {
        unsigned int pw_size;
        printf(_("You will be prompted for the database Master Password.\n"));
        printf(_("It is important that you NOT FORGET this password.\n"));
        fflush(stdout);

        pw_size = sizeof (pw_str);
        memset(pw_str, 0, pw_size);

        retval = krb5_read_password(util_context, KRB5_KDC_MKEY_1, KRB5_KDC_MKEY_2,
                                    pw_str, &pw_size);
        if (retval) {
            com_err(progname, retval,
                    _("while reading master key from keyboard"));
            goto err_nomsg;
        }
        mkey_password = pw_str;
    }

    rparams->realm_name = strdup(global_params.realm);
    if (rparams->realm_name == NULL) {
        retval = ENOMEM;
        com_err(progname, ENOMEM, _("while creating realm '%s'"),
                global_params.realm);
        goto err_nomsg;
    }

    dal_handle = util_context->dal_handle;
    ldap_context = (krb5_ldap_context *) dal_handle->db_context;
    if (!ldap_context) {
        retval = EINVAL;
        goto cleanup;
    }

    /* read the kerberos container */
    if ((retval=krb5_ldap_read_krbcontainer_params (util_context,
                                                    &(ldap_context->krbcontainer))) == KRB5_KDB_NOENTRY) {
        /* Prompt the user for entering the DN of Kerberos container */
        char krb_location[MAX_KRB_CONTAINER_LEN];
        krb5_ldap_krbcontainer_params kparams;
        int krb_location_len = 0;
        memset(&kparams, 0, sizeof(kparams));

        /* Read the kerberos container location from configuration file */
        if (ldap_context->conf_section) {
            if ((retval=profile_get_string(util_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 ((retval=profile_get_string(util_context->profile,
                                           KDB_MODULE_DEF_SECTION,
                                           KRB5_CONF_LDAP_KERBEROS_CONTAINER_DN, NULL,
                                           NULL, &kparams.DN)) != 0) {
                goto cleanup;
            }
        }

        printf(_("\nKerberos container is missing. Creating now...\n"));
        if (kparams.DN == NULL) {
#ifdef HAVE_EDIRECTORY
            printf("Enter DN of Kerberos container [cn=Kerberos,cn=Security]: ");
#else
            printf(_("Enter DN of Kerberos container: "));
#endif
            if (fgets(krb_location, MAX_KRB_CONTAINER_LEN, stdin) != NULL) {
                /* Remove the newline character at the end */
                krb_location_len = strlen(krb_location);
                if ((krb_location[krb_location_len - 1] == '\n') ||
                    (krb_location[krb_location_len - 1] == '\r')) {
                    krb_location[krb_location_len - 1] = '\0';
                    krb_location_len--;
                }
                /* If the user has not given any input, take the default location */
                else if (krb_location[0] == '\0')
                    kparams.DN = NULL;
                else
                    kparams.DN = krb_location;
            } else
                kparams.DN = NULL;
        }

        /* create the kerberos container */
        retval = krb5_ldap_create_krbcontainer(util_context,
                                               ((kparams.DN != NULL) ? &kparams : NULL));
        if (retval)
            goto cleanup;

        retval = krb5_ldap_read_krbcontainer_params(util_context,
                                                    &(ldap_context->krbcontainer));
        if (retval) {
            com_err(progname, retval,
                    _("while reading kerberos container information"));
            goto cleanup;
        }
    } else if (retval) {
        com_err(progname, retval,
                _("while reading kerberos container information"));
        goto cleanup;
    }

    if ((retval = krb5_ldap_create_realm(util_context,
                                         /* global_params.realm, */ rparams, mask))) {
        goto cleanup;
    }

    /* We just created the Realm container. Here starts our transaction tracking */
    realm_obj_created = TRUE;

    if ((retval = krb5_ldap_read_realm_params(util_context,
                                              global_params.realm,
                                              &(ldap_context->lrparams),
                                              &mask))) {
        com_err(progname, retval, _("while reading information of realm '%s'"),
                global_params.realm);
        goto err_nomsg;
    }
    ldap_context->lrparams->realm_name = strdup(global_params.realm);
    if (ldap_context->lrparams->realm_name == NULL) {
        retval = ENOMEM;
        goto cleanup;
    }

    /* assemble & parse the master key name */
    if ((retval = krb5_db_setup_mkey_name(util_context,
                                          global_params.mkey_name,
                                          global_params.realm,
                                          0, &master_princ))) {
        com_err(progname, retval, _("while setting up master key name"));
        goto err_nomsg;
    }

    /* Obtain master key from master password */
    {
        krb5_data master_salt, pwd;

        pwd.data = mkey_password;
        pwd.length = strlen(mkey_password);
        retval = krb5_principal2salt(util_context, master_princ, &master_salt);
        if (retval) {
            com_err(progname, retval, _("while calculating master key salt"));
            goto err_nomsg;
        }

        retval = krb5_c_string_to_key(util_context, global_params.enctype,
                                      &pwd, &master_salt, &master_keyblock);

        if (master_salt.data)
            free(master_salt.data);

        if (retval) {
            com_err(progname, retval,
                    _("while transforming master key from password"));
            goto err_nomsg;
        }

        rblock.key = &master_keyblock;
    }

    /* Create special principals inside the realm subtree */
    {
        char princ_name[MAX_PRINC_SIZE];
        krb5_principal_data tgt_princ = {
            0,                                  /* magic number */
            {0, 0, 0},                          /* krb5_data realm */
            tgt_princ_entries,                  /* krb5_data *data */
            2,                                  /* int length */
            KRB5_NT_SRV_INST                    /* int type */
        };
        krb5_principal p, temp_p=NULL;

        krb5_princ_set_realm_data(util_context, &tgt_princ, global_params.realm);
        krb5_princ_set_realm_length(util_context, &tgt_princ, strlen(global_params.realm));
        krb5_princ_component(util_context, &tgt_princ,1)->data = global_params.realm;
        krb5_princ_component(util_context, &tgt_princ,1)->length = strlen(global_params.realm);
        /* The container reference value is set to NULL, to avoid service principals
         * getting created within the container reference at realm creation */
        if (ldap_context->lrparams->containerref != NULL) {
            oldcontainerref = ldap_context->lrparams->containerref;
            ldap_context->lrparams->containerref = NULL;
        }

        /* Create 'K/M' ... */
        rblock.flags |= KRB5_KDB_DISALLOW_ALL_TIX;
        if ((retval = kdb_ldap_create_principal(util_context, master_princ,
                                                MASTER_KEY, &rblock,
                                                &master_keyblock))) {
            com_err(progname, retval,
                    _("while adding entries to the database"));
            goto err_nomsg;
        }

        /* Create 'krbtgt' ... */
        rblock.flags = 0; /* reset the flags */
        if ((retval = kdb_ldap_create_principal(util_context, &tgt_princ,
                                                TGT_KEY, &rblock,
                                                &master_keyblock))) {
            com_err(progname, retval,
                    _("while adding entries to the database"));
            goto err_nomsg;
        }

        /* Create 'kadmin/admin' ... */
        snprintf(princ_name, sizeof(princ_name), "%s@%s", KADM5_ADMIN_SERVICE, global_params.realm);
        if ((retval = krb5_parse_name(util_context, princ_name, &p))) {
            com_err(progname, retval,
                    _("while adding entries to the database"));
            goto err_nomsg;
        }
        rblock.max_life = ADMIN_LIFETIME;
        rblock.flags = KRB5_KDB_DISALLOW_TGT_BASED;
        if ((retval = kdb_ldap_create_principal(util_context, p, TGT_KEY,
                                                &rblock, &master_keyblock))) {
            krb5_free_principal(util_context, p);
            com_err(progname, retval,
                    _("while adding entries to the database"));
            goto err_nomsg;
        }
        krb5_free_principal(util_context, p);

        /* Create 'kadmin/changepw' ... */
        snprintf(princ_name, sizeof(princ_name), "%s@%s", KADM5_CHANGEPW_SERVICE, global_params.realm);
        if ((retval = krb5_parse_name(util_context, princ_name, &p))) {
            com_err(progname, retval,
                    _("while adding entries to the database"));
            goto err_nomsg;
        }
        rblock.max_life = CHANGEPW_LIFETIME;
        rblock.flags = KRB5_KDB_DISALLOW_TGT_BASED |
            KRB5_KDB_PWCHANGE_SERVICE;
        if ((retval = kdb_ldap_create_principal(util_context, p, TGT_KEY,
                                                &rblock, &master_keyblock))) {
            krb5_free_principal(util_context, p);
            com_err(progname, retval,
                    _("while adding entries to the database"));
            goto err_nomsg;
        }
        krb5_free_principal(util_context, p);

        /* Create 'kadmin/history' ... */
        snprintf(princ_name, sizeof(princ_name), "%s@%s", KADM5_HIST_PRINCIPAL, global_params.realm);
        if ((retval = krb5_parse_name(util_context, princ_name, &p))) {
            com_err(progname, retval,
                    _("while adding entries to the database"));
            goto err_nomsg;
        }
        rblock.max_life = global_params.max_life;
        rblock.flags = 0;
        if ((retval = kdb_ldap_create_principal(util_context, p, TGT_KEY,
                                                &rblock, &master_keyblock))) {
            krb5_free_principal(util_context, p);
            com_err(progname, retval,
                    _("while adding entries to the database"));
            goto err_nomsg;
        }
        krb5_free_principal(util_context, p);

        /* Create 'kadmin/<hostname>' ... */
        if ((retval=krb5_sname_to_principal(util_context, NULL, "kadmin", KRB5_NT_SRV_HST, &p))) {
            com_err(progname, retval, _("krb5_sname_to_principal, while "
                                        "adding entries to the database"));
            goto err_nomsg;
        }

        if ((retval=krb5_copy_principal(util_context, p, &temp_p))) {
            com_err(progname, retval, _("krb5_copy_principal, while adding "
                                        "entries to the database"));
            goto err_nomsg;
        }

        /* change the realm portion to the default realm */
        free(temp_p->realm.data);
        temp_p->realm.length = strlen(util_context->default_realm);
        temp_p->realm.data = strdup(util_context->default_realm);
        if (temp_p->realm.data == NULL) {
            com_err(progname, ENOMEM,
                    _("while adding entries to the database"));
            goto err_nomsg;
        }

        rblock.max_life = ADMIN_LIFETIME;
        rblock.flags = KRB5_KDB_DISALLOW_TGT_BASED;
        if ((retval = kdb_ldap_create_principal(util_context, temp_p, TGT_KEY,
                                                &rblock, &master_keyblock))) {
            krb5_free_principal(util_context, p);
            com_err(progname, retval,
                    _("while adding entries to the database"));
            goto err_nomsg;
        }
        krb5_free_principal(util_context, temp_p);
        krb5_free_principal(util_context, p);

        if (oldcontainerref != NULL) {
            ldap_context->lrparams->containerref = oldcontainerref;
            oldcontainerref=NULL;
        }
    }

#ifdef HAVE_EDIRECTORY
    if ((mask & LDAP_REALM_KDCSERVERS) || (mask & LDAP_REALM_ADMINSERVERS) ||
        (mask & LDAP_REALM_PASSWDSERVERS)) {

        printf(_("Changing rights for the service object. Please wait ... "));
        fflush(stdout);

        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 ((retval=krb5_ldap_add_service_rights(util_context,
                                                         LDAP_KDC_SERVICE, rparams->kdcservers[i],
                                                         rparams->realm_name, rparams->subtree, rparams->containerref, rightsmask)) != 0) {
                    printf(_("failed\n"));
                    com_err(progname, retval,
                            _("while assigning rights to '%s'"),
                            rparams->realm_name);
                    goto err_nomsg;
                }
            }
        }

        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 ((retval=krb5_ldap_add_service_rights(util_context,
                                                         LDAP_ADMIN_SERVICE, rparams->adminservers[i],
                                                         rparams->realm_name, rparams->subtree, rparams->containerref, rightsmask)) != 0) {
                    printf(_("failed\n"));
                    com_err(progname, retval,
                            _("while assigning rights to '%s'"),
                            rparams->realm_name);
                    goto err_nomsg;
                }
            }
        }

        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 ((retval=krb5_ldap_add_service_rights(util_context,
                                                         LDAP_PASSWD_SERVICE, rparams->passwdservers[i],
                                                         rparams->realm_name, rparams->subtree, rparams->containerref, rightsmask)) != 0) {
                    printf(_("failed\n"));
                    com_err(progname, retval,
                            _("while assigning rights to '%s'"),
                            rparams->realm_name);
                    goto err_nomsg;
                }
            }
        }

        printf(_("done\n"));
    }
#endif
    /* The Realm creation is completed. Here is the end of transaction */
    create_complete = TRUE;

    /* Stash the master key only if '-s' option is specified */
    if (do_stash || global_params.mask & KADM5_CONFIG_STASH_FILE) {
        krb5_kvno mkey_kvno;
        /*
         * Determine the kvno to use, it must be that used to create the master
         * key princ.
         */
        if (global_params.mask & KADM5_CONFIG_KVNO)
            mkey_kvno = global_params.kvno; /* user specified */
        else
            mkey_kvno = 1;  /* Default */

        retval = krb5_db_store_master_key(util_context,
                                          global_params.stash_file,
                                          master_princ,
                                          mkey_kvno,
                                          &master_keyblock, NULL);
        if (retval) {
            com_err(progname, errno, _("while storing key"));
            printf(_("Warning: couldn't stash master key.\n"));
        }
    }

    goto cleanup;


err_usage:
    print_usage = TRUE;

err_nomsg:
    no_msg = TRUE;

cleanup:
    /* If the Realm creation is not complete, do the roll-back here */
    if ((realm_obj_created) && (!create_complete))
        krb5_ldap_delete_realm(util_context, global_params.realm);

    if (rparams)
        krb5_ldap_free_realm_params(rparams);

    memset (pw_str, 0, sizeof (pw_str));

    if (print_usage)
        db_usage(CREATE_REALM);

    if (retval) {
        if (!no_msg) {
            com_err(progname, retval, _("while creating realm '%s'"),
                    global_params.realm);
        }
        exit_status++;
    }

    return;
}


/*
 * This function will modify the attributes of a given realm object
 */
void
kdb5_ldap_modify(int argc, char *argv[])
{
    krb5_error_code retval = 0;
    krb5_ldap_realm_params *rparams = NULL;
    krb5_boolean print_usage = FALSE;
    krb5_boolean no_msg = FALSE;
    kdb5_dal_handle *dal_handle = NULL;
    krb5_ldap_context *ldap_context=NULL;
    int i = 0;
    int mask = 0, rmask = 0, ret_mask = 0;
    char **slist = {NULL};
#ifdef HAVE_EDIRECTORY
    int j = 0, idx = 0;
    char *list[MAX_LIST_ENTRIES];
    int existing_entries = 0, list_entries = 0;
    int newkdcdn = 0, newadmindn = 0, newpwddn = 0;
    char **tempstr = NULL;
    char **oldkdcdns = NULL;
    char **oldadmindns = NULL;
    char **oldpwddns = NULL;
    char **newkdcdns = NULL;
    char **newsubtrees = NULL;
    char **newadmindns = NULL;
    char **newpwddns = NULL;
    char **oldsubtrees = NULL;
    char *oldcontainerref = NULL;
    int rightsmask = 0;
    int subtree_changed = 0;
#endif

    dal_handle = util_context->dal_handle;
    ldap_context = (krb5_ldap_context *) dal_handle->db_context;
    if (!(ldap_context)) {
        retval = EINVAL;
        goto cleanup;
    }

    if ((retval = krb5_ldap_read_krbcontainer_params(util_context,
                                                     &(ldap_context->krbcontainer)))) {
        com_err(progname, retval,
                _("while reading Kerberos container information"));
        goto err_nomsg;
    }

    retval = krb5_ldap_read_realm_params(util_context,
                                         global_params.realm, &rparams, &rmask);
    if (retval)
        goto cleanup;
    /* Parse the arguments */
    for (i = 1; i < argc; i++) {
        int k = 0;
        if (!strcmp(argv[i], "-subtrees")) {
            if (++i > argc-1)
                goto err_usage;

            if (rmask & LDAP_REALM_SUBTREE) {
                if (rparams->subtree) {
#ifdef HAVE_EDIRECTORY
                    oldsubtrees =  (char **) calloc(rparams->subtreecount+1, sizeof(char *));
                    if (oldsubtrees == NULL) {
                        retval = ENOMEM;
                        goto cleanup;
                    }
                    for (k=0; rparams->subtree[k]!=NULL && rparams->subtreecount; k++) {
                        oldsubtrees[k] = strdup(rparams->subtree[k]);
                        if (oldsubtrees[k] == NULL) {
                            retval = ENOMEM;
                            goto cleanup;
                        }
                    }
#endif
                    for (k=0; k<rparams->subtreecount && rparams->subtree[k]; k++)
                        free(rparams->subtree[k]);
                    rparams->subtreecount=0;
                }
            }
            if (strncmp(argv[i] ,"", strlen(argv[i]))!=0) {
                slist =  (char **) calloc(MAX_LIST_ENTRIES, sizeof(char *));
                if (slist == NULL) {
                    retval = ENOMEM;
                    goto cleanup;
                }
                if ((retval = krb5_parse_list(argv[i], LIST_DELIMITER, slist))) {
                    free(slist);
                    slist = NULL;
                    goto cleanup;
                }

                rparams->subtreecount=0;
                while (slist[rparams->subtreecount]!=NULL)
                    (rparams->subtreecount)++;
                rparams->subtree =  slist;
            } else if (strncmp(argv[i], "", strlen(argv[i]))==0) {
                /* dont allow subtree value to be set at the root(NULL, "") of the tree */
                com_err(progname, EINVAL,
                        _("for subtree while modifying realm '%s'"),
                        global_params.realm);
                goto err_nomsg;
            }
            rparams->subtree[rparams->subtreecount] = NULL;
            mask |= LDAP_REALM_SUBTREE;
        } else if (!strncmp(argv[i], "-containerref", strlen(argv[i]))) {
            if (++i > argc-1)
                goto err_usage;
            if (strncmp(argv[i], "", strlen(argv[i]))==0) {
                /* dont allow containerref value to be set at the root(NULL, "") of the tree */
                com_err(progname, EINVAL, _("for container reference while "
                                            "modifying realm '%s'"),
                        global_params.realm);
                goto err_nomsg;
            }
#ifdef HAVE_EDIRECTORY
            if (rparams->containerref != NULL) {
                oldcontainerref = rparams->containerref;
            }
#endif
            rparams->containerref = strdup(argv[i]);
            if (rparams->containerref == NULL) {
                retval = ENOMEM;
                goto cleanup;
            }
            mask |= LDAP_REALM_CONTREF;
        } else if (!strcmp(argv[i], "-sscope")) {
            if (++i > argc-1)
                goto err_usage;
            /* Possible values for search scope are
             * one (or 1) and sub (or 2)
             */
            if (strcasecmp(argv[i], "one") == 0) {
                rparams->search_scope = 1;
            } else if (strcasecmp(argv[i], "sub") == 0) {
                rparams->search_scope = 2;
            } else {
                rparams->search_scope = atoi(argv[i]);
                if ((rparams->search_scope != 1) &&
                    (rparams->search_scope != 2)) {
                    retval = EINVAL;
                    com_err(progname, retval,
                            _("specified for search scope while modifying "
                              "information of realm '%s'"),
                            global_params.realm);
                    goto err_nomsg;
                }
            }
            mask |= LDAP_REALM_SEARCHSCOPE;
        }
#ifdef HAVE_EDIRECTORY
        else if (!strcmp(argv[i], "-kdcdn")) {
            if (++i > argc-1)
                goto err_usage;

            if ((rmask & LDAP_REALM_KDCSERVERS) && (rparams->kdcservers)) {
                if (!oldkdcdns) {
                    /* Store the old kdc dns list for removing rights */
                    oldkdcdns = (char**) calloc(MAX_LIST_ENTRIES, sizeof(char*));
                    if (oldkdcdns == NULL) {
                        retval = ENOMEM;
                        goto cleanup;
                    }

                    for (j=0; rparams->kdcservers[j] != NULL; j++) {
                        oldkdcdns[j] = strdup(rparams->kdcservers[j]);
                        if (oldkdcdns[j] == NULL) {
                            retval = ENOMEM;
                            goto cleanup;
                        }
                    }
                    oldkdcdns[j] = NULL;
                }

                krb5_free_list_entries(rparams->kdcservers);
                free(rparams->kdcservers);
            }

            rparams->kdcservers = (char **)malloc(
                sizeof(char *) * MAX_LIST_ENTRIES);
            if (rparams->kdcservers == NULL) {
                retval = ENOMEM;
                goto cleanup;
            }
            memset(rparams->kdcservers, 0, sizeof(char *)*MAX_LIST_ENTRIES);
            if ((retval = krb5_parse_list(argv[i], LIST_DELIMITER,
                                          rparams->kdcservers))) {
                goto cleanup;
            }
            mask |= LDAP_REALM_KDCSERVERS;
            /* Going to replace the existing value by this new value. Hence
             * setting flag indicating that add or clear options will be ignored
             */
            newkdcdn = 1;
        } else if (!strcmp(argv[i], "-clearkdcdn")) {
            if (++i > argc-1)
                goto err_usage;
            if ((!newkdcdn) && (rmask & LDAP_REALM_KDCSERVERS) && (rparams->kdcservers)) {
                if (!oldkdcdns) {
                    /* Store the old kdc dns list for removing rights */
                    oldkdcdns = (char**) calloc(MAX_LIST_ENTRIES, sizeof(char*));
                    if (oldkdcdns == NULL) {
                        retval = ENOMEM;
                        goto cleanup;
                    }

                    for (j=0; rparams->kdcservers[j] != NULL; j++) {
                        oldkdcdns[j] = strdup(rparams->kdcservers[j]);
                        if (oldkdcdns[j] == NULL) {
                            retval = ENOMEM;
                            goto cleanup;
                        }
                    }
                    oldkdcdns[j] = NULL;
                }

                memset(list, 0, sizeof(char *) * MAX_LIST_ENTRIES);
                if ((retval = krb5_parse_list(argv[i], LIST_DELIMITER, list))) {
                    goto cleanup;
                }
                list_modify_str_array(&rparams->kdcservers, (const char **)list,
                                      LIST_MODE_DELETE);
                mask |= LDAP_REALM_KDCSERVERS;
                krb5_free_list_entries(list);
            }
        } else if (!strcmp(argv[i], "-addkdcdn")) {
            if (++i > argc-1)
                goto err_usage;
            if (!newkdcdn) {
                if ((rmask & LDAP_REALM_KDCSERVERS) && (rparams->kdcservers) && (!oldkdcdns)) {
                    /* Store the old kdc dns list for removing rights */
                    oldkdcdns = (char**) calloc(MAX_LIST_ENTRIES, sizeof(char*));
                    if (oldkdcdns == NULL) {
                        retval = ENOMEM;
                        goto cleanup;
                    }

                    for (j = 0; rparams->kdcservers[j] != NULL; j++) {
                        oldkdcdns[j] = strdup(rparams->kdcservers[j]);
                        if (oldkdcdns[j] == NULL) {
                            retval = ENOMEM;
                            goto cleanup;
                        }
                    }
                    oldkdcdns[j] = NULL;
                }

                memset(list, 0, sizeof(char *) * MAX_LIST_ENTRIES);
                if ((retval = krb5_parse_list(argv[i], LIST_DELIMITER, list))) {
                    goto cleanup;
                }
                existing_entries = list_count_str_array(rparams->kdcservers);
                list_entries = list_count_str_array(list);
                if (rmask & LDAP_REALM_KDCSERVERS) {
                    tempstr = (char **)realloc(
                        rparams->kdcservers,
                        sizeof(char *) * (existing_entries+list_entries+1));
                    if (tempstr == NULL) {
                        retval = ENOMEM;
                        goto cleanup;
                    }
                    rparams->kdcservers = tempstr;
                } else {
                    rparams->kdcservers = (char **)malloc(sizeof(char *) * (list_entries+1));
                    if (rparams->kdcservers == NULL) {
                        retval = ENOMEM;
                        goto cleanup;
                    }
                    memset(rparams->kdcservers, 0, sizeof(char *) * (list_entries+1));
                }
                list_modify_str_array(&rparams->kdcservers, (const char **)list,
                                      LIST_MODE_ADD);
                mask |= LDAP_REALM_KDCSERVERS;
            }
        } else if (!strcmp(argv[i], "-admindn")) {
            if (++i > argc-1)
                goto err_usage;

            if ((rmask & LDAP_REALM_ADMINSERVERS) && (rparams->adminservers)) {
                if (!oldadmindns) {
                    /* Store the old admin dns list for removing rights */
                    oldadmindns = (char**) calloc(MAX_LIST_ENTRIES, sizeof(char*));
                    if (oldadmindns == NULL) {
                        retval = ENOMEM;
                        goto cleanup;
                    }

                    for (j=0; rparams->adminservers[j] != NULL; j++) {
                        oldadmindns[j] = strdup(rparams->adminservers[j]);
                        if (oldadmindns[j] == NULL) {
                            retval = ENOMEM;
                            goto cleanup;
                        }
                    }
                    oldadmindns[j] = NULL;
                }

                krb5_free_list_entries(rparams->adminservers);
                free(rparams->adminservers);
            }

            rparams->adminservers = (char **)malloc(
                sizeof(char *) * MAX_LIST_ENTRIES);
            if (rparams->adminservers == NULL) {
                retval = ENOMEM;
                goto cleanup;
            }
            memset(rparams->adminservers, 0, sizeof(char *)*MAX_LIST_ENTRIES);
            if ((retval = krb5_parse_list(argv[i], LIST_DELIMITER,
                                          rparams->adminservers))) {
                goto cleanup;
            }
            mask |= LDAP_REALM_ADMINSERVERS;
            /* Going to replace the existing value by this new value. Hence
             * setting flag indicating that add or clear options will be ignored
             */
            newadmindn = 1;
        } else if (!strcmp(argv[i], "-clearadmindn")) {
            if (++i > argc-1)
                goto err_usage;

            if ((!newadmindn) && (rmask & LDAP_REALM_ADMINSERVERS) && (rparams->adminservers)) {
                if (!oldadmindns) {
                    /* Store the old admin dns list for removing rights */
                    oldadmindns = (char**) calloc(MAX_LIST_ENTRIES, sizeof(char*));
                    if (oldadmindns == NULL) {
                        retval = ENOMEM;
                        goto cleanup;
                    }

                    for (j=0; rparams->adminservers[j] != NULL; j++) {
                        oldadmindns[j] = strdup(rparams->adminservers[j]);
                        if (oldadmindns[j] == NULL) {
                            retval = ENOMEM;
                            goto cleanup;
                        }
                    }
                    oldadmindns[j] = NULL;
                }

                memset(list, 0, sizeof(char *) * MAX_LIST_ENTRIES);
                if ((retval = krb5_parse_list(argv[i], LIST_DELIMITER, list))) {
                    goto cleanup;
                }
                list_modify_str_array(&rparams->adminservers, (const char **)list,
                                      LIST_MODE_DELETE);
                mask |= LDAP_REALM_ADMINSERVERS;
                krb5_free_list_entries(list);
            }
        } else if (!strcmp(argv[i], "-addadmindn")) {
            if (++i > argc-1)
                goto err_usage;
            if (!newadmindn) {
                if ((rmask & LDAP_REALM_ADMINSERVERS) && (rparams->adminservers) && (!oldadmindns)) {
                    /* Store the old admin dns list for removing rights */
                    oldadmindns = (char**) calloc(MAX_LIST_ENTRIES, sizeof(char*));
                    if (oldadmindns == NULL) {
                        retval = ENOMEM;
                        goto cleanup;
                    }

                    for (j=0; rparams->adminservers[j] != NULL; j++) {
                        oldadmindns[j] = strdup(rparams->adminservers[j]);
                        if (oldadmindns[j] == NULL) {
                            retval = ENOMEM;
                            goto cleanup;
                        }
                    }
                    oldadmindns[j] = NULL;
                }

                memset(list, 0, sizeof(char *) * MAX_LIST_ENTRIES);
                if ((retval = krb5_parse_list(argv[i], LIST_DELIMITER, list))) {
                    goto cleanup;
                }
                existing_entries = list_count_str_array(rparams->adminservers);
                list_entries = list_count_str_array(list);
                if (rmask & LDAP_REALM_ADMINSERVERS) {
                    tempstr = (char **)realloc(
                        rparams->adminservers,
                        sizeof(char *) * (existing_entries+list_entries+1));
                    if (tempstr == NULL) {
                        retval = ENOMEM;
                        goto cleanup;
                    }
                    rparams->adminservers = tempstr;
                } else {
                    rparams->adminservers = (char **)malloc(sizeof(char *) * (list_entries+1));
                    if (rparams->adminservers == NULL) {
                        retval = ENOMEM;
                        goto cleanup;
                    }
                    memset(rparams->adminservers, 0, sizeof(char *) * (list_entries+1));
                }
                list_modify_str_array(&rparams->adminservers, (const char **)list,
                                      LIST_MODE_ADD);
                mask |= LDAP_REALM_ADMINSERVERS;
            }
        } else if (!strcmp(argv[i], "-pwddn")) {
            if (++i > argc-1)
                goto err_usage;

            if ((rmask & LDAP_REALM_PASSWDSERVERS) && (rparams->passwdservers)) {
                if (!oldpwddns) {
                    /* Store the old pwd dns list for removing rights */
                    oldpwddns = (char**) calloc(MAX_LIST_ENTRIES, sizeof(char*));
                    if (oldpwddns == NULL) {
                        retval = ENOMEM;
                        goto cleanup;
                    }

                    for (j=0; rparams->passwdservers[j] != NULL; j++) {
                        oldpwddns[j] = strdup(rparams->passwdservers[j]);
                        if (oldpwddns[j] == NULL) {
                            retval = ENOMEM;
                            goto cleanup;
                        }
                    }
                    oldpwddns[j] = NULL;
                }

                krb5_free_list_entries(rparams->passwdservers);
                free(rparams->passwdservers);
            }

            rparams->passwdservers = (char **)malloc(
                sizeof(char *) * MAX_LIST_ENTRIES);
            if (rparams->passwdservers == NULL) {
                retval = ENOMEM;
                goto cleanup;
            }
            memset(rparams->passwdservers, 0, sizeof(char *)*MAX_LIST_ENTRIES);
            if ((retval = krb5_parse_list(argv[i], LIST_DELIMITER,
                                          rparams->passwdservers))) {
                goto cleanup;
            }
            mask |= LDAP_REALM_PASSWDSERVERS;
            /* Going to replace the existing value by this new value. Hence
             * setting flag indicating that add or clear options will be ignored
             */
            newpwddn = 1;
        } else if (!strcmp(argv[i], "-clearpwddn")) {
            if (++i > argc-1)
                goto err_usage;

            if ((!newpwddn) && (rmask & LDAP_REALM_PASSWDSERVERS) && (rparams->passwdservers)) {
                if (!oldpwddns) {
                    /* Store the old pwd dns list for removing rights */
                    oldpwddns = (char**) calloc(MAX_LIST_ENTRIES, sizeof(char*));
                    if (oldpwddns == NULL) {
                        retval = ENOMEM;
                        goto cleanup;
                    }

                    for (j=0; rparams->passwdservers[j] != NULL; j++) {
                        oldpwddns[j] = strdup(rparams->passwdservers[j]);
                        if (oldpwddns[j] == NULL) {
                            retval = ENOMEM;
                            goto cleanup;
                        }
                    }
                    oldpwddns[j] = NULL;
                }

                memset(list, 0, sizeof(char *) * MAX_LIST_ENTRIES);
                if ((retval = krb5_parse_list(argv[i], LIST_DELIMITER, list))) {
                    goto cleanup;
                }
                list_modify_str_array(&rparams->passwdservers, (const char**)list,
                                      LIST_MODE_DELETE);
                mask |= LDAP_REALM_PASSWDSERVERS;
                krb5_free_list_entries(list);
            }
        } else if (!strcmp(argv[i], "-addpwddn")) {
            if (++i > argc-1)
                goto err_usage;
            if (!newpwddn) {
                if ((rmask & LDAP_REALM_PASSWDSERVERS) && (rparams->passwdservers) && (!oldpwddns)) {
                    /* Store the old pwd dns list for removing rights */
                    oldpwddns = (char**) calloc(MAX_LIST_ENTRIES, sizeof(char*));
                    if (oldpwddns == NULL) {
                        retval = ENOMEM;
                        goto cleanup;
                    }

                    for (j=0; rparams->passwdservers[j] != NULL; j++) {
                        oldpwddns[j] = strdup(rparams->passwdservers[j]);
                        if (oldpwddns[j] == NULL) {
                            retval = ENOMEM;
                            goto cleanup;
                        }
                    }
                    oldpwddns[j] = NULL;
                }

                memset(list, 0, sizeof(char *) * MAX_LIST_ENTRIES);
                if ((retval = krb5_parse_list(argv[i], LIST_DELIMITER, list))) {
                    goto cleanup;
                }
                existing_entries = list_count_str_array(rparams->passwdservers);
                list_entries = list_count_str_array(list);
                if (rmask & LDAP_REALM_PASSWDSERVERS) {
                    tempstr = (char **)realloc(
                        rparams->passwdservers,
                        sizeof(char *) * (existing_entries+list_entries+1));
                    if (tempstr == NULL) {
                        retval = ENOMEM;
                        goto cleanup;
                    }
                    rparams->passwdservers = tempstr;
                } else {
                    rparams->passwdservers = (char **)malloc(sizeof(char *) * (list_entries+1));
                    if (rparams->passwdservers == NULL) {
                        retval = ENOMEM;
                        goto cleanup;
                    }
                    memset(rparams->passwdservers, 0, sizeof(char *) * (list_entries+1));
                }
                list_modify_str_array(&rparams->passwdservers, (const char**)list,
                                      LIST_MODE_ADD);
                mask |= LDAP_REALM_PASSWDSERVERS;
            }
        }
#endif
        else if ((ret_mask= get_ticket_policy(rparams,&i,argv,argc)) !=0) {
            mask|=ret_mask;
        } else {
            printf(_("'%s' is an invalid option\n"), argv[i]);
            goto err_usage;
        }
    }

    if ((retval = krb5_ldap_modify_realm(util_context,
                                         /* global_params.realm, */ rparams, mask))) {
        goto cleanup;
    }

#ifdef HAVE_EDIRECTORY
    if ((mask & LDAP_REALM_SUBTREE) || (mask & LDAP_REALM_CONTREF) || (mask & LDAP_REALM_KDCSERVERS) ||
        (mask & LDAP_REALM_ADMINSERVERS) || (mask & LDAP_REALM_PASSWDSERVERS)) {

        printf(_("Changing rights for the service object. Please wait ... "));
        fflush(stdout);

        if ((mask & LDAP_REALM_SUBTREE) || (mask & LDAP_REALM_CONTREF)) {
            subtree_changed = 1;
        }

        if ((subtree_changed) || (mask & LDAP_REALM_KDCSERVERS)) {

            if (!(mask & LDAP_REALM_KDCSERVERS)) {
                if (rparams->kdcservers != NULL) {
                    char **kdcdns = rparams->kdcservers;
                    /* Only subtree and/or container ref has changed */
                    rightsmask =0;
                    /*  KDCSERVERS have not changed. Realm rights need not be changed */;
                    rightsmask |= LDAP_SUBTREE_RIGHTS;
                    if ((oldsubtrees != NULL) || (oldcontainerref != NULL)) {
                        /* Remove the rights on the old subtrees */
                        for (i=0; (kdcdns[i] != NULL); i++) {
                            if ((retval=krb5_ldap_delete_service_rights(util_context,
                                                                        LDAP_KDC_SERVICE, kdcdns[i],
                                                                        rparams->realm_name, oldsubtrees, oldcontainerref, rightsmask)) != 0) {
                                printf(_("failed\n"));
                                com_err(progname, retval,
                                        _("while assigning rights '%s'"),
                                        rparams->realm_name);
                                goto err_nomsg;
                            }
                        }
                    }
                    for (i=0; (kdcdns[i] != NULL); i++) {
                        if ((retval=krb5_ldap_add_service_rights(util_context,
                                                                 LDAP_KDC_SERVICE, kdcdns[i],
                                                                 rparams->realm_name, rparams->subtree, rparams->containerref, rightsmask)) != 0) {
                            printf(_("failed\n"));
                            com_err(progname, retval,
                                    _("while assigning rights '%s'"),
                                    rparams->realm_name);
                            goto err_nomsg;
                        }
                    }
                }
            }

            if (!subtree_changed) {
                char **newdns = NULL;
                /* Only kdc servers have changed */
                rightsmask =0;
                rightsmask = LDAP_REALM_RIGHTS;
                rightsmask |= LDAP_SUBTREE_RIGHTS;
                if (oldkdcdns != NULL) {
                    newdns = (char**) calloc(MAX_LIST_ENTRIES, sizeof(char*));
                    if (newdns == NULL) {
                        retval = ENOMEM;
                        goto cleanup;
                    }

                    if ((rparams != NULL) && (rparams->kdcservers != NULL)) {
                        for (j=0;  rparams->kdcservers[j]!= NULL; j++) {
                            newdns[j] = strdup(rparams->kdcservers[j]);
                            if (newdns[j] == NULL) {
                                FREE_DN_LIST(newdns);
                                retval = ENOMEM;
                                goto cleanup;
                            }
                        }
                        newdns[j] = NULL;
                    }

                    disjoint_members(oldkdcdns, newdns);

                    for (i=0; (oldkdcdns[i] != NULL); i++) {
                        if ((retval=krb5_ldap_delete_service_rights(util_context,
                                                                    LDAP_KDC_SERVICE, oldkdcdns[i],
                                                                    rparams->realm_name, rparams->subtree, rparams->containerref, rightsmask)) != 0) {
                            printf(_("failed\n"));
                            com_err(progname, retval,
                                    _("while assigning rights '%s'"),
                                    rparams->realm_name);
                            FREE_DN_LIST(newdns);
                            goto err_nomsg;
                        }
                    }
                    for (i=0; (newdns[i] != NULL); i++) {
                        if ((retval=krb5_ldap_add_service_rights(util_context,
                                                                 LDAP_KDC_SERVICE, newdns[i],
                                                                 rparams->realm_name, rparams->subtree, rparams->containerref, rightsmask)) != 0) {
                            printf(_("failed\n"));
                            com_err(progname, retval,
                                    _("while assigning rights '%s'"),
                                    rparams->realm_name);
                            FREE_DN_LIST(newdns);
                            goto err_nomsg;
                        }
                    }
                    for (i=0; (newdns[i] != NULL); i++) {
                        free(newdns[i]);
                    }
                    free(newdns);
                } else {
                    newdns = rparams->kdcservers;
                    for (i=0; (newdns[i] != NULL); i++) {
                        if ((retval=krb5_ldap_add_service_rights(util_context,
                                                                 LDAP_KDC_SERVICE, newdns[i],
                                                                 rparams->realm_name, rparams->subtree, rparams->containerref, rightsmask)) != 0) {
                            printf(_("failed\n"));
                            com_err(progname, retval,
                                    _("while assigning rights '%s'"),
                                    rparams->realm_name);
                            goto err_nomsg;
                        }
                    }
                }
            }

            if (subtree_changed && (mask & LDAP_REALM_KDCSERVERS)) {
                char **newdns = rparams->kdcservers;

                rightsmask =0;
                rightsmask = LDAP_REALM_RIGHTS;
                rightsmask |= LDAP_SUBTREE_RIGHTS;
                if (oldkdcdns != NULL) {
                    for (i=0; (oldkdcdns[i] != NULL); i++) {
                        if ((retval=krb5_ldap_delete_service_rights(util_context,
                                                                    LDAP_KDC_SERVICE, oldkdcdns[i],
                                                                    rparams->realm_name, oldsubtrees, oldcontainerref, rightsmask)) != 0) {
                            printf(_("failed\n"));
                            com_err(progname, retval,
                                    _("while assigning rights '%s'"),
                                    rparams->realm_name);
                            goto err_nomsg;
                        }
                    }
                }
                for (i=0; (newdns[i] != NULL); i++) {
                    if ((retval=krb5_ldap_add_service_rights(util_context,
                                                             LDAP_KDC_SERVICE, newdns[i],
                                                             rparams->realm_name, rparams->subtree, rparams->containerref, rightsmask)) != 0) {
                        printf(_("failed\n"));
                        com_err(progname, retval,
                                _("while assigning rights '%s'"),
                                rparams->realm_name);
                        goto err_nomsg;
                    }
                }
            }
        }

        if (subtree_changed || (mask & LDAP_REALM_ADMINSERVERS)) {

            if (!(mask & LDAP_REALM_ADMINSERVERS)) {
                if (rparams->adminservers != NULL) {
                    char **admindns = rparams->adminservers;
                    /* Only subtree and/or container ref has changed */
                    rightsmask =0;
                    /*  KADMINSERVERS have not changed. Realm rights need not be changed */;
                    rightsmask |= LDAP_SUBTREE_RIGHTS;
                    if ((oldsubtrees != NULL) || (oldcontainerref != NULL)) {
                        /* Remove the rights on the old subtrees */
                        for (i=0; (admindns[i] != NULL); i++) {
                            if ((retval=krb5_ldap_delete_service_rights(util_context,
                                                                        LDAP_ADMIN_SERVICE, admindns[i],
                                                                        rparams->realm_name, oldsubtrees, oldcontainerref, rightsmask)) != 0) {
                                printf(_("failed\n"));
                                com_err(progname, retval,
                                        _("while assigning rights '%s'"),
                                        rparams->realm_name);
                                goto err_nomsg;
                            }
                        }
                    }
                    for (i=0; (admindns[i] != NULL); i++) {
                        if ((retval=krb5_ldap_add_service_rights(util_context,
                                                                 LDAP_ADMIN_SERVICE, admindns[i],
                                                                 rparams->realm_name, rparams->subtree, rparams->containerref, rightsmask)) != 0) {
                            printf(_("failed\n"));
                            com_err(progname, retval,
                                    _("while assigning rights '%s'"),
                                    rparams->realm_name);
                            goto err_nomsg;
                        }
                    }
                }
            }

            if (!subtree_changed) {
                char **newdns = NULL;
                /* Only admin servers have changed */
                rightsmask =0;
                rightsmask = LDAP_REALM_RIGHTS;
                rightsmask |= LDAP_SUBTREE_RIGHTS;
                if (oldadmindns != NULL) {
                    newdns = (char**) calloc(MAX_LIST_ENTRIES, sizeof(char*));
                    if (newdns == NULL) {
                        retval = ENOMEM;
                        goto cleanup;
                    }

                    if ((rparams != NULL) && (rparams->adminservers != NULL)) {
                        for (j=0;  rparams->adminservers[j]!= NULL; j++) {
                            newdns[j] = strdup(rparams->adminservers[j]);
                            if (newdns[j] == NULL) {
                                FREE_DN_LIST(newdns);
                                retval = ENOMEM;
                                goto cleanup;
                            }
                        }
                        newdns[j] = NULL;
                    }

                    disjoint_members(oldadmindns, newdns);

                    for (i=0; (oldadmindns[i] != NULL); i++) {
                        if ((retval=krb5_ldap_delete_service_rights(util_context,
                                                                    LDAP_ADMIN_SERVICE, oldadmindns[i],
                                                                    rparams->realm_name, rparams->subtree, rparams->containerref, rightsmask)) != 0) {
                            printf(_("failed\n"));
                            com_err(progname, retval,
                                    _("while assigning rights '%s'"),
                                    rparams->realm_name);
                            FREE_DN_LIST(newdns);
                            goto err_nomsg;
                        }
                    }
                    for (i=0; (newdns[i] != NULL); i++) {
                        if ((retval=krb5_ldap_add_service_rights(util_context,
                                                                 LDAP_ADMIN_SERVICE, newdns[i],
                                                                 rparams->realm_name, rparams->subtree, rparams->containerref, rightsmask)) != 0) {
                            printf(_("failed\n"));
                            com_err(progname, retval,
                                    _("while assigning rights '%s'"),
                                    rparams->realm_name);
                            FREE_DN_LIST(newdns);
                            goto err_nomsg;
                        }
                    }
                    for (i=0; (newdns[i] != NULL); i++) {
                        free(newdns[i]);
                    }
                    free(newdns);
                } else {
                    newdns = rparams->adminservers;
                    for (i=0; (newdns[i] != NULL); i++) {
                        if ((retval=krb5_ldap_add_service_rights(util_context,
                                                                 LDAP_ADMIN_SERVICE, newdns[i],
                                                                 rparams->realm_name, rparams->subtree, rparams->containerref, rightsmask)) != 0) {
                            printf(_("failed\n"));
                            com_err(progname, retval,
                                    _("while assigning rights '%s'"),
                                    rparams->realm_name);
                            goto err_nomsg;
                        }
                    }
                }
            }

            if (subtree_changed && (mask & LDAP_REALM_ADMINSERVERS)) {
                char **newdns = rparams->adminservers;

                rightsmask = 0;
                rightsmask = LDAP_REALM_RIGHTS;
                rightsmask |= LDAP_SUBTREE_RIGHTS;
                if (oldadmindns != NULL) {
                    for (i=0; (oldadmindns[i] != NULL); i++) {
                        if ((retval=krb5_ldap_delete_service_rights(util_context,
                                                                    LDAP_ADMIN_SERVICE, oldadmindns[i],
                                                                    rparams->realm_name, oldsubtrees, oldcontainerref, rightsmask)) != 0) {
                            printf(_("failed\n"));
                            com_err(progname, retval,
                                    _("while assigning rights '%s'"),
                                    rparams->realm_name);
                            goto err_nomsg;
                        }
                    }
                }
                for (i=0; (newdns[i] != NULL); i++) {
                    if ((retval=krb5_ldap_add_service_rights(util_context,
                                                             LDAP_ADMIN_SERVICE, newdns[i],
                                                             rparams->realm_name, rparams->subtree, rparams->containerref, rightsmask)) != 0) {
                        printf(_("failed\n"));
                        com_err(progname, retval,
                                _("while assigning rights '%s'"),
                                rparams->realm_name);
                        goto err_nomsg;
                    }
                }
            }
        }

        if (subtree_changed || (mask & LDAP_REALM_PASSWDSERVERS)) {

            if (!(mask & LDAP_REALM_PASSWDSERVERS)) {
                if (rparams->passwdservers != NULL) {
                    char **passwddns = rparams->passwdservers;
                    /* Only subtree and/or container ref has changed */
                    rightsmask = 0;
                    /*  KPASSWDSERVERS have not changed. Realm rights need not be changed */;
                    rightsmask |= LDAP_SUBTREE_RIGHTS;
                    if ((oldsubtrees != NULL) || (oldcontainerref != NULL)) {
                        /* Remove the rights on the old subtrees */
                        for (i=0; (passwddns[i] != NULL); i++) {
                            if ((retval=krb5_ldap_delete_service_rights(util_context,
                                                                        LDAP_PASSWD_SERVICE, passwddns[i],
                                                                        rparams->realm_name, oldsubtrees, oldcontainerref, rightsmask)) != 0) {
                                printf(_("failed\n"));
                                com_err(progname, retval,
                                        _("while assigning rights '%s'"),
                                        rparams->realm_name);
                                goto err_nomsg;
                            }
                        }
                    }
                    for (i=0; (passwddns[i] != NULL); i++) {
                        if ((retval=krb5_ldap_add_service_rights(util_context,
                                                                 LDAP_PASSWD_SERVICE, passwddns[i],
                                                                 rparams->realm_name, rparams->subtree, rparams->containerref, rightsmask)) != 0) {
                            printf(_("failed\n"));
                            com_err(progname, retval,
                                    _("while assigning rights '%s'"),
                                    rparams->realm_name);
                            goto err_nomsg;
                        }
                    }
                }
            }

            if (!subtree_changed) {
                char **newdns = NULL;
                /* Only passwd servers have changed */
                rightsmask =0;
                rightsmask = LDAP_REALM_RIGHTS;
                rightsmask |= LDAP_SUBTREE_RIGHTS;
                if (oldpwddns != NULL) {
                    newdns = (char**) calloc(MAX_LIST_ENTRIES, sizeof(char*));
                    if (newdns == NULL) {
                        retval = ENOMEM;
                        goto cleanup;
                    }

                    if ((rparams != NULL) && (rparams->passwdservers != NULL)) {
                        for (j=0;  rparams->passwdservers[j]!= NULL; j++) {
                            newdns[j] = strdup(rparams->passwdservers[j]);
                            if (newdns[j] == NULL) {
                                FREE_DN_LIST(newdns);
                                retval = ENOMEM;
                                goto cleanup;
                            }
                        }
                        newdns[j] = NULL;
                    }

                    disjoint_members(oldpwddns, newdns);

                    for (i=0; (oldpwddns[i] != NULL); i++) {
                        if ((retval=krb5_ldap_delete_service_rights(util_context,
                                                                    LDAP_PASSWD_SERVICE, oldpwddns[i],
                                                                    rparams->realm_name, rparams->subtree, rparams->containerref, rightsmask)) != 0) {
                            printf(_("failed\n"));
                            com_err(progname, retval,
                                    _("while assigning rights '%s'"),
                                    rparams->realm_name);
                            FREE_DN_LIST(newdns);
                            goto err_nomsg;
                        }
                    }
                    for (i=0; (newdns[i] != NULL); i++) {
                        if ((retval=krb5_ldap_add_service_rights(util_context,
                                                                 LDAP_PASSWD_SERVICE, newdns[i],
                                                                 rparams->realm_name, rparams->subtree, rparams->containerref, rightsmask)) != 0) {
                            printf(_("failed\n"));
                            com_err(progname, retval,
                                    _("while assigning rights '%s'"),
                                    rparams->realm_name);
                            FREE_DN_LIST(newdns);
                            goto err_nomsg;
                        }
                    }
                    for (i=0; (newdns[i] != NULL); i++) {
                        free(newdns[i]);
                    }
                    free(newdns);
                } else {
                    newdns = rparams->passwdservers;
                    for (i=0; (newdns[i] != NULL); i++) {
                        if ((retval=krb5_ldap_add_service_rights(util_context,
                                                                 LDAP_PASSWD_SERVICE, newdns[i],
                                                                 rparams->realm_name, rparams->subtree, rparams->containerref, rightsmask)) != 0) {
                            printf(_("failed\n"));
                            com_err(progname, retval,
                                    _("while assigning rights '%s'"),
                                    rparams->realm_name);
                            goto err_nomsg;
                        }
                    }
                }
            }

            if (subtree_changed && (mask & LDAP_REALM_PASSWDSERVERS)) {
                char **newdns = rparams->passwdservers;

                rightsmask =0;
                rightsmask = LDAP_REALM_RIGHTS;
                rightsmask |= LDAP_SUBTREE_RIGHTS;
                if (oldpwddns != NULL) {
                    for (i=0; (oldpwddns[i] != NULL); i++) {
                        if ((retval = krb5_ldap_delete_service_rights(util_context,
                                                                      LDAP_PASSWD_SERVICE, oldpwddns[i],
                                                                      rparams->realm_name, oldsubtrees, oldcontainerref, rightsmask)) != 0) {
                            printf(_("failed\n"));
                            com_err(progname, retval,
                                    _("while assigning rights '%s'"),
                                    rparams->realm_name);
                            goto err_nomsg;
                        }
                    }
                }
                for (i=0; (newdns[i] != NULL); i++) {
                    if ((retval = krb5_ldap_add_service_rights(util_context,
                                                               LDAP_PASSWD_SERVICE, newdns[i],
                                                               rparams->realm_name, rparams->subtree, rparams->containerref, rightsmask)) != 0) {
                        printf(_("failed\n"));
                        com_err(progname, retval,
                                _("while assigning rights '%s'"),
                                rparams->realm_name);
                        goto err_nomsg;
                    }
                }
            }
        }
        printf(_("done\n"));
    }
#endif

    goto cleanup;

err_usage:
    print_usage = TRUE;

err_nomsg:
    no_msg = TRUE;

cleanup:
    krb5_ldap_free_realm_params(rparams);


#ifdef HAVE_EDIRECTORY
    if (oldkdcdns) {
        for (i=0; oldkdcdns[i] != NULL; i++)
            free(oldkdcdns[i]);
        free(oldkdcdns);
    }
    if (oldpwddns) {
        for (i=0; oldpwddns[i] != NULL; i++)
            free(oldpwddns[i]);
        free(oldpwddns);
    }
    if (oldadmindns) {
        for (i=0; oldadmindns[i] != NULL; i++)
            free(oldadmindns[i]);
        free(oldadmindns);
    }
    if (newkdcdns) {
        for (i=0; newkdcdns[i] != NULL; i++)
            free(newkdcdns[i]);
        free(newkdcdns);
    }
    if (newpwddns) {
        for (i=0; newpwddns[i] != NULL; i++)
            free(newpwddns[i]);
        free(newpwddns);
    }
    if (newadmindns) {
        for (i=0; newadmindns[i] != NULL; i++)
            free(newadmindns[i]);
        free(newadmindns);
    }
    if (oldsubtrees) {
        for (i=0;oldsubtrees[i]!=NULL; i++)
            free(oldsubtrees[i]);
        free(oldsubtrees);
    }
    if (newsubtrees) {
        for (i=0;newsubtrees[i]!=NULL; i++)
            free(newsubtrees[i]);
        free(oldsubtrees);
    }
#endif
    if (print_usage) {
        db_usage(MODIFY_REALM);
    }

    if (retval) {
        if (!no_msg)
            com_err(progname, retval,
                    _("while modifying information of realm '%s'"),
                    global_params.realm);
        exit_status++;
    }

    return;
}



/*
 * This function displays the attributes of a Realm
 */
void
kdb5_ldap_view(int argc, char *argv[])
{
    krb5_ldap_realm_params *rparams = NULL;
    krb5_error_code retval = 0;
    kdb5_dal_handle *dal_handle=NULL;
    krb5_ldap_context *ldap_context=NULL;
    int mask = 0;

    dal_handle = util_context->dal_handle;
    ldap_context = (krb5_ldap_context *) dal_handle->db_context;
    if (!(ldap_context)) {
        retval = EINVAL;
        com_err(progname, retval, _("while initializing database"));
        exit_status++;
        return;
    }

    /* Read the kerberos container information */
    if ((retval = krb5_ldap_read_krbcontainer_params(util_context,
                                                     &(ldap_context->krbcontainer))) != 0) {
        com_err(progname, retval,
                _("while reading kerberos container information"));
        exit_status++;
        return;
    }

    if ((retval = krb5_ldap_read_realm_params(util_context,
                                              global_params.realm, &rparams, &mask)) || (!rparams)) {
        com_err(progname, retval, _("while reading information of realm '%s'"),
                global_params.realm);
        exit_status++;
        return;
    }
    print_realm_params(rparams, mask);
    krb5_ldap_free_realm_params(rparams);

    return;
}

static char *
strdur(time_t duration)
{
    static char out[50];
    int neg, days, hours, minutes, seconds;

    if (duration < 0) {
        duration *= -1;
        neg = 1;
    } else
        neg = 0;
    days = duration / (24 * 3600);
    duration %= 24 * 3600;
    hours = duration / 3600;
    duration %= 3600;
    minutes = duration / 60;
    duration %= 60;
    seconds = duration;
    snprintf(out, sizeof(out), "%s%d %s %02d:%02d:%02d", neg ? "-" : "",
             days, days == 1 ? "day" : "days",
             hours, minutes, seconds);
    return out;
}

/*
 * This function prints the attributes of a given realm to the
 * standard output.
 */
static void
print_realm_params(krb5_ldap_realm_params *rparams, int mask)
{
    char **slist = NULL;
    unsigned int num_entry_printed = 0, i = 0;

    /* Print the Realm Attributes on the standard output */
    printf("%25s: %-50s\n", _("Realm Name"), global_params.realm);
    if (mask & LDAP_REALM_SUBTREE) {
        for (i=0; rparams->subtree[i]!=NULL; i++)
            printf("%25s: %-50s\n", _("Subtree"), rparams->subtree[i]);
    }
    if (mask & LDAP_REALM_CONTREF)
        printf("%25s: %-50s\n", _("Principal Container Reference"),
               rparams->containerref);
    if (mask & LDAP_REALM_SEARCHSCOPE) {
        if ((rparams->search_scope != 1) &&
            (rparams->search_scope != 2)) {
            printf("%25s: %-50s\n", _("SearchScope"), _("Invalid !"));
        } else {
            printf("%25s: %-50s\n", _("SearchScope"),
                   (rparams->search_scope == 1) ? "ONE" : "SUB");
        }
    }
    if (mask & LDAP_REALM_KDCSERVERS) {
        printf("%25s:", _("KDC Services"));
        if (rparams->kdcservers != NULL) {
            num_entry_printed = 0;
            for (slist = rparams->kdcservers; *slist != NULL; slist++) {
                if (num_entry_printed)
                    printf(" %25s %-50s\n", " ", *slist);
                else
                    printf(" %-50s\n", *slist);
                num_entry_printed++;
            }
        }
        if (num_entry_printed == 0)
            printf("\n");
    }
    if (mask & LDAP_REALM_ADMINSERVERS) {
        printf("%25s:", _("Admin Services"));
        if (rparams->adminservers != NULL) {
            num_entry_printed = 0;
            for (slist = rparams->adminservers; *slist != NULL; slist++) {
                if (num_entry_printed)
                    printf(" %25s %-50s\n", " ", *slist);
                else
                    printf(" %-50s\n", *slist);
                num_entry_printed++;
            }
        }
        if (num_entry_printed == 0)
            printf("\n");
    }
    if (mask & LDAP_REALM_PASSWDSERVERS) {
        printf("%25s:", _("Passwd Services"));
        if (rparams->passwdservers != NULL) {
            num_entry_printed = 0;
            for (slist = rparams->passwdservers; *slist != NULL; slist++) {
                if (num_entry_printed)
                    printf(" %25s %-50s\n", " ", *slist);
                else
                    printf(" %-50s\n", *slist);
                num_entry_printed++;
            }
        }
        if (num_entry_printed == 0)
            printf("\n");
    }

    if (mask & LDAP_REALM_MAXTICKETLIFE) {
        printf("%25s:", _("Maximum Ticket Life"));
        printf(" %s \n", strdur(rparams->max_life));
    }

    if (mask & LDAP_REALM_MAXRENEWLIFE) {
        printf("%25s:", _("Maximum Renewable Life"));
        printf(" %s \n", strdur(rparams->max_renewable_life));
    }

    if (mask & LDAP_REALM_KRBTICKETFLAGS) {
        int ticketflags = rparams->tktflags;

        printf("%25s: ", _("Ticket flags"));
        if (ticketflags & KRB5_KDB_DISALLOW_POSTDATED)
            printf("%s ","DISALLOW_POSTDATED");

        if (ticketflags & KRB5_KDB_DISALLOW_FORWARDABLE)
            printf("%s ","DISALLOW_FORWARDABLE");

        if (ticketflags & KRB5_KDB_DISALLOW_RENEWABLE)
            printf("%s ","DISALLOW_RENEWABLE");

        if (ticketflags & KRB5_KDB_DISALLOW_PROXIABLE)
            printf("%s ","DISALLOW_PROXIABLE");

        if (ticketflags & KRB5_KDB_DISALLOW_DUP_SKEY)
            printf("%s ","DISALLOW_DUP_SKEY");

        if (ticketflags & KRB5_KDB_REQUIRES_PRE_AUTH)
            printf("%s ","REQUIRES_PRE_AUTH");

        if (ticketflags & KRB5_KDB_REQUIRES_HW_AUTH)
            printf("%s ","REQUIRES_HW_AUTH");

        if (ticketflags & KRB5_KDB_DISALLOW_SVR)
            printf("%s ","DISALLOW_SVR");

        if (ticketflags & KRB5_KDB_DISALLOW_TGT_BASED)
            printf("%s ","DISALLOW_TGT_BASED");

        if (ticketflags & KRB5_KDB_DISALLOW_ALL_TIX)
            printf("%s ","DISALLOW_ALL_TIX");

        if (ticketflags & KRB5_KDB_REQUIRES_PWCHANGE)
            printf("%s ","REQUIRES_PWCHANGE");

        if (ticketflags & KRB5_KDB_PWCHANGE_SERVICE)
            printf("%s ","PWCHANGE_SERVICE");

        printf("\n");
    }


    return;
}



/*
 * This function lists the Realm(s) present under the Kerberos container
 * on the LDAP Server.
 */
void
kdb5_ldap_list(int argc, char *argv[])
{
    char **list = NULL;
    char **plist = NULL;
    krb5_error_code retval = 0;
    kdb5_dal_handle *dal_handle=NULL;
    krb5_ldap_context *ldap_context=NULL;

    dal_handle = util_context->dal_handle;
    ldap_context = (krb5_ldap_context *) dal_handle->db_context;
    if (!(ldap_context)) {
        retval = EINVAL;
        exit_status++;
        return;
    }

    /* Read the kerberos container information */
    if ((retval = krb5_ldap_read_krbcontainer_params(util_context,
                                                     &(ldap_context->krbcontainer))) != 0) {
        com_err(progname, retval,
                _("while reading kerberos container information"));
        exit_status++;
        return;
    }

    retval = krb5_ldap_list_realm(util_context, &list);
    if (retval != 0) {
        krb5_ldap_free_krbcontainer_params(ldap_context->krbcontainer);
        ldap_context->krbcontainer = NULL;
        com_err(progname, retval, _("while listing realms"));
        exit_status++;
        return;
    }
    /* This is to handle the case of realm not present */
    if (list == NULL) {
        krb5_ldap_free_krbcontainer_params(ldap_context->krbcontainer);
        ldap_context->krbcontainer = NULL;
        return;
    }

    for (plist = list; *plist != NULL; plist++) {
        printf("%s\n", *plist);
    }
    krb5_ldap_free_krbcontainer_params(ldap_context->krbcontainer);
    ldap_context->krbcontainer = NULL;
    krb5_free_list_entries(list);
    free(list);

    return;
}

/*
 * Duplicating the following two functions here because
 * 'krb5_dbe_update_tl_data' uses backend specific memory allocation. The catch
 * here is that the backend is not initialized - kdb5_ldap_util doesn't go
 * through DAL.
 * 1. krb5_dbe_update_tl_data
 * 2. krb5_dbe_update_mod_princ_data
 */

/* Start duplicate code ... */

static krb5_error_code
krb5_dbe_update_tl_data_new(krb5_context context, krb5_db_entry *entry,
                            krb5_tl_data *new_tl_data)
{
    krb5_tl_data *tl_data = NULL;
    krb5_octet *tmp;

    /* copy the new data first, so we can fail cleanly if malloc()
     * fails */
/*
  if ((tmp =
  (krb5_octet *) krb5_db_alloc(context, NULL,
  new_tl_data->tl_data_length)) == NULL)
*/
    if ((tmp = (krb5_octet *) malloc (new_tl_data->tl_data_length)) == NULL)
        return (ENOMEM);

    /* Find an existing entry of the specified type and point at
     * it, or NULL if not found */

    if (new_tl_data->tl_data_type != KRB5_TL_DB_ARGS) { /* db_args can be multiple */
        for (tl_data = entry->tl_data; tl_data;
             tl_data = tl_data->tl_data_next)
            if (tl_data->tl_data_type == new_tl_data->tl_data_type)
                break;
    }

    /* if necessary, chain a new record in the beginning and point at it */

    if (!tl_data) {
/*
  if ((tl_data =
  (krb5_tl_data *) krb5_db_alloc(context, NULL,
  sizeof(krb5_tl_data)))
  == NULL) {
*/
        if ((tl_data = (krb5_tl_data *) malloc (sizeof(krb5_tl_data))) == NULL) {
            free(tmp);
            return (ENOMEM);
        }
        memset(tl_data, 0, sizeof(krb5_tl_data));
        tl_data->tl_data_next = entry->tl_data;
        entry->tl_data = tl_data;
        entry->n_tl_data++;
    }

    /* fill in the record */

    if (tl_data->tl_data_contents)
        krb5_db_free(context, tl_data->tl_data_contents);

    tl_data->tl_data_type = new_tl_data->tl_data_type;
    tl_data->tl_data_length = new_tl_data->tl_data_length;
    tl_data->tl_data_contents = tmp;
    memcpy(tmp, new_tl_data->tl_data_contents, tl_data->tl_data_length);

    return (0);
}

static krb5_error_code
krb5_dbe_update_mod_princ_data_new(krb5_context context, krb5_db_entry *entry,
                                   krb5_timestamp mod_date,
                                   krb5_const_principal mod_princ)
{
    krb5_tl_data          tl_data;

    krb5_error_code       retval = 0;
    krb5_octet          * nextloc = 0;
    char                * unparse_mod_princ = 0;
    unsigned int        unparse_mod_princ_size;

    if ((retval = krb5_unparse_name(context, mod_princ,
                                    &unparse_mod_princ)))
        return(retval);

    unparse_mod_princ_size = strlen(unparse_mod_princ) + 1;

    if ((nextloc = (krb5_octet *) malloc(unparse_mod_princ_size + 4))
        == NULL) {
        free(unparse_mod_princ);
        return(ENOMEM);
    }

    tl_data.tl_data_type = KRB5_TL_MOD_PRINC;
    tl_data.tl_data_length = unparse_mod_princ_size + 4;
    tl_data.tl_data_contents = nextloc;

    /* Mod Date */
    krb5_kdb_encode_int32(mod_date, nextloc);

    /* Mod Princ */
    memcpy(nextloc+4, unparse_mod_princ, unparse_mod_princ_size);

    retval = krb5_dbe_update_tl_data_new(context, entry, &tl_data);

    free(unparse_mod_princ);
    free(nextloc);

    return(retval);
}

static krb5_error_code
kdb_ldap_tgt_keysalt_iterate(krb5_key_salt_tuple *ksent, krb5_pointer ptr)
{
    krb5_context        context;
    krb5_error_code     kret;
    struct iterate_args *iargs;
    krb5_keyblock       key;
    krb5_int32          ind;
    krb5_data   pwd;
    krb5_db_entry       *entry;

    iargs = (struct iterate_args *) ptr;
    kret = 0;

    context = iargs->ctx;
    entry = iargs->dbentp;

    /*
     * Convert the master key password into a key for this particular
     * encryption system.
     */
    pwd.data = mkey_password;
    pwd.length = strlen(mkey_password);
    kret = krb5_c_random_seed(context, &pwd);
    if (kret)
        return kret;

    /*if (!(kret = krb5_dbe_create_key_data(iargs->ctx, iargs->dbentp))) {*/
    if ((entry->key_data =
         (krb5_key_data *) realloc(entry->key_data,
                                   (sizeof(krb5_key_data) *
                                    (entry->n_key_data + 1)))) == NULL)
        return (ENOMEM);

    memset(entry->key_data + entry->n_key_data, 0, sizeof(krb5_key_data));
    ind = entry->n_key_data++;

    if (!(kret = krb5_c_make_random_key(context, ksent->ks_enctype,
                                        &key))) {
        kret = krb5_dbe_encrypt_key_data(context, iargs->rblock->key, &key,
                                         NULL, 1, &entry->key_data[ind]);
        krb5_free_keyblock_contents(context, &key);
    }
    /*}*/

    return(kret);
}
/* End duplicate code */

/*
 * This function creates service principals when
 * creating the realm object.
 */
static int
kdb_ldap_create_principal(krb5_context context, krb5_principal princ,
                          enum ap_op op, struct realm_info *pblock,
                          const krb5_keyblock *master_keyblock)
{
    int              retval=0, currlen=0, princtype = 2 /* Service Principal */;
    unsigned char    *curr=NULL;
    krb5_tl_data     *tl_data=NULL;
    krb5_db_entry    entry;
    long             mask = 0;
    krb5_keyblock    key;
    int              kvno = 0;
    kdb5_dal_handle *dal_handle = NULL;
    krb5_ldap_context *ldap_context=NULL;
    struct iterate_args   iargs;
    krb5_data       *pdata;
    krb5_timestamp now;
    krb5_actkvno_node     actkvno;

    if ((pblock == NULL) || (context == NULL)) {
        retval = EINVAL;
        goto cleanup;
    }
    dal_handle = context->dal_handle;
    ldap_context = (krb5_ldap_context *) dal_handle->db_context;
    if (!(ldap_context)) {
        retval = EINVAL;
        goto cleanup;
    }

    memset(&entry, 0, sizeof(entry));

    tl_data = malloc(sizeof(*tl_data));
    if (tl_data == NULL) {
        retval = ENOMEM;
        goto cleanup;
    }
    memset(tl_data, 0, sizeof(*tl_data));
    tl_data->tl_data_length = 1 + 2 + 2 + 1 + 2 + 4;
    tl_data->tl_data_type = 7; /* KDB_TL_USER_INFO */
    curr = tl_data->tl_data_contents = malloc(tl_data->tl_data_length);
    if (tl_data->tl_data_contents == NULL) {
        retval = ENOMEM;
        goto cleanup;
    }

    memset(curr, 1, 1); /* Passing the mask as principal type */
    curr += 1;
    currlen = 2;
    STORE16_INT(curr, currlen);
    curr += currlen;
    STORE16_INT(curr, princtype);
    curr += currlen;

    mask |= KADM5_PRINCIPAL;
    mask |= KADM5_ATTRIBUTES ;
    mask |= KADM5_MAX_LIFE ;
    mask |= KADM5_MAX_RLIFE ;
    mask |= KADM5_PRINC_EXPIRE_TIME ;
    mask |= KADM5_KEY_DATA;

    entry.tl_data = tl_data;
    entry.n_tl_data += 1;
    /* Set the creator's name */
    if ((retval = krb5_timeofday(context, &now)))
        goto cleanup;
    if ((retval = krb5_dbe_update_mod_princ_data_new(context, &entry,
                                                     now, &db_create_princ)))
        goto cleanup;

    entry.attributes = pblock->flags;
    entry.max_life = pblock->max_life;
    entry.max_renewable_life = pblock->max_rlife;
    entry.expiration = pblock->expiration;
    entry.mask = mask;
    if ((retval = krb5_copy_principal(context, princ, &entry.princ)))
        goto cleanup;


    switch (op) {
    case TGT_KEY:
        if ((pdata = krb5_princ_component(context, princ, 1)) &&
            pdata->length == strlen("history") &&
            !memcmp(pdata->data, "history", strlen("history"))) {

            /* Allocate memory for storing the key */
            if ((entry.key_data = (krb5_key_data *) malloc(
                     sizeof(krb5_key_data))) == NULL) {
                retval = ENOMEM;
                goto cleanup;
            }

            memset(entry.key_data, 0, sizeof(krb5_key_data));
            entry.n_key_data++;

            retval = krb5_c_make_random_key(context, global_params.enctype, &key);
            if (retval) {
                goto cleanup;
            }
            kvno = 1; /* New key is getting set */
            retval = krb5_dbe_encrypt_key_data(context, master_keyblock,
                                               &key, NULL, kvno,
                                               &entry.key_data[entry.n_key_data - 1]);
            krb5_free_keyblock_contents(context, &key);
            if (retval) {
                goto cleanup;
            }
        } else {
            /*retval = krb5_c_make_random_key(context, 16, &key) ;*/
            iargs.ctx = context;
            iargs.rblock = pblock;
            iargs.dbentp = &entry;

            /*
             * Iterate through the key/salt list, ignoring salt types.
             */
            if ((retval = krb5_keysalt_iterate(pblock->kslist,
                                               pblock->nkslist,
                                               1,
                                               kdb_ldap_tgt_keysalt_iterate,
                                               (krb5_pointer) &iargs)))
                return retval;
        }
        break;

    case MASTER_KEY:
        /* Allocate memory for storing the key */
        if ((entry.key_data = (krb5_key_data *) malloc(
                 sizeof(krb5_key_data))) == NULL) {
            retval = ENOMEM;
            goto cleanup;
        }

        memset(entry.key_data, 0, sizeof(krb5_key_data));
        entry.n_key_data++;
        kvno = 1; /* New key is getting set */
        retval = krb5_dbe_encrypt_key_data(context, pblock->key,
                                           master_keyblock, NULL, kvno,
                                           &entry.key_data[entry.n_key_data - 1]);
        if (retval) {
            goto cleanup;
        }
        /*
         * There should always be at least one "active" mkey so creating the
         * KRB5_TL_ACTKVNO entry now so the initial mkey is active.
         */
        actkvno.next = NULL;
        actkvno.act_kvno = kvno;
        actkvno.act_time = now;
        retval = krb5_dbe_update_actkvno(context, &entry, &actkvno);
        if (retval)
            goto cleanup;

        break;

    case NULL_KEY:
    default:
        break;
    } /* end of switch */

    retval = krb5_ldap_put_principal(context, &entry, NULL);
    if (retval) {
        com_err(NULL, retval, _("while adding entries to database"));
        goto cleanup;
    }

cleanup:
    krb5_dbe_free_contents(context, &entry);
    return retval;
}


/*
 * This function destroys the realm object and the associated principals
 */
void
kdb5_ldap_destroy(int argc, char *argv[])
{
    extern char *optarg;
    extern int optind;
    int optchar = 0;
    char buf[5] = {0};
    krb5_error_code retval = 0;
    int force = 0;
    int mask = 0;
    kdb5_dal_handle *dal_handle = NULL;
    krb5_ldap_context *ldap_context = NULL;
#ifdef HAVE_EDIRECTORY
    int i = 0, rightsmask = 0;
    krb5_ldap_realm_params *rparams = NULL;
#endif

    optind = 1;
    while ((optchar = getopt(argc, argv, "f")) != -1) {
        switch (optchar) {
        case 'f':
            force++;
            break;
        case '?':
        default:
            db_usage(DESTROY_REALM);
            return;
            /*NOTREACHED*/
        }
    }

    if (!force) {
        printf(_("Deleting KDC database of '%s', are you sure?\n"),
               global_params.realm);
        printf(_("(type 'yes' to confirm)? "));
        if (fgets(buf, sizeof(buf), stdin) == NULL) {
            exit_status++;
            return;
        }
        if (strcmp(buf, yes)) {
            exit_status++;
            return;
        }
        printf(_("OK, deleting database of '%s'...\n"), global_params.realm);
    }

    dal_handle = util_context->dal_handle;
    ldap_context = (krb5_ldap_context *) dal_handle->db_context;
    if (!(ldap_context)) {
        com_err(progname, EINVAL, _("while initializing database"));
        exit_status++;
        return;
    }

    /* Read the kerberos container from the LDAP Server */
    if ((retval = krb5_ldap_read_krbcontainer_params(util_context,
                                                     &(ldap_context->krbcontainer))) != 0) {
        com_err(progname, retval,
                _("while reading kerberos container information"));
        exit_status++;
        return;
    }

    /* Read the Realm information from the LDAP Server */
    if ((retval = krb5_ldap_read_realm_params(util_context, global_params.realm,
                                              &(ldap_context->lrparams), &mask)) != 0) {
        com_err(progname, retval, _("while reading realm information"));
        exit_status++;
        return;
    }

#ifdef HAVE_EDIRECTORY
    if ((mask & LDAP_REALM_KDCSERVERS) || (mask & LDAP_REALM_ADMINSERVERS) ||
        (mask & LDAP_REALM_PASSWDSERVERS)) {

        printf(_("Changing rights for the service object. Please wait ... "));
        fflush(stdout);

        rparams = ldap_context->lrparams;
        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 ((retval = krb5_ldap_delete_service_rights(util_context,
                                                              LDAP_KDC_SERVICE, rparams->kdcservers[i],
                                                              rparams->realm_name, rparams->subtree, rparams->containerref, rightsmask)) != 0) {
                    printf(_("failed\n"));
                    com_err(progname, retval,
                            _("while assigning rights to '%s'"),
                            rparams->realm_name);
                    return;
                }
            }
        }
        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 ((retval = krb5_ldap_delete_service_rights(util_context,
                                                              LDAP_ADMIN_SERVICE, rparams->adminservers[i],
                                                              rparams->realm_name, rparams->subtree, rparams->containerref, rightsmask)) != 0) {
                    printf(_("failed\n"));
                    com_err(progname, retval,
                            _("while assigning rights to '%s'"),
                            rparams->realm_name);
                    return;
                }
            }
        }
        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 ((retval = krb5_ldap_delete_service_rights(util_context,
                                                              LDAP_PASSWD_SERVICE, rparams->passwdservers[i],
                                                              rparams->realm_name, rparams->subtree, rparams->containerref, rightsmask)) != 0) {
                    printf(_("failed\n"));
                    com_err(progname, retval,
                            _("while assigning rights to '%s'"),
                            rparams->realm_name);
                    return;
                }
            }
        }
        printf("done\n");
    }
#endif
    /* Delete the realm container and all the associated principals */
    retval = krb5_ldap_delete_realm(util_context, global_params.realm);
    if (retval) {
        com_err(progname, retval,
                _("deleting database of '%s'"), global_params.realm);
        exit_status++;
        return;
    }

    printf(_("** Database of '%s' destroyed.\n"), global_params.realm);

    return;
}
