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