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);
84 retval->keys = calloc(retval->nkeys, sizeof(struct afsconf_typedKey *));
87 for(opr_queue_Scan(&kvnoEntry->subTypeList, cursor)) {
88 struct subTypeList *entry;
90 entry = opr_queue_Entry(cursor, struct subTypeList, link);
91 retval->keys[i] = afsconf_typedKey_get(entry->key);
99 static struct keyTypeList *
100 findByType(struct afsconf_dir *dir, afsconf_keyType type)
102 struct opr_queue *cursor;
103 struct keyTypeList *entry = NULL;
105 for (opr_queue_Scan(&dir->keyList, cursor)) {
106 entry = opr_queue_Entry(cursor, struct keyTypeList, link);
107 if (entry->type >= type)
110 if (entry == NULL || entry->type != type)
116 static struct kvnoList *
117 findInTypeList(struct keyTypeList *parent, int kvno)
119 struct opr_queue *cursor;
120 struct kvnoList *entry = NULL;
122 for (opr_queue_Scan(&parent->kvnoList, cursor)) {
123 entry = opr_queue_Entry(cursor, struct kvnoList, link);
124 if (entry->kvno >= kvno)
127 if (entry == NULL || entry->kvno != kvno)
133 static struct kvnoList *
134 findByKvno(struct afsconf_dir *dir, afsconf_keyType type, int kvno)
136 struct keyTypeList *entry;
137 entry = findByType(dir, type);
142 return findInTypeList(entry, kvno);
145 static struct subTypeList *
146 findInKvnoList(struct kvnoList *parent, int subType)
148 struct opr_queue *cursor;
149 struct subTypeList *entry = NULL;
151 for (opr_queue_Scan(&parent->subTypeList, cursor)) {
152 entry = opr_queue_Entry(cursor, struct subTypeList, link);
153 if (entry->subType >= subType)
156 if (entry == NULL || entry->subType != subType)
162 static struct subTypeList *
163 findBySubType(struct afsconf_dir *dir, afsconf_keyType type, int kvno,
166 struct kvnoList *entry;
168 entry = findByKvno(dir, type, kvno);
172 return findInKvnoList(entry, subType);
178 addMemoryKey(struct afsconf_dir *dir, struct afsconf_typedKey *key,
181 struct opr_queue *cursor;
182 struct keyTypeList *typeEntry = NULL;
183 struct kvnoList *kvnoEntry = NULL;
184 struct subTypeList *subType = NULL;
186 /* Find the place in the keyType list to insert the key into */
187 for (opr_queue_Scan(&dir->keyList, cursor)) {
188 typeEntry = opr_queue_Entry(cursor, struct keyTypeList, link);
189 if (typeEntry->type >= key->type)
193 if (typeEntry == NULL || typeEntry->type != key->type) {
194 struct keyTypeList *list;
196 list = malloc(sizeof(struct keyTypeList));
197 opr_queue_Init(&list->kvnoList);
198 list->type = key->type;
199 opr_queue_InsertBefore(cursor, &list->link);
203 /* And the place in the kvno list */
204 for (opr_queue_Scan(&typeEntry->kvnoList, cursor)) {
205 kvnoEntry = opr_queue_Entry(cursor, struct kvnoList, link);
206 if (kvnoEntry->kvno >= key->kvno)
210 if (kvnoEntry == NULL || kvnoEntry->kvno != key->kvno) {
211 struct kvnoList *list;
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)
219 list = malloc(sizeof(struct kvnoList));
220 opr_queue_Init(&list->subTypeList);
221 list->kvno = key->kvno;
222 opr_queue_InsertBefore(cursor, &list->link);
226 /* And the place in the subtype list */
227 for (opr_queue_Scan(&kvnoEntry->subTypeList, cursor)) {
228 subType = opr_queue_Entry(cursor, struct subTypeList, link);
229 if (subType->subType >= key->subType)
233 if (subType == NULL || subType->subType != key->subType) {
234 struct subTypeList *list;
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);
242 /* Give up our reference to the existing key */
243 afsconf_typedKey_put(&subType->key);
244 subType->key = afsconf_typedKey_get(key);
246 return AFSCONF_KEYINUSE;
253 deleteKvnoEntry(struct kvnoList *entry)
255 struct subTypeList *subTypeEntry;
257 while (!opr_queue_IsEmpty(&entry->subTypeList)) {
258 subTypeEntry = opr_queue_First(&entry->subTypeList,
259 struct subTypeList, link);
260 afsconf_typedKey_put(&subTypeEntry->key);
261 opr_queue_Remove(&subTypeEntry->link);
264 opr_queue_Remove(&entry->link);
269 _afsconf_FreeAllKeys(struct afsconf_dir *dir)
271 struct keyTypeList *typeEntry;
272 struct kvnoList *kvnoEntry;
274 while (!opr_queue_IsEmpty(&dir->keyList)) {
275 typeEntry = opr_queue_First(&dir->keyList, struct keyTypeList, link);
277 while (!opr_queue_IsEmpty(&typeEntry->kvnoList)) {
278 kvnoEntry = opr_queue_First(&typeEntry->kvnoList,
279 struct kvnoList, link);
281 deleteKvnoEntry(kvnoEntry);
283 opr_queue_Remove(&typeEntry->link);
288 _afsconf_InitKeys(struct afsconf_dir *dir)
290 opr_queue_Init(&dir->keyList);
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.
298 * All other keys are stored in the file KeyFileEx, which has the following
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 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
303 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
305 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
309 * The version number is 1 at present. Version numbers higher than 1
310 * indicate a keyfile that is not backwards compatible with this
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)
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 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
321 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
322 * | key version number |
323 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
325 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
326 * | length of key material |
327 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
331 * All values are expressed in network byte order
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.
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.
346 _parseOriginalKeyFile(struct afsconf_dir *dir, char *fileName)
348 int fd, code, nkeys, i;
349 struct afsconf_typedKey *key;
351 fd = open(fileName, O_RDONLY);
355 code = read(fd, &nkeys, sizeof(afs_int32));
356 if (code!= sizeof(afs_int32))
360 for(i=0; i<nkeys; i++) {
362 key = afsconf_typedKey_blank();
364 key->type = afsconf_rxkad;
367 code = read(fd, &key->kvno, sizeof(afs_int32));
368 if (code != sizeof(afs_int32)) {
372 key->kvno = ntohl(key->kvno);
374 rx_opaque_alloc(&key->key, 8);
375 code = read(fd, key->key.val, 8);
377 rx_opaque_freeContents(&key->key);
381 code = addMemoryKey(dir, key, 1);
382 afsconf_typedKey_put(&key); /* Done with key */
395 writeWord(int fd, afs_int32 data)
400 if (write(fd, &data, sizeof(afs_int32)) != sizeof(afs_int32))
407 _writeOriginalKeyFile(struct afsconf_dir *dir, char *fileName)
410 struct opr_queue *cursor;
411 struct keyTypeList *typeEntry;
413 fd = open(fileName, O_RDWR | O_CREAT | O_TRUNC, 0600);
415 return AFSCONF_FAILURE;
417 typeEntry = findByType(dir, afsconf_rxkad);
419 nkeys = opr_queue_Count(&typeEntry->kvnoList);
423 if (writeWord(fd, nkeys))
426 if (typeEntry == NULL)
429 for (opr_queue_Scan(&typeEntry->kvnoList, cursor)) {
430 struct kvnoList *kvnoEntry;
431 struct subTypeList *subEntry;
433 kvnoEntry = opr_queue_Entry(cursor, struct kvnoList, link);
434 subEntry = opr_queue_First(&kvnoEntry->subTypeList,
435 struct subTypeList, link);
436 if (writeWord(fd, subEntry->key->kvno))
438 if (write(fd, subEntry->key->key.val, 8) != 8)
448 return AFSCONF_FAILURE;
452 _parseExtendedKeyFile(struct afsconf_dir *dir, char *fileName)
456 struct afsconf_typedKey *key;
458 fd = open(fileName, O_RDONLY);
462 code = read(fd, &nkeys, sizeof(afs_int32));
463 if (code!= sizeof(afs_int32))
467 for(i=0; i<nkeys; i++) {
470 key = afsconf_typedKey_blank();
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))
478 reclen = ntohl(reclen);
481 reclen-=sizeof(afs_int32);
483 code = read(fd, &key->type, sizeof(afs_int32));
484 if (code != sizeof(afs_int32))
486 key->type = ntohl(key->type);
487 reclen-=sizeof(afs_int32);
489 code = read(fd, &key->kvno, sizeof(afs_int32));
490 if (code != sizeof(afs_int32))
492 key->kvno = ntohl(key->kvno);
493 reclen-=sizeof(afs_int32);
495 code = read(fd, &key->subType, sizeof(afs_int32));
496 if (code != sizeof(afs_int32))
498 key->subType = ntohl(key->subType);
499 reclen-=sizeof(afs_int32);
502 code = lseek(fd, reclen, SEEK_CUR);
507 code = read(fd, &reclen, sizeof(afs_int32));
508 if (code != sizeof(afs_int32))
510 reclen = ntohl(reclen);
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);
519 code = addMemoryKey(dir, key, 1);
520 afsconf_typedKey_put(&key);
534 _writeExtendedKeyFile(struct afsconf_dir *dir, char *fileName)
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;
546 fd = open(fileName, O_RDWR | O_CREAT | O_TRUNC, 0600);
548 return AFSCONF_FAILURE;
550 /* Iterate over the whole in-memory key store, and write everything
551 * except keys with type rxkad into the extended key file */
553 /* Write a 0 key count - we'll fill it in later */
555 if (writeWord(fd, 0))
558 for (opr_queue_Scan(&dir->keyList, keyCursor)) {
559 typeEntry = opr_queue_Entry(keyCursor, struct keyTypeList, link);
561 if (typeEntry->type != afsconf_rxkad) {
562 for (opr_queue_Scan(&typeEntry->kvnoList, kvnoCursor)) {
563 kvnoEntry = opr_queue_Entry(kvnoCursor, struct kvnoList, link);
564 for (opr_queue_Scan(&kvnoEntry->subTypeList, subCursor)) {
565 entry = opr_queue_Entry(subCursor, struct subTypeList, link);
566 if (writeWord(fd, 16)) /* record length */
568 if (writeWord(fd, entry->key->type))
570 if (writeWord(fd, entry->key->kvno))
572 if (writeWord(fd, entry->key->subType))
574 if (writeWord(fd, entry->key->key.len))
576 if (write(fd, entry->key->key.val,
577 entry->key->key.len) !=
586 if (lseek(fd, 0, SEEK_SET)<0)
589 if (writeWord(fd, nkeys))
598 return AFSCONF_FAILURE;
602 _afsconf_LoadKeys(struct afsconf_dir *dir)
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 */
611 if (_afsconf_IsClientConfigDirectory(dir->name))
613 #endif /* AFS_NT40_ENV */
617 /* Delete all of our existing keys */
618 _afsconf_FreeAllKeys(dir);
620 /* Start by opening the original KeyFile */
621 asnprintf(&fileName, 256, "%s/%s", dir->name, AFSDIR_KEY_FILE);
622 code = _parseOriginalKeyFile(dir, fileName);
627 /* Now open the new style KeyFile */
628 asnprintf(&fileName, 256, "%s/%s", dir->name, AFSDIR_EXT_KEY_FILE);
629 code = _parseExtendedKeyFile(dir, fileName);
636 _afsconf_FreeAllKeys(dir);
644 _afsconf_SaveKeys(struct afsconf_dir *dir)
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 */
653 if (_afsconf_IsClientConfigDirectory(dir->name))
655 #endif /* AFS_NT40_ENV */
659 /* Start by opening the original KeyFile */
660 asnprintf(&fileName, 256, "%s/%s", dir->name, AFSDIR_KEY_FILE);
661 code = _writeOriginalKeyFile(dir, fileName);
666 /* Now open the new style KeyFile */
667 asnprintf(&fileName, 256, "%s/%s", dir->name, AFSDIR_EXT_KEY_FILE);
668 code = _writeExtendedKeyFile(dir, fileName);
681 /* get keys structure */
683 afsconf_GetKeys(struct afsconf_dir *dir, struct afsconf_keys *astr)
686 struct keyTypeList *typeEntry;
687 struct opr_queue *cursor;
689 memset(astr, 0, sizeof(struct afsconf_keys));
693 code = _afsconf_Check(dir);
697 typeEntry = findByType(dir, afsconf_rxkad);
698 if (typeEntry == NULL)
701 for (opr_queue_Scan(&typeEntry->kvnoList, cursor)) {
702 struct kvnoList *kvnoEntry;
703 struct subTypeList *subEntry;
705 kvnoEntry = opr_queue_Entry(cursor, struct kvnoList, link);
706 subEntry = opr_queue_First(&kvnoEntry->subTypeList,
707 struct subTypeList, 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
712 memcpy(&astr->key[astr->nkeys].key, subEntry->key->key.val, 8);
722 afsconf_GetLatestKey(struct afsconf_dir *dir, afs_int32 *kvno,
723 struct ktc_encryptionKey *key)
725 struct afsconf_typedKey *typedKey;
728 code = afsconf_GetLatestKeyByTypes(dir, afsconf_rxkad, 0, &typedKey);
732 /* XXX - Should check that the key is of the correct length */
734 /* Copy out the relevant details */
736 *kvno = typedKey->kvno;
739 memcpy(key, typedKey->key.val, 8);
741 afsconf_typedKey_put(&typedKey);
747 afsconf_GetKey(void *rock, int kvno, struct ktc_encryptionKey *key)
749 struct afsconf_typedKey *typedKey;
752 code = afsconf_GetKeyByTypes(rock, afsconf_rxkad, kvno, 0, &typedKey);
756 memcpy(key, typedKey->key.val, 8);
758 afsconf_typedKey_put(&typedKey);
764 afsconf_AddKey(struct afsconf_dir *dir, afs_int32 kvno, char key[8],
767 struct rx_opaque buffer;
768 struct afsconf_typedKey *typedKey;
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)
775 return AFSCONF_FAILURE;
777 rx_opaque_freeContents(&buffer);
779 code = afsconf_AddTypedKey(dir, typedKey, overwrite);
780 afsconf_typedKey_put(&typedKey);
785 afsconf_DeleteKey(struct afsconf_dir *dir, afs_int32 kvno)
787 return afsconf_DeleteKeyByType(dir, afsconf_rxkad, kvno);
791 afsconf_GetKeysByType(struct afsconf_dir *dir, afsconf_keyType type,
792 int kvno, struct afsconf_typedKeyList **keys)
794 struct kvnoList *kvnoEntry;
799 code = _afsconf_Check(dir);
803 kvnoEntry = findByKvno(dir, type, kvno);
804 if (kvnoEntry == NULL) {
805 code = AFSCONF_NOTFOUND;
809 code = listToArray(kvnoEntry, keys);
817 afsconf_GetKeyByTypes(struct afsconf_dir *dir, afsconf_keyType type,
818 int kvno, int subType, struct afsconf_typedKey **key)
821 struct subTypeList *subTypeEntry;
825 code = _afsconf_Check(dir);
829 subTypeEntry = findBySubType(dir, type, kvno, subType);
830 if (subTypeEntry == NULL) {
831 code = AFSCONF_NOTFOUND;
835 *key = afsconf_typedKey_get(subTypeEntry->key);
842 static struct kvnoList *
843 pickBestKvno(struct afsconf_dir *dir, afsconf_keyType type)
845 struct keyTypeList *typeEntry;
846 struct kvnoList *kvnoEntry;
848 typeEntry = findByType(dir, type);
849 if (typeEntry == NULL)
852 /* We store all of the key lists ordered, so the last entry in the
853 * kvno list must be the highest kvno. */
855 kvnoEntry = opr_queue_Last(&typeEntry->kvnoList, struct kvnoList, link);
857 /* Except, if we're in the rxkad list, we might have a bcrypt entry that
858 * has a kvno of 999. So we need to skip that one
860 while (type == afsconf_rxgk && kvnoEntry->kvno == 999) {
861 kvnoEntry = opr_queue_Prev(&typeEntry->kvnoList, struct kvnoList,
863 if (opr_queue_IsEnd(&typeEntry->kvnoList, &kvnoEntry->link))
872 afsconf_GetLatestKeysByType(struct afsconf_dir *dir, afsconf_keyType type,
873 struct afsconf_typedKeyList **keys)
876 struct kvnoList *kvnoEntry;
880 code = _afsconf_Check(dir);
885 kvnoEntry = pickBestKvno(dir, type);
886 if (kvnoEntry == NULL) {
887 code = AFSCONF_NOTFOUND;
891 code = listToArray(kvnoEntry, keys);
899 afsconf_GetLatestKeyByTypes(struct afsconf_dir *dir, afsconf_keyType type,
900 int subType, struct afsconf_typedKey **key)
903 struct kvnoList *kvnoEntry;
904 struct subTypeList *subTypeEntry;
908 code = _afsconf_Check(dir);
912 kvnoEntry = pickBestKvno(dir, type);
913 if (kvnoEntry == NULL) {
914 code = AFSCONF_NOTFOUND;
918 subTypeEntry = findInKvnoList(kvnoEntry, subType);
919 if (subTypeEntry == NULL) {
920 code = AFSCONF_NOTFOUND;
924 *key = afsconf_typedKey_get(subTypeEntry->key);
932 afsconf_PutTypedKeyList(struct afsconf_typedKeyList **keys)
936 for (i=0;i<(*keys)->nkeys;i++)
937 afsconf_typedKey_put(&((*keys)->keys[i]));
943 static struct afsconf_typedKey *
944 afsconf_typedKey_blank(void)
946 struct afsconf_typedKey *key;
948 key = malloc(sizeof(struct afsconf_typedKey));
952 memset(key, 0, sizeof(struct afsconf_typedKey));
953 rx_atomic_set(&key->refcnt, 1);
958 struct afsconf_typedKey *
959 afsconf_typedKey_new(afsconf_keyType type, int kvno, int subType,
960 struct rx_opaque *keyMaterial)
962 struct afsconf_typedKey *key;
965 key = afsconf_typedKey_blank();
971 key->subType = subType;
973 code = rx_opaque_copy(&key->key, keyMaterial);
983 afsconf_typedKey_free(struct afsconf_typedKey **key)
985 rx_opaque_freeContents(&(*key)->key);
990 struct afsconf_typedKey *
991 afsconf_typedKey_get(struct afsconf_typedKey *key)
993 rx_atomic_inc(&key->refcnt);
998 afsconf_typedKey_put(struct afsconf_typedKey **key)
1000 if (rx_atomic_dec_and_read(&(*key)->refcnt) == 0)
1001 afsconf_typedKey_free(key);
1007 afsconf_typedKey_values(struct afsconf_typedKey *key, afsconf_keyType *type,
1008 int *kvno, int *subType, struct rx_opaque **material)
1012 *subType = key->subType;
1013 *material = &key->key;
1017 afsconf_AddTypedKey(struct afsconf_dir *dir,
1018 struct afsconf_typedKey *key,
1025 code = _afsconf_Check(dir);
1029 if (key->type == afsconf_rxkad) {
1030 /* There are restrictions on rxkad keys so that we can still
1031 * return them using the old interface. We only enforce the
1032 * same restrictions as that interface does - that is, we don't
1033 * check that the key we're passed is a valid DES key */
1034 if (key->key.len != 8 || key->subType != 0) {
1035 code = AFSCONF_BADKEY;
1040 code = addMemoryKey(dir, key, overwrite);
1044 code = _afsconf_SaveKeys(dir);
1045 _afsconf_Touch(dir);
1048 UNLOCK_GLOBAL_MUTEX;
1053 afsconf_DeleteKeyByType(struct afsconf_dir *dir,
1054 afsconf_keyType type, int kvno)
1056 struct keyTypeList *typeEntry;
1057 struct kvnoList *kvnoEntry;
1062 code = _afsconf_Check(dir);
1066 typeEntry = findByType(dir, type);
1067 if (typeEntry == NULL) {
1068 code = AFSCONF_NOTFOUND;
1072 kvnoEntry = findInTypeList(typeEntry, kvno);
1073 if (kvnoEntry == NULL) {
1074 code = AFSCONF_NOTFOUND;
1078 deleteKvnoEntry(kvnoEntry);
1080 /* Remove the typeEntry, if it has no sub elements */
1081 if (opr_queue_IsEmpty(&typeEntry->kvnoList)) {
1082 opr_queue_Remove(&typeEntry->link);
1086 code = _afsconf_SaveKeys(dir);
1087 _afsconf_Touch(dir);
1090 UNLOCK_GLOBAL_MUTEX;
1095 afsconf_DeleteKeyBySubType(struct afsconf_dir *dir,
1096 afsconf_keyType type, int kvno, int subType)
1098 struct keyTypeList *typeEntry;
1099 struct kvnoList *kvnoEntry;
1100 struct subTypeList *subTypeEntry;
1105 code = _afsconf_Check(dir);
1109 typeEntry = findByType(dir, type);
1110 if (typeEntry == NULL)
1111 return AFSCONF_NOTFOUND;
1113 kvnoEntry = findInTypeList(typeEntry, kvno);
1114 if (kvnoEntry == NULL)
1115 return AFSCONF_NOTFOUND;
1117 subTypeEntry = findInKvnoList(kvnoEntry, subType);
1118 if (subTypeEntry == NULL)
1119 return AFSCONF_NOTFOUND;
1121 /* Remove the subTypeEntry */
1122 afsconf_typedKey_put(&subTypeEntry->key);
1123 opr_queue_Remove(&subTypeEntry->link);
1126 /* Remove the kvnoEntry, if it has no sub elements */
1127 if (opr_queue_IsEmpty(&kvnoEntry->subTypeList)) {
1128 opr_queue_Remove(&kvnoEntry->link);
1132 /* Remove the typeEntry, if it has no sub elements */
1133 if (opr_queue_IsEmpty(&typeEntry->kvnoList)) {
1134 opr_queue_Remove(&typeEntry->link);
1138 code = _afsconf_SaveKeys(dir);
1139 _afsconf_Touch(dir);
1142 UNLOCK_GLOBAL_MUTEX;
1147 afsconf_DeleteTypedKey(struct afsconf_dir *dir, struct afsconf_typedKey *key)
1149 return afsconf_DeleteKeyBySubType(dir, key->type, key->kvno, key->subType);