Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/crypto/krb5/src/kadmin/dbutil/kdb5_util.c
34907 views
1
/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2
/* kadmin/dbutil/kdb5_util.c - Administer a KDC database */
3
/*
4
* (C) Copyright 1990,1991, 1996, 2008, 2009 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
/*
52
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
53
* Use is subject to license terms.
54
*/
55
56
#include <k5-int.h>
57
#include <kadm5/admin.h>
58
#include <locale.h>
59
#include <adm_proto.h>
60
#include <time.h>
61
#include "kdb5_util.h"
62
63
/*
64
* XXX Ick, ick, ick. These global variables shouldn't be global....
65
*/
66
char *mkey_password = 0;
67
68
/*
69
* I can't figure out any way for this not to be global, given how ss
70
* works.
71
*/
72
73
int exit_status = 0;
74
krb5_context util_context;
75
kadm5_config_params global_params;
76
77
void usage(void)
78
{
79
fprintf(stderr,
80
_("Usage: kdb5_util [-r realm] [-d dbname] "
81
"[-k mkeytype] [-kv mkeyVNO]\n"
82
"\t [-M mkeyname] [-m] [-sf stashfilename] "
83
"[-P password]\n"
84
"\t [-x db_args]* cmd [cmd_options]\n"
85
"\tcreate [-s]\n"
86
"\tdestroy [-f]\n"
87
"\tstash [-f keyfile]\n"
88
"\tdump [-b7|-r13|-r18] [-verbose]\n"
89
"\t [-mkey_convert] [-new_mkey_file mkey_file]\n"
90
"\t [-rev] [-recurse] [filename [princs...]]\n"
91
"\tload [-b7|-r13|-r18] [-hash] [-verbose] [-update] "
92
"filename\n"
93
"\tark [-e etype_list] principal\n"
94
"\tadd_mkey [-e etype] [-s]\n"
95
"\tuse_mkey kvno [time]\n"
96
"\tlist_mkeys\n"));
97
/* avoid a string length compiler warning */
98
fprintf(stderr,
99
_("\tupdate_princ_encryption [-f] [-n] [-v] [princ-pattern]\n"
100
"\tpurge_mkeys [-f] [-n] [-v]\n"
101
"\ttabdump [-H] [-c] [-e] [-n] [-o outfile] dumptype\n"
102
"\nwhere,\n\t[-x db_args]* - any number of database specific "
103
"arguments.\n"
104
"\t\t\tLook at each database documentation for supported "
105
"arguments\n"));
106
exit(1);
107
}
108
109
krb5_keyblock master_keyblock;
110
krb5_kvno master_kvno; /* fetched */
111
extern krb5_principal master_princ;
112
char *mkey_fullname;
113
krb5_db_entry *master_entry = NULL;
114
int valid_master_key = 0;
115
116
char *progname;
117
krb5_boolean manual_mkey = FALSE;
118
krb5_boolean dbactive = FALSE;
119
120
static int open_db_and_mkey(void);
121
122
static void add_random_key(int, char **);
123
124
typedef void (*cmd_func)(int, char **);
125
126
struct _cmd_table {
127
char *name;
128
cmd_func func;
129
int opendb;
130
} cmd_table[] = {
131
{"create", kdb5_create, 0},
132
{"destroy", kdb5_destroy, 1}, /* 1 opens the kdb */
133
{"stash", kdb5_stash, 1},
134
{"dump", dump_db, 1},
135
{"load", load_db, 0},
136
{"ark", add_random_key, 1},
137
{"add_mkey", kdb5_add_mkey, 1},
138
{"use_mkey", kdb5_use_mkey, 1},
139
{"list_mkeys", kdb5_list_mkeys, 1},
140
{"update_princ_encryption", kdb5_update_princ_encryption, 1},
141
{"purge_mkeys", kdb5_purge_mkeys, 1},
142
{"tabdump", tabdump, 1},
143
{NULL, NULL, 0},
144
};
145
146
static struct _cmd_table *
147
cmd_lookup(char *name)
148
{
149
struct _cmd_table *cmd = cmd_table;
150
while (cmd->name) {
151
if (strcmp(cmd->name, name) == 0)
152
return cmd;
153
else
154
cmd++;
155
}
156
157
return NULL;
158
}
159
160
#define ARG_VAL (--argc > 0 ? (koptarg = *(++argv)) : (char *)(usage(), NULL))
161
162
char **db5util_db_args = NULL;
163
size_t db5util_db_args_size = 0;
164
165
static void
166
extended_com_err_fn(const char *myprog, errcode_t code, const char *fmt,
167
va_list args)
168
{
169
const char *emsg;
170
if (code) {
171
emsg = krb5_get_error_message (util_context, code);
172
fprintf (stderr, "%s: %s ", myprog, emsg);
173
krb5_free_error_message (util_context, emsg);
174
} else {
175
fprintf (stderr, "%s: ", myprog);
176
}
177
vfprintf (stderr, fmt, args);
178
fprintf (stderr, "\n");
179
}
180
181
int
182
add_db_arg(char *arg)
183
{
184
char **temp;
185
db5util_db_args_size++;
186
temp = realloc(db5util_db_args,
187
sizeof(char *) * (db5util_db_args_size + 1));
188
if (temp == NULL)
189
return 0;
190
db5util_db_args = temp;
191
db5util_db_args[db5util_db_args_size-1] = arg;
192
db5util_db_args[db5util_db_args_size] = NULL;
193
return 1;
194
}
195
196
int
197
main(int argc, char *argv[])
198
{
199
struct _cmd_table *cmd = NULL;
200
char *koptarg, **cmd_argv;
201
char *db_name_tmp = NULL;
202
int cmd_argc;
203
krb5_error_code retval;
204
205
setlocale(LC_ALL, "");
206
set_com_err_hook(extended_com_err_fn);
207
208
/*
209
* Ensure that "progname" is set before calling com_err.
210
*/
211
progname = (strrchr(argv[0], '/') ?
212
strrchr(argv[0], '/') + 1 : argv[0]);
213
214
retval = kadm5_init_krb5_context(&util_context);
215
if (retval) {
216
com_err (progname, retval, _("while initializing Kerberos code"));
217
exit(1);
218
}
219
220
cmd_argv = (char **) malloc(sizeof(char *)*argc);
221
if (cmd_argv == NULL) {
222
com_err(progname, ENOMEM, _("while creating sub-command arguments"));
223
exit(1);
224
}
225
memset(cmd_argv, 0, sizeof(char *)*argc);
226
cmd_argc = 0;
227
228
argv++; argc--;
229
while (*argv) {
230
if (strcmp(*argv, "-P") == 0 && ARG_VAL) {
231
mkey_password = koptarg;
232
manual_mkey = TRUE;
233
} else if (strcmp(*argv, "-d") == 0 && ARG_VAL) {
234
global_params.dbname = koptarg;
235
global_params.mask |= KADM5_CONFIG_DBNAME;
236
237
if (asprintf(&db_name_tmp, "dbname=%s", global_params.dbname) < 0)
238
{
239
com_err(progname, ENOMEM,
240
_("while parsing command arguments"));
241
exit(1);
242
}
243
244
if (!add_db_arg(db_name_tmp)) {
245
com_err(progname, ENOMEM,
246
_("while parsing command arguments\n"));
247
exit(1);
248
}
249
250
} else if (strcmp(*argv, "-x") == 0 && ARG_VAL) {
251
if (!add_db_arg(koptarg)) {
252
com_err(progname, ENOMEM,
253
_("while parsing command arguments\n"));
254
exit(1);
255
}
256
257
} else if (strcmp(*argv, "-r") == 0 && ARG_VAL) {
258
global_params.realm = koptarg;
259
global_params.mask |= KADM5_CONFIG_REALM;
260
/* not sure this is really necessary */
261
if ((retval = krb5_set_default_realm(util_context,
262
global_params.realm))) {
263
com_err(progname, retval,
264
_("while setting default realm name"));
265
exit(1);
266
}
267
} else if (strcmp(*argv, "-k") == 0 && ARG_VAL) {
268
if (krb5_string_to_enctype(koptarg, &global_params.enctype)) {
269
com_err(progname, EINVAL, _(": %s is an invalid enctype"),
270
koptarg);
271
exit(1);
272
} else
273
global_params.mask |= KADM5_CONFIG_ENCTYPE;
274
} else if (strcmp(*argv, "-kv") == 0 && ARG_VAL) {
275
global_params.kvno = (krb5_kvno) atoi(koptarg);
276
if (global_params.kvno == IGNORE_VNO) {
277
com_err(progname, EINVAL, _(": %s is an invalid mkeyVNO"),
278
koptarg);
279
exit(1);
280
} else
281
global_params.mask |= KADM5_CONFIG_KVNO;
282
} else if (strcmp(*argv, "-M") == 0 && ARG_VAL) {
283
global_params.mkey_name = koptarg;
284
global_params.mask |= KADM5_CONFIG_MKEY_NAME;
285
} else if (strcmp(*argv, "-sf") == 0 && ARG_VAL) {
286
global_params.stash_file = koptarg;
287
global_params.mask |= KADM5_CONFIG_STASH_FILE;
288
} else if (strcmp(*argv, "-m") == 0) {
289
manual_mkey = TRUE;
290
global_params.mkey_from_kbd = 1;
291
global_params.mask |= KADM5_CONFIG_MKEY_FROM_KBD;
292
} else {
293
cmd_argv[cmd_argc++] = *argv;
294
}
295
argv++; argc--;
296
}
297
298
if (cmd_argv[0] == NULL)
299
usage();
300
cmd = cmd_lookup(cmd_argv[0]);
301
if (cmd == NULL)
302
usage();
303
304
if( !util_context->default_realm )
305
{
306
char *temp = NULL;
307
retval = krb5_get_default_realm(util_context, &temp);
308
if( retval )
309
{
310
com_err(progname, retval, _("while getting default realm"));
311
exit(1);
312
}
313
krb5_free_default_realm(util_context, temp);
314
}
315
316
retval = kadm5_get_config_params(util_context, 1,
317
&global_params, &global_params);
318
if (retval) {
319
com_err(progname, retval,
320
_("while retrieving configuration parameters"));
321
exit(1);
322
}
323
324
/*
325
* Dump creates files which should not be world-readable. It is
326
* easiest to do a single umask call here.
327
*/
328
(void) umask(077);
329
330
master_keyblock.enctype = global_params.enctype;
331
if ((master_keyblock.enctype != ENCTYPE_UNKNOWN) &&
332
(!krb5_c_valid_enctype(master_keyblock.enctype))) {
333
com_err(progname, KRB5_PROG_KEYTYPE_NOSUPP,
334
"while setting up enctype %d", master_keyblock.enctype);
335
}
336
337
if (cmd->opendb && open_db_and_mkey())
338
return exit_status;
339
340
if (global_params.iprop_enabled == TRUE)
341
ulog_set_role(util_context, IPROP_PRIMARY);
342
else
343
ulog_set_role(util_context, IPROP_NULL);
344
345
(*cmd->func)(cmd_argc, cmd_argv);
346
347
if( db_name_tmp )
348
free( db_name_tmp );
349
350
if( db5util_db_args )
351
free(db5util_db_args);
352
353
quit();
354
kadm5_free_config_params(util_context, &global_params);
355
krb5_free_context(util_context);
356
free(cmd_argv);
357
return exit_status;
358
}
359
360
/*
361
* open_db_and_mkey: Opens the KDC and policy database, and sets the
362
* global master_* variables. Sets dbactive to TRUE if the databases
363
* are opened, and valid_master_key to 1 if the global master
364
* variables are set properly. Returns 0 on success, and 1 on
365
* failure, but it is not considered a failure if the master key
366
* cannot be fetched (the master key stash file may not exist when the
367
* program is run).
368
*/
369
static int
370
open_db_and_mkey(void)
371
{
372
krb5_error_code retval;
373
krb5_data scratch, pwd, seed;
374
375
dbactive = FALSE;
376
valid_master_key = 0;
377
378
if ((retval = krb5_db_open(util_context, db5util_db_args,
379
KRB5_KDB_OPEN_RW | KRB5_KDB_SRV_TYPE_ADMIN))) {
380
com_err(progname, retval, _("while initializing database"));
381
exit_status++;
382
return(1);
383
}
384
385
/* assemble & parse the master key name */
386
387
if ((retval = krb5_db_setup_mkey_name(util_context,
388
global_params.mkey_name,
389
global_params.realm,
390
&mkey_fullname, &master_princ))) {
391
com_err(progname, retval, _("while setting up master key name"));
392
exit_status++;
393
return(1);
394
}
395
if ((retval = krb5_db_get_principal(util_context, master_princ, 0,
396
&master_entry))) {
397
com_err(progname, retval, _("while retrieving master entry"));
398
exit_status++;
399
(void) krb5_db_fini(util_context);
400
return(1);
401
}
402
403
if (global_params.mask & KADM5_CONFIG_KVNO)
404
master_kvno = global_params.kvno; /* user specified */
405
else
406
master_kvno = IGNORE_VNO;
407
408
/* the databases are now open, and the master principal exists */
409
dbactive = TRUE;
410
411
if (mkey_password) {
412
pwd.data = mkey_password;
413
pwd.length = strlen(mkey_password);
414
retval = krb5_principal2salt(util_context, master_princ, &scratch);
415
if (retval) {
416
com_err(progname, retval, _("while calculated master key salt"));
417
exit_status++;
418
return(1);
419
}
420
421
/* If no encryption type is set, use the default */
422
if (master_keyblock.enctype == ENCTYPE_UNKNOWN)
423
master_keyblock.enctype = DEFAULT_KDC_ENCTYPE;
424
if (!krb5_c_valid_enctype(master_keyblock.enctype))
425
com_err(progname, KRB5_PROG_KEYTYPE_NOSUPP,
426
"while setting up enctype %d",
427
master_keyblock.enctype);
428
429
retval = krb5_c_string_to_key(util_context, master_keyblock.enctype,
430
&pwd, &scratch, &master_keyblock);
431
if (retval) {
432
com_err(progname, retval,
433
_("while transforming master key from password"));
434
exit_status++;
435
return(1);
436
}
437
free(scratch.data);
438
mkey_password = 0;
439
440
} else {
441
if ((retval = krb5_db_fetch_mkey(util_context, master_princ,
442
master_keyblock.enctype,
443
manual_mkey, FALSE,
444
global_params.stash_file,
445
&master_kvno,
446
0, &master_keyblock))) {
447
com_err(progname, retval, _("while reading master key"));
448
com_err(progname, 0, _("Warning: proceeding without master key"));
449
exit_status++;
450
return(0);
451
}
452
}
453
454
if ((retval = krb5_db_fetch_mkey_list(util_context, master_princ,
455
&master_keyblock))) {
456
com_err(progname, retval, "while getting master key list");
457
com_err(progname, 0, "Warning: proceeding without master key list");
458
exit_status++;
459
return(0);
460
}
461
462
seed.length = master_keyblock.length;
463
seed.data = (char *) master_keyblock.contents;
464
465
if ((retval = krb5_c_random_seed(util_context, &seed))) {
466
com_err(progname, retval, _("while seeding random number generator"));
467
exit_status++;
468
memset(master_keyblock.contents, 0, master_keyblock.length);
469
krb5_free_keyblock_contents(util_context, &master_keyblock);
470
return(1);
471
}
472
473
if (global_params.iprop_enabled) {
474
if (ulog_map(util_context, global_params.iprop_logfile,
475
global_params.iprop_ulogsize)) {
476
fprintf(stderr, _("%s: Could not map log\n"), progname);
477
exit_status++;
478
return(1);
479
}
480
}
481
482
valid_master_key = 1;
483
dbactive = TRUE;
484
return 0;
485
}
486
487
#ifdef HAVE_GETCWD
488
#undef getwd
489
#endif
490
491
int
492
quit(void)
493
{
494
krb5_error_code retval;
495
static krb5_boolean finished = 0;
496
497
if (finished)
498
return 0;
499
ulog_fini(util_context);
500
retval = krb5_db_fini(util_context);
501
zapfree(master_keyblock.contents, master_keyblock.length);
502
krb5_free_principal(util_context, master_princ);
503
finished = TRUE;
504
if (retval && retval != KRB5_KDB_DBNOTINITED) {
505
com_err(progname, retval, _("while closing database"));
506
exit_status++;
507
return 1;
508
}
509
return 0;
510
}
511
512
static void
513
add_random_key(int argc, char **argv)
514
{
515
krb5_error_code ret;
516
krb5_principal princ;
517
krb5_db_entry *dbent;
518
krb5_timestamp now;
519
520
krb5_key_salt_tuple *keysalts = NULL;
521
krb5_int32 num_keysalts = 0;
522
523
int free_keysalts;
524
char *me = progname;
525
char *ks_str = "";
526
char *pr_str;
527
krb5_keyblock *tmp_mkey;
528
529
if (argc < 2)
530
usage();
531
for (argv++, argc--; *argv; argv++, argc--) {
532
if (!strcmp(*argv, "-e")) {
533
argv++; argc--;
534
ks_str = *argv;
535
continue;
536
} else
537
break;
538
}
539
if (argc < 1)
540
usage();
541
pr_str = *argv;
542
ret = krb5_parse_name(util_context, pr_str, &princ);
543
if (ret) {
544
com_err(me, ret, _("while parsing principal name %s"), pr_str);
545
exit_status++;
546
return;
547
}
548
ret = krb5_db_get_principal(util_context, princ, 0, &dbent);
549
if (ret) {
550
com_err(me, ret, _("while fetching principal %s"), pr_str);
551
exit_status++;
552
return;
553
}
554
ret = krb5_string_to_keysalts(ks_str,
555
NULL, NULL, 0,
556
&keysalts,
557
&num_keysalts);
558
if (ret) {
559
com_err(me, ret, _("while parsing keysalts %s"), ks_str);
560
exit_status++;
561
return;
562
}
563
if (!num_keysalts || keysalts == NULL) {
564
num_keysalts = global_params.num_keysalts;
565
keysalts = global_params.keysalts;
566
free_keysalts = 0;
567
} else
568
free_keysalts = 1;
569
570
/* Find the mkey used to protect the existing keys */
571
ret = krb5_dbe_find_mkey(util_context, dbent, &tmp_mkey);
572
if (ret) {
573
com_err(me, ret, _("while finding mkey"));
574
krb5_db_free_principal(util_context, dbent);
575
exit_status++;
576
return;
577
}
578
579
ret = krb5_dbe_ark(util_context, tmp_mkey, keysalts, num_keysalts, dbent);
580
if (free_keysalts)
581
free(keysalts);
582
if (ret) {
583
com_err(me, ret, "while randomizing principal %s", pr_str);
584
krb5_db_free_principal(util_context, dbent);
585
exit_status++;
586
return;
587
}
588
dbent->attributes &= ~KRB5_KDB_REQUIRES_PWCHANGE;
589
ret = krb5_timeofday(util_context, &now);
590
if (ret) {
591
com_err(me, ret, _("while getting time"));
592
krb5_db_free_principal(util_context, dbent);
593
exit_status++;
594
return;
595
}
596
ret = krb5_dbe_update_last_pwd_change(util_context, dbent, now);
597
if (ret) {
598
com_err(me, ret, _("while setting changetime"));
599
krb5_db_free_principal(util_context, dbent);
600
exit_status++;
601
return;
602
}
603
604
dbent->mask |= KADM5_ATTRIBUTES | KADM5_KEY_DATA | KADM5_TL_DATA;
605
606
ret = krb5_db_put_principal(util_context, dbent);
607
krb5_db_free_principal(util_context, dbent);
608
if (ret) {
609
com_err(me, ret, _("while saving principal %s"), pr_str);
610
exit_status++;
611
return;
612
}
613
printf(_("%s changed\n"), pr_str);
614
}
615
616