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