2 * Copyright (c) 2010 Your File System Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
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.
25 #include <afsconfig.h>
26 #include <afs/param.h>
30 #include <opr/queue.h>
32 /* Need rx/rx.h to get working assert(), used by LOCK_GLOBAL_MUTEX */
34 #include <rx/rx_atomic.h>
37 #include <afs/pthread_glock.h>
38 #include <afs/afsutil.h>
40 #include "cellconfig.h"
44 struct afsconf_typedKey {
52 static struct afsconf_typedKey *afsconf_typedKey_blank(void);
54 /* Memory storage for keyfile contents. */
57 struct opr_queue link;
59 struct opr_queue kvnoList;
63 struct opr_queue link;
65 struct opr_queue subTypeList;
69 struct opr_queue link;
71 struct afsconf_typedKey *key;
75 listToArray(struct kvnoList *kvnoEntry, struct afsconf_typedKeyList **keys)
77 struct afsconf_typedKeyList *retval;
78 struct opr_queue *cursor;
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);
85 if (retval->nkeys > 0) {
86 retval->keys = calloc(retval->nkeys, sizeof(struct afsconf_typedKey *));
89 for(opr_queue_Scan(&kvnoEntry->subTypeList, cursor)) {
90 struct subTypeList *entry;
92 entry = opr_queue_Entry(cursor, struct subTypeList, link);
93 retval->keys[i] = afsconf_typedKey_get(entry->key);
104 static struct keyTypeList *
105 findByType(struct afsconf_dir *dir, afsconf_keyType type)
107 struct opr_queue *cursor;
108 struct keyTypeList *entry = NULL;
110 for (opr_queue_Scan(&dir->keyList, cursor)) {
111 entry = opr_queue_Entry(cursor, struct keyTypeList, link);
112 if (entry->type >= type)
115 if (entry == NULL || entry->type != type)
121 static struct kvnoList *
122 findInTypeList(struct keyTypeList *parent, int kvno)
124 struct opr_queue *cursor;
125 struct kvnoList *entry = NULL;
127 for (opr_queue_Scan(&parent->kvnoList, cursor)) {
128 entry = opr_queue_Entry(cursor, struct kvnoList, link);
129 if (entry->kvno >= kvno)
132 if (entry == NULL || entry->kvno != kvno)
138 static struct kvnoList *
139 findByKvno(struct afsconf_dir *dir, afsconf_keyType type, int kvno)
141 struct keyTypeList *entry;
142 entry = findByType(dir, type);
147 return findInTypeList(entry, kvno);
150 static struct subTypeList *
151 findInKvnoList(struct kvnoList *parent, int subType)
153 struct opr_queue *cursor;
154 struct subTypeList *entry = NULL;
156 for (opr_queue_Scan(&parent->subTypeList, cursor)) {
157 entry = opr_queue_Entry(cursor, struct subTypeList, link);
158 if (entry->subType >= subType)
161 if (entry == NULL || entry->subType != subType)
167 static struct subTypeList *
168 findBySubType(struct afsconf_dir *dir, afsconf_keyType type, int kvno,
171 struct kvnoList *entry;
173 entry = findByKvno(dir, type, kvno);
177 return findInKvnoList(entry, subType);
183 addMemoryKey(struct afsconf_dir *dir, struct afsconf_typedKey *key,
186 struct opr_queue *cursor;
187 struct keyTypeList *typeEntry = NULL;
188 struct kvnoList *kvnoEntry = NULL;
189 struct subTypeList *subType = NULL;
191 /* Find the place in the keyType list to insert the key into */
192 for (opr_queue_Scan(&dir->keyList, cursor)) {
193 typeEntry = opr_queue_Entry(cursor, struct keyTypeList, link);
194 if (typeEntry->type >= key->type)
198 if (typeEntry == NULL || typeEntry->type != key->type) {
199 struct keyTypeList *list;
201 list = malloc(sizeof(struct keyTypeList));
202 opr_queue_Init(&list->kvnoList);
203 list->type = key->type;
204 opr_queue_InsertBefore(cursor, &list->link);
208 /* And the place in the kvno list */
209 for (opr_queue_Scan(&typeEntry->kvnoList, cursor)) {
210 kvnoEntry = opr_queue_Entry(cursor, struct kvnoList, link);
211 if (kvnoEntry->kvno >= key->kvno)
215 if (kvnoEntry == NULL || kvnoEntry->kvno != key->kvno) {
216 struct kvnoList *list;
218 /* In the legacy rxkad key case, we need to check to see if we've
219 * gone over the maximum of 8 keys */
220 if (key->type == afsconf_rxkad &&
221 opr_queue_Count(&typeEntry->kvnoList)>=8)
224 list = malloc(sizeof(struct kvnoList));
225 opr_queue_Init(&list->subTypeList);
226 list->kvno = key->kvno;
227 opr_queue_InsertBefore(cursor, &list->link);
231 /* And the place in the subtype list */
232 for (opr_queue_Scan(&kvnoEntry->subTypeList, cursor)) {
233 subType = opr_queue_Entry(cursor, struct subTypeList, link);
234 if (subType->subType >= key->subType)
238 if (subType == NULL || subType->subType != key->subType) {
239 struct subTypeList *list;
241 list = malloc(sizeof(struct subTypeList));
242 list->subType = key->subType;
243 list->key = afsconf_typedKey_get(key);
244 opr_queue_InsertBefore(cursor, &list->link);
247 /* Give up our reference to the existing key */
248 afsconf_typedKey_put(&subType->key);
249 subType->key = afsconf_typedKey_get(key);
251 return AFSCONF_KEYINUSE;
258 deleteKvnoEntry(struct kvnoList *entry)
260 struct subTypeList *subTypeEntry;
262 while (!opr_queue_IsEmpty(&entry->subTypeList)) {
263 subTypeEntry = opr_queue_First(&entry->subTypeList,
264 struct subTypeList, link);
265 afsconf_typedKey_put(&subTypeEntry->key);
266 opr_queue_Remove(&subTypeEntry->link);
269 opr_queue_Remove(&entry->link);
274 _afsconf_FreeAllKeys(struct afsconf_dir *dir)
276 struct keyTypeList *typeEntry;
277 struct kvnoList *kvnoEntry;
279 while (!opr_queue_IsEmpty(&dir->keyList)) {
280 typeEntry = opr_queue_First(&dir->keyList, struct keyTypeList, link);
282 while (!opr_queue_IsEmpty(&typeEntry->kvnoList)) {
283 kvnoEntry = opr_queue_First(&typeEntry->kvnoList,
284 struct kvnoList, link);
286 deleteKvnoEntry(kvnoEntry);
288 opr_queue_Remove(&typeEntry->link);
293 _afsconf_InitKeys(struct afsconf_dir *dir)
295 opr_queue_Init(&dir->keyList);
298 /* Disk based key storage. This is made somewhat complicated because we
299 * store keys in more than one place - keys of type 'rxkad' (0) are stored
300 * in the original KeyFile, so that we can continue to be compatible with
301 * utilities that directly modify that file.
303 * All other keys are stored in the file KeyFileEx, which has the following
305 * 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
306 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
308 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
310 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
314 * The version number is 1 at present. Version numbers higher than 1
315 * indicate a keyfile that is not backwards compatible with this
318 * Key data is a sequence of the following records (note that these are
319 * not word aligned - the next record begins where the previous one ends)
321 * 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
322 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
323 * | meta-data length |
324 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
326 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
327 * | key version number |
328 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
330 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
331 * | length of key material |
332 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
336 * All values are expressed in network byte order
338 * Meta data length is the length of the initial portion of the record
339 * (itself, key type, key version number, and key sub type). In this
340 * version of the specification it would be 16. It is there to allow
341 * additional fields to be added to this specification at a later date
342 * without breaking backwards compatibility.
345 /* XXX - We need to be careful with failure here, because failure due to
346 * a missing file is fine, but failure due to read errors needs to be trapped,
347 * before it results in a corrupted file being written out.
351 _parseOriginalKeyFile(struct afsconf_dir *dir, char *fileName)
353 int fd, code, nkeys, i;
354 struct afsconf_typedKey *key;
356 fd = open(fileName, O_RDONLY);
360 code = read(fd, &nkeys, sizeof(afs_int32));
361 if (code!= sizeof(afs_int32))
365 for(i=0; i<nkeys; i++) {
367 key = afsconf_typedKey_blank();
371 key->type = afsconf_rxkad;
374 code = read(fd, &key->kvno, sizeof(afs_int32));
375 if (code != sizeof(afs_int32)) {
379 key->kvno = ntohl(key->kvno);
381 rx_opaque_alloc(&key->key, 8);
382 code = read(fd, key->key.val, 8);
384 rx_opaque_freeContents(&key->key);
388 code = addMemoryKey(dir, key, 1);
389 afsconf_typedKey_put(&key); /* Done with key */
402 writeWord(int fd, afs_int32 data)
407 if (write(fd, &data, sizeof(afs_int32)) != sizeof(afs_int32))
414 _writeOriginalKeyFile(struct afsconf_dir *dir, char *fileName)
417 struct opr_queue *cursor;
418 struct keyTypeList *typeEntry;
420 fd = open(fileName, O_RDWR | O_CREAT | O_TRUNC, 0600);
422 return AFSCONF_FAILURE;
424 typeEntry = findByType(dir, afsconf_rxkad);
426 nkeys = opr_queue_Count(&typeEntry->kvnoList);
430 if (writeWord(fd, nkeys))
433 if (typeEntry == NULL)
436 for (opr_queue_Scan(&typeEntry->kvnoList, cursor)) {
437 struct kvnoList *kvnoEntry;
438 struct subTypeList *subEntry;
440 kvnoEntry = opr_queue_Entry(cursor, struct kvnoList, link);
441 subEntry = opr_queue_First(&kvnoEntry->subTypeList,
442 struct subTypeList, link);
443 if (writeWord(fd, subEntry->key->kvno))
445 if (write(fd, subEntry->key->key.val, 8) != 8)
455 return AFSCONF_FAILURE;
459 _parseExtendedKeyFile(struct afsconf_dir *dir, char *fileName)
463 struct afsconf_typedKey *key = NULL;
465 fd = open(fileName, O_RDONLY);
469 code = read(fd, &nkeys, sizeof(afs_int32));
470 if (code!= sizeof(afs_int32))
474 for(i=0; i<nkeys; i++) {
477 key = afsconf_typedKey_blank();
481 /* The only data version we currently parse has a reclen of 16.
482 * Anything smaller indicates a corrupt key file. Anything more,
483 * and we just skip the extra fields */
484 code = read(fd, &reclen, sizeof(afs_int32));
485 if (code != sizeof(afs_int32))
487 reclen = ntohl(reclen);
490 reclen-=sizeof(afs_int32);
492 code = read(fd, &key->type, sizeof(afs_int32));
493 if (code != sizeof(afs_int32))
495 key->type = ntohl(key->type);
496 reclen-=sizeof(afs_int32);
498 code = read(fd, &key->kvno, sizeof(afs_int32));
499 if (code != sizeof(afs_int32))
501 key->kvno = ntohl(key->kvno);
502 reclen-=sizeof(afs_int32);
504 code = read(fd, &key->subType, sizeof(afs_int32));
505 if (code != sizeof(afs_int32))
507 key->subType = ntohl(key->subType);
508 reclen-=sizeof(afs_int32);
511 code = lseek(fd, reclen, SEEK_CUR);
516 code = read(fd, &reclen, sizeof(afs_int32));
517 if (code != sizeof(afs_int32))
519 reclen = ntohl(reclen);
521 rx_opaque_alloc(&key->key, reclen);
522 code = read(fd, key->key.val, reclen);
523 if (code != reclen) {
524 rx_opaque_freeContents(&key->key);
527 code = addMemoryKey(dir, key, 1);
528 afsconf_typedKey_put(&key);
537 afsconf_typedKey_put(&key);
545 _writeExtendedKeyFile(struct afsconf_dir *dir, char *fileName)
550 struct keyTypeList *typeEntry;
551 struct kvnoList *kvnoEntry;
552 struct subTypeList *entry;
553 struct opr_queue *keyCursor;
554 struct opr_queue *kvnoCursor;
555 struct opr_queue *subCursor;
557 fd = open(fileName, O_RDWR | O_CREAT | O_TRUNC, 0600);
559 return AFSCONF_FAILURE;
561 /* Iterate over the whole in-memory key store, and write everything
562 * except keys with type rxkad into the extended key file */
564 /* Write a 0 key count - we'll fill it in later */
566 if (writeWord(fd, 0))
569 for (opr_queue_Scan(&dir->keyList, keyCursor)) {
570 typeEntry = opr_queue_Entry(keyCursor, struct keyTypeList, link);
572 if (typeEntry->type != afsconf_rxkad) {
573 for (opr_queue_Scan(&typeEntry->kvnoList, kvnoCursor)) {
574 kvnoEntry = opr_queue_Entry(kvnoCursor, struct kvnoList, link);
575 for (opr_queue_Scan(&kvnoEntry->subTypeList, subCursor)) {
576 entry = opr_queue_Entry(subCursor, struct subTypeList, link);
577 if (writeWord(fd, 16)) /* record length */
579 if (writeWord(fd, entry->key->type))
581 if (writeWord(fd, entry->key->kvno))
583 if (writeWord(fd, entry->key->subType))
585 if (writeWord(fd, entry->key->key.len))
587 if (write(fd, entry->key->key.val,
588 entry->key->key.len) !=
597 if (lseek(fd, 0, SEEK_SET)<0)
600 if (writeWord(fd, nkeys))
609 return AFSCONF_FAILURE;
613 _afsconf_LoadKeys(struct afsconf_dir *dir)
618 /* If we're running on Windows, and we are a client, we don't have a
619 * KeyFile, so don't try and open one */
622 if (_afsconf_IsClientConfigDirectory(dir->name))
624 #endif /* AFS_NT40_ENV */
628 /* Delete all of our existing keys */
629 _afsconf_FreeAllKeys(dir);
631 /* Start by opening the original KeyFile */
632 asnprintf(&fileName, 256, "%s/%s", dir->name, AFSDIR_KEY_FILE);
633 code = _parseOriginalKeyFile(dir, fileName);
638 /* Now open the new style KeyFile */
639 asnprintf(&fileName, 256, "%s/%s", dir->name, AFSDIR_EXT_KEY_FILE);
640 code = _parseExtendedKeyFile(dir, fileName);
647 _afsconf_FreeAllKeys(dir);
655 _afsconf_SaveKeys(struct afsconf_dir *dir)
660 /* If we're running on Windows, and we are a client, we don't have a
661 * KeyFile, so don't try and open one */
664 if (_afsconf_IsClientConfigDirectory(dir->name))
666 #endif /* AFS_NT40_ENV */
670 /* Start by opening the original KeyFile */
671 asnprintf(&fileName, 256, "%s/%s", dir->name, AFSDIR_KEY_FILE);
672 code = _writeOriginalKeyFile(dir, fileName);
677 /* Now open the new style KeyFile */
678 asnprintf(&fileName, 256, "%s/%s", dir->name, AFSDIR_EXT_KEY_FILE);
679 code = _writeExtendedKeyFile(dir, fileName);
692 /* get keys structure */
694 afsconf_GetKeys(struct afsconf_dir *dir, struct afsconf_keys *astr)
697 struct keyTypeList *typeEntry;
698 struct opr_queue *cursor;
700 memset(astr, 0, sizeof(struct afsconf_keys));
704 code = _afsconf_Check(dir);
708 typeEntry = findByType(dir, afsconf_rxkad);
709 if (typeEntry == NULL)
712 for (opr_queue_Scan(&typeEntry->kvnoList, cursor)) {
713 struct kvnoList *kvnoEntry;
714 struct subTypeList *subEntry;
716 kvnoEntry = opr_queue_Entry(cursor, struct kvnoList, link);
717 subEntry = opr_queue_First(&kvnoEntry->subTypeList,
718 struct subTypeList, link);
719 /* XXX - If there is more than one key in this list, it's an error */
720 astr->key[astr->nkeys].kvno = subEntry->key->kvno;
721 /* XXX - If the opaque contains a number of bytes other than 8, it's
723 memcpy(&astr->key[astr->nkeys].key, subEntry->key->key.val, 8);
733 afsconf_GetLatestKey(struct afsconf_dir *dir, afs_int32 *kvno,
734 struct ktc_encryptionKey *key)
736 struct afsconf_typedKey *typedKey;
739 code = afsconf_GetLatestKeyByTypes(dir, afsconf_rxkad, 0, &typedKey);
743 /* XXX - Should check that the key is of the correct length */
745 /* Copy out the relevant details */
747 *kvno = typedKey->kvno;
750 memcpy(key, typedKey->key.val, 8);
752 afsconf_typedKey_put(&typedKey);
758 afsconf_GetKey(void *rock, int kvno, struct ktc_encryptionKey *key)
760 struct afsconf_typedKey *typedKey;
763 code = afsconf_GetKeyByTypes(rock, afsconf_rxkad, kvno, 0, &typedKey);
767 memcpy(key, typedKey->key.val, 8);
769 afsconf_typedKey_put(&typedKey);
775 afsconf_AddKey(struct afsconf_dir *dir, afs_int32 kvno, char key[8],
778 struct rx_opaque buffer;
779 struct afsconf_typedKey *typedKey;
782 rx_opaque_alloc(&buffer, 8);
783 memcpy(buffer.val, key, 8);
784 typedKey = afsconf_typedKey_new(afsconf_rxkad, kvno, 0, &buffer);
785 if (typedKey == NULL)
786 return AFSCONF_FAILURE;
788 rx_opaque_freeContents(&buffer);
790 code = afsconf_AddTypedKey(dir, typedKey, overwrite);
791 afsconf_typedKey_put(&typedKey);
796 afsconf_DeleteKey(struct afsconf_dir *dir, afs_int32 kvno)
798 return afsconf_DeleteKeyByType(dir, afsconf_rxkad, kvno);
802 afsconf_GetKeysByType(struct afsconf_dir *dir, afsconf_keyType type,
803 int kvno, struct afsconf_typedKeyList **keys)
805 struct kvnoList *kvnoEntry;
810 code = _afsconf_Check(dir);
814 kvnoEntry = findByKvno(dir, type, kvno);
815 if (kvnoEntry == NULL) {
816 code = AFSCONF_NOTFOUND;
820 code = listToArray(kvnoEntry, keys);
828 afsconf_GetAllKeys(struct afsconf_dir *dir, struct afsconf_typedKeyList **keys)
831 struct afsconf_typedKeyList *retval;
832 struct opr_queue *typeCursor;
833 struct keyTypeList *typeEntry;
834 struct opr_queue *kvnoCursor;
835 struct kvnoList *kvnoEntry;
836 struct opr_queue *subCursor;
837 struct subTypeList *subEntry;
842 code = _afsconf_Check(dir);
847 /* First, work out how many keys we have in total */
848 for (opr_queue_Scan(&dir->keyList, typeCursor)) {
849 typeEntry = opr_queue_Entry(typeCursor, struct keyTypeList, link);
850 for (opr_queue_Scan(&typeEntry->kvnoList, kvnoCursor)) {
851 kvnoEntry = opr_queue_Entry(kvnoCursor, struct kvnoList, link);
852 for (opr_queue_Scan(&kvnoEntry->subTypeList, subCursor))
857 /* Allocate space for all of these */
858 retval = malloc(sizeof(struct afsconf_typedKeyList));
859 retval->nkeys = count;
862 retval->keys = calloc(retval->nkeys,
863 sizeof(struct afsconf_typedKey *));
865 /* Populate the key list */
867 for (opr_queue_Scan(&dir->keyList, typeCursor)) {
868 typeEntry = opr_queue_Entry(typeCursor,
869 struct keyTypeList, link);
870 for (opr_queue_Scan(&typeEntry->kvnoList, kvnoCursor)) {
871 kvnoEntry = opr_queue_Entry(kvnoCursor,
872 struct kvnoList, link);
873 for (opr_queue_Scan(&kvnoEntry->subTypeList, subCursor)) {
874 subEntry = opr_queue_Entry(subCursor,
875 struct subTypeList, link);
876 retval->keys[count] = afsconf_typedKey_get(subEntry->key);
893 afsconf_GetKeyByTypes(struct afsconf_dir *dir, afsconf_keyType type,
894 int kvno, int subType, struct afsconf_typedKey **key)
897 struct subTypeList *subTypeEntry;
901 code = _afsconf_Check(dir);
905 subTypeEntry = findBySubType(dir, type, kvno, subType);
906 if (subTypeEntry == NULL) {
907 code = AFSCONF_NOTFOUND;
911 *key = afsconf_typedKey_get(subTypeEntry->key);
918 static struct kvnoList *
919 pickBestKvno(struct afsconf_dir *dir, afsconf_keyType type)
921 struct keyTypeList *typeEntry;
922 struct kvnoList *kvnoEntry;
924 typeEntry = findByType(dir, type);
925 if (typeEntry == NULL)
928 /* We store all of the key lists ordered, so the last entry in the
929 * kvno list must be the highest kvno. */
931 kvnoEntry = opr_queue_Last(&typeEntry->kvnoList, struct kvnoList, link);
933 /* Except, if we're in the rxkad list, we might have a bcrypt entry that
934 * has a kvno of 999. So we need to skip that one
936 while (type == afsconf_rxgk && kvnoEntry->kvno == 999) {
937 kvnoEntry = opr_queue_Prev(&typeEntry->kvnoList, struct kvnoList,
939 if (opr_queue_IsEnd(&typeEntry->kvnoList, &kvnoEntry->link))
948 afsconf_GetLatestKeysByType(struct afsconf_dir *dir, afsconf_keyType type,
949 struct afsconf_typedKeyList **keys)
952 struct kvnoList *kvnoEntry;
956 code = _afsconf_Check(dir);
961 kvnoEntry = pickBestKvno(dir, type);
962 if (kvnoEntry == NULL) {
963 code = AFSCONF_NOTFOUND;
967 code = listToArray(kvnoEntry, keys);
975 afsconf_GetLatestKeyByTypes(struct afsconf_dir *dir, afsconf_keyType type,
976 int subType, struct afsconf_typedKey **key)
979 struct kvnoList *kvnoEntry;
980 struct subTypeList *subTypeEntry;
984 code = _afsconf_Check(dir);
988 kvnoEntry = pickBestKvno(dir, type);
989 if (kvnoEntry == NULL) {
990 code = AFSCONF_NOTFOUND;
994 subTypeEntry = findInKvnoList(kvnoEntry, subType);
995 if (subTypeEntry == NULL) {
996 code = AFSCONF_NOTFOUND;
1000 *key = afsconf_typedKey_get(subTypeEntry->key);
1003 UNLOCK_GLOBAL_MUTEX;
1008 afsconf_PutTypedKeyList(struct afsconf_typedKeyList **keys)
1012 for (i=0;i<(*keys)->nkeys;i++)
1013 afsconf_typedKey_put(&((*keys)->keys[i]));
1015 if ((*keys)->keys != NULL)
1016 free((*keys)->keys);
1022 static struct afsconf_typedKey *
1023 afsconf_typedKey_blank(void)
1025 struct afsconf_typedKey *key;
1027 key = calloc(1, sizeof(struct afsconf_typedKey));
1031 rx_atomic_set(&key->refcnt, 1);
1036 struct afsconf_typedKey *
1037 afsconf_typedKey_new(afsconf_keyType type, int kvno, int subType,
1038 struct rx_opaque *keyMaterial)
1040 struct afsconf_typedKey *key;
1043 key = afsconf_typedKey_blank();
1049 key->subType = subType;
1051 code = rx_opaque_copy(&key->key, keyMaterial);
1061 afsconf_typedKey_free(struct afsconf_typedKey **key)
1063 rx_opaque_freeContents(&(*key)->key);
1068 struct afsconf_typedKey *
1069 afsconf_typedKey_get(struct afsconf_typedKey *key)
1071 rx_atomic_inc(&key->refcnt);
1076 afsconf_typedKey_put(struct afsconf_typedKey **key)
1078 if (rx_atomic_dec_and_read(&(*key)->refcnt) == 0)
1079 afsconf_typedKey_free(key);
1085 afsconf_typedKey_values(struct afsconf_typedKey *key, afsconf_keyType *type,
1086 int *kvno, int *subType, struct rx_opaque **material)
1090 *subType = key->subType;
1091 *material = &key->key;
1095 afsconf_AddTypedKey(struct afsconf_dir *dir,
1096 struct afsconf_typedKey *key,
1103 code = _afsconf_Check(dir);
1107 if (key->type == afsconf_rxkad) {
1108 /* There are restrictions on rxkad keys so that we can still
1109 * return them using the old interface. We only enforce the
1110 * same restrictions as that interface does - that is, we don't
1111 * check that the key we're passed is a valid DES key */
1112 if (key->key.len != 8 || key->subType != 0) {
1113 code = AFSCONF_BADKEY;
1118 code = addMemoryKey(dir, key, overwrite);
1122 code = _afsconf_SaveKeys(dir);
1123 _afsconf_Touch(dir);
1126 UNLOCK_GLOBAL_MUTEX;
1131 afsconf_DeleteKeyByType(struct afsconf_dir *dir,
1132 afsconf_keyType type, int kvno)
1134 struct keyTypeList *typeEntry;
1135 struct kvnoList *kvnoEntry;
1140 code = _afsconf_Check(dir);
1144 typeEntry = findByType(dir, type);
1145 if (typeEntry == NULL) {
1146 code = AFSCONF_NOTFOUND;
1150 kvnoEntry = findInTypeList(typeEntry, kvno);
1151 if (kvnoEntry == NULL) {
1152 code = AFSCONF_NOTFOUND;
1156 deleteKvnoEntry(kvnoEntry);
1158 /* Remove the typeEntry, if it has no sub elements */
1159 if (opr_queue_IsEmpty(&typeEntry->kvnoList)) {
1160 opr_queue_Remove(&typeEntry->link);
1164 code = _afsconf_SaveKeys(dir);
1165 _afsconf_Touch(dir);
1168 UNLOCK_GLOBAL_MUTEX;
1173 afsconf_DeleteKeyBySubType(struct afsconf_dir *dir,
1174 afsconf_keyType type, int kvno, int subType)
1176 struct keyTypeList *typeEntry;
1177 struct kvnoList *kvnoEntry;
1178 struct subTypeList *subTypeEntry;
1183 code = _afsconf_Check(dir);
1187 typeEntry = findByType(dir, type);
1188 if (typeEntry == NULL)
1189 return AFSCONF_NOTFOUND;
1191 kvnoEntry = findInTypeList(typeEntry, kvno);
1192 if (kvnoEntry == NULL)
1193 return AFSCONF_NOTFOUND;
1195 subTypeEntry = findInKvnoList(kvnoEntry, subType);
1196 if (subTypeEntry == NULL)
1197 return AFSCONF_NOTFOUND;
1199 /* Remove the subTypeEntry */
1200 afsconf_typedKey_put(&subTypeEntry->key);
1201 opr_queue_Remove(&subTypeEntry->link);
1204 /* Remove the kvnoEntry, if it has no sub elements */
1205 if (opr_queue_IsEmpty(&kvnoEntry->subTypeList)) {
1206 opr_queue_Remove(&kvnoEntry->link);
1210 /* Remove the typeEntry, if it has no sub elements */
1211 if (opr_queue_IsEmpty(&typeEntry->kvnoList)) {
1212 opr_queue_Remove(&typeEntry->link);
1216 code = _afsconf_SaveKeys(dir);
1217 _afsconf_Touch(dir);
1220 UNLOCK_GLOBAL_MUTEX;
1225 afsconf_DeleteTypedKey(struct afsconf_dir *dir, struct afsconf_typedKey *key)
1227 return afsconf_DeleteKeyBySubType(dir, key->type, key->kvno, key->subType);