Bug Summary

File:auth/keys.c
Location:line 842, column 3
Description:Value stored to 'subEntry' is never read

Annotated Source Code

1/*
2 * Copyright (c) 2010 Your File System Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS'' AND ANY EXPRESS OR
14 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
15 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
16 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
17 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
18 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
19 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
20 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
22 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23 */
24
25#include <afsconfig.h>
26#include <afs/param.h>
27
28#include <roken.h>
29
30#include <opr/queue.h>
31
32/* Need rx/rx.h to get working assert(), used by LOCK_GLOBAL_MUTEX */
33#include <rx/rx.h>
34#include <rx/rx_atomic.h>
35
36#include <afs/stds.h>
37#include <afs/pthread_glock.h>
38#include <afs/afsutil.h>
39
40#include "cellconfig.h"
41#include "keys.h"
42#include "internal.h"
43
44struct afsconf_typedKey {
45 rx_atomic_t refcnt;
46 afsconf_keyType type;
47 int kvno;
48 int subType;
49 struct rx_opaque key;
50};
51
52static struct afsconf_typedKey *afsconf_typedKey_blank(void);
53
54/* Memory storage for keyfile contents. */
55
56struct keyTypeList {
57 struct opr_queue link;
58 afsconf_keyType type;
59 struct opr_queue kvnoList;
60};
61
62struct kvnoList {
63 struct opr_queue link;
64 int kvno;
65 struct opr_queue subTypeList;
66};
67
68struct subTypeList {
69 struct opr_queue link;
70 int subType;
71 struct afsconf_typedKey *key;
72};
73
74static int
75listToArray(struct kvnoList *kvnoEntry, struct afsconf_typedKeyList **keys)
76{
77 struct afsconf_typedKeyList *retval;
78 struct opr_queue *cursor;
79 int i;
80
81 /* Allocate space for the keys we've got stored */
82 retval = malloc(sizeof(struct afsconf_typedKeyList));
83 retval->nkeys = opr_queue_Count(&kvnoEntry->subTypeList);
84 retval->keys = calloc(retval->nkeys, sizeof(struct afsconf_typedKey *));
85
86 i = 0;
87 for(opr_queue_Scan(&kvnoEntry->subTypeList, cursor)cursor = (&kvnoEntry->subTypeList)->next; cursor !=
(&kvnoEntry->subTypeList); cursor = cursor->next
) {
88 struct subTypeList *entry;
89
90 entry = opr_queue_Entry(cursor, struct subTypeList, link)((struct subTypeList *)((char *)(cursor)-(char *)(&((struct
subTypeList *)((void *)0))->link)))
;
91 retval->keys[i] = afsconf_typedKey_get(entry->key);
92 i++;
93 }
94
95 *keys = retval;
96 return 0;
97}
98
99static struct keyTypeList *
100findByType(struct afsconf_dir *dir, afsconf_keyType type)
101{
102 struct opr_queue *cursor;
103 struct keyTypeList *entry = NULL((void *)0);
104
105 for (opr_queue_Scan(&dir->keyList, cursor)cursor = (&dir->keyList)->next; cursor != (&dir
->keyList); cursor = cursor->next
) {
106 entry = opr_queue_Entry(cursor, struct keyTypeList, link)((struct keyTypeList *)((char *)(cursor)-(char *)(&((struct
keyTypeList *)((void *)0))->link)))
;
107 if (entry->type >= type)
108 break;
109 }
110 if (entry == NULL((void *)0) || entry->type != type)
111 return NULL((void *)0);
112
113 return entry;
114}
115
116static struct kvnoList *
117findInTypeList(struct keyTypeList *parent, int kvno)
118{
119 struct opr_queue *cursor;
120 struct kvnoList *entry = NULL((void *)0);
121
122 for (opr_queue_Scan(&parent->kvnoList, cursor)cursor = (&parent->kvnoList)->next; cursor != (&
parent->kvnoList); cursor = cursor->next
) {
123 entry = opr_queue_Entry(cursor, struct kvnoList, link)((struct kvnoList *)((char *)(cursor)-(char *)(&((struct kvnoList
*)((void *)0))->link)))
;
124 if (entry->kvno >= kvno)
125 break;
126 }
127 if (entry == NULL((void *)0) || entry->kvno != kvno)
128 return NULL((void *)0);
129
130 return entry;
131}
132
133static struct kvnoList *
134findByKvno(struct afsconf_dir *dir, afsconf_keyType type, int kvno)
135{
136 struct keyTypeList *entry;
137 entry = findByType(dir, type);
138
139 if (entry == NULL((void *)0))
140 return NULL((void *)0);
141
142 return findInTypeList(entry, kvno);
143}
144
145static struct subTypeList *
146findInKvnoList(struct kvnoList *parent, int subType)
147{
148 struct opr_queue *cursor;
149 struct subTypeList *entry = NULL((void *)0);
150
151 for (opr_queue_Scan(&parent->subTypeList, cursor)cursor = (&parent->subTypeList)->next; cursor != (&
parent->subTypeList); cursor = cursor->next
) {
152 entry = opr_queue_Entry(cursor, struct subTypeList, link)((struct subTypeList *)((char *)(cursor)-(char *)(&((struct
subTypeList *)((void *)0))->link)))
;
153 if (entry->subType >= subType)
154 break;
155 }
156 if (entry == NULL((void *)0) || entry->subType != subType)
157 return NULL((void *)0);
158
159 return entry;
160}
161
162static struct subTypeList *
163findBySubType(struct afsconf_dir *dir, afsconf_keyType type, int kvno,
164 int subType)
165{
166 struct kvnoList *entry;
167
168 entry = findByKvno(dir, type, kvno);
169 if (entry == NULL((void *)0))
170 return NULL((void *)0);
171
172 return findInKvnoList(entry, subType);
173}
174
175
176/* Add key. */
177static int
178addMemoryKey(struct afsconf_dir *dir, struct afsconf_typedKey *key,
179 int overwrite)
180{
181 struct opr_queue *cursor;
182 struct keyTypeList *typeEntry = NULL((void *)0);
183 struct kvnoList *kvnoEntry = NULL((void *)0);
184 struct subTypeList *subType = NULL((void *)0);
185
186 /* Find the place in the keyType list to insert the key into */
187 for (opr_queue_Scan(&dir->keyList, cursor)cursor = (&dir->keyList)->next; cursor != (&dir
->keyList); cursor = cursor->next
) {
188 typeEntry = opr_queue_Entry(cursor, struct keyTypeList, link)((struct keyTypeList *)((char *)(cursor)-(char *)(&((struct
keyTypeList *)((void *)0))->link)))
;
189 if (typeEntry->type >= key->type)
190 break;
191 }
192
193 if (typeEntry == NULL((void *)0) || typeEntry->type != key->type) {
194 struct keyTypeList *list;
195
196 list = malloc(sizeof(struct keyTypeList));
197 opr_queue_Init(&list->kvnoList);
198 list->type = key->type;
199 opr_queue_InsertBefore(cursor, &list->link);
200 typeEntry = list;
201 }
202
203 /* And the place in the kvno list */
204 for (opr_queue_Scan(&typeEntry->kvnoList, cursor)cursor = (&typeEntry->kvnoList)->next; cursor != (&
typeEntry->kvnoList); cursor = cursor->next
) {
205 kvnoEntry = opr_queue_Entry(cursor, struct kvnoList, link)((struct kvnoList *)((char *)(cursor)-(char *)(&((struct kvnoList
*)((void *)0))->link)))
;
206 if (kvnoEntry->kvno >= key->kvno)
207 break;
208 }
209
210 if (kvnoEntry == NULL((void *)0) || kvnoEntry->kvno != key->kvno) {
211 struct kvnoList *list;
212
213 /* In the legacy rxkad key case, we need to check to see if we've
214 * gone over the maximum of 8 keys */
215 if (key->type == afsconf_rxkad &&
216 opr_queue_Count(&typeEntry->kvnoList)>=8)
217 return AFSCONF_FULL(70354694L);
218
219 list = malloc(sizeof(struct kvnoList));
220 opr_queue_Init(&list->subTypeList);
221 list->kvno = key->kvno;
222 opr_queue_InsertBefore(cursor, &list->link);
223 kvnoEntry = list;
224 }
225
226 /* And the place in the subtype list */
227 for (opr_queue_Scan(&kvnoEntry->subTypeList, cursor)cursor = (&kvnoEntry->subTypeList)->next; cursor !=
(&kvnoEntry->subTypeList); cursor = cursor->next
) {
228 subType = opr_queue_Entry(cursor, struct subTypeList, link)((struct subTypeList *)((char *)(cursor)-(char *)(&((struct
subTypeList *)((void *)0))->link)))
;
229 if (subType->subType >= key->subType)
230 break;
231 }
232
233 if (subType == NULL((void *)0) || subType->subType != key->subType) {
234 struct subTypeList *list;
235
236 list = malloc(sizeof(struct subTypeList));
237 list->subType = key->subType;
238 list->key = afsconf_typedKey_get(key);
239 opr_queue_InsertBefore(cursor, &list->link);
240 } else {
241 if (overwrite) {
242 /* Give up our reference to the existing key */
243 afsconf_typedKey_put(&subType->key);
244 subType->key = afsconf_typedKey_get(key);
245 } else {
246 return AFSCONF_KEYINUSE512;
247 }
248 }
249 return 0;
250}
251
252static void
253deleteKvnoEntry(struct kvnoList *entry)
254{
255 struct subTypeList *subTypeEntry;
256
257 while (!opr_queue_IsEmpty(&entry->subTypeList)) {
258 subTypeEntry = opr_queue_First(&entry->subTypeList,((struct subTypeList *)((char *)((&entry->subTypeList)
->next)-(char *)(&((struct subTypeList *)((void *)0))->
link)))
259 struct subTypeList, link)((struct subTypeList *)((char *)((&entry->subTypeList)
->next)-(char *)(&((struct subTypeList *)((void *)0))->
link)))
;
260 afsconf_typedKey_put(&subTypeEntry->key);
261 opr_queue_Remove(&subTypeEntry->link);
262 free(subTypeEntry);
263 }
264 opr_queue_Remove(&entry->link);
265 free(entry);
266}
267
268void
269_afsconf_FreeAllKeys(struct afsconf_dir *dir)
270{
271 struct keyTypeList *typeEntry;
272 struct kvnoList *kvnoEntry;
273
274 while (!opr_queue_IsEmpty(&dir->keyList)) {
275 typeEntry = opr_queue_First(&dir->keyList, struct keyTypeList, link)((struct keyTypeList *)((char *)((&dir->keyList)->next
)-(char *)(&((struct keyTypeList *)((void *)0))->link)
))
;
276
277 while (!opr_queue_IsEmpty(&typeEntry->kvnoList)) {
278 kvnoEntry = opr_queue_First(&typeEntry->kvnoList,((struct kvnoList *)((char *)((&typeEntry->kvnoList)->
next)-(char *)(&((struct kvnoList *)((void *)0))->link
)))
279 struct kvnoList, link)((struct kvnoList *)((char *)((&typeEntry->kvnoList)->
next)-(char *)(&((struct kvnoList *)((void *)0))->link
)))
;
280
281 deleteKvnoEntry(kvnoEntry);
282 }
283 opr_queue_Remove(&typeEntry->link);
284 free(typeEntry);
285 }
286}
287void
288_afsconf_InitKeys(struct afsconf_dir *dir)
289{
290 opr_queue_Init(&dir->keyList);
291}
292
293/* Disk based key storage. This is made somewhat complicated because we
294 * store keys in more than one place - keys of type 'rxkad' (0) are stored
295 * in the original KeyFile, so that we can continue to be compatible with
296 * utilities that directly modify that file.
297 *
298 * All other keys are stored in the file KeyFileEx, which has the following
299 * format:
300 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2
301 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
302 * | version number |
303 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
304 * | number of keys |
305 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
306 * | Key data ...
307 * +-+-+-+-+-+-+-+
308 *
309 * The version number is 1 at present. Version numbers higher than 1
310 * indicate a keyfile that is not backwards compatible with this
311 * specification.
312 *
313 * Key data is a sequence of the following records (note that these are
314 * not word aligned - the next record begins where the previous one ends)
315 *
316 * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2
317 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
318 * | meta-data length |
319 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
320 * | key type |
321 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
322 * | key version number |
323 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
324 * | key sub type |
325 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
326 * | length of key material |
327 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
328 * | Key material
329 * +-+-+-+-+-+-+-+
330 *
331 * All values are expressed in network byte order
332 *
333 * Meta data length is the length of the initial portion of the record
334 * (itself, key type, key version number, and key sub type). In this
335 * version of the specification it would be 16. It is there to allow
336 * additional fields to be added to this specification at a later date
337 * without breaking backwards compatibility.
338 */
339
340/* XXX - We need to be careful with failure here, because failure due to
341 * a missing file is fine, but failure due to read errors needs to be trapped,
342 * before it results in a corrupted file being written out.
343 */
344
345static int
346_parseOriginalKeyFile(struct afsconf_dir *dir, char *fileName)
347{
348 int fd, code, nkeys, i;
349 struct afsconf_typedKey *key;
350
351 fd = open(fileName, O_RDONLY0x0000);
352 if (fd < 0)
353 return 0;
354
355 code = read(fd, &nkeys, sizeof(afs_int32));
356 if (code!= sizeof(afs_int32))
357 goto fail;
358
359 nkeys=ntohl(nkeys)(__builtin_constant_p(nkeys) ? ((((__uint32_t)(nkeys)) >>
24) | ((((__uint32_t)(nkeys)) & (0xff << 16)) >>
8) | ((((__uint32_t)(nkeys)) & (0xff << 8)) <<
8) | (((__uint32_t)(nkeys)) << 24)) : __bswap32_var(nkeys
))
;
360 for(i=0; i<nkeys; i++) {
361
362 key = afsconf_typedKey_blank();
363
364 key->type = afsconf_rxkad;
365 key->subType = 0;
366
367 code = read(fd, &key->kvno, sizeof(afs_int32));
368 if (code != sizeof(afs_int32)) {
369 free(key);
370 goto fail;
371 }
372 key->kvno = ntohl(key->kvno)(__builtin_constant_p(key->kvno) ? ((((__uint32_t)(key->
kvno)) >> 24) | ((((__uint32_t)(key->kvno)) & (0xff
<< 16)) >> 8) | ((((__uint32_t)(key->kvno)) &
(0xff << 8)) << 8) | (((__uint32_t)(key->kvno
)) << 24)) : __bswap32_var(key->kvno))
;
373
374 rx_opaque_alloc(&key->key, 8);
375 code = read(fd, key->key.val, 8);
376 if (code != 8) {
377 rx_opaque_freeContents(&key->key);
378 free(key);
379 goto fail;
380 }
381 code = addMemoryKey(dir, key, 1);
382 afsconf_typedKey_put(&key); /* Done with key */
383 if (code)
384 goto fail;
385 }
386 close(fd);
387 return 0;
388
389fail:
390 close(fd);
391 return EIO5;
392}
393
394static_inlinestatic inline int
395writeWord(int fd, afs_int32 data)
396{
397
398 data = htonl(data)(__builtin_constant_p(data) ? ((((__uint32_t)(data)) >>
24) | ((((__uint32_t)(data)) & (0xff << 16)) >>
8) | ((((__uint32_t)(data)) & (0xff << 8)) <<
8) | (((__uint32_t)(data)) << 24)) : __bswap32_var(data
))
;
399
400 if (write(fd, &data, sizeof(afs_int32)) != sizeof(afs_int32))
401 return EIO5;
402
403 return 0;
404}
405
406static int
407_writeOriginalKeyFile(struct afsconf_dir *dir, char *fileName)
408{
409 int nkeys, fd;
410 struct opr_queue *cursor;
411 struct keyTypeList *typeEntry;
412
413 fd = open(fileName, O_RDWR0x0002 | O_CREAT0x0200 | O_TRUNC0x0400, 0600);
414 if (fd < 0)
415 return AFSCONF_FAILURE(70354688L);
416
417 typeEntry = findByType(dir, afsconf_rxkad);
418 if (typeEntry)
419 nkeys = opr_queue_Count(&typeEntry->kvnoList);
420 else
421 nkeys = 0;
422
423 if (writeWord(fd, nkeys))
424 goto fail;
425
426 if (typeEntry == NULL((void *)0))
427 goto out;
428
429 for (opr_queue_Scan(&typeEntry->kvnoList, cursor)cursor = (&typeEntry->kvnoList)->next; cursor != (&
typeEntry->kvnoList); cursor = cursor->next
) {
430 struct kvnoList *kvnoEntry;
431 struct subTypeList *subEntry;
432
433 kvnoEntry = opr_queue_Entry(cursor, struct kvnoList, link)((struct kvnoList *)((char *)(cursor)-(char *)(&((struct kvnoList
*)((void *)0))->link)))
;
434 subEntry = opr_queue_First(&kvnoEntry->subTypeList,((struct subTypeList *)((char *)((&kvnoEntry->subTypeList
)->next)-(char *)(&((struct subTypeList *)((void *)0))
->link)))
435 struct subTypeList, link)((struct subTypeList *)((char *)((&kvnoEntry->subTypeList
)->next)-(char *)(&((struct subTypeList *)((void *)0))
->link)))
;
436 if (writeWord(fd, subEntry->key->kvno))
437 goto fail;
438 if (write(fd, subEntry->key->key.val, 8) != 8)
439 goto fail;
440 }
441
442out:
443 close(fd);
444 return 0;
445
446fail:
447 close(fd);
448 return AFSCONF_FAILURE(70354688L);
449}
450
451static int
452_parseExtendedKeyFile(struct afsconf_dir *dir, char *fileName)
453{
454 int fd, i, code;
455 afs_int32 nkeys;
456 struct afsconf_typedKey *key;
457
458 fd = open(fileName, O_RDONLY0x0000);
459 if (fd < 0)
460 return 0;
461
462 code = read(fd, &nkeys, sizeof(afs_int32));
463 if (code!= sizeof(afs_int32))
464 goto fail;
465
466 nkeys=ntohl(nkeys)(__builtin_constant_p(nkeys) ? ((((__uint32_t)(nkeys)) >>
24) | ((((__uint32_t)(nkeys)) & (0xff << 16)) >>
8) | ((((__uint32_t)(nkeys)) & (0xff << 8)) <<
8) | (((__uint32_t)(nkeys)) << 24)) : __bswap32_var(nkeys
))
;
467 for(i=0; i<nkeys; i++) {
468 afs_int32 reclen;
469
470 key = afsconf_typedKey_blank();
471
472 /* The only data version we currently parse has a reclen of 16.
473 * Anything smaller indicates a corrupt key file. Anything more,
474 * and we just skip the extra fields */
475 code = read(fd, &reclen, sizeof(afs_int32));
476 if (code != sizeof(afs_int32))
477 goto fail;
478 reclen = ntohl(reclen)(__builtin_constant_p(reclen) ? ((((__uint32_t)(reclen)) >>
24) | ((((__uint32_t)(reclen)) & (0xff << 16)) >>
8) | ((((__uint32_t)(reclen)) & (0xff << 8)) <<
8) | (((__uint32_t)(reclen)) << 24)) : __bswap32_var(reclen
))
;
479 if (reclen < 16)
480 goto fail;
481 reclen-=sizeof(afs_int32);
482
483 code = read(fd, &key->type, sizeof(afs_int32));
484 if (code != sizeof(afs_int32))
485 goto fail;
486 key->type = ntohl(key->type)(__builtin_constant_p(key->type) ? ((((__uint32_t)(key->
type)) >> 24) | ((((__uint32_t)(key->type)) & (0xff
<< 16)) >> 8) | ((((__uint32_t)(key->type)) &
(0xff << 8)) << 8) | (((__uint32_t)(key->type
)) << 24)) : __bswap32_var(key->type))
;
487 reclen-=sizeof(afs_int32);
488
489 code = read(fd, &key->kvno, sizeof(afs_int32));
490 if (code != sizeof(afs_int32))
491 goto fail;
492 key->kvno = ntohl(key->kvno)(__builtin_constant_p(key->kvno) ? ((((__uint32_t)(key->
kvno)) >> 24) | ((((__uint32_t)(key->kvno)) & (0xff
<< 16)) >> 8) | ((((__uint32_t)(key->kvno)) &
(0xff << 8)) << 8) | (((__uint32_t)(key->kvno
)) << 24)) : __bswap32_var(key->kvno))
;
493 reclen-=sizeof(afs_int32);
494
495 code = read(fd, &key->subType, sizeof(afs_int32));
496 if (code != sizeof(afs_int32))
497 goto fail;
498 key->subType = ntohl(key->subType)(__builtin_constant_p(key->subType) ? ((((__uint32_t)(key->
subType)) >> 24) | ((((__uint32_t)(key->subType)) &
(0xff << 16)) >> 8) | ((((__uint32_t)(key->subType
)) & (0xff << 8)) << 8) | (((__uint32_t)(key->
subType)) << 24)) : __bswap32_var(key->subType))
;
499 reclen-=sizeof(afs_int32);
500
501 if (reclen > 0) {
502 code = lseek(fd, reclen, SEEK_CUR1);
503 if (code < 0)
504 goto fail;
505 }
506
507 code = read(fd, &reclen, sizeof(afs_int32));
508 if (code != sizeof(afs_int32))
509 goto fail;
510 reclen = ntohl(reclen)(__builtin_constant_p(reclen) ? ((((__uint32_t)(reclen)) >>
24) | ((((__uint32_t)(reclen)) & (0xff << 16)) >>
8) | ((((__uint32_t)(reclen)) & (0xff << 8)) <<
8) | (((__uint32_t)(reclen)) << 24)) : __bswap32_var(reclen
))
;
511
512 rx_opaque_alloc(&key->key, reclen);
513 code = read(fd, key->key.val, reclen);
514 if (code != reclen) {
515 rx_opaque_freeContents(&key->key);
516 free(key);
517 goto fail;
518 }
519 code = addMemoryKey(dir, key, 1);
520 afsconf_typedKey_put(&key);
521 if (code)
522 goto fail;
523 }
524 close(fd);
525 return 0;
526
527fail:
528 close(fd);
529 return EIO5;
530}
531
532
533static int
534_writeExtendedKeyFile(struct afsconf_dir *dir, char *fileName)
535{
536 int nkeys;
537 int fd;
538
539 struct keyTypeList *typeEntry;
540 struct kvnoList *kvnoEntry;
541 struct subTypeList *entry;
542 struct opr_queue *keyCursor;
543 struct opr_queue *kvnoCursor;
544 struct opr_queue *subCursor;
545
546 fd = open(fileName, O_RDWR0x0002 | O_CREAT0x0200 | O_TRUNC0x0400, 0600);
547 if (fd < 0)
548 return AFSCONF_FAILURE(70354688L);
549
550 /* Iterate over the whole in-memory key store, and write everything
551 * except keys with type rxkad into the extended key file */
552
553 /* Write a 0 key count - we'll fill it in later */
554 nkeys = 0;
555 if (writeWord(fd, 0))
556 goto fail;
557
558 for (opr_queue_Scan(&dir->keyList, keyCursor)keyCursor = (&dir->keyList)->next; keyCursor != (&
dir->keyList); keyCursor = keyCursor->next
) {
559 typeEntry = opr_queue_Entry(keyCursor, struct keyTypeList, link)((struct keyTypeList *)((char *)(keyCursor)-(char *)(&((struct
keyTypeList *)((void *)0))->link)))
;
560
561 if (typeEntry->type != afsconf_rxkad) {
562 for (opr_queue_Scan(&typeEntry->kvnoList, kvnoCursor)kvnoCursor = (&typeEntry->kvnoList)->next; kvnoCursor
!= (&typeEntry->kvnoList); kvnoCursor = kvnoCursor->
next
) {
563 kvnoEntry = opr_queue_Entry(kvnoCursor, struct kvnoList, link)((struct kvnoList *)((char *)(kvnoCursor)-(char *)(&((struct
kvnoList *)((void *)0))->link)))
;
564 for (opr_queue_Scan(&kvnoEntry->subTypeList, subCursor)subCursor = (&kvnoEntry->subTypeList)->next; subCursor
!= (&kvnoEntry->subTypeList); subCursor = subCursor->
next
) {
565 entry = opr_queue_Entry(subCursor, struct subTypeList, link)((struct subTypeList *)((char *)(subCursor)-(char *)(&((struct
subTypeList *)((void *)0))->link)))
;
566 if (writeWord(fd, 16)) /* record length */
567 goto fail;
568 if (writeWord(fd, entry->key->type))
569 goto fail;
570 if (writeWord(fd, entry->key->kvno))
571 goto fail;
572 if (writeWord(fd, entry->key->subType))
573 goto fail;
574 if (writeWord(fd, entry->key->key.len))
575 goto fail;
576 if (write(fd, entry->key->key.val,
577 entry->key->key.len) !=
578 entry->key->key.len)
579 goto fail;
580 nkeys++;
581 }
582 }
583 }
584 }
585
586 if (lseek(fd, 0, SEEK_SET0)<0)
587 goto fail;
588
589 if (writeWord(fd, nkeys))
590 goto fail;
591
592 close(fd);
593
594 return 0;
595
596fail:
597 close(fd);
598 return AFSCONF_FAILURE(70354688L);
599}
600
601int
602_afsconf_LoadKeys(struct afsconf_dir *dir)
603{
604 int code;
605 char *fileName;
606
607 /* If we're running on Windows, and we are a client, we don't have a
608 * KeyFile, so don't try and open one */
609
610#ifdef AFS_NT40_ENV
611 if (_afsconf_IsClientConfigDirectory(dir->name))
612 return 0;
613#endif /* AFS_NT40_ENV */
614
615 LOCK_GLOBAL_MUTEX;
616
617 /* Delete all of our existing keys */
618 _afsconf_FreeAllKeys(dir);
619
620 /* Start by opening the original KeyFile */
621 asnprintfrk_asnprintf(&fileName, 256, "%s/%s", dir->name, AFSDIR_KEY_FILE"KeyFile");
622 code = _parseOriginalKeyFile(dir, fileName);
623 free(fileName);
624 if (code)
625 goto out;
626
627 /* Now open the new style KeyFile */
628 asnprintfrk_asnprintf(&fileName, 256, "%s/%s", dir->name, AFSDIR_EXT_KEY_FILE"KeyFileExt");
629 code = _parseExtendedKeyFile(dir, fileName);
630 free(fileName);
631 if (code)
632 goto out;
633
634out:
635 if (code)
636 _afsconf_FreeAllKeys(dir);
637
638 UNLOCK_GLOBAL_MUTEX;
639
640 return code;
641}
642
643static int
644_afsconf_SaveKeys(struct afsconf_dir *dir)
645{
646 char *fileName;
647 int code;
648
649 /* If we're running on Windows, and we are a client, we don't have a
650 * KeyFile, so don't try and open one */
651
652#ifdef AFS_NT40_ENV
653 if (_afsconf_IsClientConfigDirectory(dir->name))
654 return 0;
655#endif /* AFS_NT40_ENV */
656
657 LOCK_GLOBAL_MUTEX;
658
659 /* Start by opening the original KeyFile */
660 asnprintfrk_asnprintf(&fileName, 256, "%s/%s", dir->name, AFSDIR_KEY_FILE"KeyFile");
661 code = _writeOriginalKeyFile(dir, fileName);
662 free(fileName);
663 if (code)
664 goto out;
665
666 /* Now open the new style KeyFile */
667 asnprintfrk_asnprintf(&fileName, 256, "%s/%s", dir->name, AFSDIR_EXT_KEY_FILE"KeyFileExt");
668 code = _writeExtendedKeyFile(dir, fileName);
669 free(fileName);
670 if (code)
671 goto out;
672
673out:
674 UNLOCK_GLOBAL_MUTEX;
675
676 return code;
677}
678
679
680
681/* get keys structure */
682int
683afsconf_GetKeys(struct afsconf_dir *dir, struct afsconf_keys *astr)
684{
685 afs_int32 code;
686 struct keyTypeList *typeEntry;
687 struct opr_queue *cursor;
688
689 memset(astr, 0, sizeof(struct afsconf_keys));
690
691 LOCK_GLOBAL_MUTEX;
692
693 code = _afsconf_Check(dir);
694 if (code)
695 goto out;
696
697 typeEntry = findByType(dir, afsconf_rxkad);
698 if (typeEntry == NULL((void *)0))
699 goto out;
700
701 for (opr_queue_Scan(&typeEntry->kvnoList, cursor)cursor = (&typeEntry->kvnoList)->next; cursor != (&
typeEntry->kvnoList); cursor = cursor->next
) {
702 struct kvnoList *kvnoEntry;
703 struct subTypeList *subEntry;
704
705 kvnoEntry = opr_queue_Entry(cursor, struct kvnoList, link)((struct kvnoList *)((char *)(cursor)-(char *)(&((struct kvnoList
*)((void *)0))->link)))
;
706 subEntry = opr_queue_First(&kvnoEntry->subTypeList,((struct subTypeList *)((char *)((&kvnoEntry->subTypeList
)->next)-(char *)(&((struct subTypeList *)((void *)0))
->link)))
707 struct subTypeList, link)((struct subTypeList *)((char *)((&kvnoEntry->subTypeList
)->next)-(char *)(&((struct subTypeList *)((void *)0))
->link)))
;
708 /* XXX - If there is more than one key in this list, it's an error */
709 astr->key[astr->nkeys].kvno = subEntry->key->kvno;
710 /* XXX - If the opaque contains a number of bytes other than 8, it's
711 * an error */
712 memcpy(&astr->key[astr->nkeys].key, subEntry->key->key.val, 8);
713 astr->nkeys++;
714 }
715
716out:
717 UNLOCK_GLOBAL_MUTEX;
718 return code;
719}
720
721afs_int32
722afsconf_GetLatestKey(struct afsconf_dir *dir, afs_int32 *kvno,
723 struct ktc_encryptionKey *key)
724{
725 struct afsconf_typedKey *typedKey;
726 int code;
727
728 code = afsconf_GetLatestKeyByTypes(dir, afsconf_rxkad, 0, &typedKey);
729 if (code)
730 return code;
731
732 /* XXX - Should check that the key is of the correct length */
733
734 /* Copy out the relevant details */
735 if (kvno != NULL((void *)0))
736 *kvno = typedKey->kvno;
737
738 if (key != NULL((void *)0))
739 memcpy(key, typedKey->key.val, 8);
740
741 afsconf_typedKey_put(&typedKey);
742
743 return 0;
744}
745
746int
747afsconf_GetKey(void *rock, int kvno, struct ktc_encryptionKey *key)
748{
749 struct afsconf_typedKey *typedKey;
750 int code;
751
752 code = afsconf_GetKeyByTypes(rock, afsconf_rxkad, kvno, 0, &typedKey);
753 if (code)
754 return code;
755
756 memcpy(key, typedKey->key.val, 8);
757
758 afsconf_typedKey_put(&typedKey);
759
760 return 0;
761}
762
763int
764afsconf_AddKey(struct afsconf_dir *dir, afs_int32 kvno, char key[8],
765 afs_int32 overwrite)
766{
767 struct rx_opaque buffer;
768 struct afsconf_typedKey *typedKey;
769 int code;
770
771 rx_opaque_alloc(&buffer, 8);
772 memcpy(buffer.val, key, 8);
773 typedKey = afsconf_typedKey_new(afsconf_rxkad, kvno, 0, &buffer);
774 if (typedKey == NULL((void *)0))
775 return AFSCONF_FAILURE(70354688L);
776
777 rx_opaque_freeContents(&buffer);
778
779 code = afsconf_AddTypedKey(dir, typedKey, overwrite);
780 afsconf_typedKey_put(&typedKey);
781 return code;
782}
783
784int
785afsconf_DeleteKey(struct afsconf_dir *dir, afs_int32 kvno)
786{
787 return afsconf_DeleteKeyByType(dir, afsconf_rxkad, kvno);
788}
789
790int
791afsconf_GetKeysByType(struct afsconf_dir *dir, afsconf_keyType type,
792 int kvno, struct afsconf_typedKeyList **keys)
793{
794 struct kvnoList *kvnoEntry;
795 int code;
796
797 LOCK_GLOBAL_MUTEX;
798
799 code = _afsconf_Check(dir);
800 if (code)
801 goto out;
802
803 kvnoEntry = findByKvno(dir, type, kvno);
804 if (kvnoEntry == NULL((void *)0)) {
805 code = AFSCONF_NOTFOUND(70354689L);
806 goto out;
807 }
808
809 code = listToArray(kvnoEntry, keys);
810
811out:
812 UNLOCK_GLOBAL_MUTEX;
813 return code;
814}
815
816int
817afsconf_GetAllKeys(struct afsconf_dir *dir, struct afsconf_typedKeyList **keys)
818{
819 int code;
820 struct afsconf_typedKeyList *retval;
821 struct opr_queue *typeCursor;
822 struct keyTypeList *typeEntry;
823 struct opr_queue *kvnoCursor;
824 struct kvnoList *kvnoEntry;
825 struct opr_queue *subCursor;
826 struct subTypeList *subEntry;
827 int count;
828
829 LOCK_GLOBAL_MUTEX;
830
831 code = _afsconf_Check(dir);
832 if (code)
833 goto out;
834
835 count = 0;
836 /* First, work out how many keys we have in total */
837 for (opr_queue_Scan(&dir->keyList, typeCursor)typeCursor = (&dir->keyList)->next; typeCursor != (
&dir->keyList); typeCursor = typeCursor->next
) {
838 typeEntry = opr_queue_Entry(typeCursor, struct keyTypeList, link)((struct keyTypeList *)((char *)(typeCursor)-(char *)(&((
struct keyTypeList *)((void *)0))->link)))
;
839 for (opr_queue_Scan(&typeEntry->kvnoList, kvnoCursor)kvnoCursor = (&typeEntry->kvnoList)->next; kvnoCursor
!= (&typeEntry->kvnoList); kvnoCursor = kvnoCursor->
next
) {
840 kvnoEntry = opr_queue_Entry(kvnoCursor, struct kvnoList, link)((struct kvnoList *)((char *)(kvnoCursor)-(char *)(&((struct
kvnoList *)((void *)0))->link)))
;
841 for (opr_queue_Scan(&kvnoEntry->subTypeList, subCursor)subCursor = (&kvnoEntry->subTypeList)->next; subCursor
!= (&kvnoEntry->subTypeList); subCursor = subCursor->
next
) {
842 subEntry = opr_queue_Entry(subCursor, struct subTypeList, link)((struct subTypeList *)((char *)(subCursor)-(char *)(&((struct
subTypeList *)((void *)0))->link)))
;
Value stored to 'subEntry' is never read
843 count++;
844 }
845 }
846 }
847
848 /* Allocate space for all of these */
849 retval = malloc(sizeof(struct afsconf_typedKeyList));
850 retval->nkeys = count;
851 retval->keys = calloc(retval->nkeys, sizeof(struct afsconf_typedKey *));
852
853 /* Populate the key list */
854 count = 0;
855 for (opr_queue_Scan(&dir->keyList, typeCursor)typeCursor = (&dir->keyList)->next; typeCursor != (
&dir->keyList); typeCursor = typeCursor->next
) {
856 typeEntry = opr_queue_Entry(typeCursor, struct keyTypeList, link)((struct keyTypeList *)((char *)(typeCursor)-(char *)(&((
struct keyTypeList *)((void *)0))->link)))
;
857 for (opr_queue_Scan(&typeEntry->kvnoList, kvnoCursor)kvnoCursor = (&typeEntry->kvnoList)->next; kvnoCursor
!= (&typeEntry->kvnoList); kvnoCursor = kvnoCursor->
next
) {
858 kvnoEntry = opr_queue_Entry(kvnoCursor, struct kvnoList, link)((struct kvnoList *)((char *)(kvnoCursor)-(char *)(&((struct
kvnoList *)((void *)0))->link)))
;
859 for (opr_queue_Scan(&kvnoEntry->subTypeList, subCursor)subCursor = (&kvnoEntry->subTypeList)->next; subCursor
!= (&kvnoEntry->subTypeList); subCursor = subCursor->
next
) {
860 subEntry = opr_queue_Entry(subCursor, struct subTypeList, link)((struct subTypeList *)((char *)(subCursor)-(char *)(&((struct
subTypeList *)((void *)0))->link)))
;
861 retval->keys[count] = afsconf_typedKey_get(subEntry->key);
862 count++;
863 }
864 }
865 }
866
867 *keys = retval;
868
869out:
870 UNLOCK_GLOBAL_MUTEX;
871 return code;
872}
873
874int
875afsconf_GetKeyByTypes(struct afsconf_dir *dir, afsconf_keyType type,
876 int kvno, int subType, struct afsconf_typedKey **key)
877{
878 int code = 0;
879 struct subTypeList *subTypeEntry;
880
881 LOCK_GLOBAL_MUTEX;
882
883 code = _afsconf_Check(dir);
884 if (code)
885 goto out;
886
887 subTypeEntry = findBySubType(dir, type, kvno, subType);
888 if (subTypeEntry == NULL((void *)0)) {
889 code = AFSCONF_NOTFOUND(70354689L);
890 goto out;
891 }
892
893 *key = afsconf_typedKey_get(subTypeEntry->key);
894
895out:
896 UNLOCK_GLOBAL_MUTEX;
897 return code;
898}
899
900static struct kvnoList *
901pickBestKvno(struct afsconf_dir *dir, afsconf_keyType type)
902{
903 struct keyTypeList *typeEntry;
904 struct kvnoList *kvnoEntry;
905
906 typeEntry = findByType(dir, type);
907 if (typeEntry == NULL((void *)0))
908 return NULL((void *)0);
909
910 /* We store all of the key lists ordered, so the last entry in the
911 * kvno list must be the highest kvno. */
912
913 kvnoEntry = opr_queue_Last(&typeEntry->kvnoList, struct kvnoList, link)((struct kvnoList *)((char *)((&typeEntry->kvnoList)->
prev)-(char *)(&((struct kvnoList *)((void *)0))->link
)))
;
914
915 /* Except, if we're in the rxkad list, we might have a bcrypt entry that
916 * has a kvno of 999. So we need to skip that one
917 */
918 while (type == afsconf_rxgk && kvnoEntry->kvno == 999) {
919 kvnoEntry = opr_queue_Prev(&typeEntry->kvnoList, struct kvnoList,((struct kvnoList *)((char *)((&typeEntry->kvnoList)->
prev)-(char *)(&((struct kvnoList *)((void *)0))->link
)))
920 link)((struct kvnoList *)((char *)((&typeEntry->kvnoList)->
prev)-(char *)(&((struct kvnoList *)((void *)0))->link
)))
;
921 if (opr_queue_IsEnd(&typeEntry->kvnoList, &kvnoEntry->link))
922 return NULL((void *)0);
923 }
924
925 return kvnoEntry;
926}
927
928
929int
930afsconf_GetLatestKeysByType(struct afsconf_dir *dir, afsconf_keyType type,
931 struct afsconf_typedKeyList **keys)
932{
933 int code;
934 struct kvnoList *kvnoEntry;
935
936 LOCK_GLOBAL_MUTEX;
937
938 code = _afsconf_Check(dir);
939 if (code)
940 goto out;
941
942
943 kvnoEntry = pickBestKvno(dir, type);
944 if (kvnoEntry == NULL((void *)0)) {
945 code = AFSCONF_NOTFOUND(70354689L);
946 goto out;
947 }
948
949 code = listToArray(kvnoEntry, keys);
950
951out:
952 UNLOCK_GLOBAL_MUTEX;
953 return code;
954}
955
956int
957afsconf_GetLatestKeyByTypes(struct afsconf_dir *dir, afsconf_keyType type,
958 int subType, struct afsconf_typedKey **key)
959{
960 int code;
961 struct kvnoList *kvnoEntry;
962 struct subTypeList *subTypeEntry;
963
964 LOCK_GLOBAL_MUTEX;
965
966 code = _afsconf_Check(dir);
967 if (code)
968 goto out;
969
970 kvnoEntry = pickBestKvno(dir, type);
971 if (kvnoEntry == NULL((void *)0)) {
972 code = AFSCONF_NOTFOUND(70354689L);
973 goto out;
974 }
975
976 subTypeEntry = findInKvnoList(kvnoEntry, subType);
977 if (subTypeEntry == NULL((void *)0)) {
978 code = AFSCONF_NOTFOUND(70354689L);
979 goto out;
980 }
981
982 *key = afsconf_typedKey_get(subTypeEntry->key);
983
984out:
985 UNLOCK_GLOBAL_MUTEX;
986 return code;
987}
988
989void
990afsconf_PutTypedKeyList(struct afsconf_typedKeyList **keys)
991{
992 int i;
993
994 for (i=0;i<(*keys)->nkeys;i++)
995 afsconf_typedKey_put(&((*keys)->keys[i]));
996 free((*keys)->keys);
997 free(*keys);
998 *keys = NULL((void *)0);
999}
1000
1001static struct afsconf_typedKey *
1002afsconf_typedKey_blank(void)
1003{
1004 struct afsconf_typedKey *key;
1005
1006 key = malloc(sizeof(struct afsconf_typedKey));
1007 if (key == NULL((void *)0))
1008 return NULL((void *)0);
1009
1010 memset(key, 0, sizeof(struct afsconf_typedKey));
1011 rx_atomic_set(&key->refcnt, 1);
1012
1013 return key;
1014}
1015
1016struct afsconf_typedKey *
1017afsconf_typedKey_new(afsconf_keyType type, int kvno, int subType,
1018 struct rx_opaque *keyMaterial)
1019{
1020 struct afsconf_typedKey *key;
1021 int code;
1022
1023 key = afsconf_typedKey_blank();
1024 if (key == NULL((void *)0))
1025 return key;
1026
1027 key->type = type;
1028 key->kvno = kvno;
1029 key->subType = subType;
1030
1031 code = rx_opaque_copy(&key->key, keyMaterial);
1032 if (code != 0) {
1033 free(key);
1034 return NULL((void *)0);
1035 }
1036
1037 return key;
1038}
1039
1040void
1041afsconf_typedKey_free(struct afsconf_typedKey **key)
1042{
1043 rx_opaque_freeContents(&(*key)->key);
1044 free(*key);
1045 *key = NULL((void *)0);
1046}
1047
1048struct afsconf_typedKey *
1049afsconf_typedKey_get(struct afsconf_typedKey *key)
1050{
1051 rx_atomic_inc(&key->refcnt);
1052 return key;
1053}
1054
1055void
1056afsconf_typedKey_put(struct afsconf_typedKey **key)
1057{
1058 if (rx_atomic_dec_and_read(&(*key)->refcnt) == 0)
1059 afsconf_typedKey_free(key);
1060 else
1061 *key = NULL((void *)0);
1062}
1063
1064void
1065afsconf_typedKey_values(struct afsconf_typedKey *key, afsconf_keyType *type,
1066 int *kvno, int *subType, struct rx_opaque **material)
1067{
1068 *type = key->type;
1069 *kvno = key->kvno;
1070 *subType = key->subType;
1071 *material = &key->key;
1072}
1073
1074int
1075afsconf_AddTypedKey(struct afsconf_dir *dir,
1076 struct afsconf_typedKey *key,
1077 int overwrite)
1078{
1079 int code;
1080
1081 LOCK_GLOBAL_MUTEX;
1082
1083 code = _afsconf_Check(dir);
1084 if (code)
1085 goto out;
1086
1087 if (key->type == afsconf_rxkad) {
1088 /* There are restrictions on rxkad keys so that we can still
1089 * return them using the old interface. We only enforce the
1090 * same restrictions as that interface does - that is, we don't
1091 * check that the key we're passed is a valid DES key */
1092 if (key->key.len != 8 || key->subType != 0) {
1093 code = AFSCONF_BADKEY(70354697L);
1094 goto out;
1095 }
1096 }
1097
1098 code = addMemoryKey(dir, key, overwrite);
1099 if (code)
1100 goto out;
1101
1102 code = _afsconf_SaveKeys(dir);
1103 _afsconf_Touch(dir);
1104
1105out:
1106 UNLOCK_GLOBAL_MUTEX;
1107 return code;
1108}
1109
1110int
1111afsconf_DeleteKeyByType(struct afsconf_dir *dir,
1112 afsconf_keyType type, int kvno)
1113{
1114 struct keyTypeList *typeEntry;
1115 struct kvnoList *kvnoEntry;
1116 int code;
1117
1118 LOCK_GLOBAL_MUTEX;
1119
1120 code = _afsconf_Check(dir);
1121 if (code)
1122 goto out;
1123
1124 typeEntry = findByType(dir, type);
1125 if (typeEntry == NULL((void *)0)) {
1126 code = AFSCONF_NOTFOUND(70354689L);
1127 goto out;
1128 }
1129
1130 kvnoEntry = findInTypeList(typeEntry, kvno);
1131 if (kvnoEntry == NULL((void *)0)) {
1132 code = AFSCONF_NOTFOUND(70354689L);
1133 goto out;
1134 }
1135
1136 deleteKvnoEntry(kvnoEntry);
1137
1138 /* Remove the typeEntry, if it has no sub elements */
1139 if (opr_queue_IsEmpty(&typeEntry->kvnoList)) {
1140 opr_queue_Remove(&typeEntry->link);
1141 free(typeEntry);
1142 }
1143
1144 code = _afsconf_SaveKeys(dir);
1145 _afsconf_Touch(dir);
1146
1147out:
1148 UNLOCK_GLOBAL_MUTEX;
1149 return code;
1150}
1151
1152int
1153afsconf_DeleteKeyBySubType(struct afsconf_dir *dir,
1154 afsconf_keyType type, int kvno, int subType)
1155{
1156 struct keyTypeList *typeEntry;
1157 struct kvnoList *kvnoEntry;
1158 struct subTypeList *subTypeEntry;
1159 int code;
1160
1161 LOCK_GLOBAL_MUTEX;
1162
1163 code = _afsconf_Check(dir);
1164 if (code)
1165 goto out;
1166
1167 typeEntry = findByType(dir, type);
1168 if (typeEntry == NULL((void *)0))
1169 return AFSCONF_NOTFOUND(70354689L);
1170
1171 kvnoEntry = findInTypeList(typeEntry, kvno);
1172 if (kvnoEntry == NULL((void *)0))
1173 return AFSCONF_NOTFOUND(70354689L);
1174
1175 subTypeEntry = findInKvnoList(kvnoEntry, subType);
1176 if (subTypeEntry == NULL((void *)0))
1177 return AFSCONF_NOTFOUND(70354689L);
1178
1179 /* Remove the subTypeEntry */
1180 afsconf_typedKey_put(&subTypeEntry->key);
1181 opr_queue_Remove(&subTypeEntry->link);
1182 free(subTypeEntry);
1183
1184 /* Remove the kvnoEntry, if it has no sub elements */
1185 if (opr_queue_IsEmpty(&kvnoEntry->subTypeList)) {
1186 opr_queue_Remove(&kvnoEntry->link);
1187 free(kvnoEntry);
1188 }
1189
1190 /* Remove the typeEntry, if it has no sub elements */
1191 if (opr_queue_IsEmpty(&typeEntry->kvnoList)) {
1192 opr_queue_Remove(&typeEntry->link);
1193 free(typeEntry);
1194 }
1195
1196 code = _afsconf_SaveKeys(dir);
1197 _afsconf_Touch(dir);
1198
1199out:
1200 UNLOCK_GLOBAL_MUTEX;
1201 return code;
1202}
1203
1204int
1205afsconf_DeleteTypedKey(struct afsconf_dir *dir, struct afsconf_typedKey *key)
1206{
1207 return afsconf_DeleteKeyBySubType(dir, key->type, key->kvno, key->subType);
1208}