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 KeyFileExt, 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 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
312 * If the format ever needs to chanage incompatibly, a new file name
315 * Key data is a sequence of the following records (note that these are
316 * not word aligned - the next record begins where the previous one ends)
318 * 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
319 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
320 * | meta-data length |
321 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
323 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
324 * | key version number |
325 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
327 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
328 * | length of key material |
329 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
333 * All values are expressed in network byte order
335 * Meta data length is the length of the initial portion of the record
336 * (itself, key type, key version number, and key sub type). In this
337 * version of the specification it would be 16. It is there to allow
338 * additional fields to be added to this specification at a later date
339 * without breaking backwards compatibility.
342 /* XXX - We need to be careful with failure here, because failure due to
343 * a missing file is fine, but failure due to read errors needs to be trapped,
344 * before it results in a corrupted file being written out.
348 _parseOriginalKeyFile(struct afsconf_dir *dir, char *fileName)
350 int fd, code, nkeys, i;
351 struct afsconf_typedKey *key;
353 fd = open(fileName, O_RDONLY);
357 code = read(fd, &nkeys, sizeof(afs_int32));
358 if (code!= sizeof(afs_int32))
362 for(i=0; i<nkeys; i++) {
364 key = afsconf_typedKey_blank();
368 key->type = afsconf_rxkad;
371 code = read(fd, &key->kvno, sizeof(afs_int32));
372 if (code != sizeof(afs_int32)) {
376 key->kvno = ntohl(key->kvno);
378 rx_opaque_alloc(&key->key, 8);
379 code = read(fd, key->key.val, 8);
381 rx_opaque_freeContents(&key->key);
385 code = addMemoryKey(dir, key, 1);
386 afsconf_typedKey_put(&key); /* Done with key */
399 writeWord(int fd, afs_int32 data)
404 if (write(fd, &data, sizeof(afs_int32)) != sizeof(afs_int32))
411 _writeOriginalKeyFile(struct afsconf_dir *dir, char *fileName)
414 struct opr_queue *cursor;
415 struct keyTypeList *typeEntry;
417 fd = open(fileName, O_RDWR | O_CREAT | O_TRUNC, 0600);
419 return AFSCONF_FAILURE;
421 typeEntry = findByType(dir, afsconf_rxkad);
423 nkeys = opr_queue_Count(&typeEntry->kvnoList);
427 if (writeWord(fd, nkeys))
430 if (typeEntry == NULL)
433 for (opr_queue_Scan(&typeEntry->kvnoList, cursor)) {
434 struct kvnoList *kvnoEntry;
435 struct subTypeList *subEntry;
437 kvnoEntry = opr_queue_Entry(cursor, struct kvnoList, link);
438 subEntry = opr_queue_First(&kvnoEntry->subTypeList,
439 struct subTypeList, link);
440 if (writeWord(fd, subEntry->key->kvno))
442 if (write(fd, subEntry->key->key.val, 8) != 8)
452 return AFSCONF_FAILURE;
456 _parseExtendedKeyFile(struct afsconf_dir *dir, char *fileName)
460 struct afsconf_typedKey *key = NULL;
462 fd = open(fileName, O_RDONLY);
466 code = read(fd, &nkeys, sizeof(afs_int32));
467 if (code!= sizeof(afs_int32))
471 for(i=0; i<nkeys; i++) {
474 key = afsconf_typedKey_blank();
478 /* The only data version we currently parse has a reclen of 16.
479 * Anything smaller indicates a corrupt key file. Anything more,
480 * and we just skip the extra fields */
481 code = read(fd, &reclen, sizeof(afs_int32));
482 if (code != sizeof(afs_int32))
484 reclen = ntohl(reclen);
487 reclen-=sizeof(afs_int32);
489 code = read(fd, &key->type, sizeof(afs_int32));
490 if (code != sizeof(afs_int32))
492 key->type = ntohl(key->type);
493 reclen-=sizeof(afs_int32);
495 code = read(fd, &key->kvno, sizeof(afs_int32));
496 if (code != sizeof(afs_int32))
498 key->kvno = ntohl(key->kvno);
499 reclen-=sizeof(afs_int32);
501 code = read(fd, &key->subType, sizeof(afs_int32));
502 if (code != sizeof(afs_int32))
504 key->subType = ntohl(key->subType);
505 reclen-=sizeof(afs_int32);
508 code = lseek(fd, reclen, SEEK_CUR);
513 code = read(fd, &reclen, sizeof(afs_int32));
514 if (code != sizeof(afs_int32))
516 reclen = ntohl(reclen);
518 rx_opaque_alloc(&key->key, reclen);
519 code = read(fd, key->key.val, reclen);
520 if (code != reclen) {
521 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))
854 /* Allocate space for all of these */
855 retval = malloc(sizeof(struct afsconf_typedKeyList));
856 retval->nkeys = count;
859 retval->keys = calloc(retval->nkeys,
860 sizeof(struct afsconf_typedKey *));
862 /* Populate the key list */
864 for (opr_queue_Scan(&dir->keyList, typeCursor)) {
865 typeEntry = opr_queue_Entry(typeCursor,
866 struct keyTypeList, link);
867 for (opr_queue_Scan(&typeEntry->kvnoList, kvnoCursor)) {
868 kvnoEntry = opr_queue_Entry(kvnoCursor,
869 struct kvnoList, link);
870 for (opr_queue_Scan(&kvnoEntry->subTypeList, subCursor)) {
871 subEntry = opr_queue_Entry(subCursor,
872 struct subTypeList, link);
873 retval->keys[count] = afsconf_typedKey_get(subEntry->key);
890 afsconf_GetKeyByTypes(struct afsconf_dir *dir, afsconf_keyType type,
891 int kvno, int subType, struct afsconf_typedKey **key)
894 struct subTypeList *subTypeEntry;
898 code = _afsconf_Check(dir);
902 subTypeEntry = findBySubType(dir, type, kvno, subType);
903 if (subTypeEntry == NULL) {
904 code = AFSCONF_NOTFOUND;
908 *key = afsconf_typedKey_get(subTypeEntry->key);
915 static struct kvnoList *
916 pickBestKvno(struct afsconf_dir *dir, afsconf_keyType type)
918 struct keyTypeList *typeEntry;
919 struct kvnoList *kvnoEntry;
921 typeEntry = findByType(dir, type);
922 if (typeEntry == NULL)
925 /* We store all of the key lists ordered, so the last entry in the
926 * kvno list must be the highest kvno. */
928 kvnoEntry = opr_queue_Last(&typeEntry->kvnoList, struct kvnoList, link);
930 /* Except, if we're in the rxkad list, we might have a bcrypt entry that
931 * has a kvno of 999. So we need to skip that one
933 while (type == afsconf_rxgk && kvnoEntry->kvno == 999) {
934 kvnoEntry = opr_queue_Prev(&typeEntry->kvnoList, struct kvnoList,
936 if (opr_queue_IsEnd(&typeEntry->kvnoList, &kvnoEntry->link))
945 afsconf_GetLatestKeysByType(struct afsconf_dir *dir, afsconf_keyType type,
946 struct afsconf_typedKeyList **keys)
949 struct kvnoList *kvnoEntry;
953 code = _afsconf_Check(dir);
958 kvnoEntry = pickBestKvno(dir, type);
959 if (kvnoEntry == NULL) {
960 code = AFSCONF_NOTFOUND;
964 code = listToArray(kvnoEntry, keys);
972 afsconf_GetLatestKeyByTypes(struct afsconf_dir *dir, afsconf_keyType type,
973 int subType, struct afsconf_typedKey **key)
976 struct kvnoList *kvnoEntry;
977 struct subTypeList *subTypeEntry;
981 code = _afsconf_Check(dir);
985 kvnoEntry = pickBestKvno(dir, type);
986 if (kvnoEntry == NULL) {
987 code = AFSCONF_NOTFOUND;
991 subTypeEntry = findInKvnoList(kvnoEntry, subType);
992 if (subTypeEntry == NULL) {
993 code = AFSCONF_NOTFOUND;
997 *key = afsconf_typedKey_get(subTypeEntry->key);
1000 UNLOCK_GLOBAL_MUTEX;
1005 afsconf_PutTypedKeyList(struct afsconf_typedKeyList **keys)
1009 for (i=0;i<(*keys)->nkeys;i++)
1010 afsconf_typedKey_put(&((*keys)->keys[i]));
1012 if ((*keys)->keys != NULL)
1013 free((*keys)->keys);
1019 static struct afsconf_typedKey *
1020 afsconf_typedKey_blank(void)
1022 struct afsconf_typedKey *key;
1024 key = calloc(1, sizeof(struct afsconf_typedKey));
1028 rx_atomic_set(&key->refcnt, 1);
1033 struct afsconf_typedKey *
1034 afsconf_typedKey_new(afsconf_keyType type, int kvno, int subType,
1035 struct rx_opaque *keyMaterial)
1037 struct afsconf_typedKey *key;
1040 key = afsconf_typedKey_blank();
1046 key->subType = subType;
1048 code = rx_opaque_copy(&key->key, keyMaterial);
1058 afsconf_typedKey_free(struct afsconf_typedKey **key)
1060 rx_opaque_freeContents(&(*key)->key);
1065 struct afsconf_typedKey *
1066 afsconf_typedKey_get(struct afsconf_typedKey *key)
1068 rx_atomic_inc(&key->refcnt);
1073 afsconf_typedKey_put(struct afsconf_typedKey **key)
1075 if (rx_atomic_dec_and_read(&(*key)->refcnt) == 0)
1076 afsconf_typedKey_free(key);
1082 afsconf_typedKey_values(struct afsconf_typedKey *key, afsconf_keyType *type,
1083 int *kvno, int *subType, struct rx_opaque **material)
1087 *subType = key->subType;
1088 *material = &key->key;
1092 afsconf_AddTypedKey(struct afsconf_dir *dir,
1093 struct afsconf_typedKey *key,
1100 code = _afsconf_Check(dir);
1104 if (key->type == afsconf_rxkad) {
1105 /* There are restrictions on rxkad keys so that we can still
1106 * return them using the old interface. We only enforce the
1107 * same restrictions as that interface does - that is, we don't
1108 * check that the key we're passed is a valid DES key */
1109 if (key->key.len != 8 || key->subType != 0) {
1110 code = AFSCONF_BADKEY;
1115 code = addMemoryKey(dir, key, overwrite);
1119 code = _afsconf_SaveKeys(dir);
1120 _afsconf_Touch(dir);
1123 UNLOCK_GLOBAL_MUTEX;
1128 afsconf_DeleteKeyByType(struct afsconf_dir *dir,
1129 afsconf_keyType type, int kvno)
1131 struct keyTypeList *typeEntry;
1132 struct kvnoList *kvnoEntry;
1137 code = _afsconf_Check(dir);
1141 typeEntry = findByType(dir, type);
1142 if (typeEntry == NULL) {
1143 code = AFSCONF_NOTFOUND;
1147 kvnoEntry = findInTypeList(typeEntry, kvno);
1148 if (kvnoEntry == NULL) {
1149 code = AFSCONF_NOTFOUND;
1153 deleteKvnoEntry(kvnoEntry);
1155 /* Remove the typeEntry, if it has no sub elements */
1156 if (opr_queue_IsEmpty(&typeEntry->kvnoList)) {
1157 opr_queue_Remove(&typeEntry->link);
1161 code = _afsconf_SaveKeys(dir);
1162 _afsconf_Touch(dir);
1165 UNLOCK_GLOBAL_MUTEX;
1170 afsconf_DeleteKeyBySubType(struct afsconf_dir *dir,
1171 afsconf_keyType type, int kvno, int subType)
1173 struct keyTypeList *typeEntry;
1174 struct kvnoList *kvnoEntry;
1175 struct subTypeList *subTypeEntry;
1180 code = _afsconf_Check(dir);
1184 typeEntry = findByType(dir, type);
1185 if (typeEntry == NULL)
1186 return AFSCONF_NOTFOUND;
1188 kvnoEntry = findInTypeList(typeEntry, kvno);
1189 if (kvnoEntry == NULL)
1190 return AFSCONF_NOTFOUND;
1192 subTypeEntry = findInKvnoList(kvnoEntry, subType);
1193 if (subTypeEntry == NULL)
1194 return AFSCONF_NOTFOUND;
1196 /* Remove the subTypeEntry */
1197 afsconf_typedKey_put(&subTypeEntry->key);
1198 opr_queue_Remove(&subTypeEntry->link);
1201 /* Remove the kvnoEntry, if it has no sub elements */
1202 if (opr_queue_IsEmpty(&kvnoEntry->subTypeList)) {
1203 opr_queue_Remove(&kvnoEntry->link);
1207 /* Remove the typeEntry, if it has no sub elements */
1208 if (opr_queue_IsEmpty(&typeEntry->kvnoList)) {
1209 opr_queue_Remove(&typeEntry->link);
1213 code = _afsconf_SaveKeys(dir);
1214 _afsconf_Touch(dir);
1217 UNLOCK_GLOBAL_MUTEX;
1222 afsconf_DeleteTypedKey(struct afsconf_dir *dir, struct afsconf_typedKey *key)
1224 return afsconf_DeleteKeyBySubType(dir, key->type, key->kvno, key->subType);