1 /*
2  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
3  * Use is subject to license terms.
4  */
5 
6 
7 /*
8  * kadmin/ldap_util/kdb5_ldap_util.c
9  *
10  * (C) Copyright 1990,1991, 1996 by the Massachusetts Institute of Technology.
11  * All Rights Reserved.
12  *
13  * Export of this software from the United States of America may
14  *   require a specific license from the United States Government.
15  *   It is the responsibility of any person or organization contemplating
16  *   export to obtain such a license before exporting.
17  *
18  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
19  * distribute this software and its documentation for any purpose and
20  * without fee is hereby granted, provided that the above copyright
21  * notice appear in all copies and that both that copyright notice and
22  * this permission notice appear in supporting documentation, and that
23  * the name of M.I.T. not be used in advertising or publicity pertaining
24  * to distribution of the software without specific, written prior
25  * permission.  Furthermore if you modify this software you must label
26  * your software as modified software and not distribute it in such a
27  * fashion that it might be confused with the original M.I.T. software.
28  * M.I.T. makes no representations about the suitability of
29  * this software for any purpose.  It is provided "as is" without express
30  * or implied warranty.
31  *
32  *
33  * Edit a KDC database.
34  */
35 
36 /*
37  * Copyright (C) 1998 by the FundsXpress, INC.
38  *
39  * All rights reserved.
40  *
41  * Export of this software from the United States of America may require
42  * a specific license from the United States Government.  It is the
43  * responsibility of any person or organization contemplating export to
44  * obtain such a license before exporting.
45  *
46  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
47  * distribute this software and its documentation for any purpose and
48  * without fee is hereby granted, provided that the above copyright
49  * notice appear in all copies and that both that copyright notice and
50  * this permission notice appear in supporting documentation, and that
51  * the name of FundsXpress. not be used in advertising or publicity pertaining
52  * to distribution of the software without specific, written prior
53  * permission.  FundsXpress makes no representations about the suitability of
54  * this software for any purpose.  It is provided "as is" without express
55  * or implied warranty.
56  *
57  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
58  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
59  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
60  */
61 
62 /* Copyright (c) 2004-2005, Novell, Inc.
63  * All rights reserved.
64  *
65  * Redistribution and use in source and binary forms, with or without
66  * modification, are permitted provided that the following conditions are met:
67  *
68  *   * Redistributions of source code must retain the above copyright notice,
69  *       this list of conditions and the following disclaimer.
70  *   * Redistributions in binary form must reproduce the above copyright
71  *       notice, this list of conditions and the following disclaimer in the
72  *       documentation and/or other materials provided with the distribution.
73  *   * The copyright holder's name is not used to endorse or promote products
74  *       derived from this software without specific prior written permission.
75  *
76  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
77  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
78  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
79  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
80  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
81  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
82  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
83  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
84  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
85  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
86  * POSSIBILITY OF SUCH DAMAGE.
87  */
88 
89 #include <stdio.h>
90 #include <time.h>
91 
92 #include <k5-int.h>
93 #include <kadm5/admin.h>
94 #include <adm_proto.h>
95 #include <libintl.h>
96 #include <locale.h>
97 #include "kdb5_ldap_util.h"
98 
99 typedef void (*cmd_func)(int, char **);
100 int cmd_index(char *name);
101 
102 char *mkey_password = 0;
103 int exit_status = 0;
104 krb5_context util_context;
105 kadm5_config_params global_params;
106 krb5_boolean db_inited = FALSE;
107 
108 char *progname;
109 krb5_boolean manual_mkey = FALSE;
110 
111 /*
112  * This function prints the usage of kdb5_ldap_util, which is
113  * the LDAP configuration utility.
114  */
115 void usage()
116 {
117     fprintf(stderr, "%s: "
118 "kdb5_ldap_util [-D user_dn [-w passwd]] [-H ldapuri]\n"
119 "\tcmd [cmd_options]\n"
120 
121 /* Create realm */
122 "create          [-subtrees subtree_dn_list] [-sscope search_scope] [-containerref container_reference_dn]\n"
123 #ifdef HAVE_EDIRECTORY
124 "\t\t[-kdcdn kdc_service_list] [-admindn admin_service_list]\n"
125 "\t\t[-pwddn passwd_service_list]\n"
126 #endif
127 "\t\t[-m|-P password|-sf stashfilename] [-k mkeytype] [-s]\n"
128 "\t\t[-maxtktlife max_ticket_life] [-maxrenewlife max_renewable_ticket_life]\n"
129 "\t\t[ticket_flags] [-r realm]\n"
130 
131 /* modify realm */
132 "modify          [-subtrees subtree_dn_list] [-sscope search_scope] [-containerref container_reference_dn]\n"
133 #ifdef HAVE_EDIRECTORY
134 "\t\t[-kdcdn kdc_service_list |\n"
135 "\t\t[-clearkdcdn kdc_service_list] [-addkdcdn kdc_service_list]]\n"
136 "\t\t[-admindn admin_service_list | [-clearadmindn admin_service_list]\n"
137 "\t\t[-addadmindn admin_service_list]] [-pwddn passwd_service_list |\n"
138 "\t\t[-clearpwddn passwd_service_list] [-addpwddn passwd_service_list]]\n"
139 #endif
140 "\t\t[-maxtktlife max_ticket_life] [-maxrenewlife max_renewable_ticket_life]\n"
141 "\t\t[ticket_flags] [-r realm]\n"
142 /* View realm */
143 "view            [-r realm]\n"
144 
145 /* Destroy realm */
146 "destroy	        [-f] [-r realm]\n"
147 
148 /* List realms */
149 "list\n"
150 
151 #ifdef HAVE_EDIRECTORY
152 /* Create Service */
153 "create_service  {-kdc|-admin|-pwd} [-servicehost service_host_list]\n"
154 "\t\t[-realm realm_list] \n"
155 "\t\t[-randpw|-fileonly] [-f filename] service_dn\n"
156 
157 /* Modify service */
158 "modify_service  [-servicehost service_host_list |\n"
159 "\t\t[-clearservicehost service_host_list]\n"
160 "\t\t[-addservicehost service_host_list]]\n"
161 "\t\t[-realm realm_list | [-clearrealm realm_list]\n"
162 "\t\t[-addrealm realm_list]] service_dn\n"
163 
164 /* View Service */
165 "view_service    service_dn\n"
166 
167 /* Destroy Service */
168 "destroy_service [-force] [-f stashfilename] service_dn\n"
169 
170 /* List services */
171 "list_service    [-basedn base_dn]\n"
172 
173 /* Set Service password */
174 "setsrvpw        [-randpw|-fileonly] [-f filename] service_dn\n"
175 
176 #else
177 
178 /* Stash the service password */
179 "stashsrvpw      [-f filename] service_dn\n"
180 
181 #endif
182 
183 /* Create policy */
184 "create_policy   [-r realm] [-maxtktlife max_ticket_life]\n"
185 "\t\t[-maxrenewlife max_renewable_ticket_life] [ticket_flags] policy\n"
186 
187 /* Modify policy */
188 "modify_policy   [-r realm] [-maxtktlife max_ticket_life]\n"
189 "\t\t[-maxrenewlife max_renewable_ticket_life] [ticket_flags] policy\n"
190 
191 /* View policy */
192 "view_policy     [-r realm] policy\n"
193 
194 /* Destroy policy */
195 "destroy_policy  [-r realm] [-force] policy\n"
196 
197 /* List policies */
198 "list_policy     [-r realm]\n",
199     gettext("Usage"));
200 }
201 
202 void db_usage (int type) {
203     /*
204      * This should print usage of 'type' command. For now, we will print usage
205      * of all commands.
206      */
207     usage ();
208 }
209 
210 /* The help messages for all sub-commands should be in the
211  * same order as listed in this table.
212  */
213 static struct _cmd_table {
214     char *name;
215     cmd_func func;
216     int opendb;
217 } cmd_table[] = {
218     {"create", kdb5_ldap_create, 1},
219     {"modify", kdb5_ldap_modify, 1},
220     {"view", kdb5_ldap_view, 1},
221     {"destroy", kdb5_ldap_destroy, 1},
222     {"list", kdb5_ldap_list, 1},
223 #ifdef HAVE_EDIRECTORY
224     {"create_service", kdb5_ldap_create_service, 1},
225     {"modify_service", kdb5_ldap_modify_service, 1},
226     {"view_service", kdb5_ldap_view_service, 1},
227     {"destroy_service", kdb5_ldap_destroy_service, 1},
228     {"list_service",kdb5_ldap_list_services,1},
229     {"setsrvpw", kdb5_ldap_set_service_password, 0},
230 #else
231     {"stashsrvpw", kdb5_ldap_stash_service_password, 0},
232 #endif
233     {"create_policy", kdb5_ldap_create_policy, 1},
234     {"modify_policy", kdb5_ldap_modify_policy, 1},
235     {"view_policy", kdb5_ldap_view_policy, 1},
236     {"destroy_policy", kdb5_ldap_destroy_policy, 1},
237     {"list_policy", kdb5_ldap_list_policies, 1},
238     {NULL, NULL, 0},
239 };
240 
241 
242 /*
243  * The function cmd_lookup returns the structure matching the
244  * command name and returns NULL if nothing matches.
245  */
246 static struct _cmd_table *cmd_lookup(name)
247     char *name;
248 {
249     int i;
250 
251     for (i = 0; cmd_table[i].name != NULL; i++)
252 	if (strcmp(cmd_table[i].name, name) == 0)
253 	    return &cmd_table[i];
254 
255     return NULL;
256 }
257 
258 
259 /*
260  * The function cmd_index provides the offset of the command
261  * in the command table, which can be used to get the corresponding
262  * help from the help message table.
263  */
264 int cmd_index(name)
265     char *name;
266 {
267     int i;
268 
269     if (name == NULL)
270 	return -1;
271 
272     for (i = 0; cmd_table[i].name != NULL; i++)
273 	if (strcmp(cmd_table[i].name, name) == 0)
274 	    return i;
275 
276     return -1;
277 }
278 
279 static void extended_com_err_fn (const char *myprog, errcode_t code,
280 				 const char *fmt, va_list args)
281 {
282     const char *emsg;
283     /* Solaris Kerberos: code should be like that in kdb5_util.c */
284     if (code) {
285 	emsg = krb5_get_error_message (util_context, code);
286 	fprintf (stderr, "%s: %s ", myprog, emsg);
287 	krb5_free_error_message (util_context, emsg);
288     } else {
289 	fprintf (stderr, "%s: ", myprog);
290     }
291     vfprintf (stderr, fmt, args);
292     fprintf (stderr, "\n");
293 }
294 
295 int main(argc, argv)
296     int argc;
297     char *argv[];
298 {
299     struct _cmd_table *cmd = NULL;
300     char *koptarg = NULL, **cmd_argv = NULL;
301     int cmd_argc = 0;
302     krb5_error_code retval;
303     int usage_print = 0;
304     int gp_is_static = 1;
305     krb5_error_code db_retval = 1;
306     char *bind_dn = NULL;
307     char *passwd = NULL;
308     char *ldap_server = NULL;
309     unsigned int ldapmask = 0;
310     unsigned int passwd_len = 0;
311     char *prompt = NULL;
312     kdb5_dal_handle *dal_handle = NULL;
313     krb5_ldap_context *ldap_context=NULL;
314     char *value = NULL, *conf_section = NULL;
315     krb5_boolean realm_name_required = TRUE;
316     krb5_boolean print_help_message = FALSE;
317 
318     /*
319      * Solaris Kerberos:
320      * Ensure that "progname" is set before calling com_err.
321      */
322     progname = (strrchr(argv[0], '/') ? strrchr(argv[0], '/')+1 : argv[0]);
323 
324     retval = krb5_init_context(&util_context);
325     set_com_err_hook(extended_com_err_fn);
326     if (retval) {
327 	com_err (progname, retval, gettext("while initializing Kerberos code"));
328 	exit_status++;
329 	goto cleanup;
330     }
331 
332     cmd_argv = (char **) malloc(sizeof(char *)*argc);
333     if (cmd_argv == NULL) {
334 	com_err(progname, ENOMEM, gettext("while creating sub-command arguments"));
335 	exit_status++;
336 	goto cleanup;
337     }
338     memset(cmd_argv, 0, sizeof(char *)*argc);
339     cmd_argc = 1;
340 
341     memset(&global_params, 0, sizeof(kadm5_config_params));
342 
343     argv++; argc--;
344     while (*argv) {
345 	if (strcmp(*argv, "--help") == 0) {
346 	    print_help_message = TRUE;
347 	}
348 	if (strcmp(*argv, "-P") == 0 && ARG_VAL) {
349 	    mkey_password = koptarg;
350 	    manual_mkey = TRUE;
351 	} else if (strcmp(*argv, "-r") == 0 && ARG_VAL) {
352 	    global_params.realm = koptarg;
353 	    global_params.mask |= KADM5_CONFIG_REALM;
354 	    /* not sure this is really necessary */
355 	    if ((retval = krb5_set_default_realm(util_context,
356 						 global_params.realm))) {
357 		com_err(progname, retval, gettext("while setting default realm name"));
358 		exit_status++;
359 		goto cleanup;
360 	    }
361 	} else if (strcmp(*argv, "-k") == 0 && ARG_VAL) {
362 	    if (krb5_string_to_enctype(koptarg, &global_params.enctype))
363 		com_err(argv[0], 0, gettext("%s is an invalid enctype"), koptarg);
364 	    else
365 		global_params.mask |= KADM5_CONFIG_ENCTYPE;
366 	} else if (strcmp(*argv, "-M") == 0 && ARG_VAL) {
367 	    global_params.mkey_name = koptarg;
368 	    global_params.mask |= KADM5_CONFIG_MKEY_NAME;
369 	} else if (strcmp(*argv, "-sf") == 0 && ARG_VAL) {
370 	    global_params.stash_file = koptarg;
371 	    global_params.mask |= KADM5_CONFIG_STASH_FILE;
372 	} else if (strcmp(*argv, "-m") == 0) {
373 	    manual_mkey = TRUE;
374 	    global_params.mkey_from_kbd = 1;
375 	    global_params.mask |= KADM5_CONFIG_MKEY_FROM_KBD;
376 	} else if (strcmp(*argv, "-D") == 0 && ARG_VAL) {
377 	    bind_dn = koptarg;
378 	    if (bind_dn == NULL) {
379 		com_err(progname, ENOMEM, gettext("while reading ldap parameters"));
380 		exit_status++;
381 		goto cleanup;
382 	    }
383 	    ldapmask |= CMD_LDAP_D;
384 	} else if (strcmp(*argv, "-w") == 0 && ARG_VAL) {
385 	    passwd = strdup(koptarg);
386 	    if (passwd == NULL) {
387 		com_err(progname, ENOMEM, gettext("while reading ldap parameters"));
388 		exit_status++;
389 		goto cleanup;
390 	    }
391 	    ldapmask |= CMD_LDAP_W;
392 	} else if (strcmp(*argv, "-H") == 0 && ARG_VAL) {
393 	    ldap_server = koptarg;
394 	    if (ldap_server == NULL) {
395 		com_err(progname, ENOMEM, gettext("while reading ldap parameters"));
396 		exit_status++;
397 		goto cleanup;
398 	    }
399 	    ldapmask |= CMD_LDAP_H;
400 	} else if (cmd_lookup(*argv) != NULL) {
401 	    if (cmd_argv[0] == NULL)
402 		cmd_argv[0] = *argv;
403 	    else {
404 		free(cmd_argv);
405 		cmd_argv = NULL;
406 		usage();
407 		goto cleanup;
408 	    }
409 	} else {
410 	    cmd_argv[cmd_argc++] = *argv;
411 	}
412 	argv++; argc--;
413     }
414 
415     if (cmd_argv[0] == NULL) {
416 	free(cmd_argv);
417 	cmd_argv = NULL;
418 	usage();
419 	goto cleanup;
420     }
421 
422     /* if we need to print the help message (because of --help option)
423      * we will print the help corresponding to the sub-command.
424      */
425     if (print_help_message) {
426 	char *cmd_name = cmd_argv[0];
427 	free(cmd_argv);
428 	cmd_argv = NULL;
429 	usage();
430 	goto cleanup;
431     }
432 
433     /* We need to check for the presence of default realm name only in
434      * the case of realm related operations like create, destroy etc.
435      */
436     if ((strcmp(cmd_argv[0], "list") == 0) ||
437         (strcmp(cmd_argv[0], "stashsrvpw") == 0)) {
438         realm_name_required = FALSE;
439     }
440 
441     if (!util_context->default_realm) {
442 	char *temp = NULL;
443 	retval = krb5_get_default_realm(util_context, &temp);
444 	if (retval) {
445 	    if (realm_name_required) {
446 		com_err (progname, retval, gettext("while getting default realm"));
447 		exit_status++;
448 		goto cleanup;
449 	    }
450 	} else
451 	    util_context->default_realm = temp;
452     }
453     /* If we have the realm name, we can safely say that
454      * realm_name is required so that we don't neglect any information.
455      */
456     else
457 	realm_name_required = TRUE;
458 
459     retval = profile_get_string(util_context->profile, KDB_REALM_SECTION,
460 				util_context->default_realm, KDB_MODULE_POINTER,
461 				NULL,
462 				&value);
463 
464     if (!(value)) {
465 	retval = profile_get_string(util_context->profile, KDB_MODULE_DEF_SECTION,
466 				    KDB_MODULE_POINTER, NULL,
467 				    NULL,
468 				    &value);
469 	if (!(value)) {
470 	    if (util_context->default_realm)
471 		conf_section = strdup(util_context->default_realm);
472 	} else {
473 	    conf_section = strdup(value);
474 	    free(value);
475 	}
476     } else {
477 	conf_section = strdup(value);
478 	free(value);
479     }
480 
481     if (realm_name_required) {
482 	retval = kadm5_get_config_params(util_context, 1,
483 					 &global_params, &global_params);
484 	if (retval) {
485 	    com_err(argv[0], retval, gettext("while retreiving configuration parameters"));
486 	    exit_status++;
487 	    goto cleanup;
488 	}
489 	gp_is_static = 0;
490     }
491 
492     if ((retval = krb5_ldap_lib_init()) != 0) {
493 	com_err(argv[0], retval, gettext("while initializing error handling"));
494 	exit_status++;
495 	goto cleanup;
496     }
497 
498     /* Initialize the ldap context */
499     ldap_context = calloc(sizeof(krb5_ldap_context), 1);
500     if (ldap_context == NULL) {
501 	com_err(argv[0], ENOMEM, gettext("while initializing ldap handle"));
502 	exit_status++;
503 	goto cleanup;
504     }
505 
506     ldap_context->kcontext = util_context;
507 
508     /* If LDAP parameters are specified, replace them with the values from config */
509     if (ldapmask & CMD_LDAP_D) {
510 	/* If password is not specified, prompt for it */
511 	if (passwd == NULL) {
512 	    passwd = (char *)malloc(MAX_PASSWD_LEN);
513 	    if (passwd == NULL) {
514 		com_err(argv[0], ENOMEM, gettext("while retrieving ldap configuration"));
515 		exit_status++;
516 		goto cleanup;
517 	    }
518 	    prompt = (char *)malloc(MAX_PASSWD_PROMPT_LEN);
519 	    if (prompt == NULL) {
520 		free(passwd);
521 		passwd = NULL;
522 		com_err(argv[0], ENOMEM, gettext("while retrieving ldap configuration"));
523 		exit_status++;
524 		goto cleanup;
525 	    }
526 	    memset(passwd, 0, sizeof(passwd));
527 	    passwd_len = MAX_PASSWD_LEN - 1;
528 	    snprintf(prompt, MAX_PASSWD_PROMPT_LEN, gettext("Password for \"%s\""), bind_dn);
529 
530 	    db_retval = krb5_read_password(util_context, prompt, NULL, passwd, &passwd_len);
531 
532 	    if ((db_retval) || (passwd_len == 0)) {
533 		com_err(argv[0], ENOMEM, gettext("while retrieving ldap configuration"));
534 		free(passwd);
535 		passwd = NULL;
536 		exit_status++;
537 		goto cleanup;
538 	    }
539 	}
540 
541 	ldap_context->bind_pwd = passwd;
542     }
543 
544     /* If ldaphost is specified, release entry filled by configuration & use this */
545     if (ldapmask & CMD_LDAP_H) {
546 
547 	ldap_context->server_info_list = (krb5_ldap_server_info **) calloc (2, sizeof (krb5_ldap_server_info *)) ;
548 	if (ldap_context->server_info_list == NULL) {
549 	    com_err(argv[0], ENOMEM, gettext("while initializing server list"));
550 	    exit_status++;
551 	    goto cleanup;
552 	}
553 
554 	ldap_context->server_info_list[0] = (krb5_ldap_server_info *) calloc (1, sizeof (krb5_ldap_server_info));
555 	if (ldap_context->server_info_list[0] == NULL) {
556 	    com_err(argv[0], ENOMEM, gettext("while initializing server list"));
557 	    exit_status++;
558 	    goto cleanup;
559 	}
560 
561 	ldap_context->server_info_list[0]->server_status = NOTSET;
562 
563 	ldap_context->server_info_list[0]->server_name = strdup(ldap_server);
564 	if (ldap_context->server_info_list[0]->server_name == NULL) {
565 	    com_err(argv[0], ENOMEM, gettext("while initializing server list"));
566 	    exit_status++;
567 	    goto cleanup;
568 	}
569     }
570     if (bind_dn) {
571 	ldap_context->bind_dn = strdup(bind_dn);
572 	if (ldap_context->bind_dn == NULL) {
573 	    com_err(argv[0], ENOMEM, gettext("while retrieving ldap configuration"));
574 	    exit_status++;
575 	    goto cleanup;
576 	}
577     } else
578 	ldap_context->bind_dn = NULL;
579 
580     ldap_context->service_type = SERVICE_DN_TYPE_CLIENT;
581 
582     if (realm_name_required) {
583 	if ((global_params.enctype != ENCTYPE_UNKNOWN) &&
584 	    (!krb5_c_valid_enctype(global_params.enctype))) {
585 	    com_err(argv[0], KRB5_PROG_KEYTYPE_NOSUPP,
586 		    gettext("while setting up enctype %d"), global_params.enctype);
587 	}
588     }
589 
590     cmd = cmd_lookup(cmd_argv[0]);
591 
592     /* Setup DAL handle to access the database */
593     dal_handle = calloc((size_t)1, sizeof(kdb5_dal_handle));
594     if (dal_handle == NULL) {
595 	goto cleanup;
596     }
597     dal_handle->db_context = ldap_context;
598     util_context->db_context = (void *) dal_handle;
599 
600     db_retval = krb5_ldap_read_server_params(util_context, conf_section, KRB5_KDB_SRV_TYPE_OTHER);
601     if (db_retval) {
602 	com_err(argv[0], db_retval, gettext("while reading ldap configuration"));
603 	exit_status++;
604 	goto cleanup;
605     }
606 
607     if (cmd->opendb) {
608 	db_retval = krb5_ldap_db_init(util_context, ldap_context);
609 	if (db_retval) {
610 	    com_err(progname, db_retval, gettext("while initializing database"));
611 	    exit_status++;
612 	    goto cleanup;
613 	}
614 	db_inited = TRUE;
615     }
616     (*cmd->func)(cmd_argc, cmd_argv);
617 
618     goto cleanup;
619 
620 cleanup:
621     if (passwd)
622 	memset(passwd, 0, sizeof(passwd));
623     if (ldap_context && ldap_context->bind_pwd)
624 	memset(ldap_context->bind_pwd, 0, sizeof(ldap_context->bind_pwd));
625 
626     if (util_context) {
627 	if (gp_is_static == 0)
628 	    kadm5_free_config_params(util_context, &global_params);
629 	krb5_ldap_close(util_context);
630 	krb5_free_context(util_context);
631     }
632 
633     if (cmd_argv)
634 	free(cmd_argv);
635     if (prompt)
636 	free(prompt);
637     if (conf_section)
638 	free(conf_section);
639     if (dal_handle)
640 	free(dal_handle);
641 
642     if (usage_print) {
643 	usage();
644     }
645 
646     return exit_status;
647 }
648