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);
418 if (typeEntry == NULL)
421 nkeys = opr_queue_Count(&typeEntry->kvnoList);
423 if (writeWord(fd, nkeys))
426 for (opr_queue_Scan(&typeEntry->kvnoList, cursor)) {
427 struct kvnoList *kvnoEntry;
428 struct subTypeList *subEntry;
430 kvnoEntry = opr_queue_Entry(cursor, struct kvnoList, link);
431 subEntry = opr_queue_First(&kvnoEntry->subTypeList,
432 struct subTypeList, link);
433 if (writeWord(fd, subEntry->key->kvno))
435 if (write(fd, subEntry->key->key.val, 8) != 8)
445 return AFSCONF_FAILURE;
449 _parseExtendedKeyFile(struct afsconf_dir *dir, char *fileName)
453 struct afsconf_typedKey *key;
455 fd = open(fileName, O_RDONLY);
459 code = read(fd, &nkeys, sizeof(afs_int32));
460 if (code!= sizeof(afs_int32))
464 for(i=0; i<nkeys; i++) {
467 key = afsconf_typedKey_blank();
469 /* The only data version we currently parse has a reclen of 16.
470 * Anything smaller indicates a corrupt key file. Anything more,
471 * and we just skip the extra fields */
472 code = read(fd, &reclen, sizeof(afs_int32));
473 if (code != sizeof(afs_int32))
475 reclen = ntohl(reclen);
478 reclen-=sizeof(afs_int32);
480 code = read(fd, &key->type, sizeof(afs_int32));
481 if (code != sizeof(afs_int32))
483 key->type = ntohl(key->type);
484 reclen-=sizeof(afs_int32);
486 code = read(fd, &key->kvno, sizeof(afs_int32));
487 if (code != sizeof(afs_int32))
489 key->kvno = ntohl(key->kvno);
490 reclen-=sizeof(afs_int32);
492 code = read(fd, &key->subType, sizeof(afs_int32));
493 if (code != sizeof(afs_int32))
495 key->subType = ntohl(key->subType);
496 reclen-=sizeof(afs_int32);
499 code = lseek(fd, reclen, SEEK_CUR);
504 code = read(fd, &reclen, sizeof(afs_int32));
505 if (code != sizeof(afs_int32))
507 reclen = ntohl(reclen);
509 rx_opaque_alloc(&key->key, reclen);
510 code = read(fd, key->key.val, reclen);
511 if (code != reclen) {
512 rx_opaque_freeContents(&key->key);
516 code = addMemoryKey(dir, key, 1);
517 afsconf_typedKey_put(&key);
531 _writeExtendedKeyFile(struct afsconf_dir *dir, char *fileName)
536 struct keyTypeList *typeEntry;
537 struct kvnoList *kvnoEntry;
538 struct subTypeList *entry;
539 struct opr_queue *keyCursor;
540 struct opr_queue *kvnoCursor;
541 struct opr_queue *subCursor;
543 fd = open(fileName, O_RDWR | O_CREAT | O_TRUNC, 0600);
545 return AFSCONF_FAILURE;
547 /* Iterate over the whole in-memory key store, and write everything
548 * except keys with type rxkad into the extended key file */
550 /* Write a 0 key count - we'll fill it in later */
552 if (writeWord(fd, 0))
555 for (opr_queue_Scan(&dir->keyList, keyCursor)) {
556 typeEntry = opr_queue_Entry(keyCursor, struct keyTypeList, link);
558 if (typeEntry->type != afsconf_rxkad) {
559 for (opr_queue_Scan(&typeEntry->kvnoList, kvnoCursor)) {
560 kvnoEntry = opr_queue_Entry(kvnoCursor, struct kvnoList, link);
561 for (opr_queue_Scan(&kvnoEntry->subTypeList, subCursor)) {
562 entry = opr_queue_Entry(subCursor, struct subTypeList, link);
563 if (writeWord(fd, 16)) /* record length */
565 if (writeWord(fd, entry->key->type))
567 if (writeWord(fd, entry->key->kvno))
569 if (writeWord(fd, entry->key->subType))
571 if (writeWord(fd, entry->key->key.len))
573 if (write(fd, entry->key->key.val,
574 entry->key->key.len) !=
583 if (lseek(fd, 0, SEEK_SET)<0)
586 if (writeWord(fd, nkeys))
595 return AFSCONF_FAILURE;
599 _afsconf_LoadKeys(struct afsconf_dir *dir)
604 /* If we're running on Windows, and we are a client, we don't have a
605 * KeyFile, so don't try and open one */
608 if (_afsconf_IsClientConfigDirectory(dir->name))
610 #endif /* AFS_NT40_ENV */
614 /* Delete all of our existing keys */
615 _afsconf_FreeAllKeys(dir);
617 /* Start by opening the original KeyFile */
618 asnprintf(&fileName, 256, "%s/%s", dir->name, AFSDIR_KEY_FILE);
619 code = _parseOriginalKeyFile(dir, fileName);
624 /* Now open the new style KeyFile */
625 asnprintf(&fileName, 256, "%s/%s", dir->name, AFSDIR_EXT_KEY_FILE);
626 code = _parseExtendedKeyFile(dir, fileName);
633 _afsconf_FreeAllKeys(dir);
641 _afsconf_SaveKeys(struct afsconf_dir *dir)
646 /* If we're running on Windows, and we are a client, we don't have a
647 * KeyFile, so don't try and open one */
650 if (_afsconf_IsClientConfigDirectory(dir->name))
652 #endif /* AFS_NT40_ENV */
656 /* Start by opening the original KeyFile */
657 asnprintf(&fileName, 256, "%s/%s", dir->name, AFSDIR_KEY_FILE);
658 code = _writeOriginalKeyFile(dir, fileName);
663 /* Now open the new style KeyFile */
664 asnprintf(&fileName, 256, "%s/%s", dir->name, AFSDIR_EXT_KEY_FILE);
665 code = _writeExtendedKeyFile(dir, fileName);
678 /* get keys structure */
680 afsconf_GetKeys(struct afsconf_dir *dir, struct afsconf_keys *astr)
683 struct keyTypeList *typeEntry;
684 struct opr_queue *cursor;
686 memset(astr, 0, sizeof(struct afsconf_keys));
690 code = _afsconf_Check(dir);
694 typeEntry = findByType(dir, afsconf_rxkad);
695 if (typeEntry == NULL)
698 for (opr_queue_Scan(&typeEntry->kvnoList, cursor)) {
699 struct kvnoList *kvnoEntry;
700 struct subTypeList *subEntry;
702 kvnoEntry = opr_queue_Entry(cursor, struct kvnoList, link);
703 subEntry = opr_queue_First(&kvnoEntry->subTypeList,
704 struct subTypeList, link);
705 /* XXX - If there is more than one key in this list, it's an error */
706 astr->key[astr->nkeys].kvno = subEntry->key->kvno;
707 /* XXX - If the opaque contains a number of bytes other than 8, it's
709 memcpy(&astr->key[astr->nkeys].key, subEntry->key->key.val, 8);
719 afsconf_GetLatestKey(struct afsconf_dir *dir, afs_int32 *kvno,
720 struct ktc_encryptionKey *key)
722 struct afsconf_typedKey *typedKey;
725 code = afsconf_GetLatestKeyByTypes(dir, afsconf_rxkad, 0, &typedKey);
729 /* XXX - Should check that the key is of the correct length */
731 /* Copy out the relevant details */
733 *kvno = typedKey->kvno;
736 memcpy(key, typedKey->key.val, 8);
738 afsconf_typedKey_put(&typedKey);
744 afsconf_GetKey(void *rock, int kvno, struct ktc_encryptionKey *key)
746 struct afsconf_typedKey *typedKey;
749 code = afsconf_GetKeyByTypes(rock, afsconf_rxkad, kvno, 0, &typedKey);
753 memcpy(key, typedKey->key.val, 8);
755 afsconf_typedKey_put(&typedKey);
761 afsconf_AddKey(struct afsconf_dir *dir, afs_int32 kvno, char key[8],
764 struct rx_opaque buffer;
765 struct afsconf_typedKey *typedKey;
768 rx_opaque_alloc(&buffer, 8);
769 memcpy(buffer.val, key, 8);
770 typedKey = afsconf_typedKey_new(afsconf_rxkad, kvno, 0, &buffer);
771 if (typedKey == NULL)
772 return AFSCONF_FAILURE;
774 rx_opaque_freeContents(&buffer);
776 code = afsconf_AddTypedKey(dir, typedKey, overwrite);
777 afsconf_typedKey_put(&typedKey);
782 afsconf_DeleteKey(struct afsconf_dir *dir, afs_int32 kvno)
784 return afsconf_DeleteKeyByType(dir, afsconf_rxkad, kvno);
788 afsconf_GetKeysByType(struct afsconf_dir *dir, afsconf_keyType type,
789 int kvno, struct afsconf_typedKeyList **keys)
791 struct kvnoList *kvnoEntry;
796 code = _afsconf_Check(dir);
800 kvnoEntry = findByKvno(dir, type, kvno);
801 if (kvnoEntry == NULL) {
802 code = AFSCONF_NOTFOUND;
806 code = listToArray(kvnoEntry, keys);
814 afsconf_GetKeyByTypes(struct afsconf_dir *dir, afsconf_keyType type,
815 int kvno, int subType, struct afsconf_typedKey **key)
818 struct subTypeList *subTypeEntry;
822 code = _afsconf_Check(dir);
826 subTypeEntry = findBySubType(dir, type, kvno, subType);
827 if (subTypeEntry == NULL) {
828 code = AFSCONF_NOTFOUND;
832 *key = afsconf_typedKey_get(subTypeEntry->key);
839 static struct kvnoList *
840 pickBestKvno(struct afsconf_dir *dir, afsconf_keyType type)
842 struct keyTypeList *typeEntry;
843 struct kvnoList *kvnoEntry;
845 typeEntry = findByType(dir, type);
846 if (typeEntry == NULL)
849 /* We store all of the key lists ordered, so the last entry in the
850 * kvno list must be the highest kvno. */
852 kvnoEntry = opr_queue_Last(&typeEntry->kvnoList, struct kvnoList, link);
854 /* Except, if we're in the rxkad list, we might have a bcrypt entry that
855 * has a kvno of 999. So we need to skip that one
857 while (type == afsconf_rxgk && kvnoEntry->kvno == 999) {
858 kvnoEntry = opr_queue_Prev(&typeEntry->kvnoList, struct kvnoList,
860 if (opr_queue_IsEnd(&typeEntry->kvnoList, &kvnoEntry->link))
869 afsconf_GetLatestKeysByType(struct afsconf_dir *dir, afsconf_keyType type,
870 struct afsconf_typedKeyList **keys)
873 struct kvnoList *kvnoEntry;
877 code = _afsconf_Check(dir);
882 kvnoEntry = pickBestKvno(dir, type);
883 if (kvnoEntry == NULL) {
884 code = AFSCONF_NOTFOUND;
888 code = listToArray(kvnoEntry, keys);
896 afsconf_GetLatestKeyByTypes(struct afsconf_dir *dir, afsconf_keyType type,
897 int subType, struct afsconf_typedKey **key)
900 struct kvnoList *kvnoEntry;
901 struct subTypeList *subTypeEntry;
905 code = _afsconf_Check(dir);
909 kvnoEntry = pickBestKvno(dir, type);
910 if (kvnoEntry == NULL) {
911 code = AFSCONF_NOTFOUND;
915 subTypeEntry = findInKvnoList(kvnoEntry, subType);
916 if (subTypeEntry == NULL) {
917 code = AFSCONF_NOTFOUND;
921 *key = afsconf_typedKey_get(subTypeEntry->key);
929 afsconf_PutTypedKeyList(struct afsconf_typedKeyList **keys)
933 for (i=0;i<(*keys)->nkeys;i++)
934 afsconf_typedKey_put(&((*keys)->keys[i]));
940 static struct afsconf_typedKey *
941 afsconf_typedKey_blank(void)
943 struct afsconf_typedKey *key;
945 key = malloc(sizeof(struct afsconf_typedKey));
949 memset(key, 0, sizeof(struct afsconf_typedKey));
950 rx_atomic_set(&key->refcnt, 1);
955 struct afsconf_typedKey *
956 afsconf_typedKey_new(afsconf_keyType type, int kvno, int subType,
957 struct rx_opaque *keyMaterial)
959 struct afsconf_typedKey *key;
962 key = afsconf_typedKey_blank();
968 key->subType = subType;
970 code = rx_opaque_copy(&key->key, keyMaterial);
980 afsconf_typedKey_free(struct afsconf_typedKey **key)
982 rx_opaque_freeContents(&(*key)->key);
987 struct afsconf_typedKey *
988 afsconf_typedKey_get(struct afsconf_typedKey *key)
990 rx_atomic_inc(&key->refcnt);
995 afsconf_typedKey_put(struct afsconf_typedKey **key)
997 if (rx_atomic_dec_and_read(&(*key)->refcnt) == 0)
998 afsconf_typedKey_free(key);
1004 afsconf_typedKey_values(struct afsconf_typedKey *key, afsconf_keyType *type,
1005 int *kvno, int *subType, struct rx_opaque **material)
1009 *subType = key->subType;
1010 *material = &key->key;
1014 afsconf_AddTypedKey(struct afsconf_dir *dir,
1015 struct afsconf_typedKey *key,
1022 code = _afsconf_Check(dir);
1026 if (key->type == afsconf_rxkad) {
1027 /* There are restrictions on rxkad keys so that we can still
1028 * return them using the old interface. We only enforce the
1029 * same restrictions as that interface does - that is, we don't
1030 * check that the key we're passed is a valid DES key */
1031 if (key->key.len != 8 || key->subType != 0) {
1032 code = AFSCONF_BADKEY;
1037 code = addMemoryKey(dir, key, overwrite);
1041 code = _afsconf_SaveKeys(dir);
1042 _afsconf_Touch(dir);
1045 UNLOCK_GLOBAL_MUTEX;
1050 afsconf_DeleteKeyByType(struct afsconf_dir *dir,
1051 afsconf_keyType type, int kvno)
1053 struct keyTypeList *typeEntry;
1054 struct kvnoList *kvnoEntry;
1059 code = _afsconf_Check(dir);
1063 typeEntry = findByType(dir, type);
1064 if (typeEntry == NULL) {
1065 code = AFSCONF_NOTFOUND;
1069 kvnoEntry = findInTypeList(typeEntry, kvno);
1070 if (kvnoEntry == NULL) {
1071 code = AFSCONF_NOTFOUND;
1075 deleteKvnoEntry(kvnoEntry);
1077 /* Remove the typeEntry, if it has no sub elements */
1078 if (opr_queue_IsEmpty(&typeEntry->kvnoList)) {
1079 opr_queue_Remove(&typeEntry->link);
1083 code = _afsconf_SaveKeys(dir);
1084 _afsconf_Touch(dir);
1087 UNLOCK_GLOBAL_MUTEX;
1092 afsconf_DeleteKeyBySubType(struct afsconf_dir *dir,
1093 afsconf_keyType type, int kvno, int subType)
1095 struct keyTypeList *typeEntry;
1096 struct kvnoList *kvnoEntry;
1097 struct subTypeList *subTypeEntry;
1102 code = _afsconf_Check(dir);
1106 typeEntry = findByType(dir, type);
1107 if (typeEntry == NULL)
1108 return AFSCONF_NOTFOUND;
1110 kvnoEntry = findInTypeList(typeEntry, kvno);
1111 if (kvnoEntry == NULL)
1112 return AFSCONF_NOTFOUND;
1114 subTypeEntry = findInKvnoList(kvnoEntry, subType);
1115 if (subTypeEntry == NULL)
1116 return AFSCONF_NOTFOUND;
1118 /* Remove the subTypeEntry */
1119 afsconf_typedKey_put(&subTypeEntry->key);
1120 opr_queue_Remove(&subTypeEntry->link);
1123 /* Remove the kvnoEntry, if it has no sub elements */
1124 if (opr_queue_IsEmpty(&kvnoEntry->subTypeList)) {
1125 opr_queue_Remove(&kvnoEntry->link);
1129 /* Remove the typeEntry, if it has no sub elements */
1130 if (opr_queue_IsEmpty(&typeEntry->kvnoList)) {
1131 opr_queue_Remove(&typeEntry->link);
1135 code = _afsconf_SaveKeys(dir);
1136 _afsconf_Touch(dir);
1139 UNLOCK_GLOBAL_MUTEX;
1144 afsconf_DeleteTypedKey(struct afsconf_dir *dir, struct afsconf_typedKey *key)
1146 return afsconf_DeleteKeyBySubType(dir, key->type, key->kvno, key->subType);