Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/crypto/krb5/src/kadmin/cli/keytab.c
34914 views
1
/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2
/*
3
* Copyright 1993 OpenVision Technologies, Inc., All Rights Reserved.
4
*
5
* $Id$
6
* $Source$
7
*/
8
9
/*
10
* Copyright (C) 1998 by the FundsXpress, INC.
11
*
12
* All rights reserved.
13
*
14
* Export of this software from the United States of America may require
15
* a specific license from the United States Government. It is the
16
* responsibility of any person or organization contemplating export to
17
* 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 FundsXpress. not be used in advertising or publicity pertaining
25
* to distribution of the software without specific, written prior
26
* permission. FundsXpress makes no representations about the suitability of
27
* this software for any purpose. It is provided "as is" without express
28
* or implied warranty.
29
*
30
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
31
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
32
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
33
*/
34
35
#include "k5-int.h"
36
#include <kadm5/admin.h>
37
#include <adm_proto.h>
38
#include "kadmin.h"
39
40
static void add_principal(void *lhandle, char *keytab_str, krb5_keytab keytab,
41
krb5_boolean keepold,
42
int n_ks_tuple, krb5_key_salt_tuple *ks_tuple,
43
char *princ_str);
44
static void remove_principal(char *keytab_str, krb5_keytab keytab,
45
char *princ_str, char *kvno_str);
46
static char *etype_string(krb5_enctype enctype);
47
48
static int quiet;
49
50
static int norandkey;
51
52
static void
53
add_usage(void)
54
{
55
fprintf(stderr, _("Usage: ktadd [-k[eytab] keytab] [-q] [-e keysaltlist] "
56
"[-norandkey] [principal | -glob princ-exp] [...]\n"));
57
}
58
59
static void
60
rem_usage(void)
61
{
62
fprintf(stderr, _("Usage: ktremove [-k[eytab] keytab] [-q] principal "
63
"[kvno|\"all\"|\"old\"]\n"));
64
}
65
66
static int
67
process_keytab(krb5_context my_context, char **keytab_str,
68
krb5_keytab *keytab)
69
{
70
int code;
71
char *name = *keytab_str;
72
73
if (name == NULL) {
74
name = malloc(BUFSIZ);
75
if (!name) {
76
com_err(whoami, ENOMEM, _("while creating keytab name"));
77
return 1;
78
}
79
code = krb5_kt_default(my_context, keytab);
80
if (code != 0) {
81
com_err(whoami, code, _("while opening default keytab"));
82
free(name);
83
return 1;
84
}
85
code = krb5_kt_get_name(my_context, *keytab, name, BUFSIZ);
86
if (code != 0) {
87
com_err(whoami, code, _("while getting keytab name"));
88
free(name);
89
return 1;
90
}
91
} else {
92
if (strchr(name, ':') != NULL)
93
name = strdup(name);
94
else if (asprintf(&name, "WRFILE:%s", name) < 0)
95
name = NULL;
96
if (name == NULL) {
97
com_err(whoami, ENOMEM, _("while creating keytab name"));
98
return 1;
99
}
100
101
code = krb5_kt_resolve(my_context, name, keytab);
102
if (code != 0) {
103
com_err(whoami, code, _("while resolving keytab %s"), name);
104
free(name);
105
return 1;
106
}
107
}
108
109
*keytab_str = name;
110
return 0;
111
}
112
113
void
114
kadmin_keytab_add(int argc, char **argv, int sci_idx, void *info_ptr)
115
{
116
krb5_keytab keytab = 0;
117
char *keytab_str = NULL, **princs;
118
int code, num, i;
119
krb5_error_code retval;
120
int n_ks_tuple = 0;
121
krb5_boolean keepold = FALSE;
122
krb5_key_salt_tuple *ks_tuple = NULL;
123
124
argc--; argv++;
125
quiet = 0;
126
norandkey = 0;
127
while (argc) {
128
if (strncmp(*argv, "-k", 2) == 0) {
129
argc--; argv++;
130
if (!argc || keytab_str) {
131
add_usage();
132
return;
133
}
134
keytab_str = *argv;
135
} else if (strcmp(*argv, "-q") == 0) {
136
quiet++;
137
} else if (strcmp(*argv, "-norandkey") == 0) {
138
norandkey++;
139
} else if (strcmp(*argv, "-e") == 0) {
140
argc--;
141
if (argc < 1) {
142
add_usage();
143
return;
144
}
145
retval = krb5_string_to_keysalts(*++argv, NULL, NULL, 0,
146
&ks_tuple, &n_ks_tuple);
147
if (retval) {
148
com_err("ktadd", retval, _("while parsing keysalts %s"),
149
*argv);
150
151
return;
152
}
153
} else
154
break;
155
argc--; argv++;
156
}
157
158
if (argc == 0) {
159
add_usage();
160
return;
161
}
162
163
if (norandkey && ks_tuple) {
164
fprintf(stderr,
165
_("cannot specify keysaltlist when not changing key\n"));
166
return;
167
}
168
169
if (process_keytab(context, &keytab_str, &keytab))
170
return;
171
172
while (*argv) {
173
if (strcmp(*argv, "-glob") == 0) {
174
if (*++argv == NULL) {
175
add_usage();
176
break;
177
}
178
179
code = kadm5_get_principals(handle, *argv, &princs, &num);
180
if (code) {
181
com_err(whoami, code, _("while expanding expression \"%s\"."),
182
*argv);
183
argv++;
184
continue;
185
}
186
187
for (i = 0; i < num; i++)
188
add_principal(handle, keytab_str, keytab, keepold,
189
n_ks_tuple, ks_tuple, princs[i]);
190
kadm5_free_name_list(handle, princs, num);
191
} else {
192
add_principal(handle, keytab_str, keytab, keepold,
193
n_ks_tuple, ks_tuple, *argv);
194
argv++;
195
}
196
}
197
198
code = krb5_kt_close(context, keytab);
199
if (code != 0)
200
com_err(whoami, code, _("while closing keytab"));
201
202
free(keytab_str);
203
}
204
205
void
206
kadmin_keytab_remove(int argc, char **argv, int sci_idx, void *info_ptr)
207
{
208
krb5_keytab keytab = 0;
209
char *keytab_str = NULL;
210
int code;
211
212
argc--; argv++;
213
quiet = 0;
214
while (argc) {
215
if (strncmp(*argv, "-k", 2) == 0) {
216
argc--; argv++;
217
if (!argc || keytab_str) {
218
rem_usage();
219
return;
220
}
221
keytab_str = *argv;
222
} else if (strcmp(*argv, "-q") == 0) {
223
quiet++;
224
} else
225
break;
226
argc--; argv++;
227
}
228
229
if (argc != 1 && argc != 2) {
230
rem_usage();
231
return;
232
}
233
if (process_keytab(context, &keytab_str, &keytab))
234
return;
235
236
remove_principal(keytab_str, keytab, argv[0], argv[1]);
237
238
code = krb5_kt_close(context, keytab);
239
if (code != 0)
240
com_err(whoami, code, _("while closing keytab"));
241
242
free(keytab_str);
243
}
244
245
/* Generate new random keys for princ, and convert them into a kadm5_key_data
246
* array (with no salt information). */
247
static krb5_error_code
248
fetch_new_keys(void *lhandle, krb5_principal princ, krb5_boolean keepold,
249
int n_ks_tuple, krb5_key_salt_tuple *ks_tuple,
250
kadm5_key_data **key_data_out, int *nkeys_out)
251
{
252
krb5_error_code code;
253
kadm5_key_data *key_data;
254
kadm5_principal_ent_rec princ_rec;
255
krb5_keyblock *keys = NULL;
256
int i, nkeys = 0;
257
258
*key_data_out = NULL;
259
*nkeys_out = 0;
260
memset(&princ_rec, 0, sizeof(princ_rec));
261
262
/* Generate new random keys. */
263
code = randkey_princ(lhandle, princ, keepold, n_ks_tuple, ks_tuple,
264
&keys, &nkeys);
265
if (code)
266
goto cleanup;
267
268
/* Get the principal entry to find the kvno of the new keys. (This is not
269
* atomic, but randkey doesn't report the new kvno.) */
270
code = kadm5_get_principal(lhandle, princ, &princ_rec,
271
KADM5_PRINCIPAL_NORMAL_MASK);
272
if (code)
273
goto cleanup;
274
275
key_data = k5calloc(nkeys, sizeof(*key_data), &code);
276
if (key_data == NULL)
277
goto cleanup;
278
279
/* Transfer the keyblocks and free the container array. */
280
for (i = 0; i < nkeys; i++) {
281
key_data[i].key = keys[i];
282
key_data[i].kvno = princ_rec.kvno;
283
}
284
*key_data_out = key_data;
285
*nkeys_out = nkeys;
286
free(keys);
287
keys = NULL;
288
nkeys = 0;
289
290
cleanup:
291
for (i = 0; i < nkeys; i++)
292
krb5_free_keyblock_contents(context, &keys[i]);
293
free(keys);
294
kadm5_free_principal_ent(lhandle, &princ_rec);
295
return code;
296
}
297
298
static void
299
add_principal(void *lhandle, char *keytab_str, krb5_keytab keytab,
300
krb5_boolean keepold, int n_ks_tuple,
301
krb5_key_salt_tuple *ks_tuple, char *princ_str)
302
{
303
krb5_principal princ = NULL;
304
krb5_keytab_entry new_entry;
305
kadm5_key_data *key_data;
306
int code, nkeys, i;
307
308
princ = NULL;
309
key_data = NULL;
310
nkeys = 0;
311
312
code = krb5_parse_name(context, princ_str, &princ);
313
if (code != 0) {
314
com_err(whoami, code, _("while parsing -add principal name %s"),
315
princ_str);
316
goto cleanup;
317
}
318
319
if (norandkey) {
320
code = kadm5_get_principal_keys(handle, princ, 0, &key_data, &nkeys);
321
} else {
322
code = fetch_new_keys(handle, princ, keepold, n_ks_tuple, ks_tuple,
323
&key_data, &nkeys);
324
}
325
326
if (code != 0) {
327
if (code == KADM5_UNK_PRINC) {
328
fprintf(stderr, _("%s: Principal %s does not exist.\n"),
329
whoami, princ_str);
330
} else
331
com_err(whoami, code, _("while changing %s's key"), princ_str);
332
goto cleanup;
333
}
334
335
for (i = 0; i < nkeys; i++) {
336
memset(&new_entry, 0, sizeof(new_entry));
337
new_entry.principal = princ;
338
new_entry.key = key_data[i].key;
339
new_entry.vno = key_data[i].kvno;
340
341
code = krb5_kt_add_entry(context, keytab, &new_entry);
342
if (code != 0) {
343
com_err(whoami, code, _("while adding key to keytab"));
344
goto cleanup;
345
}
346
347
if (!quiet) {
348
printf(_("Entry for principal %s with kvno %d, "
349
"encryption type %s added to keytab %s.\n"),
350
princ_str, key_data[i].kvno,
351
etype_string(key_data[i].key.enctype), keytab_str);
352
}
353
}
354
355
cleanup:
356
kadm5_free_kadm5_key_data(context, nkeys, key_data);
357
krb5_free_principal(context, princ);
358
}
359
360
static void
361
remove_principal(char *keytab_str, krb5_keytab keytab,
362
char *princ_str, char *kvno_str)
363
{
364
krb5_principal princ = NULL;
365
krb5_keytab_entry entry;
366
krb5_kt_cursor cursor = NULL;
367
enum { UNDEF, SPEC, HIGH, ALL, OLD } mode;
368
int code, did_something;
369
krb5_kvno kvno;
370
371
code = krb5_parse_name(context, princ_str, &princ);
372
if (code != 0) {
373
com_err(whoami, code, _("while parsing principal name %s"), princ_str);
374
goto cleanup;
375
}
376
377
mode = UNDEF;
378
if (kvno_str == NULL) {
379
mode = HIGH;
380
kvno = 0;
381
} else if (strcmp(kvno_str, "all") == 0) {
382
mode = ALL;
383
kvno = 0;
384
} else if (strcmp(kvno_str, "old") == 0) {
385
mode = OLD;
386
kvno = 0;
387
} else {
388
mode = SPEC;
389
kvno = atoi(kvno_str);
390
}
391
392
/* kvno is set to specified value for SPEC, 0 otherwise */
393
code = krb5_kt_get_entry(context, keytab, princ, kvno, 0, &entry);
394
if (code != 0) {
395
if (code == ENOENT) {
396
fprintf(stderr, _("%s: Keytab %s does not exist.\n"),
397
whoami, keytab_str);
398
} else if (code == KRB5_KT_NOTFOUND) {
399
if (mode != SPEC) {
400
fprintf(stderr, _("%s: No entry for principal %s exists in "
401
"keytab %s\n"),
402
whoami, princ_str, keytab_str);
403
} else {
404
fprintf(stderr, _("%s: No entry for principal %s with kvno %d "
405
"exists in keytab %s\n"),
406
whoami, princ_str, kvno, keytab_str);
407
}
408
} else {
409
com_err(whoami, code,
410
_("while retrieving highest kvno from keytab"));
411
}
412
goto cleanup;
413
}
414
415
/* set kvno to spec'ed value for SPEC, highest kvno otherwise */
416
if (mode != SPEC)
417
kvno = entry.vno;
418
krb5_kt_free_entry(context, &entry);
419
420
code = krb5_kt_start_seq_get(context, keytab, &cursor);
421
if (code != 0) {
422
com_err(whoami, code, _("while starting keytab scan"));
423
goto cleanup;
424
}
425
426
did_something = 0;
427
while ((code = krb5_kt_next_entry(context, keytab, &entry,
428
&cursor)) == 0) {
429
if (krb5_principal_compare(context, princ, entry.principal) &&
430
((mode == ALL) ||
431
(mode == SPEC && entry.vno == kvno) ||
432
(mode == OLD && entry.vno != kvno) ||
433
(mode == HIGH && entry.vno == kvno))) {
434
435
/*
436
* Ack! What a kludge... the scanning functions lock
437
* the keytab so entries cannot be removed while they
438
* are operating.
439
*/
440
code = krb5_kt_end_seq_get(context, keytab, &cursor);
441
if (code != 0) {
442
com_err(whoami, code,
443
_("while temporarily ending keytab scan"));
444
goto cleanup;
445
}
446
cursor = NULL;
447
code = krb5_kt_remove_entry(context, keytab, &entry);
448
if (code != 0) {
449
com_err(whoami, code, _("while deleting entry from keytab"));
450
goto cleanup;
451
}
452
code = krb5_kt_start_seq_get(context, keytab, &cursor);
453
if (code != 0) {
454
com_err(whoami, code, _("while restarting keytab scan"));
455
goto cleanup;
456
}
457
458
did_something++;
459
if (!quiet) {
460
printf(_("Entry for principal %s with kvno %d removed from "
461
"keytab %s.\n"), princ_str, entry.vno, keytab_str);
462
}
463
}
464
krb5_kt_free_entry(context, &entry);
465
}
466
if (code && code != KRB5_KT_END) {
467
com_err(whoami, code, _("while scanning keytab"));
468
goto cleanup;
469
}
470
code = krb5_kt_end_seq_get(context, keytab, &cursor);
471
if (code) {
472
com_err(whoami, code, _("while ending keytab scan"));
473
goto cleanup;
474
}
475
cursor = NULL;
476
477
/*
478
* If !did_someting then mode must be OLD or we would have
479
* already returned with an error. But check it anyway just to
480
* prevent unexpected error messages...
481
*/
482
if (!did_something && mode == OLD) {
483
fprintf(stderr, _("%s: There is only one entry for principal %s in "
484
"keytab %s\n"), whoami, princ_str, keytab_str);
485
}
486
487
cleanup:
488
if (cursor != NULL)
489
(void)krb5_kt_end_seq_get(context, keytab, &cursor);
490
krb5_free_principal(context, princ);
491
}
492
493
/*
494
* etype_string(enctype): return a string representation of the
495
* encryption type. XXX copied from klist.c; this should be a
496
* library function, or perhaps just #defines
497
*/
498
static char *
499
etype_string(krb5_enctype enctype)
500
{
501
static char buf[100];
502
krb5_error_code ret;
503
504
ret = krb5_enctype_to_name(enctype, FALSE, buf, sizeof(buf));
505
if (ret)
506
snprintf(buf, sizeof(buf), "etype %d", enctype);
507
508
return buf;
509
}
510
511