xref: /freebsd/crypto/heimdal/lib/krb5/keytab.c (revision ae77177087c655fc883075af4f425b37e032cd05)
1b528cefcSMark Murray /*
2*ae771770SStanislav Sedov  * Copyright (c) 1997 - 2005 Kungliga Tekniska Högskolan
3b528cefcSMark Murray  * (Royal Institute of Technology, Stockholm, Sweden).
4b528cefcSMark Murray  * All rights reserved.
5b528cefcSMark Murray  *
6b528cefcSMark Murray  * Redistribution and use in source and binary forms, with or without
7b528cefcSMark Murray  * modification, are permitted provided that the following conditions
8b528cefcSMark Murray  * are met:
9b528cefcSMark Murray  *
10b528cefcSMark Murray  * 1. Redistributions of source code must retain the above copyright
11b528cefcSMark Murray  *    notice, this list of conditions and the following disclaimer.
12b528cefcSMark Murray  *
13b528cefcSMark Murray  * 2. Redistributions in binary form must reproduce the above copyright
14b528cefcSMark Murray  *    notice, this list of conditions and the following disclaimer in the
15b528cefcSMark Murray  *    documentation and/or other materials provided with the distribution.
16b528cefcSMark Murray  *
17b528cefcSMark Murray  * 3. Neither the name of the Institute nor the names of its contributors
18b528cefcSMark Murray  *    may be used to endorse or promote products derived from this software
19b528cefcSMark Murray  *    without specific prior written permission.
20b528cefcSMark Murray  *
21b528cefcSMark Murray  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22b528cefcSMark Murray  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23b528cefcSMark Murray  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24b528cefcSMark Murray  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25b528cefcSMark Murray  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26b528cefcSMark Murray  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27b528cefcSMark Murray  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28b528cefcSMark Murray  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29b528cefcSMark Murray  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30b528cefcSMark Murray  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31b528cefcSMark Murray  * SUCH DAMAGE.
32b528cefcSMark Murray  */
33b528cefcSMark Murray 
34b528cefcSMark Murray #include "krb5_locl.h"
35b528cefcSMark Murray 
36*ae771770SStanislav Sedov /**
37*ae771770SStanislav Sedov  * @page krb5_keytab_intro The keytab handing functions
38*ae771770SStanislav Sedov  * @section section_krb5_keytab Kerberos Keytabs
39*ae771770SStanislav Sedov  *
40*ae771770SStanislav Sedov  * See the library functions here: @ref krb5_keytab
41*ae771770SStanislav Sedov  *
42*ae771770SStanislav Sedov  * Keytabs are long term key storage for servers, their equvalment of
43*ae771770SStanislav Sedov  * password files.
44*ae771770SStanislav Sedov  *
45*ae771770SStanislav Sedov  * Normally the only function that useful for server are to specify
46*ae771770SStanislav Sedov  * what keytab to use to other core functions like krb5_rd_req()
47*ae771770SStanislav Sedov  * krb5_kt_resolve(), and krb5_kt_close().
48*ae771770SStanislav Sedov  *
49*ae771770SStanislav Sedov  * @subsection krb5_keytab_names Keytab names
50*ae771770SStanislav Sedov  *
51*ae771770SStanislav Sedov  * A keytab name is on the form type:residual. The residual part is
52*ae771770SStanislav Sedov  * specific to each keytab-type.
53*ae771770SStanislav Sedov  *
54*ae771770SStanislav Sedov  * When a keytab-name is resolved, the type is matched with an internal
55*ae771770SStanislav Sedov  * list of keytab types. If there is no matching keytab type,
56*ae771770SStanislav Sedov  * the default keytab is used. The current default type is FILE.
57*ae771770SStanislav Sedov  *
58*ae771770SStanislav Sedov  * The default value can be changed in the configuration file
59*ae771770SStanislav Sedov  * /etc/krb5.conf by setting the variable
60*ae771770SStanislav Sedov  * [defaults]default_keytab_name.
61*ae771770SStanislav Sedov  *
62*ae771770SStanislav Sedov  * The keytab types that are implemented in Heimdal are:
63*ae771770SStanislav Sedov  * - file
64*ae771770SStanislav Sedov  *   store the keytab in a file, the type's name is FILE .  The
65*ae771770SStanislav Sedov  *   residual part is a filename. For compatibility with other
66*ae771770SStanislav Sedov  *   Kerberos implemtation WRFILE and JAVA14 is also accepted.  WRFILE
67*ae771770SStanislav Sedov  *   has the same format as FILE. JAVA14 have a format that is
68*ae771770SStanislav Sedov  *   compatible with older versions of MIT kerberos and SUN's Java
69*ae771770SStanislav Sedov  *   based installation.  They store a truncted kvno, so when the knvo
70*ae771770SStanislav Sedov  *   excess 255, they are truncted in this format.
71*ae771770SStanislav Sedov  *
72*ae771770SStanislav Sedov  * - keytab
73*ae771770SStanislav Sedov  *   store the keytab in a AFS keyfile (usually /usr/afs/etc/KeyFile ),
74*ae771770SStanislav Sedov  *   the type's name is AFSKEYFILE. The residual part is a filename.
75*ae771770SStanislav Sedov  *
76*ae771770SStanislav Sedov  * - memory
77*ae771770SStanislav Sedov  *   The keytab is stored in a memory segment. This allows sensitive
78*ae771770SStanislav Sedov  *   and/or temporary data not to be stored on disk. The type's name
79*ae771770SStanislav Sedov  *   is MEMORY. Each MEMORY keytab is referenced counted by and
80*ae771770SStanislav Sedov  *   opened by the residual name, so two handles can point to the
81*ae771770SStanislav Sedov  *   same memory area.  When the last user closes using krb5_kt_close()
82*ae771770SStanislav Sedov  *   the keytab, the keys in they keytab is memset() to zero and freed
83*ae771770SStanislav Sedov  *   and can no longer be looked up by name.
84*ae771770SStanislav Sedov  *
85*ae771770SStanislav Sedov  *
86*ae771770SStanislav Sedov  * @subsection krb5_keytab_example Keytab example
87*ae771770SStanislav Sedov  *
88*ae771770SStanislav Sedov  *  This is a minimalistic version of ktutil.
89*ae771770SStanislav Sedov  *
90*ae771770SStanislav Sedov  * @code
91*ae771770SStanislav Sedov int
92*ae771770SStanislav Sedov main (int argc, char **argv)
93*ae771770SStanislav Sedov {
94*ae771770SStanislav Sedov     krb5_context context;
95*ae771770SStanislav Sedov     krb5_keytab keytab;
96*ae771770SStanislav Sedov     krb5_kt_cursor cursor;
97*ae771770SStanislav Sedov     krb5_keytab_entry entry;
98*ae771770SStanislav Sedov     krb5_error_code ret;
99*ae771770SStanislav Sedov     char *principal;
100b528cefcSMark Murray 
101*ae771770SStanislav Sedov     if (krb5_init_context (&context) != 0)
102*ae771770SStanislav Sedov 	errx(1, "krb5_context");
103*ae771770SStanislav Sedov 
104*ae771770SStanislav Sedov     ret = krb5_kt_default (context, &keytab);
105*ae771770SStanislav Sedov     if (ret)
106*ae771770SStanislav Sedov 	krb5_err(context, 1, ret, "krb5_kt_default");
107*ae771770SStanislav Sedov 
108*ae771770SStanislav Sedov     ret = krb5_kt_start_seq_get(context, keytab, &cursor);
109*ae771770SStanislav Sedov     if (ret)
110*ae771770SStanislav Sedov 	krb5_err(context, 1, ret, "krb5_kt_start_seq_get");
111*ae771770SStanislav Sedov     while((ret = krb5_kt_next_entry(context, keytab, &entry, &cursor)) == 0){
112*ae771770SStanislav Sedov 	krb5_unparse_name(context, entry.principal, &principal);
113*ae771770SStanislav Sedov 	printf("principal: %s\n", principal);
114*ae771770SStanislav Sedov 	free(principal);
115*ae771770SStanislav Sedov 	krb5_kt_free_entry(context, &entry);
116*ae771770SStanislav Sedov     }
117*ae771770SStanislav Sedov     ret = krb5_kt_end_seq_get(context, keytab, &cursor);
118*ae771770SStanislav Sedov     if (ret)
119*ae771770SStanislav Sedov 	krb5_err(context, 1, ret, "krb5_kt_end_seq_get");
120*ae771770SStanislav Sedov     ret = krb5_kt_close(context, keytab);
121*ae771770SStanislav Sedov     if (ret)
122*ae771770SStanislav Sedov 	krb5_err(context, 1, ret, "krb5_kt_close");
123*ae771770SStanislav Sedov     krb5_free_context(context);
124*ae771770SStanislav Sedov     return 0;
125*ae771770SStanislav Sedov }
126*ae771770SStanislav Sedov  * @endcode
127*ae771770SStanislav Sedov  *
128b528cefcSMark Murray  */
129b528cefcSMark Murray 
130*ae771770SStanislav Sedov 
131*ae771770SStanislav Sedov /**
132*ae771770SStanislav Sedov  * Register a new keytab backend.
133*ae771770SStanislav Sedov  *
134*ae771770SStanislav Sedov  * @param context a Keberos context.
135*ae771770SStanislav Sedov  * @param ops a backend to register.
136*ae771770SStanislav Sedov  *
137*ae771770SStanislav Sedov  * @return Return an error code or 0, see krb5_get_error_message().
138*ae771770SStanislav Sedov  *
139*ae771770SStanislav Sedov  * @ingroup krb5_keytab
140*ae771770SStanislav Sedov  */
141*ae771770SStanislav Sedov 
142*ae771770SStanislav Sedov KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
143b528cefcSMark Murray krb5_kt_register(krb5_context context,
144b528cefcSMark Murray 		 const krb5_kt_ops *ops)
145b528cefcSMark Murray {
146b528cefcSMark Murray     struct krb5_keytab_data *tmp;
147b528cefcSMark Murray 
148bbd80c28SJacques Vidrine     if (strlen(ops->prefix) > KRB5_KT_PREFIX_MAX_LEN - 1) {
149*ae771770SStanislav Sedov 	krb5_set_error_message(context, KRB5_KT_BADNAME,
150*ae771770SStanislav Sedov 			       N_("can't register cache type, prefix too long", ""));
151c19800e8SDoug Rabson 	return KRB5_KT_BADNAME;
152bbd80c28SJacques Vidrine     }
153bbd80c28SJacques Vidrine 
154b528cefcSMark Murray     tmp = realloc(context->kt_types,
155b528cefcSMark Murray 		  (context->num_kt_types + 1) * sizeof(*context->kt_types));
156adb0ddaeSAssar Westerlund     if(tmp == NULL) {
157*ae771770SStanislav Sedov 	krb5_set_error_message(context, ENOMEM,
158*ae771770SStanislav Sedov 			       N_("malloc: out of memory", ""));
159b528cefcSMark Murray 	return ENOMEM;
160adb0ddaeSAssar Westerlund     }
161b528cefcSMark Murray     memcpy(&tmp[context->num_kt_types], ops,
162b528cefcSMark Murray 	   sizeof(tmp[context->num_kt_types]));
163b528cefcSMark Murray     context->kt_types = tmp;
164b528cefcSMark Murray     context->num_kt_types++;
165b528cefcSMark Murray     return 0;
166b528cefcSMark Murray }
167b528cefcSMark Murray 
168*ae771770SStanislav Sedov static const char *
169*ae771770SStanislav Sedov keytab_name(const char *name, const char **type, size_t *type_len)
170*ae771770SStanislav Sedov {
171*ae771770SStanislav Sedov     const char *residual;
172*ae771770SStanislav Sedov 
173*ae771770SStanislav Sedov     residual = strchr(name, ':');
174*ae771770SStanislav Sedov 
175*ae771770SStanislav Sedov     if (residual == NULL ||
176*ae771770SStanislav Sedov 	name[0] == '/'
177*ae771770SStanislav Sedov #ifdef _WIN32
178*ae771770SStanislav Sedov         /* Avoid treating <drive>:<path> as a keytab type
179*ae771770SStanislav Sedov          * specification */
180*ae771770SStanislav Sedov         || name + 1 == residual
181*ae771770SStanislav Sedov #endif
182*ae771770SStanislav Sedov         ) {
183*ae771770SStanislav Sedov 
184*ae771770SStanislav Sedov         *type = "FILE";
185*ae771770SStanislav Sedov         *type_len = strlen(*type);
186*ae771770SStanislav Sedov         residual = name;
187*ae771770SStanislav Sedov     } else {
188*ae771770SStanislav Sedov         *type = name;
189*ae771770SStanislav Sedov         *type_len = residual - name;
190*ae771770SStanislav Sedov         residual++;
191*ae771770SStanislav Sedov     }
192*ae771770SStanislav Sedov 
193*ae771770SStanislav Sedov     return residual;
194*ae771770SStanislav Sedov }
195*ae771770SStanislav Sedov 
196*ae771770SStanislav Sedov /**
197b528cefcSMark Murray  * Resolve the keytab name (of the form `type:residual') in `name'
198b528cefcSMark Murray  * into a keytab in `id'.
199*ae771770SStanislav Sedov  *
200*ae771770SStanislav Sedov  * @param context a Keberos context.
201*ae771770SStanislav Sedov  * @param name name to resolve
202*ae771770SStanislav Sedov  * @param id resulting keytab, free with krb5_kt_close().
203*ae771770SStanislav Sedov  *
204*ae771770SStanislav Sedov  * @return Return an error code or 0, see krb5_get_error_message().
205*ae771770SStanislav Sedov  *
206*ae771770SStanislav Sedov  * @ingroup krb5_keytab
207b528cefcSMark Murray  */
208b528cefcSMark Murray 
209*ae771770SStanislav Sedov 
210*ae771770SStanislav Sedov KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
211b528cefcSMark Murray krb5_kt_resolve(krb5_context context,
212b528cefcSMark Murray 		const char *name,
213b528cefcSMark Murray 		krb5_keytab *id)
214b528cefcSMark Murray {
215b528cefcSMark Murray     krb5_keytab k;
216b528cefcSMark Murray     int i;
217b528cefcSMark Murray     const char *type, *residual;
218b528cefcSMark Murray     size_t type_len;
219b528cefcSMark Murray     krb5_error_code ret;
220b528cefcSMark Murray 
221*ae771770SStanislav Sedov     residual = keytab_name(name, &type, &type_len);
222b528cefcSMark Murray 
223b528cefcSMark Murray     for(i = 0; i < context->num_kt_types; i++) {
2244137ff4cSJacques Vidrine 	if(strncasecmp(type, context->kt_types[i].prefix, type_len) == 0)
225b528cefcSMark Murray 	    break;
226b528cefcSMark Murray     }
227adb0ddaeSAssar Westerlund     if(i == context->num_kt_types) {
228*ae771770SStanislav Sedov 	krb5_set_error_message(context, KRB5_KT_UNKNOWN_TYPE,
229*ae771770SStanislav Sedov 			       N_("unknown keytab type %.*s", "type"),
230adb0ddaeSAssar Westerlund 			       (int)type_len, type);
231b528cefcSMark Murray 	return KRB5_KT_UNKNOWN_TYPE;
232adb0ddaeSAssar Westerlund     }
233b528cefcSMark Murray 
234b528cefcSMark Murray     k = malloc (sizeof(*k));
235adb0ddaeSAssar Westerlund     if (k == NULL) {
236*ae771770SStanislav Sedov 	krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
237b528cefcSMark Murray 	return ENOMEM;
238adb0ddaeSAssar Westerlund     }
239b528cefcSMark Murray     memcpy(k, &context->kt_types[i], sizeof(*k));
240b528cefcSMark Murray     k->data = NULL;
241b528cefcSMark Murray     ret = (*k->resolve)(context, residual, k);
242b528cefcSMark Murray     if(ret) {
243b528cefcSMark Murray 	free(k);
244b528cefcSMark Murray 	k = NULL;
245b528cefcSMark Murray     }
246b528cefcSMark Murray     *id = k;
247b528cefcSMark Murray     return ret;
248b528cefcSMark Murray }
249b528cefcSMark Murray 
250*ae771770SStanislav Sedov /**
251b528cefcSMark Murray  * copy the name of the default keytab into `name'.
252*ae771770SStanislav Sedov  *
253*ae771770SStanislav Sedov  * @param context a Keberos context.
254*ae771770SStanislav Sedov  * @param name buffer where the name will be written
255*ae771770SStanislav Sedov  * @param namesize length of name
256*ae771770SStanislav Sedov  *
257*ae771770SStanislav Sedov  * @return Return an error code or 0, see krb5_get_error_message().
258*ae771770SStanislav Sedov  *
259*ae771770SStanislav Sedov  * @ingroup krb5_keytab
260b528cefcSMark Murray  */
261b528cefcSMark Murray 
262*ae771770SStanislav Sedov KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
263b528cefcSMark Murray krb5_kt_default_name(krb5_context context, char *name, size_t namesize)
264b528cefcSMark Murray {
265adb0ddaeSAssar Westerlund     if (strlcpy (name, context->default_keytab, namesize) >= namesize) {
266*ae771770SStanislav Sedov 	krb5_clear_error_message (context);
267b528cefcSMark Murray 	return KRB5_CONFIG_NOTENUFSPACE;
268adb0ddaeSAssar Westerlund     }
269adb0ddaeSAssar Westerlund     return 0;
270adb0ddaeSAssar Westerlund }
271adb0ddaeSAssar Westerlund 
272*ae771770SStanislav Sedov /**
273*ae771770SStanislav Sedov  * Copy the name of the default modify keytab into `name'.
274*ae771770SStanislav Sedov  *
275*ae771770SStanislav Sedov  * @param context a Keberos context.
276*ae771770SStanislav Sedov  * @param name buffer where the name will be written
277*ae771770SStanislav Sedov  * @param namesize length of name
278*ae771770SStanislav Sedov  *
279*ae771770SStanislav Sedov  * @return Return an error code or 0, see krb5_get_error_message().
280*ae771770SStanislav Sedov  *
281*ae771770SStanislav Sedov  * @ingroup krb5_keytab
282adb0ddaeSAssar Westerlund  */
283adb0ddaeSAssar Westerlund 
284*ae771770SStanislav Sedov KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
285adb0ddaeSAssar Westerlund krb5_kt_default_modify_name(krb5_context context, char *name, size_t namesize)
286adb0ddaeSAssar Westerlund {
2874137ff4cSJacques Vidrine     const char *kt = NULL;
2884137ff4cSJacques Vidrine     if(context->default_keytab_modify == NULL) {
2894137ff4cSJacques Vidrine 	if(strncasecmp(context->default_keytab, "ANY:", 4) != 0)
2904137ff4cSJacques Vidrine 	    kt = context->default_keytab;
2914137ff4cSJacques Vidrine 	else {
2924137ff4cSJacques Vidrine 	    size_t len = strcspn(context->default_keytab + 4, ",");
2934137ff4cSJacques Vidrine 	    if(len >= namesize) {
294*ae771770SStanislav Sedov 		krb5_clear_error_message(context);
2954137ff4cSJacques Vidrine 		return KRB5_CONFIG_NOTENUFSPACE;
2964137ff4cSJacques Vidrine 	    }
2974137ff4cSJacques Vidrine 	    strlcpy(name, context->default_keytab + 4, namesize);
2984137ff4cSJacques Vidrine 	    name[len] = '\0';
2994137ff4cSJacques Vidrine 	    return 0;
3004137ff4cSJacques Vidrine 	}
3014137ff4cSJacques Vidrine     } else
3024137ff4cSJacques Vidrine 	kt = context->default_keytab_modify;
3034137ff4cSJacques Vidrine     if (strlcpy (name, kt, namesize) >= namesize) {
304*ae771770SStanislav Sedov 	krb5_clear_error_message (context);
305adb0ddaeSAssar Westerlund 	return KRB5_CONFIG_NOTENUFSPACE;
306adb0ddaeSAssar Westerlund     }
307b528cefcSMark Murray     return 0;
308b528cefcSMark Murray }
309b528cefcSMark Murray 
310*ae771770SStanislav Sedov /**
311b528cefcSMark Murray  * Set `id' to the default keytab.
312*ae771770SStanislav Sedov  *
313*ae771770SStanislav Sedov  * @param context a Keberos context.
314*ae771770SStanislav Sedov  * @param id the new default keytab.
315*ae771770SStanislav Sedov  *
316*ae771770SStanislav Sedov  * @return Return an error code or 0, see krb5_get_error_message().
317*ae771770SStanislav Sedov  *
318*ae771770SStanislav Sedov  * @ingroup krb5_keytab
319b528cefcSMark Murray  */
320b528cefcSMark Murray 
321*ae771770SStanislav Sedov KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
322b528cefcSMark Murray krb5_kt_default(krb5_context context, krb5_keytab *id)
323b528cefcSMark Murray {
324b528cefcSMark Murray     return krb5_kt_resolve (context, context->default_keytab, id);
325b528cefcSMark Murray }
326b528cefcSMark Murray 
327*ae771770SStanislav Sedov /**
328b528cefcSMark Murray  * Read the key identified by `(principal, vno, enctype)' from the
329b528cefcSMark Murray  * keytab in `keyprocarg' (the default if == NULL) into `*key'.
330*ae771770SStanislav Sedov  *
331*ae771770SStanislav Sedov  * @param context a Keberos context.
332*ae771770SStanislav Sedov  * @param keyprocarg
333*ae771770SStanislav Sedov  * @param principal
334*ae771770SStanislav Sedov  * @param vno
335*ae771770SStanislav Sedov  * @param enctype
336*ae771770SStanislav Sedov  * @param key
337*ae771770SStanislav Sedov  *
338*ae771770SStanislav Sedov  * @return Return an error code or 0, see krb5_get_error_message().
339*ae771770SStanislav Sedov  *
340*ae771770SStanislav Sedov  * @ingroup krb5_keytab
341b528cefcSMark Murray  */
342b528cefcSMark Murray 
343*ae771770SStanislav Sedov KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
344b528cefcSMark Murray krb5_kt_read_service_key(krb5_context context,
345b528cefcSMark Murray 			 krb5_pointer keyprocarg,
346b528cefcSMark Murray 			 krb5_principal principal,
347b528cefcSMark Murray 			 krb5_kvno vno,
348b528cefcSMark Murray 			 krb5_enctype enctype,
349b528cefcSMark Murray 			 krb5_keyblock **key)
350b528cefcSMark Murray {
351b528cefcSMark Murray     krb5_keytab keytab;
352b528cefcSMark Murray     krb5_keytab_entry entry;
353b528cefcSMark Murray     krb5_error_code ret;
354b528cefcSMark Murray 
355b528cefcSMark Murray     if (keyprocarg)
356b528cefcSMark Murray 	ret = krb5_kt_resolve (context, keyprocarg, &keytab);
357b528cefcSMark Murray     else
358b528cefcSMark Murray 	ret = krb5_kt_default (context, &keytab);
359b528cefcSMark Murray 
360b528cefcSMark Murray     if (ret)
361b528cefcSMark Murray 	return ret;
362b528cefcSMark Murray 
363b528cefcSMark Murray     ret = krb5_kt_get_entry (context, keytab, principal, vno, enctype, &entry);
364b528cefcSMark Murray     krb5_kt_close (context, keytab);
365b528cefcSMark Murray     if (ret)
366b528cefcSMark Murray 	return ret;
367b528cefcSMark Murray     ret = krb5_copy_keyblock (context, &entry.keyblock, key);
368b528cefcSMark Murray     krb5_kt_free_entry(context, &entry);
369b528cefcSMark Murray     return ret;
370b528cefcSMark Murray }
371b528cefcSMark Murray 
372*ae771770SStanislav Sedov /**
373bbd80c28SJacques Vidrine  * Return the type of the `keytab' in the string `prefix of length
374bbd80c28SJacques Vidrine  * `prefixsize'.
375*ae771770SStanislav Sedov  *
376*ae771770SStanislav Sedov  * @param context a Keberos context.
377*ae771770SStanislav Sedov  * @param keytab the keytab to get the prefix for
378*ae771770SStanislav Sedov  * @param prefix prefix buffer
379*ae771770SStanislav Sedov  * @param prefixsize length of prefix buffer
380*ae771770SStanislav Sedov  *
381*ae771770SStanislav Sedov  * @return Return an error code or 0, see krb5_get_error_message().
382*ae771770SStanislav Sedov  *
383*ae771770SStanislav Sedov  * @ingroup krb5_keytab
384bbd80c28SJacques Vidrine  */
385bbd80c28SJacques Vidrine 
386*ae771770SStanislav Sedov KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
387bbd80c28SJacques Vidrine krb5_kt_get_type(krb5_context context,
388bbd80c28SJacques Vidrine 		 krb5_keytab keytab,
389bbd80c28SJacques Vidrine 		 char *prefix,
390bbd80c28SJacques Vidrine 		 size_t prefixsize)
391bbd80c28SJacques Vidrine {
392bbd80c28SJacques Vidrine     strlcpy(prefix, keytab->prefix, prefixsize);
393bbd80c28SJacques Vidrine     return 0;
394bbd80c28SJacques Vidrine }
395bbd80c28SJacques Vidrine 
396*ae771770SStanislav Sedov /**
397b528cefcSMark Murray  * Retrieve the name of the keytab `keytab' into `name', `namesize'
398*ae771770SStanislav Sedov  *
399*ae771770SStanislav Sedov  * @param context a Keberos context.
400*ae771770SStanislav Sedov  * @param keytab the keytab to get the name for.
401*ae771770SStanislav Sedov  * @param name name buffer.
402*ae771770SStanislav Sedov  * @param namesize size of name buffer.
403*ae771770SStanislav Sedov  *
404*ae771770SStanislav Sedov  * @return Return an error code or 0, see krb5_get_error_message().
405*ae771770SStanislav Sedov  *
406*ae771770SStanislav Sedov  * @ingroup krb5_keytab
407b528cefcSMark Murray  */
408b528cefcSMark Murray 
409*ae771770SStanislav Sedov KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
410b528cefcSMark Murray krb5_kt_get_name(krb5_context context,
411b528cefcSMark Murray 		 krb5_keytab keytab,
412b528cefcSMark Murray 		 char *name,
413b528cefcSMark Murray 		 size_t namesize)
414b528cefcSMark Murray {
415b528cefcSMark Murray     return (*keytab->get_name)(context, keytab, name, namesize);
416b528cefcSMark Murray }
417b528cefcSMark Murray 
418*ae771770SStanislav Sedov /**
419c19800e8SDoug Rabson  * Retrieve the full name of the keytab `keytab' and store the name in
420*ae771770SStanislav Sedov  * `str'.
421*ae771770SStanislav Sedov  *
422*ae771770SStanislav Sedov  * @param context a Keberos context.
423*ae771770SStanislav Sedov  * @param keytab keytab to get name for.
424*ae771770SStanislav Sedov  * @param str the name of the keytab name, usee krb5_xfree() to free
425*ae771770SStanislav Sedov  *        the string.  On error, *str is set to NULL.
426*ae771770SStanislav Sedov  *
427*ae771770SStanislav Sedov  * @return Return an error code or 0, see krb5_get_error_message().
428*ae771770SStanislav Sedov  *
429*ae771770SStanislav Sedov  * @ingroup krb5_keytab
430b528cefcSMark Murray  */
431b528cefcSMark Murray 
432*ae771770SStanislav Sedov KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
433c19800e8SDoug Rabson krb5_kt_get_full_name(krb5_context context,
434c19800e8SDoug Rabson 		      krb5_keytab keytab,
435c19800e8SDoug Rabson 		      char **str)
436c19800e8SDoug Rabson {
437c19800e8SDoug Rabson     char type[KRB5_KT_PREFIX_MAX_LEN];
438c19800e8SDoug Rabson     char name[MAXPATHLEN];
439c19800e8SDoug Rabson     krb5_error_code ret;
440c19800e8SDoug Rabson 
441c19800e8SDoug Rabson     *str = NULL;
442c19800e8SDoug Rabson 
443c19800e8SDoug Rabson     ret = krb5_kt_get_type(context, keytab, type, sizeof(type));
444c19800e8SDoug Rabson     if (ret)
445c19800e8SDoug Rabson 	return ret;
446c19800e8SDoug Rabson 
447c19800e8SDoug Rabson     ret = krb5_kt_get_name(context, keytab, name, sizeof(name));
448c19800e8SDoug Rabson     if (ret)
449c19800e8SDoug Rabson 	return ret;
450c19800e8SDoug Rabson 
451c19800e8SDoug Rabson     if (asprintf(str, "%s:%s", type, name) == -1) {
452*ae771770SStanislav Sedov 	krb5_set_error_message(context, ENOMEM, N_("malloc: out of memory", ""));
453c19800e8SDoug Rabson 	*str = NULL;
454c19800e8SDoug Rabson 	return ENOMEM;
455c19800e8SDoug Rabson     }
456c19800e8SDoug Rabson 
457c19800e8SDoug Rabson     return 0;
458c19800e8SDoug Rabson }
459c19800e8SDoug Rabson 
460*ae771770SStanislav Sedov /**
461c19800e8SDoug Rabson  * Finish using the keytab in `id'.  All resources will be released,
462*ae771770SStanislav Sedov  * even on errors.
463*ae771770SStanislav Sedov  *
464*ae771770SStanislav Sedov  * @param context a Keberos context.
465*ae771770SStanislav Sedov  * @param id keytab to close.
466*ae771770SStanislav Sedov  *
467*ae771770SStanislav Sedov  * @return Return an error code or 0, see krb5_get_error_message().
468*ae771770SStanislav Sedov  *
469*ae771770SStanislav Sedov  * @ingroup krb5_keytab
470c19800e8SDoug Rabson  */
471c19800e8SDoug Rabson 
472*ae771770SStanislav Sedov KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
473b528cefcSMark Murray krb5_kt_close(krb5_context context,
474b528cefcSMark Murray 	      krb5_keytab id)
475b528cefcSMark Murray {
476b528cefcSMark Murray     krb5_error_code ret;
477b528cefcSMark Murray 
478b528cefcSMark Murray     ret = (*id->close)(context, id);
479c19800e8SDoug Rabson     memset(id, 0, sizeof(*id));
480b528cefcSMark Murray     free(id);
481b528cefcSMark Murray     return ret;
482b528cefcSMark Murray }
483b528cefcSMark Murray 
484*ae771770SStanislav Sedov /**
485*ae771770SStanislav Sedov  * Destroy (remove) the keytab in `id'.  All resources will be released,
486*ae771770SStanislav Sedov  * even on errors, does the equvalment of krb5_kt_close() on the resources.
487*ae771770SStanislav Sedov  *
488*ae771770SStanislav Sedov  * @param context a Keberos context.
489*ae771770SStanislav Sedov  * @param id keytab to destroy.
490*ae771770SStanislav Sedov  *
491*ae771770SStanislav Sedov  * @return Return an error code or 0, see krb5_get_error_message().
492*ae771770SStanislav Sedov  *
493*ae771770SStanislav Sedov  * @ingroup krb5_keytab
494*ae771770SStanislav Sedov  */
495*ae771770SStanislav Sedov 
496*ae771770SStanislav Sedov KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
497*ae771770SStanislav Sedov krb5_kt_destroy(krb5_context context,
498*ae771770SStanislav Sedov 		krb5_keytab id)
499*ae771770SStanislav Sedov {
500*ae771770SStanislav Sedov     krb5_error_code ret;
501*ae771770SStanislav Sedov 
502*ae771770SStanislav Sedov     ret = (*id->destroy)(context, id);
503*ae771770SStanislav Sedov     krb5_kt_close(context, id);
504*ae771770SStanislav Sedov     return ret;
505*ae771770SStanislav Sedov }
506*ae771770SStanislav Sedov 
507b528cefcSMark Murray /*
508*ae771770SStanislav Sedov  * Match any aliases in keytab `entry' with `principal'.
509*ae771770SStanislav Sedov  */
510*ae771770SStanislav Sedov 
511*ae771770SStanislav Sedov static krb5_boolean
512*ae771770SStanislav Sedov compare_aliseses(krb5_context context,
513*ae771770SStanislav Sedov 		 krb5_keytab_entry *entry,
514*ae771770SStanislav Sedov 		 krb5_const_principal principal)
515*ae771770SStanislav Sedov {
516*ae771770SStanislav Sedov     unsigned int i;
517*ae771770SStanislav Sedov     if (entry->aliases == NULL)
518*ae771770SStanislav Sedov 	return FALSE;
519*ae771770SStanislav Sedov     for (i = 0; i < entry->aliases->len; i++)
520*ae771770SStanislav Sedov 	if (krb5_principal_compare(context, &entry->aliases->val[i], principal))
521*ae771770SStanislav Sedov 	    return TRUE;
522*ae771770SStanislav Sedov     return FALSE;
523*ae771770SStanislav Sedov }
524*ae771770SStanislav Sedov 
525*ae771770SStanislav Sedov /**
526b528cefcSMark Murray  * Compare `entry' against `principal, vno, enctype'.
527b528cefcSMark Murray  * Any of `principal, vno, enctype' might be 0 which acts as a wildcard.
528b528cefcSMark Murray  * Return TRUE if they compare the same, FALSE otherwise.
529*ae771770SStanislav Sedov  *
530*ae771770SStanislav Sedov  * @param context a Keberos context.
531*ae771770SStanislav Sedov  * @param entry an entry to match with.
532*ae771770SStanislav Sedov  * @param principal principal to match, NULL matches all principals.
533*ae771770SStanislav Sedov  * @param vno key version to match, 0 matches all key version numbers.
534*ae771770SStanislav Sedov  * @param enctype encryption type to match, 0 matches all encryption types.
535*ae771770SStanislav Sedov  *
536*ae771770SStanislav Sedov  * @return Return TRUE or match, FALSE if not matched.
537*ae771770SStanislav Sedov  *
538*ae771770SStanislav Sedov  * @ingroup krb5_keytab
539b528cefcSMark Murray  */
540b528cefcSMark Murray 
541*ae771770SStanislav Sedov KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL
542b528cefcSMark Murray krb5_kt_compare(krb5_context context,
543b528cefcSMark Murray 		krb5_keytab_entry *entry,
544b528cefcSMark Murray 		krb5_const_principal principal,
545b528cefcSMark Murray 		krb5_kvno vno,
546b528cefcSMark Murray 		krb5_enctype enctype)
547b528cefcSMark Murray {
548b528cefcSMark Murray     if(principal != NULL &&
549*ae771770SStanislav Sedov        !(krb5_principal_compare(context, entry->principal, principal) ||
550*ae771770SStanislav Sedov 	 compare_aliseses(context, entry, principal)))
551b528cefcSMark Murray 	return FALSE;
552b528cefcSMark Murray     if(vno && vno != entry->vno)
553b528cefcSMark Murray 	return FALSE;
554b528cefcSMark Murray     if(enctype && enctype != entry->keyblock.keytype)
555b528cefcSMark Murray 	return FALSE;
556b528cefcSMark Murray     return TRUE;
557b528cefcSMark Murray }
558b528cefcSMark Murray 
559*ae771770SStanislav Sedov krb5_error_code
560*ae771770SStanislav Sedov _krb5_kt_principal_not_found(krb5_context context,
561*ae771770SStanislav Sedov 			     krb5_error_code ret,
562*ae771770SStanislav Sedov 			     krb5_keytab id,
563*ae771770SStanislav Sedov 			     krb5_const_principal principal,
564*ae771770SStanislav Sedov 			     krb5_enctype enctype,
565*ae771770SStanislav Sedov 			     int kvno)
566*ae771770SStanislav Sedov {
567*ae771770SStanislav Sedov     char princ[256], kvno_str[25], *kt_name;
568*ae771770SStanislav Sedov     char *enctype_str = NULL;
569*ae771770SStanislav Sedov 
570*ae771770SStanislav Sedov     krb5_unparse_name_fixed (context, principal, princ, sizeof(princ));
571*ae771770SStanislav Sedov     krb5_kt_get_full_name (context, id, &kt_name);
572*ae771770SStanislav Sedov     krb5_enctype_to_string(context, enctype, &enctype_str);
573*ae771770SStanislav Sedov 
574*ae771770SStanislav Sedov     if (kvno)
575*ae771770SStanislav Sedov 	snprintf(kvno_str, sizeof(kvno_str), "(kvno %d)", kvno);
576*ae771770SStanislav Sedov     else
577*ae771770SStanislav Sedov 	kvno_str[0] = '\0';
578*ae771770SStanislav Sedov 
579*ae771770SStanislav Sedov     krb5_set_error_message (context, ret,
580*ae771770SStanislav Sedov 			    N_("Failed to find %s%s in keytab %s (%s)",
581*ae771770SStanislav Sedov 			       "principal, kvno, keytab file, enctype"),
582*ae771770SStanislav Sedov 			    princ,
583*ae771770SStanislav Sedov 			    kvno_str,
584*ae771770SStanislav Sedov 			    kt_name ? kt_name : "unknown keytab",
585*ae771770SStanislav Sedov 			    enctype_str ? enctype_str : "unknown enctype");
586*ae771770SStanislav Sedov     free(kt_name);
587*ae771770SStanislav Sedov     free(enctype_str);
588*ae771770SStanislav Sedov     return ret;
589*ae771770SStanislav Sedov }
590*ae771770SStanislav Sedov 
591*ae771770SStanislav Sedov 
592*ae771770SStanislav Sedov /**
593b528cefcSMark Murray  * Retrieve the keytab entry for `principal, kvno, enctype' into `entry'
594*ae771770SStanislav Sedov  * from the keytab `id'. Matching is done like krb5_kt_compare().
595*ae771770SStanislav Sedov  *
596*ae771770SStanislav Sedov  * @param context a Keberos context.
597*ae771770SStanislav Sedov  * @param id a keytab.
598*ae771770SStanislav Sedov  * @param principal principal to match, NULL matches all principals.
599*ae771770SStanislav Sedov  * @param kvno key version to match, 0 matches all key version numbers.
600*ae771770SStanislav Sedov  * @param enctype encryption type to match, 0 matches all encryption types.
601*ae771770SStanislav Sedov  * @param entry the returned entry, free with krb5_kt_free_entry().
602*ae771770SStanislav Sedov  *
603*ae771770SStanislav Sedov  * @return Return an error code or 0, see krb5_get_error_message().
604*ae771770SStanislav Sedov  *
605*ae771770SStanislav Sedov  * @ingroup krb5_keytab
606b528cefcSMark Murray  */
607b528cefcSMark Murray 
608*ae771770SStanislav Sedov KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
609b528cefcSMark Murray krb5_kt_get_entry(krb5_context context,
610b528cefcSMark Murray 		  krb5_keytab id,
611b528cefcSMark Murray 		  krb5_const_principal principal,
612b528cefcSMark Murray 		  krb5_kvno kvno,
613b528cefcSMark Murray 		  krb5_enctype enctype,
614b528cefcSMark Murray 		  krb5_keytab_entry *entry)
615b528cefcSMark Murray {
616b528cefcSMark Murray     krb5_keytab_entry tmp;
617b528cefcSMark Murray     krb5_error_code ret;
618b528cefcSMark Murray     krb5_kt_cursor cursor;
619b528cefcSMark Murray 
620b528cefcSMark Murray     if(id->get)
621b528cefcSMark Murray 	return (*id->get)(context, id, principal, kvno, enctype, entry);
622b528cefcSMark Murray 
623b528cefcSMark Murray     ret = krb5_kt_start_seq_get (context, id, &cursor);
624c19800e8SDoug Rabson     if (ret) {
625*ae771770SStanislav Sedov 	/* This is needed for krb5_verify_init_creds, but keep error
626*ae771770SStanislav Sedov 	 * string from previous error for the human. */
627*ae771770SStanislav Sedov 	context->error_code = KRB5_KT_NOTFOUND;
628*ae771770SStanislav Sedov 	return KRB5_KT_NOTFOUND;
629c19800e8SDoug Rabson     }
630b528cefcSMark Murray 
631b528cefcSMark Murray     entry->vno = 0;
632b528cefcSMark Murray     while (krb5_kt_next_entry(context, id, &tmp, &cursor) == 0) {
633b528cefcSMark Murray 	if (krb5_kt_compare(context, &tmp, principal, 0, enctype)) {
6348373020dSJacques Vidrine 	    /* the file keytab might only store the lower 8 bits of
6358373020dSJacques Vidrine 	       the kvno, so only compare those bits */
6368373020dSJacques Vidrine 	    if (kvno == tmp.vno
6378373020dSJacques Vidrine 		|| (tmp.vno < 256 && kvno % 256 == tmp.vno)) {
638b528cefcSMark Murray 		krb5_kt_copy_entry_contents (context, &tmp, entry);
639b528cefcSMark Murray 		krb5_kt_free_entry (context, &tmp);
640b528cefcSMark Murray 		krb5_kt_end_seq_get(context, id, &cursor);
641b528cefcSMark Murray 		return 0;
642b528cefcSMark Murray 	    } else if (kvno == 0 && tmp.vno > entry->vno) {
643b528cefcSMark Murray 		if (entry->vno)
644b528cefcSMark Murray 		    krb5_kt_free_entry (context, entry);
645b528cefcSMark Murray 		krb5_kt_copy_entry_contents (context, &tmp, entry);
646b528cefcSMark Murray 	    }
647b528cefcSMark Murray 	}
648b528cefcSMark Murray 	krb5_kt_free_entry(context, &tmp);
649b528cefcSMark Murray     }
650b528cefcSMark Murray     krb5_kt_end_seq_get (context, id, &cursor);
651*ae771770SStanislav Sedov     if (entry->vno == 0)
652*ae771770SStanislav Sedov 	return _krb5_kt_principal_not_found(context, KRB5_KT_NOTFOUND,
653*ae771770SStanislav Sedov 					    id, principal, enctype, kvno);
654b528cefcSMark Murray     return 0;
655adb0ddaeSAssar Westerlund }
656b528cefcSMark Murray 
657*ae771770SStanislav Sedov /**
658b528cefcSMark Murray  * Copy the contents of `in' into `out'.
659*ae771770SStanislav Sedov  *
660*ae771770SStanislav Sedov  * @param context a Keberos context.
661*ae771770SStanislav Sedov  * @param in the keytab entry to copy.
662*ae771770SStanislav Sedov  * @param out the copy of the keytab entry, free with krb5_kt_free_entry().
663*ae771770SStanislav Sedov  *
664*ae771770SStanislav Sedov  * @return Return an error code or 0, see krb5_get_error_message().
665*ae771770SStanislav Sedov  *
666*ae771770SStanislav Sedov  * @ingroup krb5_keytab
667*ae771770SStanislav Sedov  */
668b528cefcSMark Murray 
669*ae771770SStanislav Sedov KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
670b528cefcSMark Murray krb5_kt_copy_entry_contents(krb5_context context,
671b528cefcSMark Murray 			    const krb5_keytab_entry *in,
672b528cefcSMark Murray 			    krb5_keytab_entry *out)
673b528cefcSMark Murray {
674b528cefcSMark Murray     krb5_error_code ret;
675b528cefcSMark Murray 
676b528cefcSMark Murray     memset(out, 0, sizeof(*out));
677b528cefcSMark Murray     out->vno = in->vno;
678b528cefcSMark Murray 
679b528cefcSMark Murray     ret = krb5_copy_principal (context, in->principal, &out->principal);
680b528cefcSMark Murray     if (ret)
681b528cefcSMark Murray 	goto fail;
682b528cefcSMark Murray     ret = krb5_copy_keyblock_contents (context,
683b528cefcSMark Murray 				       &in->keyblock,
684b528cefcSMark Murray 				       &out->keyblock);
685b528cefcSMark Murray     if (ret)
686b528cefcSMark Murray 	goto fail;
687b528cefcSMark Murray     out->timestamp = in->timestamp;
688b528cefcSMark Murray     return 0;
689b528cefcSMark Murray fail:
690b528cefcSMark Murray     krb5_kt_free_entry (context, out);
691b528cefcSMark Murray     return ret;
692b528cefcSMark Murray }
693b528cefcSMark Murray 
694*ae771770SStanislav Sedov /**
695b528cefcSMark Murray  * Free the contents of `entry'.
696*ae771770SStanislav Sedov  *
697*ae771770SStanislav Sedov  * @param context a Keberos context.
698*ae771770SStanislav Sedov  * @param entry the entry to free
699*ae771770SStanislav Sedov  *
700*ae771770SStanislav Sedov  * @return Return an error code or 0, see krb5_get_error_message().
701*ae771770SStanislav Sedov  *
702*ae771770SStanislav Sedov  * @ingroup krb5_keytab
703b528cefcSMark Murray  */
704b528cefcSMark Murray 
705*ae771770SStanislav Sedov KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
706b528cefcSMark Murray krb5_kt_free_entry(krb5_context context,
707b528cefcSMark Murray 		   krb5_keytab_entry *entry)
708b528cefcSMark Murray {
709b528cefcSMark Murray     krb5_free_principal (context, entry->principal);
710b528cefcSMark Murray     krb5_free_keyblock_contents (context, &entry->keyblock);
711c19800e8SDoug Rabson     memset(entry, 0, sizeof(*entry));
712b528cefcSMark Murray     return 0;
713b528cefcSMark Murray }
714b528cefcSMark Murray 
715*ae771770SStanislav Sedov /**
716b528cefcSMark Murray  * Set `cursor' to point at the beginning of `id'.
717*ae771770SStanislav Sedov  *
718*ae771770SStanislav Sedov  * @param context a Keberos context.
719*ae771770SStanislav Sedov  * @param id a keytab.
720*ae771770SStanislav Sedov  * @param cursor a newly allocated cursor, free with krb5_kt_end_seq_get().
721*ae771770SStanislav Sedov  *
722*ae771770SStanislav Sedov  * @return Return an error code or 0, see krb5_get_error_message().
723*ae771770SStanislav Sedov  *
724*ae771770SStanislav Sedov  * @ingroup krb5_keytab
725b528cefcSMark Murray  */
726b528cefcSMark Murray 
727*ae771770SStanislav Sedov KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
728b528cefcSMark Murray krb5_kt_start_seq_get(krb5_context context,
729b528cefcSMark Murray 		      krb5_keytab id,
730b528cefcSMark Murray 		      krb5_kt_cursor *cursor)
731b528cefcSMark Murray {
732adb0ddaeSAssar Westerlund     if(id->start_seq_get == NULL) {
733*ae771770SStanislav Sedov 	krb5_set_error_message(context, HEIM_ERR_OPNOTSUPP,
734*ae771770SStanislav Sedov 			       N_("start_seq_get is not supported "
735*ae771770SStanislav Sedov 				  "in the %s keytab type", ""),
736*ae771770SStanislav Sedov 			       id->prefix);
737b528cefcSMark Murray 	return HEIM_ERR_OPNOTSUPP;
738adb0ddaeSAssar Westerlund     }
739b528cefcSMark Murray     return (*id->start_seq_get)(context, id, cursor);
740b528cefcSMark Murray }
741b528cefcSMark Murray 
742*ae771770SStanislav Sedov /**
743*ae771770SStanislav Sedov  * Get the next entry from keytab, advance the cursor.  On last entry
744*ae771770SStanislav Sedov  * the function will return KRB5_KT_END.
745*ae771770SStanislav Sedov  *
746*ae771770SStanislav Sedov  * @param context a Keberos context.
747*ae771770SStanislav Sedov  * @param id a keytab.
748*ae771770SStanislav Sedov  * @param entry the returned entry, free with krb5_kt_free_entry().
749*ae771770SStanislav Sedov  * @param cursor the cursor of the iteration.
750*ae771770SStanislav Sedov  *
751*ae771770SStanislav Sedov  * @return Return an error code or 0, see krb5_get_error_message().
752*ae771770SStanislav Sedov  *
753*ae771770SStanislav Sedov  * @ingroup krb5_keytab
754b528cefcSMark Murray  */
755b528cefcSMark Murray 
756*ae771770SStanislav Sedov KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
757b528cefcSMark Murray krb5_kt_next_entry(krb5_context context,
758b528cefcSMark Murray 		   krb5_keytab id,
759b528cefcSMark Murray 		   krb5_keytab_entry *entry,
760b528cefcSMark Murray 		   krb5_kt_cursor *cursor)
761b528cefcSMark Murray {
762adb0ddaeSAssar Westerlund     if(id->next_entry == NULL) {
763*ae771770SStanislav Sedov 	krb5_set_error_message(context, HEIM_ERR_OPNOTSUPP,
764*ae771770SStanislav Sedov 			       N_("next_entry is not supported in the %s "
765*ae771770SStanislav Sedov 				  " keytab", ""),
766*ae771770SStanislav Sedov 			       id->prefix);
767b528cefcSMark Murray 	return HEIM_ERR_OPNOTSUPP;
768adb0ddaeSAssar Westerlund     }
769b528cefcSMark Murray     return (*id->next_entry)(context, id, entry, cursor);
770b528cefcSMark Murray }
771b528cefcSMark Murray 
772*ae771770SStanislav Sedov /**
773b528cefcSMark Murray  * Release all resources associated with `cursor'.
774*ae771770SStanislav Sedov  *
775*ae771770SStanislav Sedov  * @param context a Keberos context.
776*ae771770SStanislav Sedov  * @param id a keytab.
777*ae771770SStanislav Sedov  * @param cursor the cursor to free.
778*ae771770SStanislav Sedov  *
779*ae771770SStanislav Sedov  * @return Return an error code or 0, see krb5_get_error_message().
780*ae771770SStanislav Sedov  *
781*ae771770SStanislav Sedov  * @ingroup krb5_keytab
782b528cefcSMark Murray  */
783b528cefcSMark Murray 
784*ae771770SStanislav Sedov KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
785b528cefcSMark Murray krb5_kt_end_seq_get(krb5_context context,
786b528cefcSMark Murray 		    krb5_keytab id,
787b528cefcSMark Murray 		    krb5_kt_cursor *cursor)
788b528cefcSMark Murray {
789adb0ddaeSAssar Westerlund     if(id->end_seq_get == NULL) {
790*ae771770SStanislav Sedov 	krb5_set_error_message(context, HEIM_ERR_OPNOTSUPP,
791adb0ddaeSAssar Westerlund 			       "end_seq_get is not supported in the %s "
792adb0ddaeSAssar Westerlund 			       " keytab", id->prefix);
793b528cefcSMark Murray 	return HEIM_ERR_OPNOTSUPP;
794adb0ddaeSAssar Westerlund     }
795b528cefcSMark Murray     return (*id->end_seq_get)(context, id, cursor);
796b528cefcSMark Murray }
797b528cefcSMark Murray 
798*ae771770SStanislav Sedov /**
799b528cefcSMark Murray  * Add the entry in `entry' to the keytab `id'.
800*ae771770SStanislav Sedov  *
801*ae771770SStanislav Sedov  * @param context a Keberos context.
802*ae771770SStanislav Sedov  * @param id a keytab.
803*ae771770SStanislav Sedov  * @param entry the entry to add
804*ae771770SStanislav Sedov  *
805*ae771770SStanislav Sedov  * @return Return an error code or 0, see krb5_get_error_message().
806*ae771770SStanislav Sedov  *
807*ae771770SStanislav Sedov  * @ingroup krb5_keytab
808b528cefcSMark Murray  */
809b528cefcSMark Murray 
810*ae771770SStanislav Sedov KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
811b528cefcSMark Murray krb5_kt_add_entry(krb5_context context,
812b528cefcSMark Murray 		  krb5_keytab id,
813b528cefcSMark Murray 		  krb5_keytab_entry *entry)
814b528cefcSMark Murray {
815adb0ddaeSAssar Westerlund     if(id->add == NULL) {
816*ae771770SStanislav Sedov 	krb5_set_error_message(context, KRB5_KT_NOWRITE,
817*ae771770SStanislav Sedov 			       N_("Add is not supported in the %s keytab", ""),
818adb0ddaeSAssar Westerlund 			       id->prefix);
819b528cefcSMark Murray 	return KRB5_KT_NOWRITE;
820adb0ddaeSAssar Westerlund     }
82113e3f4d6SMark Murray     entry->timestamp = time(NULL);
822b528cefcSMark Murray     return (*id->add)(context, id,entry);
823b528cefcSMark Murray }
824b528cefcSMark Murray 
825*ae771770SStanislav Sedov /**
826*ae771770SStanislav Sedov  * Remove an entry from the keytab, matching is done using
827*ae771770SStanislav Sedov  * krb5_kt_compare().
828*ae771770SStanislav Sedov 
829*ae771770SStanislav Sedov  * @param context a Keberos context.
830*ae771770SStanislav Sedov  * @param id a keytab.
831*ae771770SStanislav Sedov  * @param entry the entry to remove
832*ae771770SStanislav Sedov  *
833*ae771770SStanislav Sedov  * @return Return an error code or 0, see krb5_get_error_message().
834*ae771770SStanislav Sedov  *
835*ae771770SStanislav Sedov  * @ingroup krb5_keytab
836b528cefcSMark Murray  */
837b528cefcSMark Murray 
838*ae771770SStanislav Sedov KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
839b528cefcSMark Murray krb5_kt_remove_entry(krb5_context context,
840b528cefcSMark Murray 		     krb5_keytab id,
841b528cefcSMark Murray 		     krb5_keytab_entry *entry)
842b528cefcSMark Murray {
843adb0ddaeSAssar Westerlund     if(id->remove == NULL) {
844*ae771770SStanislav Sedov 	krb5_set_error_message(context, KRB5_KT_NOWRITE,
845*ae771770SStanislav Sedov 			       N_("Remove is not supported in the %s keytab", ""),
846adb0ddaeSAssar Westerlund 			       id->prefix);
847b528cefcSMark Murray 	return KRB5_KT_NOWRITE;
848adb0ddaeSAssar Westerlund     }
849b528cefcSMark Murray     return (*id->remove)(context, id, entry);
850b528cefcSMark Murray }
851*ae771770SStanislav Sedov 
852*ae771770SStanislav Sedov /**
853*ae771770SStanislav Sedov  * Return true if the keytab exists and have entries
854*ae771770SStanislav Sedov  *
855*ae771770SStanislav Sedov  * @param context a Keberos context.
856*ae771770SStanislav Sedov  * @param id a keytab.
857*ae771770SStanislav Sedov  *
858*ae771770SStanislav Sedov  * @return Return an error code or 0, see krb5_get_error_message().
859*ae771770SStanislav Sedov  *
860*ae771770SStanislav Sedov  * @ingroup krb5_keytab
861*ae771770SStanislav Sedov  */
862*ae771770SStanislav Sedov 
863*ae771770SStanislav Sedov KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL
864*ae771770SStanislav Sedov krb5_kt_have_content(krb5_context context,
865*ae771770SStanislav Sedov 		     krb5_keytab id)
866*ae771770SStanislav Sedov {
867*ae771770SStanislav Sedov     krb5_keytab_entry entry;
868*ae771770SStanislav Sedov     krb5_kt_cursor cursor;
869*ae771770SStanislav Sedov     krb5_error_code ret;
870*ae771770SStanislav Sedov     char *name;
871*ae771770SStanislav Sedov 
872*ae771770SStanislav Sedov     ret = krb5_kt_start_seq_get(context, id, &cursor);
873*ae771770SStanislav Sedov     if (ret)
874*ae771770SStanislav Sedov 	goto notfound;
875*ae771770SStanislav Sedov 
876*ae771770SStanislav Sedov     ret = krb5_kt_next_entry(context, id, &entry, &cursor);
877*ae771770SStanislav Sedov     krb5_kt_end_seq_get(context, id, &cursor);
878*ae771770SStanislav Sedov     if (ret)
879*ae771770SStanislav Sedov 	goto notfound;
880*ae771770SStanislav Sedov 
881*ae771770SStanislav Sedov     krb5_kt_free_entry(context, &entry);
882*ae771770SStanislav Sedov 
883*ae771770SStanislav Sedov     return 0;
884*ae771770SStanislav Sedov 
885*ae771770SStanislav Sedov  notfound:
886*ae771770SStanislav Sedov     ret = krb5_kt_get_full_name(context, id, &name);
887*ae771770SStanislav Sedov     if (ret == 0) {
888*ae771770SStanislav Sedov 	krb5_set_error_message(context, KRB5_KT_NOTFOUND,
889*ae771770SStanislav Sedov 			       N_("No entry in keytab: %s", ""), name);
890*ae771770SStanislav Sedov 	free(name);
891*ae771770SStanislav Sedov     }
892*ae771770SStanislav Sedov     return KRB5_KT_NOTFOUND;
893*ae771770SStanislav Sedov }
894