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