Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/crypto/krb5/src/kadmin/dbutil/kdb5_create.c
34907 views
1
/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2
/* kadmin/dbutil/kdb5_create.c - Create a KDC database */
3
/*
4
* Copyright 1990,1991,2001, 2002, 2008 by the Massachusetts Institute of
5
* Technology. 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 2004 Sun Microsystems, Inc. All rights reserved.
53
* Use is subject to license terms.
54
*/
55
56
#include <k5-int.h>
57
#include <kdb.h>
58
#include <kadm5/server_internal.h>
59
#include <kadm5/admin.h>
60
#include <adm_proto.h>
61
#include "kdb5_util.h"
62
63
enum ap_op {
64
NULL_KEY, /* setup null keys */
65
MASTER_KEY, /* use master key as new key */
66
TGT_KEY /* special handling for tgt key */
67
};
68
69
struct realm_info {
70
krb5_deltat max_life;
71
krb5_deltat max_rlife;
72
krb5_timestamp expiration;
73
krb5_flags flags;
74
krb5_keyblock *key;
75
krb5_int32 nkslist;
76
krb5_key_salt_tuple *kslist;
77
} rblock;
78
79
struct iterate_args {
80
krb5_context ctx;
81
struct realm_info *rblock;
82
krb5_db_entry *dbentp;
83
};
84
85
static krb5_error_code add_principal
86
(krb5_context,
87
krb5_principal,
88
enum ap_op,
89
struct realm_info *);
90
91
/*
92
* Steps in creating a database:
93
*
94
* 1) use the db calls to open/create a new database
95
*
96
* 2) get a realm name for the new db
97
*
98
* 3) get a master password for the new db; convert to an encryption key.
99
*
100
* 4) create various required entries in the database
101
*
102
* 5) close & exit
103
*/
104
105
extern krb5_keyblock master_keyblock;
106
extern krb5_principal master_princ;
107
extern char *mkey_fullname;
108
krb5_data master_salt;
109
110
krb5_data tgt_princ_entries[] = {
111
{0, KRB5_TGS_NAME_SIZE, KRB5_TGS_NAME},
112
{0, 0, 0} };
113
114
krb5_data db_creator_entries[] = {
115
{0, sizeof("db_creation")-1, "db_creation"} };
116
117
/* XXX knows about contents of krb5_principal, and that tgt names
118
are of form TGT/REALM@REALM */
119
krb5_principal_data tgt_princ = {
120
0, /* magic number */
121
{0, 0, 0}, /* krb5_data realm */
122
tgt_princ_entries, /* krb5_data *data */
123
2, /* int length */
124
KRB5_NT_SRV_INST /* int type */
125
};
126
127
krb5_principal_data db_create_princ = {
128
0, /* magic number */
129
{0, 0, 0}, /* krb5_data realm */
130
db_creator_entries, /* krb5_data *data */
131
1, /* int length */
132
KRB5_NT_SRV_INST /* int type */
133
};
134
135
extern char *mkey_password;
136
137
extern char *progname;
138
extern int exit_status;
139
extern kadm5_config_params global_params;
140
extern krb5_context util_context;
141
142
void
143
kdb5_create(int argc, char *argv[])
144
{
145
int optchar;
146
147
krb5_error_code retval;
148
char *pw_str = 0;
149
unsigned int pw_size = 0;
150
int do_stash = 0;
151
krb5_data pwd, seed;
152
kdb_log_context *log_ctx;
153
krb5_kvno mkey_kvno;
154
155
while ((optchar = getopt(argc, argv, "sW")) != -1) {
156
switch(optchar) {
157
case 's':
158
do_stash++;
159
break;
160
case 'W':
161
/* Ignore (deprecated weak random option). */
162
break;
163
case '?':
164
default:
165
usage();
166
return;
167
}
168
}
169
170
rblock.max_life = global_params.max_life;
171
rblock.max_rlife = global_params.max_rlife;
172
rblock.expiration = global_params.expiration;
173
rblock.flags = global_params.flags;
174
rblock.nkslist = global_params.num_keysalts;
175
rblock.kslist = global_params.keysalts;
176
177
log_ctx = util_context->kdblog_context;
178
179
/* assemble & parse the master key name */
180
181
if ((retval = krb5_db_setup_mkey_name(util_context,
182
global_params.mkey_name,
183
global_params.realm,
184
&mkey_fullname, &master_princ))) {
185
com_err(progname, retval, _("while setting up master key name"));
186
exit_status++; return;
187
}
188
189
krb5_princ_set_realm_data(util_context, &db_create_princ, global_params.realm);
190
krb5_princ_set_realm_length(util_context, &db_create_princ, strlen(global_params.realm));
191
krb5_princ_set_realm_data(util_context, &tgt_princ, global_params.realm);
192
krb5_princ_set_realm_length(util_context, &tgt_princ, strlen(global_params.realm));
193
krb5_princ_component(util_context, &tgt_princ,1)->data = global_params.realm;
194
krb5_princ_component(util_context, &tgt_princ,1)->length = strlen(global_params.realm);
195
196
printf(_("Initializing database '%s' for realm '%s',\n"
197
"master key name '%s'\n"),
198
global_params.dbname, global_params.realm, mkey_fullname);
199
200
if (!mkey_password) {
201
printf(_("You will be prompted for the database Master Password.\n"));
202
printf(_("It is important that you NOT FORGET this password.\n"));
203
fflush(stdout);
204
205
pw_size = 1024;
206
pw_str = malloc(pw_size);
207
if (pw_str == NULL) {
208
com_err(progname, ENOMEM, _("while creating new master key"));
209
exit_status++; return;
210
}
211
212
retval = krb5_read_password(util_context, KRB5_KDC_MKEY_1, KRB5_KDC_MKEY_2,
213
pw_str, &pw_size);
214
if (retval) {
215
com_err(progname, retval,
216
_("while reading master key from keyboard"));
217
exit_status++; return;
218
}
219
mkey_password = pw_str;
220
}
221
222
pwd.data = mkey_password;
223
pwd.length = strlen(mkey_password);
224
retval = krb5_principal2salt(util_context, master_princ, &master_salt);
225
if (retval) {
226
com_err(progname, retval, _("while calculating master key salt"));
227
exit_status++; return;
228
}
229
230
retval = krb5_c_string_to_key(util_context, master_keyblock.enctype,
231
&pwd, &master_salt, &master_keyblock);
232
if (retval) {
233
com_err(progname, retval,
234
_("while transforming master key from password"));
235
exit_status++; return;
236
}
237
238
rblock.key = &master_keyblock;
239
240
seed = make_data(master_keyblock.contents, master_keyblock.length);
241
242
if ((retval = krb5_c_random_seed(util_context, &seed))) {
243
com_err(progname, retval,
244
_("while initializing random key generator"));
245
exit_status++; return;
246
}
247
if ((retval = krb5_db_create(util_context,
248
db5util_db_args))) {
249
com_err(progname, retval, _("while creating database '%s'"),
250
global_params.dbname);
251
exit_status++; return;
252
}
253
/* if ((retval = krb5_db_fini(util_context))) { */
254
/* com_err(progname, retval, "while closing current database"); */
255
/* exit_status++; return; */
256
/* } */
257
/* if ((retval = krb5_db_open(util_context, db5util_db_args, KRB5_KDB_OPEN_RW))) { */
258
/* com_err(progname, retval, "while initializing the database '%s'", */
259
/* global_params.dbname); */
260
/* exit_status++; return; */
261
/* } */
262
263
if (log_ctx && log_ctx->iproprole) {
264
retval = ulog_map(util_context, global_params.iprop_logfile,
265
global_params.iprop_ulogsize);
266
if (retval) {
267
com_err(argv[0], retval, _("while creating update log"));
268
exit_status++;
269
return;
270
}
271
272
/*
273
* We're reinitializing the update log in case one already
274
* existed, but this should never happen.
275
*/
276
retval = ulog_init_header(util_context);
277
if (retval) {
278
com_err(argv[0], retval, _("while initializing update log"));
279
exit_status++;
280
return;
281
}
282
283
/*
284
* Since we're creating a new db we shouldn't worry about
285
* adding the initial principals since any replica might as
286
* well do full resyncs from this newly created db.
287
*/
288
log_ctx->iproprole = IPROP_NULL;
289
}
290
291
if ((retval = add_principal(util_context, master_princ, MASTER_KEY, &rblock)) ||
292
(retval = add_principal(util_context, &tgt_princ, TGT_KEY, &rblock))) {
293
com_err(progname, retval, _("while adding entries to the database"));
294
exit_status++; return;
295
}
296
297
298
299
/*
300
* Always stash the master key so kadm5_create does not prompt for
301
* it; delete the file below if it was not requested. DO NOT EXIT
302
* BEFORE DELETING THE KEYFILE if do_stash is not set.
303
*/
304
305
/*
306
* Determine the kvno to use, it must be that used to create the master key
307
* princ.
308
*/
309
if (global_params.mask & KADM5_CONFIG_KVNO)
310
mkey_kvno = global_params.kvno; /* user specified */
311
else
312
mkey_kvno = 1; /* Default */
313
314
retval = krb5_db_store_master_key(util_context,
315
global_params.stash_file,
316
master_princ,
317
mkey_kvno,
318
&master_keyblock,
319
mkey_password);
320
if (retval) {
321
com_err(progname, retval, _("while storing key"));
322
printf(_("Warning: couldn't stash master key.\n"));
323
}
324
/* clean up */
325
zapfree(pw_str, pw_size);
326
free(master_salt.data);
327
328
if (kadm5_create(&global_params)) {
329
if (!do_stash) unlink(global_params.stash_file);
330
exit_status++;
331
return;
332
}
333
if (!do_stash) unlink(global_params.stash_file);
334
335
return;
336
}
337
338
static krb5_error_code
339
tgt_keysalt_iterate(krb5_key_salt_tuple *ksent, krb5_pointer ptr)
340
{
341
krb5_context context;
342
krb5_error_code kret;
343
struct iterate_args *iargs;
344
krb5_keyblock key;
345
krb5_int32 ind;
346
krb5_data pwd;
347
348
iargs = (struct iterate_args *) ptr;
349
kret = 0;
350
351
context = iargs->ctx;
352
353
/*
354
* Convert the master key password into a key for this particular
355
* encryption system.
356
*/
357
pwd.data = mkey_password;
358
pwd.length = strlen(mkey_password);
359
kret = krb5_c_random_seed(context, &pwd);
360
if (kret)
361
return kret;
362
363
if (!(kret = krb5_dbe_create_key_data(iargs->ctx, iargs->dbentp))) {
364
ind = iargs->dbentp->n_key_data-1;
365
if (!(kret = krb5_c_make_random_key(context, ksent->ks_enctype,
366
&key))) {
367
kret = krb5_dbe_encrypt_key_data(context, iargs->rblock->key,
368
&key, NULL, 1,
369
&iargs->dbentp->key_data[ind]);
370
krb5_free_keyblock_contents(context, &key);
371
}
372
}
373
374
return(kret);
375
}
376
377
static krb5_error_code
378
add_principal(krb5_context context, krb5_principal princ, enum ap_op op,
379
struct realm_info *pblock)
380
{
381
krb5_error_code retval;
382
krb5_db_entry *entry = NULL;
383
krb5_kvno mkey_kvno;
384
krb5_timestamp now;
385
struct iterate_args iargs;
386
krb5_actkvno_node actkvno;
387
388
entry = calloc(1, sizeof(*entry));
389
if (entry == NULL)
390
return ENOMEM;
391
392
entry->len = KRB5_KDB_V1_BASE_LENGTH;
393
entry->attributes = pblock->flags;
394
entry->max_life = pblock->max_life;
395
entry->max_renewable_life = pblock->max_rlife;
396
entry->expiration = pblock->expiration;
397
398
if ((retval = krb5_copy_principal(context, princ, &entry->princ)))
399
goto cleanup;
400
401
if ((retval = krb5_timeofday(context, &now)))
402
goto cleanup;
403
404
if ((retval = krb5_dbe_update_mod_princ_data(context, entry,
405
now, &db_create_princ)))
406
goto cleanup;
407
408
switch (op) {
409
case MASTER_KEY:
410
if ((entry->key_data=(krb5_key_data*)malloc(sizeof(krb5_key_data)))
411
== NULL)
412
goto cleanup;
413
memset(entry->key_data, 0, sizeof(krb5_key_data));
414
entry->n_key_data = 1;
415
416
if (global_params.mask & KADM5_CONFIG_KVNO)
417
mkey_kvno = global_params.kvno; /* user specified */
418
else
419
mkey_kvno = 1; /* Default */
420
entry->attributes |= KRB5_KDB_DISALLOW_ALL_TIX;
421
if ((retval = krb5_dbe_encrypt_key_data(context, pblock->key,
422
&master_keyblock, NULL,
423
mkey_kvno, entry->key_data)))
424
goto cleanup;
425
/*
426
* There should always be at least one "active" mkey so creating the
427
* KRB5_TL_ACTKVNO entry now so the initial mkey is active.
428
*/
429
actkvno.next = NULL;
430
actkvno.act_kvno = mkey_kvno;
431
/* earliest possible time in case system clock is set back */
432
actkvno.act_time = 0;
433
if ((retval = krb5_dbe_update_actkvno(context, entry, &actkvno)))
434
goto cleanup;
435
436
/* so getprinc shows the right kvno */
437
if ((retval = krb5_dbe_update_mkvno(context, entry, mkey_kvno)))
438
goto cleanup;
439
440
break;
441
case TGT_KEY:
442
iargs.ctx = context;
443
iargs.rblock = pblock;
444
iargs.dbentp = entry;
445
/*
446
* Iterate through the key/salt list, ignoring salt types.
447
*/
448
if ((retval = krb5_keysalt_iterate(pblock->kslist,
449
pblock->nkslist,
450
1,
451
tgt_keysalt_iterate,
452
(krb5_pointer) &iargs)))
453
goto cleanup;
454
break;
455
case NULL_KEY:
456
retval = EOPNOTSUPP;
457
goto cleanup;
458
default:
459
break;
460
}
461
462
entry->mask = (KADM5_KEY_DATA | KADM5_PRINCIPAL | KADM5_ATTRIBUTES |
463
KADM5_MAX_LIFE | KADM5_MAX_RLIFE | KADM5_TL_DATA |
464
KADM5_PRINC_EXPIRE_TIME);
465
entry->attributes |= KRB5_KDB_LOCKDOWN_KEYS;
466
467
retval = krb5_db_put_principal(context, entry);
468
469
cleanup:
470
krb5_db_free_principal(context, entry);
471
return retval;
472
}
473
474