No empty .Rs/.Re
[netbsd-mini2440.git] / crypto / dist / heimdal / lib / krb5 / keytab_keyfile.c
blobaabc2a7b9bcce715eba06117217c7b4afda02b6b
1 /*
2 * Copyright (c) 1997 - 2007 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
4 * All rights reserved.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
17 * 3. Neither the name of the Institute nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
34 #include "krb5_locl.h"
36 __RCSID("$Heimdal: keytab_keyfile.c 20695 2007-05-30 14:09:09Z lha $"
37 "$NetBSD$");
39 /* afs keyfile operations --------------------------------------- */
42 * Minimum tools to handle the AFS KeyFile.
44 * Format of the KeyFile is:
45 * <int32_t numkeys> {[<int32_t kvno> <char[8] deskey>] * numkeys}
47 * It just adds to the end of the keyfile, deleting isn't implemented.
48 * Use your favorite text/hex editor to delete keys.
52 #define AFS_SERVERTHISCELL "/usr/afs/etc/ThisCell"
53 #define AFS_SERVERMAGICKRBCONF "/usr/afs/etc/krb.conf"
55 struct akf_data {
56 int num_entries;
57 char *filename;
58 char *cell;
59 char *realm;
63 * set `d->cell' and `d->realm'
66 static int
67 get_cell_and_realm (krb5_context context, struct akf_data *d)
69 FILE *f;
70 char buf[BUFSIZ], *cp;
71 int ret;
73 f = fopen (AFS_SERVERTHISCELL, "r");
74 if (f == NULL) {
75 ret = errno;
76 krb5_set_error_string (context, "open %s: %s", AFS_SERVERTHISCELL,
77 strerror(ret));
78 return ret;
80 if (fgets (buf, sizeof(buf), f) == NULL) {
81 fclose (f);
82 krb5_set_error_string (context, "no cell in %s", AFS_SERVERTHISCELL);
83 return EINVAL;
85 buf[strcspn(buf, "\n")] = '\0';
86 fclose(f);
88 d->cell = strdup (buf);
89 if (d->cell == NULL) {
90 krb5_set_error_string (context, "malloc: out of memory");
91 return ENOMEM;
94 f = fopen (AFS_SERVERMAGICKRBCONF, "r");
95 if (f != NULL) {
96 if (fgets (buf, sizeof(buf), f) == NULL) {
97 free (d->cell);
98 d->cell = NULL;
99 fclose (f);
100 krb5_set_error_string (context, "no realm in %s",
101 AFS_SERVERMAGICKRBCONF);
102 return EINVAL;
104 buf[strcspn(buf, "\n")] = '\0';
105 fclose(f);
107 /* uppercase */
108 for (cp = buf; *cp != '\0'; cp++)
109 *cp = toupper((unsigned char)*cp);
111 d->realm = strdup (buf);
112 if (d->realm == NULL) {
113 free (d->cell);
114 d->cell = NULL;
115 krb5_set_error_string (context, "malloc: out of memory");
116 return ENOMEM;
118 return 0;
122 * init and get filename
125 static krb5_error_code
126 akf_resolve(krb5_context context, const char *name, krb5_keytab id)
128 int ret;
129 struct akf_data *d = malloc(sizeof (struct akf_data));
131 if (d == NULL) {
132 krb5_set_error_string (context, "malloc: out of memory");
133 return ENOMEM;
136 d->num_entries = 0;
137 ret = get_cell_and_realm (context, d);
138 if (ret) {
139 free (d);
140 return ret;
142 d->filename = strdup (name);
143 if (d->filename == NULL) {
144 free (d->cell);
145 free (d->realm);
146 free (d);
147 krb5_set_error_string (context, "malloc: out of memory");
148 return ENOMEM;
150 id->data = d;
152 return 0;
156 * cleanup
159 static krb5_error_code
160 akf_close(krb5_context context, krb5_keytab id)
162 struct akf_data *d = id->data;
164 free (d->filename);
165 free (d->cell);
166 free (d);
167 return 0;
171 * Return filename
174 static krb5_error_code
175 akf_get_name(krb5_context context,
176 krb5_keytab id,
177 char *name,
178 size_t name_sz)
180 struct akf_data *d = id->data;
182 strlcpy (name, d->filename, name_sz);
183 return 0;
187 * Init
190 static krb5_error_code
191 akf_start_seq_get(krb5_context context,
192 krb5_keytab id,
193 krb5_kt_cursor *c)
195 int32_t ret;
196 struct akf_data *d = id->data;
198 c->fd = open (d->filename, O_RDONLY|O_BINARY, 0600);
199 if (c->fd < 0) {
200 ret = errno;
201 krb5_set_error_string(context, "open(%s): %s", d->filename,
202 strerror(ret));
203 return ret;
206 c->sp = krb5_storage_from_fd(c->fd);
207 ret = krb5_ret_int32(c->sp, &d->num_entries);
208 if(ret) {
209 krb5_storage_free(c->sp);
210 close(c->fd);
211 krb5_clear_error_string (context);
212 if(ret == KRB5_KT_END)
213 return KRB5_KT_NOTFOUND;
214 return ret;
217 return 0;
220 static krb5_error_code
221 akf_next_entry(krb5_context context,
222 krb5_keytab id,
223 krb5_keytab_entry *entry,
224 krb5_kt_cursor *cursor)
226 struct akf_data *d = id->data;
227 int32_t kvno;
228 off_t pos;
229 int ret;
231 pos = krb5_storage_seek(cursor->sp, 0, SEEK_CUR);
233 if ((pos - 4) / (4 + 8) >= d->num_entries)
234 return KRB5_KT_END;
236 ret = krb5_make_principal (context, &entry->principal,
237 d->realm, "afs", d->cell, NULL);
238 if (ret)
239 goto out;
241 ret = krb5_ret_int32(cursor->sp, &kvno);
242 if (ret) {
243 krb5_free_principal (context, entry->principal);
244 goto out;
247 entry->vno = kvno;
249 entry->keyblock.keytype = ETYPE_DES_CBC_MD5;
250 entry->keyblock.keyvalue.length = 8;
251 entry->keyblock.keyvalue.data = malloc (8);
252 if (entry->keyblock.keyvalue.data == NULL) {
253 krb5_free_principal (context, entry->principal);
254 krb5_set_error_string (context, "malloc: out of memory");
255 ret = ENOMEM;
256 goto out;
259 ret = krb5_storage_read(cursor->sp, entry->keyblock.keyvalue.data, 8);
260 if(ret != 8)
261 ret = (ret < 0) ? errno : KRB5_KT_END;
262 else
263 ret = 0;
265 entry->timestamp = time(NULL);
267 out:
268 krb5_storage_seek(cursor->sp, pos + 4 + 8, SEEK_SET);
269 return ret;
272 static krb5_error_code
273 akf_end_seq_get(krb5_context context,
274 krb5_keytab id,
275 krb5_kt_cursor *cursor)
277 krb5_storage_free(cursor->sp);
278 close(cursor->fd);
279 return 0;
282 static krb5_error_code
283 akf_add_entry(krb5_context context,
284 krb5_keytab id,
285 krb5_keytab_entry *entry)
287 struct akf_data *d = id->data;
288 int fd, created = 0;
289 krb5_error_code ret;
290 int32_t len;
291 krb5_storage *sp;
294 if (entry->keyblock.keyvalue.length != 8)
295 return 0;
296 switch(entry->keyblock.keytype) {
297 case ETYPE_DES_CBC_CRC:
298 case ETYPE_DES_CBC_MD4:
299 case ETYPE_DES_CBC_MD5:
300 break;
301 default:
302 return 0;
305 fd = open (d->filename, O_RDWR | O_BINARY);
306 if (fd < 0) {
307 fd = open (d->filename,
308 O_RDWR | O_BINARY | O_CREAT | O_EXCL, 0600);
309 if (fd < 0) {
310 ret = errno;
311 krb5_set_error_string(context, "open(%s): %s", d->filename,
312 strerror(ret));
313 return ret;
315 created = 1;
318 sp = krb5_storage_from_fd(fd);
319 if(sp == NULL) {
320 close(fd);
321 krb5_set_error_string (context, "malloc: out of memory");
322 return ENOMEM;
324 if (created)
325 len = 0;
326 else {
327 if(krb5_storage_seek(sp, 0, SEEK_SET) < 0) {
328 ret = errno;
329 krb5_storage_free(sp);
330 close(fd);
331 krb5_set_error_string (context, "seek: %s", strerror(ret));
332 return ret;
335 ret = krb5_ret_int32(sp, &len);
336 if(ret) {
337 krb5_storage_free(sp);
338 close(fd);
339 return ret;
344 * Make sure we don't add the entry twice, assumes the DES
345 * encryption types are all the same key.
347 if (len > 0) {
348 int32_t kvno;
349 int i;
351 for (i = 0; i < len; i++) {
352 ret = krb5_ret_int32(sp, &kvno);
353 if (ret) {
354 krb5_set_error_string (context, "Failed to get kvno ");
355 goto out;
357 if(krb5_storage_seek(sp, 8, SEEK_CUR) < 0) {
358 krb5_set_error_string (context, "seek: %s", strerror(ret));
359 goto out;
361 if (kvno == entry->vno) {
362 ret = 0;
363 goto out;
368 len++;
370 if(krb5_storage_seek(sp, 0, SEEK_SET) < 0) {
371 ret = errno;
372 krb5_set_error_string (context, "seek: %s", strerror(ret));
373 goto out;
376 ret = krb5_store_int32(sp, len);
377 if(ret) {
378 krb5_set_error_string(context, "keytab keyfile failed new length");
379 return ret;
382 if(krb5_storage_seek(sp, (len - 1) * (8 + 4), SEEK_CUR) < 0) {
383 ret = errno;
384 krb5_set_error_string (context, "seek to end: %s", strerror(ret));
385 goto out;
388 ret = krb5_store_int32(sp, entry->vno);
389 if(ret) {
390 krb5_set_error_string(context, "keytab keyfile failed store kvno");
391 goto out;
393 ret = krb5_storage_write(sp, entry->keyblock.keyvalue.data,
394 entry->keyblock.keyvalue.length);
395 if(ret != entry->keyblock.keyvalue.length) {
396 if (ret < 0)
397 ret = errno;
398 else
399 ret = ENOTTY;
400 krb5_set_error_string(context, "keytab keyfile failed to add key");
401 goto out;
403 ret = 0;
404 out:
405 krb5_storage_free(sp);
406 close (fd);
407 return ret;
410 const krb5_kt_ops krb5_akf_ops = {
411 "AFSKEYFILE",
412 akf_resolve,
413 akf_get_name,
414 akf_close,
415 NULL, /* get */
416 akf_start_seq_get,
417 akf_next_entry,
418 akf_end_seq_get,
419 akf_add_entry,
420 NULL /* remove */