Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/crypto/krb5/src/kadmin/ktutil/ktutil_funcs.c
34889 views
1
/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2
/* kadmin/ktutil/ktutil_funcs.c */
3
/*
4
*(C) Copyright 1995, 1996 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
/*
28
* Utility functions for ktutil.
29
*/
30
31
#include "k5-int.h"
32
#include "k5-hex.h"
33
#include "ktutil.h"
34
#include <string.h>
35
#include <ctype.h>
36
37
/*
38
* Free a kt_list
39
*/
40
krb5_error_code
41
ktutil_free_kt_list(krb5_context context, krb5_kt_list list)
42
{
43
krb5_kt_list lp, prev;
44
krb5_error_code retval = 0;
45
46
for (lp = list; lp;) {
47
retval = krb5_kt_free_entry(context, lp->entry);
48
free(lp->entry);
49
if (retval)
50
break;
51
prev = lp;
52
lp = lp->next;
53
free(prev);
54
}
55
return retval;
56
}
57
58
/*
59
* Delete a numbered entry in a kt_list. Takes a pointer to a kt_list
60
* in case head gets deleted.
61
*/
62
krb5_error_code
63
ktutil_delete(krb5_context context, krb5_kt_list *list, int idx)
64
{
65
krb5_kt_list lp, prev;
66
int i;
67
68
for (lp = *list, i = 1; lp; prev = lp, lp = lp->next, i++) {
69
if (i == idx) {
70
if (i == 1)
71
*list = lp->next;
72
else
73
prev->next = lp->next;
74
lp->next = NULL;
75
return ktutil_free_kt_list(context, lp);
76
}
77
}
78
return EINVAL;
79
}
80
81
/*
82
* Determine the enctype, salt, and s2kparams for princ based on the presence
83
* of the -f flag (fetch), the optionally specified salt string, and the
84
* optionally specified enctype. If the fetch flag is used, salt_str must not
85
* be given; if the fetch flag is not used, the enctype must be given.
86
*/
87
static krb5_error_code
88
get_etype_info(krb5_context context, krb5_principal princ, int fetch,
89
char *salt_str, krb5_enctype *enctype_inout,
90
krb5_data *salt_out, krb5_data *s2kparams_out)
91
{
92
krb5_error_code retval;
93
krb5_enctype enctype;
94
krb5_get_init_creds_opt *opt = NULL;
95
krb5_data salt;
96
97
*salt_out = empty_data();
98
*s2kparams_out = empty_data();
99
100
if (!fetch) {
101
/* Use the specified enctype and either the specified or default salt.
102
* Do not produce s2kparams. */
103
assert(*enctype_inout != ENCTYPE_NULL);
104
if (salt_str != NULL) {
105
salt = string2data(salt_str);
106
return krb5int_copy_data_contents(context, &salt, salt_out);
107
} else {
108
return krb5_principal2salt(context, princ, salt_out);
109
}
110
}
111
112
/* Get etype-info from the KDC. */
113
assert(salt_str == NULL);
114
if (*enctype_inout != ENCTYPE_NULL) {
115
retval = krb5_get_init_creds_opt_alloc(context, &opt);
116
if (retval)
117
return retval;
118
krb5_get_init_creds_opt_set_etype_list(opt, enctype_inout, 1);
119
}
120
retval = krb5_get_etype_info(context, princ, opt, &enctype, salt_out,
121
s2kparams_out);
122
krb5_get_init_creds_opt_free(context, opt);
123
if (retval)
124
return retval;
125
if (enctype == ENCTYPE_NULL)
126
return KRB5KDC_ERR_ETYPE_NOSUPP;
127
128
*enctype_inout = enctype;
129
return 0;
130
}
131
132
/*
133
* Create a new keytab entry and add it to the keytab list.
134
* Based on the value of use_pass, either prompt the user for a
135
* password or key. If the keytab list is NULL, allocate a new
136
* one first.
137
*/
138
krb5_error_code
139
ktutil_add(krb5_context context, krb5_kt_list *list, char *princ_str,
140
int fetch, krb5_kvno kvno, char *enctype_str, int use_pass,
141
char *salt_str)
142
{
143
krb5_keytab_entry *entry = NULL;
144
krb5_kt_list lp, *last;
145
krb5_principal princ;
146
krb5_enctype enctype = ENCTYPE_NULL;
147
krb5_timestamp now;
148
krb5_error_code retval;
149
krb5_data password = empty_data(), salt = empty_data();
150
krb5_data params = empty_data(), *s2kparams;
151
krb5_keyblock key;
152
char buf[BUFSIZ];
153
char promptstr[1024];
154
char *princ_full = NULL;
155
uint8_t *keybytes;
156
size_t keylen;
157
unsigned int pwsize = BUFSIZ;
158
159
retval = krb5_parse_name(context, princ_str, &princ);
160
if (retval)
161
goto cleanup;
162
/* now unparse in order to get the default realm appended
163
to princ_str, if no realm was specified */
164
retval = krb5_unparse_name(context, princ, &princ_full);
165
if (retval)
166
goto cleanup;
167
if (enctype_str != NULL) {
168
retval = krb5_string_to_enctype(enctype_str, &enctype);
169
if (retval) {
170
retval = KRB5_BAD_ENCTYPE;
171
goto cleanup;
172
}
173
}
174
retval = krb5_timeofday(context, &now);
175
if (retval)
176
goto cleanup;
177
178
entry = k5alloc(sizeof(*entry), &retval);
179
if (entry == NULL)
180
goto cleanup;
181
182
if (use_pass) {
183
retval = alloc_data(&password, pwsize);
184
if (retval)
185
goto cleanup;
186
187
snprintf(promptstr, sizeof(promptstr), _("Password for %.1000s"),
188
princ_full);
189
retval = krb5_read_password(context, promptstr, NULL, password.data,
190
&password.length);
191
if (retval)
192
goto cleanup;
193
194
retval = get_etype_info(context, princ, fetch, salt_str,
195
&enctype, &salt, &params);
196
if (retval)
197
goto cleanup;
198
s2kparams = (params.length > 0) ? &params : NULL;
199
retval = krb5_c_string_to_key_with_params(context, enctype, &password,
200
&salt, s2kparams, &key);
201
if (retval)
202
goto cleanup;
203
entry->key = key;
204
} else {
205
printf(_("Key for %s (hex): "), princ_full);
206
fgets(buf, BUFSIZ, stdin);
207
/*
208
* We need to get rid of the trailing '\n' from fgets.
209
* If we have an even number of hex digits (as we should),
210
* write a '\0' over the '\n'. If for some reason we have
211
* an odd number of hex digits, force an even number of hex
212
* digits by writing a '0' into the last position (the string
213
* will still be null-terminated).
214
*/
215
buf[strlen(buf) - 1] = strlen(buf) % 2 ? '\0' : '0';
216
if (strlen(buf) == 0) {
217
fprintf(stderr, _("addent: Error reading key.\n"));
218
retval = 0;
219
goto cleanup;
220
}
221
222
retval = k5_hex_decode(buf, &keybytes, &keylen);
223
if (retval) {
224
if (retval == EINVAL) {
225
fprintf(stderr, _("addent: Illegal character in key.\n"));
226
retval = 0;
227
}
228
goto cleanup;
229
}
230
231
entry->key.enctype = enctype;
232
entry->key.contents = keybytes;
233
entry->key.length = keylen;
234
}
235
entry->principal = princ;
236
entry->vno = kvno;
237
entry->timestamp = now;
238
239
/* Add entry to the end of the list (or create a new list if empty). */
240
lp = k5alloc(sizeof(*lp), &retval);
241
if (lp == NULL)
242
goto cleanup;
243
lp->next = NULL;
244
lp->entry = entry;
245
entry = NULL;
246
for (last = list; *last != NULL; last = &(*last)->next);
247
*last = lp;
248
249
cleanup:
250
krb5_free_keytab_entry_contents(context, entry);
251
free(entry);
252
zapfree(password.data, password.length);
253
krb5_free_data_contents(context, &salt);
254
krb5_free_data_contents(context, &params);
255
krb5_free_unparsed_name(context, princ_full);
256
return retval;
257
}
258
259
/*
260
* Read in a keytab and append it to list. If list starts as NULL,
261
* allocate a new one if necessary.
262
*/
263
krb5_error_code
264
ktutil_read_keytab(krb5_context context, char *name, krb5_kt_list *list)
265
{
266
krb5_kt_list lp = NULL, tail = NULL, back = NULL;
267
krb5_keytab kt;
268
krb5_keytab_entry *entry;
269
krb5_kt_cursor cursor;
270
krb5_error_code retval = 0;
271
272
if (*list) {
273
/* point lp at the tail of the list */
274
for (lp = *list; lp->next; lp = lp->next);
275
back = lp;
276
}
277
retval = krb5_kt_resolve(context, name, &kt);
278
if (retval)
279
return retval;
280
retval = krb5_kt_start_seq_get(context, kt, &cursor);
281
if (retval)
282
goto close_kt;
283
for (;;) {
284
entry = (krb5_keytab_entry *)malloc(sizeof (krb5_keytab_entry));
285
if (!entry) {
286
retval = ENOMEM;
287
break;
288
}
289
memset(entry, 0, sizeof (*entry));
290
retval = krb5_kt_next_entry(context, kt, entry, &cursor);
291
if (retval)
292
break;
293
294
if (!lp) { /* if list is empty, start one */
295
lp = (krb5_kt_list)malloc(sizeof (*lp));
296
if (!lp) {
297
retval = ENOMEM;
298
break;
299
}
300
} else {
301
lp->next = (krb5_kt_list)malloc(sizeof (*lp));
302
if (!lp->next) {
303
retval = ENOMEM;
304
break;
305
}
306
lp = lp->next;
307
}
308
if (!tail)
309
tail = lp;
310
lp->next = NULL;
311
lp->entry = entry;
312
}
313
if (entry)
314
free(entry);
315
if (retval) {
316
if (retval == KRB5_KT_END)
317
retval = 0;
318
else {
319
ktutil_free_kt_list(context, tail);
320
tail = NULL;
321
if (back)
322
back->next = NULL;
323
}
324
}
325
if (!*list)
326
*list = tail;
327
krb5_kt_end_seq_get(context, kt, &cursor);
328
close_kt:
329
krb5_kt_close(context, kt);
330
return retval;
331
}
332
333
/*
334
* Takes a kt_list and writes it to the named keytab.
335
*/
336
krb5_error_code
337
ktutil_write_keytab(krb5_context context, krb5_kt_list list, char *name)
338
{
339
krb5_kt_list lp;
340
krb5_keytab kt;
341
char ktname[MAXPATHLEN+sizeof("WRFILE:")+1];
342
krb5_error_code retval = 0;
343
int result;
344
345
result = snprintf(ktname, sizeof(ktname), "WRFILE:%s", name);
346
if (SNPRINTF_OVERFLOW(result, sizeof(ktname)))
347
return ENAMETOOLONG;
348
retval = krb5_kt_resolve(context, ktname, &kt);
349
if (retval)
350
return retval;
351
for (lp = list; lp; lp = lp->next) {
352
retval = krb5_kt_add_entry(context, kt, lp->entry);
353
if (retval)
354
break;
355
}
356
krb5_kt_close(context, kt);
357
return retval;
358
}
359
360