1 /*
2 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
3 * Use is subject to license terms.
4 */
5
6 /*
7 * lib/krb5/keytab/srvtab/kts_resolv.c
8 *
9 * Copyright 1990,1991,2002 by the Massachusetts Institute of Technology.
10 * All Rights Reserved.
11 *
12 * Export of this software from the United States of America may
13 * require a specific license from the United States Government.
14 * It is the responsibility of any person or organization contemplating
15 * export to obtain such a license before exporting.
16 *
17 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
18 * distribute this software and its documentation for any purpose and
19 * without fee is hereby granted, provided that the above copyright
20 * notice appear in all copies and that both that copyright notice and
21 * this permission notice appear in supporting documentation, and that
22 * the name of M.I.T. not be used in advertising or publicity pertaining
23 * to distribution of the software without specific, written prior
24 * permission. Furthermore if you modify this software you must label
25 * your software as modified software and not distribute it in such a
26 * fashion that it might be confused with the original M.I.T. software.
27 * M.I.T. makes no representations about the suitability of
28 * this software for any purpose. It is provided "as is" without express
29 * or implied warranty.
30 */
31
32 #include "k5-int.h"
33 #include <stdio.h>
34
35 /*
36 * Constants
37 */
38 #define IGNORE_VNO 0
39 #define IGNORE_ENCTYPE 0
40
41 #define KRB5_KT_VNO_1 0x0501 /* krb v5, keytab version 1 (DCE compat) */
42 #define KRB5_KT_VNO 0x0502 /* krb v5, keytab version 2 (standard) */
43
44 #define KRB5_KT_DEFAULT_VNO KRB5_KT_VNO
45
46 /*
47 * Types
48 */
49 typedef struct _krb5_ktsrvtab_data {
50 char *name; /* Name of the file */
51 FILE *openf; /* open file, if any. */
52 } krb5_ktsrvtab_data;
53
54 /*
55 * Macros
56 */
57 #define KTPRIVATE(id) ((krb5_ktsrvtab_data *)(id)->data)
58 #define KTFILENAME(id) (((krb5_ktsrvtab_data *)(id)->data)->name)
59 #define KTFILEP(id) (((krb5_ktsrvtab_data *)(id)->data)->openf)
60
61 extern const struct _krb5_kt_ops krb5_kts_ops;
62
63 static krb5_error_code KRB5_CALLCONV krb5_ktsrvtab_resolve
64 (krb5_context,
65 const char *,
66 krb5_keytab *);
67
68 static krb5_error_code KRB5_CALLCONV krb5_ktsrvtab_get_name
69 (krb5_context,
70 krb5_keytab,
71 char *,
72 unsigned int);
73
74 static krb5_error_code KRB5_CALLCONV krb5_ktsrvtab_close
75 (krb5_context,
76 krb5_keytab);
77
78 static krb5_error_code KRB5_CALLCONV krb5_ktsrvtab_get_entry
79 (krb5_context,
80 krb5_keytab,
81 krb5_const_principal,
82 krb5_kvno,
83 krb5_enctype,
84 krb5_keytab_entry *);
85
86 static krb5_error_code KRB5_CALLCONV krb5_ktsrvtab_start_seq_get
87 (krb5_context,
88 krb5_keytab,
89 krb5_kt_cursor *);
90
91 static krb5_error_code KRB5_CALLCONV krb5_ktsrvtab_get_next
92 (krb5_context,
93 krb5_keytab,
94 krb5_keytab_entry *,
95 krb5_kt_cursor *);
96
97 static krb5_error_code KRB5_CALLCONV krb5_ktsrvtab_end_get
98 (krb5_context,
99 krb5_keytab,
100 krb5_kt_cursor *);
101
102 static krb5_error_code krb5_ktsrvint_open
103 (krb5_context,
104 krb5_keytab);
105
106 static krb5_error_code krb5_ktsrvint_close
107 (krb5_context,
108 krb5_keytab);
109
110 static krb5_error_code krb5_ktsrvint_read_entry
111 (krb5_context,
112 krb5_keytab,
113 krb5_keytab_entry *);
114
115 /*
116 * This is an implementation specific resolver. It returns a keytab id
117 * initialized with srvtab keytab routines.
118 */
119
120 static krb5_error_code KRB5_CALLCONV
krb5_ktsrvtab_resolve(krb5_context context,const char * name,krb5_keytab * id)121 krb5_ktsrvtab_resolve(krb5_context context, const char *name, krb5_keytab *id)
122 {
123 krb5_ktsrvtab_data *data;
124 FILE *fp;
125
126 /* Make sure we can open the srvtab file for reading. */
127 /* Solaris Kerberos */
128 fp = fopen(name, "rF");
129 if (!fp)
130 return(errno);
131 fclose(fp);
132
133 if ((*id = (krb5_keytab) malloc(sizeof(**id))) == NULL)
134 return(ENOMEM);
135
136 (*id)->ops = &krb5_kts_ops;
137 data = (krb5_ktsrvtab_data *)malloc(sizeof(krb5_ktsrvtab_data));
138 if (data == NULL) {
139 krb5_xfree(*id);
140 return(ENOMEM);
141 }
142
143 data->name = (char *)malloc(strlen(name) + 1);
144 if (data->name == NULL) {
145 krb5_xfree(data);
146 krb5_xfree(*id);
147 return(ENOMEM);
148 }
149
150 (void) strcpy(data->name, name);
151 data->openf = 0;
152
153 (*id)->data = (krb5_pointer)data;
154 (*id)->magic = KV5M_KEYTAB;
155 return(0);
156 }
157
158 /*
159 * "Close" a file-based keytab and invalidate the id. This means
160 * free memory hidden in the structures.
161 */
162
163 krb5_error_code KRB5_CALLCONV
krb5_ktsrvtab_close(krb5_context context,krb5_keytab id)164 krb5_ktsrvtab_close(krb5_context context, krb5_keytab id)
165 /*
166 * This routine is responsible for freeing all memory allocated
167 * for this keytab. There are no system resources that need
168 * to be freed nor are there any open files.
169 *
170 * This routine should undo anything done by krb5_ktsrvtab_resolve().
171 */
172 {
173 krb5_xfree(KTFILENAME(id));
174 krb5_xfree(id->data);
175 id->ops = 0;
176 krb5_xfree(id);
177 return (0);
178 }
179
180 /*
181 * This is the get_entry routine for the file based keytab implementation.
182 * It opens the keytab file, and either retrieves the entry or returns
183 * an error.
184 */
185
186 krb5_error_code KRB5_CALLCONV
krb5_ktsrvtab_get_entry(krb5_context context,krb5_keytab id,krb5_const_principal principal,krb5_kvno kvno,krb5_enctype enctype,krb5_keytab_entry * entry)187 krb5_ktsrvtab_get_entry(krb5_context context, krb5_keytab id, krb5_const_principal principal, krb5_kvno kvno, krb5_enctype enctype, krb5_keytab_entry *entry)
188 {
189 krb5_keytab_entry best_entry, ent;
190 krb5_error_code kerror = 0;
191 int found_wrong_kvno = 0;
192
193 /* Open the srvtab. */
194 if ((kerror = krb5_ktsrvint_open(context, id)))
195 return(kerror);
196
197 /* srvtab files only have DES_CBC_CRC keys. */
198 switch (enctype) {
199 case ENCTYPE_DES_CBC_CRC:
200 case ENCTYPE_DES_CBC_MD5:
201 case ENCTYPE_DES_CBC_MD4:
202 case ENCTYPE_DES_CBC_RAW:
203 case IGNORE_ENCTYPE:
204 break;
205 default:
206 return KRB5_KT_NOTFOUND;
207 }
208
209 best_entry.principal = 0;
210 best_entry.vno = 0;
211 best_entry.key.contents = 0;
212 while ((kerror = krb5_ktsrvint_read_entry(context, id, &ent)) == 0) {
213 ent.key.enctype = enctype;
214 if (krb5_principal_compare(context, principal, ent.principal)) {
215 if (kvno == IGNORE_VNO) {
216 if (!best_entry.principal || (best_entry.vno < ent.vno)) {
217 krb5_kt_free_entry(context, &best_entry);
218 best_entry = ent;
219 }
220 } else {
221 if (ent.vno == kvno) {
222 best_entry = ent;
223 break;
224 } else {
225 found_wrong_kvno = 1;
226 }
227 }
228 } else {
229 krb5_kt_free_entry(context, &ent);
230 }
231 }
232 if (kerror == KRB5_KT_END) {
233 if (best_entry.principal)
234 kerror = 0;
235 else if (found_wrong_kvno)
236 kerror = KRB5_KT_KVNONOTFOUND;
237 else
238 kerror = KRB5_KT_NOTFOUND;
239 }
240 if (kerror) {
241 (void) krb5_ktsrvint_close(context, id);
242 krb5_kt_free_entry(context, &best_entry);
243 return kerror;
244 }
245 if ((kerror = krb5_ktsrvint_close(context, id)) != 0) {
246 krb5_kt_free_entry(context, &best_entry);
247 return kerror;
248 }
249 *entry = best_entry;
250 return 0;
251 }
252
253 /*
254 * Get the name of the file containing a srvtab-based keytab.
255 */
256
257 krb5_error_code KRB5_CALLCONV
krb5_ktsrvtab_get_name(krb5_context context,krb5_keytab id,char * name,unsigned int len)258 krb5_ktsrvtab_get_name(krb5_context context, krb5_keytab id, char *name, unsigned int len)
259 /*
260 * This routine returns the name of the name of the file associated with
261 * this srvtab-based keytab. The name is prefixed with PREFIX:, so that
262 * trt will happen if the name is passed back to resolve.
263 */
264 {
265 memset(name, 0, len);
266
267 if (len < strlen(id->ops->prefix)+2)
268 return(KRB5_KT_NAME_TOOLONG);
269 strcpy(name, id->ops->prefix);
270 name += strlen(id->ops->prefix);
271 name[0] = ':';
272 name++;
273 len -= strlen(id->ops->prefix)+1;
274
275 /* Solaris Kerberos */
276 if (len < strlen(KTFILENAME(id))+1)
277 return(KRB5_KT_NAME_TOOLONG);
278 strcpy(name, KTFILENAME(id));
279 /* strcpy will NUL-terminate the destination */
280
281 return(0);
282 }
283
284 /*
285 * krb5_ktsrvtab_start_seq_get()
286 */
287
288 krb5_error_code KRB5_CALLCONV
krb5_ktsrvtab_start_seq_get(krb5_context context,krb5_keytab id,krb5_kt_cursor * cursorp)289 krb5_ktsrvtab_start_seq_get(krb5_context context, krb5_keytab id, krb5_kt_cursor *cursorp)
290 {
291 krb5_error_code retval;
292 long *fileoff;
293
294 if ((retval = krb5_ktsrvint_open(context, id)))
295 return retval;
296
297 if (!(fileoff = (long *)malloc(sizeof(*fileoff)))) {
298 krb5_ktsrvint_close(context, id);
299 return ENOMEM;
300 }
301 *fileoff = ftell(KTFILEP(id));
302 *cursorp = (krb5_kt_cursor)fileoff;
303
304 return 0;
305 }
306
307 /*
308 * krb5_ktsrvtab_get_next()
309 */
310
311 krb5_error_code KRB5_CALLCONV
krb5_ktsrvtab_get_next(krb5_context context,krb5_keytab id,krb5_keytab_entry * entry,krb5_kt_cursor * cursor)312 krb5_ktsrvtab_get_next(krb5_context context, krb5_keytab id, krb5_keytab_entry *entry, krb5_kt_cursor *cursor)
313 {
314 long *fileoff = (long *)*cursor;
315 krb5_keytab_entry cur_entry;
316 krb5_error_code kerror;
317
318 if (fseek(KTFILEP(id), *fileoff, 0) == -1)
319 return KRB5_KT_END;
320 if ((kerror = krb5_ktsrvint_read_entry(context, id, &cur_entry)))
321 return kerror;
322 *fileoff = ftell(KTFILEP(id));
323 *entry = cur_entry;
324 return 0;
325 }
326
327 /*
328 * krb5_ktsrvtab_end_get()
329 */
330
331 krb5_error_code KRB5_CALLCONV
krb5_ktsrvtab_end_get(krb5_context context,krb5_keytab id,krb5_kt_cursor * cursor)332 krb5_ktsrvtab_end_get(krb5_context context, krb5_keytab id, krb5_kt_cursor *cursor)
333 {
334 krb5_xfree(*cursor);
335 return krb5_ktsrvint_close(context, id);
336 }
337
338 /*
339 * krb5_kts_ops
340 */
341
342 const struct _krb5_kt_ops krb5_kts_ops = {
343 0,
344 "SRVTAB", /* Prefix -- this string should not appear anywhere else! */
345 krb5_ktsrvtab_resolve,
346 krb5_ktsrvtab_get_name,
347 krb5_ktsrvtab_close,
348 krb5_ktsrvtab_get_entry,
349 krb5_ktsrvtab_start_seq_get,
350 krb5_ktsrvtab_get_next,
351 krb5_ktsrvtab_end_get,
352 0,
353 0,
354 0
355 };
356
357 /*
358 * formerly: lib/krb5/keytab/srvtab/kts_util.c
359 *
360 * Copyright (c) Hewlett-Packard Company 1991
361 * Released to the Massachusetts Institute of Technology for inclusion
362 * in the Kerberos source code distribution.
363 *
364 * Copyright 1990,1991 by the Massachusetts Institute of Technology.
365 * All Rights Reserved.
366 *
367 * Export of this software from the United States of America may
368 * require a specific license from the United States Government.
369 * It is the responsibility of any person or organization contemplating
370 * export to obtain such a license before exporting.
371 *
372 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
373 * distribute this software and its documentation for any purpose and
374 * without fee is hereby granted, provided that the above copyright
375 * notice appear in all copies and that both that copyright notice and
376 * this permission notice appear in supporting documentation, and that
377 * the name of M.I.T. not be used in advertising or publicity pertaining
378 * to distribution of the software without specific, written prior
379 * permission. Furthermore if you modify this software you must label
380 * your software as modified software and not distribute it in such a
381 * fashion that it might be confused with the original M.I.T. software.
382 * M.I.T. makes no representations about the suitability of
383 * this software for any purpose. It is provided "as is" without express
384 * or implied warranty.
385 *
386 *
387 * This function contains utilities for the srvtab based implementation
388 * of the keytab. There are no public functions in this file.
389 */
390
391 #include <stdio.h>
392
393 #ifdef ANSI_STDIO
394 /* Solaris Kerberos */
395 #define READ_MODE "rbF"
396 #else
397 /* Solaris Kerberos */
398 #define READ_MODE "rF"
399 #endif
400
401 /* The maximum sizes for V4 aname, realm, sname, and instance +1 */
402 /* Taken from krb.h */
403 #define ANAME_SZ 40
404 #define REALM_SZ 40
405 #define SNAME_SZ 40
406 #define INST_SZ 40
407
408 static krb5_error_code
read_field(FILE * fp,char * s,int len)409 read_field(FILE *fp, char *s, int len)
410 {
411 int c;
412
413 while ((c = getc(fp)) != 0) {
414 if (c == EOF || len <= 1)
415 return KRB5_KT_END;
416 *s = c;
417 s++;
418 len--;
419 }
420 *s = 0;
421 return 0;
422 }
423
424 krb5_error_code
krb5_ktsrvint_open(krb5_context context,krb5_keytab id)425 krb5_ktsrvint_open(krb5_context context, krb5_keytab id)
426 {
427 KTFILEP(id) = fopen(KTFILENAME(id), READ_MODE);
428 if (!KTFILEP(id))
429 return errno;
430 return 0;
431 }
432
433 krb5_error_code
krb5_ktsrvint_close(krb5_context context,krb5_keytab id)434 krb5_ktsrvint_close(krb5_context context, krb5_keytab id)
435 {
436 if (!KTFILEP(id))
437 return 0;
438 (void) fclose(KTFILEP(id));
439 KTFILEP(id) = 0;
440 return 0;
441 }
442
443 krb5_error_code
krb5_ktsrvint_read_entry(krb5_context context,krb5_keytab id,krb5_keytab_entry * ret_entry)444 krb5_ktsrvint_read_entry(krb5_context context, krb5_keytab id, krb5_keytab_entry *ret_entry)
445 {
446 FILE *fp;
447 char name[SNAME_SZ], instance[INST_SZ], realm[REALM_SZ];
448 unsigned char key[8];
449 int vno;
450 krb5_error_code kerror;
451
452 /* Read in an entry from the srvtab file. */
453 fp = KTFILEP(id);
454 kerror = read_field(fp, name, sizeof(name));
455 if (kerror != 0)
456 return kerror;
457 kerror = read_field(fp, instance, sizeof(instance));
458 if (kerror != 0)
459 return kerror;
460 kerror = read_field(fp, realm, sizeof(realm));
461 if (kerror != 0)
462 return kerror;
463 vno = getc(fp);
464 if (vno == EOF)
465 return KRB5_KT_END;
466 if (fread(key, 1, sizeof(key), fp) != sizeof(key))
467 return KRB5_KT_END;
468
469 /* Fill in ret_entry with the data we read. Everything maps well
470 * except for the timestamp, which we don't have a value for. For
471 * now we just set it to 0. */
472 memset(ret_entry, 0, sizeof(*ret_entry));
473 ret_entry->magic = KV5M_KEYTAB_ENTRY;
474 kerror = krb5_425_conv_principal(context, name, instance, realm,
475 &ret_entry->principal);
476 if (kerror != 0)
477 return kerror;
478 ret_entry->vno = vno;
479 ret_entry->timestamp = 0;
480 ret_entry->key.enctype = ENCTYPE_DES_CBC_CRC;
481 ret_entry->key.magic = KV5M_KEYBLOCK;
482 ret_entry->key.length = sizeof(key);
483 ret_entry->key.contents = malloc(sizeof(key));
484 if (!ret_entry->key.contents) {
485 krb5_free_principal(context, ret_entry->principal);
486 return ENOMEM;
487 }
488 memcpy(ret_entry->key.contents, key, sizeof(key));
489
490 return 0;
491 }
492