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();
369 key->type = afsconf_rxkad;
372 code = read(fd, &key->kvno, sizeof(afs_int32));
373 if (code != sizeof(afs_int32)) {
377 key->kvno = ntohl(key->kvno);
379 rx_opaque_alloc(&key->key, 8);
380 code = read(fd, key->key.val, 8);
382 rx_opaque_freeContents(&key->key);
386 code = addMemoryKey(dir, key, 1);
387 afsconf_typedKey_put(&key); /* Done with key */
400 writeWord(int fd, afs_int32 data)
405 if (write(fd, &data, sizeof(afs_int32)) != sizeof(afs_int32))
412 _writeOriginalKeyFile(struct afsconf_dir *dir, char *fileName)
415 struct opr_queue *cursor;
416 struct keyTypeList *typeEntry;
418 fd = open(fileName, O_RDWR | O_CREAT | O_TRUNC, 0600);
420 return AFSCONF_FAILURE;
422 typeEntry = findByType(dir, afsconf_rxkad);
424 nkeys = opr_queue_Count(&typeEntry->kvnoList);
428 if (writeWord(fd, nkeys))
431 if (typeEntry == NULL)
434 for (opr_queue_Scan(&typeEntry->kvnoList, cursor)) {
435 struct kvnoList *kvnoEntry;
436 struct subTypeList *subEntry;
438 kvnoEntry = opr_queue_Entry(cursor, struct kvnoList, link);
439 subEntry = opr_queue_First(&kvnoEntry->subTypeList,
440 struct subTypeList, link);
441 if (writeWord(fd, subEntry->key->kvno))
443 if (write(fd, subEntry->key->key.val, 8) != 8)
453 return AFSCONF_FAILURE;
457 _parseExtendedKeyFile(struct afsconf_dir *dir, char *fileName)
461 struct afsconf_typedKey *key = NULL;
463 fd = open(fileName, O_RDONLY);
467 code = read(fd, &nkeys, sizeof(afs_int32));
468 if (code!= sizeof(afs_int32))
472 for(i=0; i<nkeys; i++) {
475 key = afsconf_typedKey_blank();
477 /* The only data version we currently parse has a reclen of 16.
478 * Anything smaller indicates a corrupt key file. Anything more,
479 * and we just skip the extra fields */
480 code = read(fd, &reclen, sizeof(afs_int32));
481 if (code != sizeof(afs_int32))
483 reclen = ntohl(reclen);
486 reclen-=sizeof(afs_int32);
488 code = read(fd, &key->type, sizeof(afs_int32));
489 if (code != sizeof(afs_int32))
491 key->type = ntohl(key->type);
492 reclen-=sizeof(afs_int32);
494 code = read(fd, &key->kvno, sizeof(afs_int32));
495 if (code != sizeof(afs_int32))
497 key->kvno = ntohl(key->kvno);
498 reclen-=sizeof(afs_int32);
500 code = read(fd, &key->subType, sizeof(afs_int32));
501 if (code != sizeof(afs_int32))
503 key->subType = ntohl(key->subType);
504 reclen-=sizeof(afs_int32);
507 code = lseek(fd, reclen, SEEK_CUR);
512 code = read(fd, &reclen, sizeof(afs_int32));
513 if (code != sizeof(afs_int32))
515 reclen = ntohl(reclen);
517 rx_opaque_alloc(&key->key, reclen);
518 code = read(fd, key->key.val, reclen);
519 if (code != reclen) {
520 rx_opaque_freeContents(&key->key);
524 code = addMemoryKey(dir, key, 1);
525 afsconf_typedKey_put(&key);
534 afsconf_typedKey_put(&key);
542 _writeExtendedKeyFile(struct afsconf_dir *dir, char *fileName)
547 struct keyTypeList *typeEntry;
548 struct kvnoList *kvnoEntry;
549 struct subTypeList *entry;
550 struct opr_queue *keyCursor;
551 struct opr_queue *kvnoCursor;
552 struct opr_queue *subCursor;
554 fd = open(fileName, O_RDWR | O_CREAT | O_TRUNC, 0600);
556 return AFSCONF_FAILURE;
558 /* Iterate over the whole in-memory key store, and write everything
559 * except keys with type rxkad into the extended key file */
561 /* Write a 0 key count - we'll fill it in later */
563 if (writeWord(fd, 0))
566 for (opr_queue_Scan(&dir->keyList, keyCursor)) {
567 typeEntry = opr_queue_Entry(keyCursor, struct keyTypeList, link);
569 if (typeEntry->type != afsconf_rxkad) {
570 for (opr_queue_Scan(&typeEntry->kvnoList, kvnoCursor)) {
571 kvnoEntry = opr_queue_Entry(kvnoCursor, struct kvnoList, link);
572 for (opr_queue_Scan(&kvnoEntry->subTypeList, subCursor)) {
573 entry = opr_queue_Entry(subCursor, struct subTypeList, link);
574 if (writeWord(fd, 16)) /* record length */
576 if (writeWord(fd, entry->key->type))
578 if (writeWord(fd, entry->key->kvno))
580 if (writeWord(fd, entry->key->subType))
582 if (writeWord(fd, entry->key->key.len))
584 if (write(fd, entry->key->key.val,
585 entry->key->key.len) !=
594 if (lseek(fd, 0, SEEK_SET)<0)
597 if (writeWord(fd, nkeys))
606 return AFSCONF_FAILURE;
610 _afsconf_LoadKeys(struct afsconf_dir *dir)
615 /* If we're running on Windows, and we are a client, we don't have a
616 * KeyFile, so don't try and open one */
619 if (_afsconf_IsClientConfigDirectory(dir->name))
621 #endif /* AFS_NT40_ENV */
625 /* Delete all of our existing keys */
626 _afsconf_FreeAllKeys(dir);
628 /* Start by opening the original KeyFile */
629 asnprintf(&fileName, 256, "%s/%s", dir->name, AFSDIR_KEY_FILE);
630 code = _parseOriginalKeyFile(dir, fileName);
635 /* Now open the new style KeyFile */
636 asnprintf(&fileName, 256, "%s/%s", dir->name, AFSDIR_EXT_KEY_FILE);
637 code = _parseExtendedKeyFile(dir, fileName);
644 _afsconf_FreeAllKeys(dir);
652 _afsconf_SaveKeys(struct afsconf_dir *dir)
657 /* If we're running on Windows, and we are a client, we don't have a
658 * KeyFile, so don't try and open one */
661 if (_afsconf_IsClientConfigDirectory(dir->name))
663 #endif /* AFS_NT40_ENV */
667 /* Start by opening the original KeyFile */
668 asnprintf(&fileName, 256, "%s/%s", dir->name, AFSDIR_KEY_FILE);
669 code = _writeOriginalKeyFile(dir, fileName);
674 /* Now open the new style KeyFile */
675 asnprintf(&fileName, 256, "%s/%s", dir->name, AFSDIR_EXT_KEY_FILE);
676 code = _writeExtendedKeyFile(dir, fileName);
689 /* get keys structure */
691 afsconf_GetKeys(struct afsconf_dir *dir, struct afsconf_keys *astr)
694 struct keyTypeList *typeEntry;
695 struct opr_queue *cursor;
697 memset(astr, 0, sizeof(struct afsconf_keys));
701 code = _afsconf_Check(dir);
705 typeEntry = findByType(dir, afsconf_rxkad);
706 if (typeEntry == NULL)
709 for (opr_queue_Scan(&typeEntry->kvnoList, cursor)) {
710 struct kvnoList *kvnoEntry;
711 struct subTypeList *subEntry;
713 kvnoEntry = opr_queue_Entry(cursor, struct kvnoList, link);
714 subEntry = opr_queue_First(&kvnoEntry->subTypeList,
715 struct subTypeList, link);
716 /* XXX - If there is more than one key in this list, it's an error */
717 astr->key[astr->nkeys].kvno = subEntry->key->kvno;
718 /* XXX - If the opaque contains a number of bytes other than 8, it's
720 memcpy(&astr->key[astr->nkeys].key, subEntry->key->key.val, 8);
730 afsconf_GetLatestKey(struct afsconf_dir *dir, afs_int32 *kvno,
731 struct ktc_encryptionKey *key)
733 struct afsconf_typedKey *typedKey;
736 code = afsconf_GetLatestKeyByTypes(dir, afsconf_rxkad, 0, &typedKey);
740 /* XXX - Should check that the key is of the correct length */
742 /* Copy out the relevant details */
744 *kvno = typedKey->kvno;
747 memcpy(key, typedKey->key.val, 8);
749 afsconf_typedKey_put(&typedKey);
755 afsconf_GetKey(void *rock, int kvno, struct ktc_encryptionKey *key)
757 struct afsconf_typedKey *typedKey;
760 code = afsconf_GetKeyByTypes(rock, afsconf_rxkad, kvno, 0, &typedKey);
764 memcpy(key, typedKey->key.val, 8);
766 afsconf_typedKey_put(&typedKey);
772 afsconf_AddKey(struct afsconf_dir *dir, afs_int32 kvno, char key[8],
775 struct rx_opaque buffer;
776 struct afsconf_typedKey *typedKey;
779 rx_opaque_alloc(&buffer, 8);
780 memcpy(buffer.val, key, 8);
781 typedKey = afsconf_typedKey_new(afsconf_rxkad, kvno, 0, &buffer);
782 if (typedKey == NULL)
783 return AFSCONF_FAILURE;
785 rx_opaque_freeContents(&buffer);
787 code = afsconf_AddTypedKey(dir, typedKey, overwrite);
788 afsconf_typedKey_put(&typedKey);
793 afsconf_DeleteKey(struct afsconf_dir *dir, afs_int32 kvno)
795 return afsconf_DeleteKeyByType(dir, afsconf_rxkad, kvno);
799 afsconf_GetKeysByType(struct afsconf_dir *dir, afsconf_keyType type,
800 int kvno, struct afsconf_typedKeyList **keys)
802 struct kvnoList *kvnoEntry;
807 code = _afsconf_Check(dir);
811 kvnoEntry = findByKvno(dir, type, kvno);
812 if (kvnoEntry == NULL) {
813 code = AFSCONF_NOTFOUND;
817 code = listToArray(kvnoEntry, keys);
825 afsconf_GetAllKeys(struct afsconf_dir *dir, struct afsconf_typedKeyList **keys)
828 struct afsconf_typedKeyList *retval;
829 struct opr_queue *typeCursor;
830 struct keyTypeList *typeEntry;
831 struct opr_queue *kvnoCursor;
832 struct kvnoList *kvnoEntry;
833 struct opr_queue *subCursor;
834 struct subTypeList *subEntry;
839 code = _afsconf_Check(dir);
844 /* First, work out how many keys we have in total */
845 for (opr_queue_Scan(&dir->keyList, typeCursor)) {
846 typeEntry = opr_queue_Entry(typeCursor, struct keyTypeList, link);
847 for (opr_queue_Scan(&typeEntry->kvnoList, kvnoCursor)) {
848 kvnoEntry = opr_queue_Entry(kvnoCursor, struct kvnoList, link);
849 for (opr_queue_Scan(&kvnoEntry->subTypeList, subCursor)) {
850 subEntry = opr_queue_Entry(subCursor, struct subTypeList, link);
856 /* Allocate space for all of these */
857 retval = malloc(sizeof(struct afsconf_typedKeyList));
858 retval->nkeys = count;
861 retval->keys = calloc(retval->nkeys,
862 sizeof(struct afsconf_typedKey *));
864 /* Populate the key list */
866 for (opr_queue_Scan(&dir->keyList, typeCursor)) {
867 typeEntry = opr_queue_Entry(typeCursor,
868 struct keyTypeList, link);
869 for (opr_queue_Scan(&typeEntry->kvnoList, kvnoCursor)) {
870 kvnoEntry = opr_queue_Entry(kvnoCursor,
871 struct kvnoList, link);
872 for (opr_queue_Scan(&kvnoEntry->subTypeList, subCursor)) {
873 subEntry = opr_queue_Entry(subCursor,
874 struct subTypeList, link);
875 retval->keys[count] = afsconf_typedKey_get(subEntry->key);
892 afsconf_GetKeyByTypes(struct afsconf_dir *dir, afsconf_keyType type,
893 int kvno, int subType, struct afsconf_typedKey **key)
896 struct subTypeList *subTypeEntry;
900 code = _afsconf_Check(dir);
904 subTypeEntry = findBySubType(dir, type, kvno, subType);
905 if (subTypeEntry == NULL) {
906 code = AFSCONF_NOTFOUND;
910 *key = afsconf_typedKey_get(subTypeEntry->key);
917 static struct kvnoList *
918 pickBestKvno(struct afsconf_dir *dir, afsconf_keyType type)
920 struct keyTypeList *typeEntry;
921 struct kvnoList *kvnoEntry;
923 typeEntry = findByType(dir, type);
924 if (typeEntry == NULL)
927 /* We store all of the key lists ordered, so the last entry in the
928 * kvno list must be the highest kvno. */
930 kvnoEntry = opr_queue_Last(&typeEntry->kvnoList, struct kvnoList, link);
932 /* Except, if we're in the rxkad list, we might have a bcrypt entry that
933 * has a kvno of 999. So we need to skip that one
935 while (type == afsconf_rxgk && kvnoEntry->kvno == 999) {
936 kvnoEntry = opr_queue_Prev(&typeEntry->kvnoList, struct kvnoList,
938 if (opr_queue_IsEnd(&typeEntry->kvnoList, &kvnoEntry->link))
947 afsconf_GetLatestKeysByType(struct afsconf_dir *dir, afsconf_keyType type,
948 struct afsconf_typedKeyList **keys)
951 struct kvnoList *kvnoEntry;
955 code = _afsconf_Check(dir);
960 kvnoEntry = pickBestKvno(dir, type);
961 if (kvnoEntry == NULL) {
962 code = AFSCONF_NOTFOUND;
966 code = listToArray(kvnoEntry, keys);
974 afsconf_GetLatestKeyByTypes(struct afsconf_dir *dir, afsconf_keyType type,
975 int subType, struct afsconf_typedKey **key)
978 struct kvnoList *kvnoEntry;
979 struct subTypeList *subTypeEntry;
983 code = _afsconf_Check(dir);
987 kvnoEntry = pickBestKvno(dir, type);
988 if (kvnoEntry == NULL) {
989 code = AFSCONF_NOTFOUND;
993 subTypeEntry = findInKvnoList(kvnoEntry, subType);
994 if (subTypeEntry == NULL) {
995 code = AFSCONF_NOTFOUND;
999 *key = afsconf_typedKey_get(subTypeEntry->key);
1002 UNLOCK_GLOBAL_MUTEX;
1007 afsconf_PutTypedKeyList(struct afsconf_typedKeyList **keys)
1011 for (i=0;i<(*keys)->nkeys;i++)
1012 afsconf_typedKey_put(&((*keys)->keys[i]));
1014 if ((*keys)->keys != NULL)
1015 free((*keys)->keys);
1021 static struct afsconf_typedKey *
1022 afsconf_typedKey_blank(void)
1024 struct afsconf_typedKey *key;
1026 key = malloc(sizeof(struct afsconf_typedKey));
1030 memset(key, 0, 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);