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>
41 #include <afs/pthread_glock.h>
42 #include <afs/afsutil.h>
44 #include "cellconfig.h"
48 struct afsconf_typedKey {
56 static struct afsconf_typedKey *afsconf_typedKey_blank(void);
58 /* Memory storage for keyfile contents. */
61 struct opr_queue link;
63 struct opr_queue kvnoList;
67 struct opr_queue link;
69 struct opr_queue subTypeList;
73 struct opr_queue link;
75 struct afsconf_typedKey *key;
79 listToArray(struct kvnoList *kvnoEntry, struct afsconf_typedKeyList **keys)
81 struct afsconf_typedKeyList *retval;
82 struct opr_queue *cursor;
85 /* Allocate space for the keys we've got stored */
86 retval = malloc(sizeof(struct afsconf_typedKeyList));
87 retval->nkeys = opr_queue_Count(&kvnoEntry->subTypeList);
89 if (retval->nkeys > 0) {
90 retval->keys = calloc(retval->nkeys, sizeof(struct afsconf_typedKey *));
93 for(opr_queue_Scan(&kvnoEntry->subTypeList, cursor)) {
94 struct subTypeList *entry;
96 entry = opr_queue_Entry(cursor, struct subTypeList, link);
97 retval->keys[i] = afsconf_typedKey_get(entry->key);
108 static struct keyTypeList *
109 findByType(struct afsconf_dir *dir, afsconf_keyType type)
111 struct opr_queue *cursor;
112 struct keyTypeList *entry = NULL;
114 for (opr_queue_Scan(&dir->keyList, cursor)) {
115 entry = opr_queue_Entry(cursor, struct keyTypeList, link);
116 if (entry->type >= type)
119 if (entry == NULL || entry->type != type)
125 static struct kvnoList *
126 findInTypeList(struct keyTypeList *parent, int kvno)
128 struct opr_queue *cursor;
129 struct kvnoList *entry = NULL;
131 for (opr_queue_Scan(&parent->kvnoList, cursor)) {
132 entry = opr_queue_Entry(cursor, struct kvnoList, link);
133 if (entry->kvno >= kvno)
136 if (entry == NULL || entry->kvno != kvno)
142 static struct kvnoList *
143 findByKvno(struct afsconf_dir *dir, afsconf_keyType type, int kvno)
145 struct keyTypeList *entry;
146 entry = findByType(dir, type);
151 return findInTypeList(entry, kvno);
154 static struct subTypeList *
155 findInKvnoList(struct kvnoList *parent, int subType)
157 struct opr_queue *cursor;
158 struct subTypeList *entry = NULL;
160 for (opr_queue_Scan(&parent->subTypeList, cursor)) {
161 entry = opr_queue_Entry(cursor, struct subTypeList, link);
162 if (entry->subType >= subType)
165 if (entry == NULL || entry->subType != subType)
171 static struct subTypeList *
172 findBySubType(struct afsconf_dir *dir, afsconf_keyType type, int kvno,
175 struct kvnoList *entry;
177 entry = findByKvno(dir, type, kvno);
181 return findInKvnoList(entry, subType);
187 addMemoryKey(struct afsconf_dir *dir, struct afsconf_typedKey *key,
190 struct opr_queue *cursor;
191 struct keyTypeList *typeEntry = NULL;
192 struct kvnoList *kvnoEntry = NULL;
193 struct subTypeList *subType = NULL;
195 /* Find the place in the keyType list to insert the key into */
196 for (opr_queue_Scan(&dir->keyList, cursor)) {
197 typeEntry = opr_queue_Entry(cursor, struct keyTypeList, link);
198 if (typeEntry->type >= key->type)
202 if (typeEntry == NULL || typeEntry->type != key->type) {
203 struct keyTypeList *list;
205 list = malloc(sizeof(struct keyTypeList));
206 opr_queue_Init(&list->kvnoList);
207 list->type = key->type;
208 opr_queue_InsertBefore(cursor, &list->link);
212 /* And the place in the kvno list */
213 for (opr_queue_Scan(&typeEntry->kvnoList, cursor)) {
214 kvnoEntry = opr_queue_Entry(cursor, struct kvnoList, link);
215 if (kvnoEntry->kvno >= key->kvno)
219 if (kvnoEntry == NULL || kvnoEntry->kvno != key->kvno) {
220 struct kvnoList *list;
222 /* In the legacy rxkad key case, we need to check to see if we've
223 * gone over the maximum of 8 keys */
224 if (key->type == afsconf_rxkad &&
225 opr_queue_Count(&typeEntry->kvnoList)>=8)
228 list = malloc(sizeof(struct kvnoList));
229 opr_queue_Init(&list->subTypeList);
230 list->kvno = key->kvno;
231 opr_queue_InsertBefore(cursor, &list->link);
235 /* And the place in the subtype list */
236 for (opr_queue_Scan(&kvnoEntry->subTypeList, cursor)) {
237 subType = opr_queue_Entry(cursor, struct subTypeList, link);
238 if (subType->subType >= key->subType)
242 if (subType == NULL || subType->subType != key->subType) {
243 struct subTypeList *list;
245 list = malloc(sizeof(struct subTypeList));
246 list->subType = key->subType;
247 list->key = afsconf_typedKey_get(key);
248 opr_queue_InsertBefore(cursor, &list->link);
251 /* Give up our reference to the existing key */
252 afsconf_typedKey_put(&subType->key);
253 subType->key = afsconf_typedKey_get(key);
255 return AFSCONF_KEYINUSE;
262 deleteKvnoEntry(struct kvnoList *entry)
264 struct subTypeList *subTypeEntry;
266 while (!opr_queue_IsEmpty(&entry->subTypeList)) {
267 subTypeEntry = opr_queue_First(&entry->subTypeList,
268 struct subTypeList, link);
269 afsconf_typedKey_put(&subTypeEntry->key);
270 opr_queue_Remove(&subTypeEntry->link);
273 opr_queue_Remove(&entry->link);
278 _afsconf_FreeAllKeys(struct afsconf_dir *dir)
280 struct keyTypeList *typeEntry;
281 struct kvnoList *kvnoEntry;
283 while (!opr_queue_IsEmpty(&dir->keyList)) {
284 typeEntry = opr_queue_First(&dir->keyList, struct keyTypeList, link);
286 while (!opr_queue_IsEmpty(&typeEntry->kvnoList)) {
287 kvnoEntry = opr_queue_First(&typeEntry->kvnoList,
288 struct kvnoList, link);
290 deleteKvnoEntry(kvnoEntry);
292 opr_queue_Remove(&typeEntry->link);
297 _afsconf_InitKeys(struct afsconf_dir *dir)
299 opr_queue_Init(&dir->keyList);
302 /* Disk based key storage. This is made somewhat complicated because we
303 * store keys in more than one place - keys of type 'rxkad' (0) are stored
304 * in the original KeyFile, so that we can continue to be compatible with
305 * utilities that directly modify that file.
307 * All other keys are stored in the file KeyFileExt, which has the following
309 * 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
310 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
312 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
316 * If the format ever needs to chanage incompatibly, a new file name
319 * Key data is a sequence of the following records (note that these are
320 * not word aligned - the next record begins where the previous one ends)
322 * 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
323 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
324 * | meta-data length |
325 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
327 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
328 * | key version number |
329 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
331 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
332 * | length of key material |
333 * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
337 * All values are expressed in network byte order
339 * Meta data length is the length of the initial portion of the record
340 * (itself, key type, key version number, and key sub type). In this
341 * version of the specification it would be 16. It is there to allow
342 * additional fields to be added to this specification at a later date
343 * without breaking backwards compatibility.
346 /* XXX - We need to be careful with failure here, because failure due to
347 * a missing file is fine, but failure due to read errors needs to be trapped,
348 * before it results in a corrupted file being written out.
352 _parseOriginalKeyFile(struct afsconf_dir *dir, char *fileName)
354 int fd, code, nkeys, i;
355 struct afsconf_typedKey *key;
357 fd = open(fileName, O_RDONLY);
361 code = read(fd, &nkeys, sizeof(afs_int32));
362 if (code!= sizeof(afs_int32))
366 for(i=0; i<nkeys; i++) {
368 key = afsconf_typedKey_blank();
372 key->type = afsconf_rxkad;
375 code = read(fd, &key->kvno, sizeof(afs_int32));
376 if (code != sizeof(afs_int32)) {
380 key->kvno = ntohl(key->kvno);
382 rx_opaque_alloc(&key->key, 8);
383 code = read(fd, key->key.val, 8);
385 rx_opaque_freeContents(&key->key);
389 code = addMemoryKey(dir, key, 1);
390 afsconf_typedKey_put(&key); /* Done with key */
403 writeWord(int fd, afs_int32 data)
408 if (write(fd, &data, sizeof(afs_int32)) != sizeof(afs_int32))
415 _writeOriginalKeyFile(struct afsconf_dir *dir, char *fileName)
418 struct opr_queue *cursor;
419 struct keyTypeList *typeEntry;
421 fd = open(fileName, O_RDWR | O_CREAT | O_TRUNC, 0600);
423 return AFSCONF_FAILURE;
425 typeEntry = findByType(dir, afsconf_rxkad);
427 nkeys = opr_queue_Count(&typeEntry->kvnoList);
431 if (writeWord(fd, nkeys))
434 if (typeEntry == NULL)
437 for (opr_queue_Scan(&typeEntry->kvnoList, cursor)) {
438 struct kvnoList *kvnoEntry;
439 struct subTypeList *subEntry;
441 kvnoEntry = opr_queue_Entry(cursor, struct kvnoList, link);
442 subEntry = opr_queue_First(&kvnoEntry->subTypeList,
443 struct subTypeList, link);
444 if (writeWord(fd, subEntry->key->kvno))
446 if (write(fd, subEntry->key->key.val, 8) != 8)
456 return AFSCONF_FAILURE;
460 _parseExtendedKeyFile(struct afsconf_dir *dir, char *fileName)
464 struct afsconf_typedKey *key = NULL;
466 fd = open(fileName, O_RDONLY);
470 code = read(fd, &nkeys, sizeof(afs_int32));
471 if (code!= sizeof(afs_int32))
475 for(i=0; i<nkeys; i++) {
478 key = afsconf_typedKey_blank();
482 /* The only data version we currently parse has a reclen of 16.
483 * Anything smaller indicates a corrupt key file. Anything more,
484 * and we just skip the extra fields */
485 code = read(fd, &reclen, sizeof(afs_int32));
486 if (code != sizeof(afs_int32))
488 reclen = ntohl(reclen);
491 reclen-=sizeof(afs_int32);
493 code = read(fd, &key->type, sizeof(afs_int32));
494 if (code != sizeof(afs_int32))
496 key->type = ntohl(key->type);
497 reclen-=sizeof(afs_int32);
499 code = read(fd, &key->kvno, sizeof(afs_int32));
500 if (code != sizeof(afs_int32))
502 key->kvno = ntohl(key->kvno);
503 reclen-=sizeof(afs_int32);
505 code = read(fd, &key->subType, sizeof(afs_int32));
506 if (code != sizeof(afs_int32))
508 key->subType = ntohl(key->subType);
509 reclen-=sizeof(afs_int32);
512 code = lseek(fd, reclen, SEEK_CUR);
517 code = read(fd, &reclen, sizeof(afs_int32));
518 if (code != sizeof(afs_int32))
520 reclen = ntohl(reclen);
522 rx_opaque_alloc(&key->key, reclen);
523 code = read(fd, key->key.val, reclen);
524 if (code != reclen) {
525 rx_opaque_freeContents(&key->key);
528 code = addMemoryKey(dir, key, 1);
529 afsconf_typedKey_put(&key);
538 afsconf_typedKey_put(&key);
546 _writeExtendedKeyFile(struct afsconf_dir *dir, char *fileName)
551 struct keyTypeList *typeEntry;
552 struct kvnoList *kvnoEntry;
553 struct subTypeList *entry;
554 struct opr_queue *keyCursor;
555 struct opr_queue *kvnoCursor;
556 struct opr_queue *subCursor;
558 fd = open(fileName, O_RDWR | O_CREAT | O_TRUNC, 0600);
560 return AFSCONF_FAILURE;
562 /* Iterate over the whole in-memory key store, and write everything
563 * except keys with type rxkad into the extended key file */
565 /* Write a 0 key count - we'll fill it in later */
567 if (writeWord(fd, 0))
570 for (opr_queue_Scan(&dir->keyList, keyCursor)) {
571 typeEntry = opr_queue_Entry(keyCursor, struct keyTypeList, link);
573 if (typeEntry->type != afsconf_rxkad) {
574 for (opr_queue_Scan(&typeEntry->kvnoList, kvnoCursor)) {
575 kvnoEntry = opr_queue_Entry(kvnoCursor, struct kvnoList, link);
576 for (opr_queue_Scan(&kvnoEntry->subTypeList, subCursor)) {
577 entry = opr_queue_Entry(subCursor, struct subTypeList, link);
578 if (writeWord(fd, 16)) /* record length */
580 if (writeWord(fd, entry->key->type))
582 if (writeWord(fd, entry->key->kvno))
584 if (writeWord(fd, entry->key->subType))
586 if (writeWord(fd, entry->key->key.len))
588 if (write(fd, entry->key->key.val,
589 entry->key->key.len) !=
598 if (lseek(fd, 0, SEEK_SET)<0)
601 if (writeWord(fd, nkeys))
610 return AFSCONF_FAILURE;
614 _afsconf_LoadKeys(struct afsconf_dir *dir)
619 /* If we're running on Windows, and we are a client, we don't have a
620 * KeyFile, so don't try and open one */
623 if (_afsconf_IsClientConfigDirectory(dir->name))
625 #endif /* AFS_NT40_ENV */
629 /* Delete all of our existing keys */
630 _afsconf_FreeAllKeys(dir);
632 /* Start by opening the original KeyFile */
633 asnprintf(&fileName, 256, "%s/%s", dir->name, AFSDIR_KEY_FILE);
634 code = _parseOriginalKeyFile(dir, fileName);
639 /* Now open the new style KeyFile */
640 asnprintf(&fileName, 256, "%s/%s", dir->name, AFSDIR_EXT_KEY_FILE);
641 code = _parseExtendedKeyFile(dir, fileName);
648 _afsconf_FreeAllKeys(dir);
656 _afsconf_SaveKeys(struct afsconf_dir *dir)
661 /* If we're running on Windows, and we are a client, we don't have a
662 * KeyFile, so don't try and open one */
665 if (_afsconf_IsClientConfigDirectory(dir->name))
667 #endif /* AFS_NT40_ENV */
671 /* Start by opening the original KeyFile */
672 asnprintf(&fileName, 256, "%s/%s", dir->name, AFSDIR_KEY_FILE);
673 code = _writeOriginalKeyFile(dir, fileName);
678 /* Now open the new style KeyFile */
679 asnprintf(&fileName, 256, "%s/%s", dir->name, AFSDIR_EXT_KEY_FILE);
680 code = _writeExtendedKeyFile(dir, fileName);
693 /* get keys structure */
695 afsconf_GetKeys(struct afsconf_dir *dir, struct afsconf_keys *astr)
698 struct keyTypeList *typeEntry;
699 struct opr_queue *cursor;
701 memset(astr, 0, sizeof(struct afsconf_keys));
705 code = _afsconf_Check(dir);
709 typeEntry = findByType(dir, afsconf_rxkad);
710 if (typeEntry == NULL)
713 for (opr_queue_Scan(&typeEntry->kvnoList, cursor)) {
714 struct kvnoList *kvnoEntry;
715 struct subTypeList *subEntry;
717 kvnoEntry = opr_queue_Entry(cursor, struct kvnoList, link);
718 subEntry = opr_queue_First(&kvnoEntry->subTypeList,
719 struct subTypeList, link);
720 /* XXX - If there is more than one key in this list, it's an error */
721 astr->key[astr->nkeys].kvno = subEntry->key->kvno;
722 /* XXX - If the opaque contains a number of bytes other than 8, it's
724 memcpy(&astr->key[astr->nkeys].key, subEntry->key->key.val, 8);
734 afsconf_GetLatestKey(struct afsconf_dir *dir, afs_int32 *kvno,
735 struct ktc_encryptionKey *key)
737 struct afsconf_typedKey *typedKey;
740 code = afsconf_GetLatestKeyByTypes(dir, afsconf_rxkad, 0, &typedKey);
744 /* XXX - Should check that the key is of the correct length */
746 /* Copy out the relevant details */
748 *kvno = typedKey->kvno;
751 memcpy(key, typedKey->key.val, 8);
753 afsconf_typedKey_put(&typedKey);
759 afsconf_GetKey(void *rock, int kvno, struct ktc_encryptionKey *key)
761 struct afsconf_typedKey *typedKey;
764 code = afsconf_GetKeyByTypes(rock, afsconf_rxkad, kvno, 0, &typedKey);
768 memcpy(key, typedKey->key.val, 8);
770 afsconf_typedKey_put(&typedKey);
776 _afsconf_GetLatestRXGKKey(afsconf_keyType type, struct afsconf_dir *rock,
777 afs_int32 *avno, afs_int32 *enctype, rxgk_key *key)
780 struct afsconf_typedKeyList *list = NULL;
781 struct afsconf_typedKey *typedKey = NULL;
785 code = afsconf_GetLatestKeysByType(rock, type, &list);
789 for (key_i = 0; key_i < list->nkeys; key_i++) {
790 if (typedKey == NULL)
791 typedKey = list->keys[key_i];
792 else if (rxgk_enctype_better(typedKey->subType, list->keys[key_i]->subType))
793 typedKey = list->keys[key_i];
796 opr_Assert(typedKey != NULL);
798 /* We picked a key; copy to the output parameters */
799 code = rxgk_make_key(key, typedKey->key.val, typedKey->key.len,
804 *avno = typedKey->kvno;
806 *enctype = typedKey->subType;
809 afsconf_PutTypedKeyList(&list);
811 #else /* AFS_RXGK_ENV */
812 return AFSCONF_NOTFOUND;
817 * Obtain the "best" rxgk key from KeyFileExt
819 * Return the key and its enctype and kvno, for encrypting outgoing tokens.
821 * @param[in] rock The configuration directory to be used.
822 * @param[out] avno The key version number of key.
823 * @param[out] enctype The RFC 3961 enctype of key.
824 * @param[out] key The returned rxgk key.
827 afsconf_GetLatestRXGKKey(struct afsconf_dir *rock, afs_int32 *avno,
828 afs_int32 *enctype, rxgk_key *key)
830 return _afsconf_GetLatestRXGKKey(afsconf_rxgk, rock, avno, enctype, key);
834 _afsconf_GetRXGKKey(afsconf_keyType type, void *rock, afs_int32 *avno,
835 afs_int32 *enctype, rxgk_key *key)
838 struct afsconf_dir *dir = rock;
839 struct afsconf_typedKey *typedKey;
842 /* No information at all means "pick the best/newest one". */
843 if (*avno == 0 && *enctype == 0)
844 return _afsconf_GetLatestRXGKKey(type, dir, avno, enctype, key);
846 code = afsconf_GetKeyByTypes(dir, type, *avno, *enctype, &typedKey);
850 code = rxgk_make_key(key, typedKey->key.val, typedKey->key.len,
852 afsconf_typedKey_put(&typedKey);
855 #else /* AFS_RXGK_ENV */
856 return AFSCONF_NOTFOUND;
861 * Obtain a particular RXGK key from KeyFileExt
863 * Use the specified kvno and enctype to fetch an rxgk key from KeyFileExt
864 * and return it as an rxgk_key. Specifying the kvno/enctype pair as both
865 * zeros causes the "best" rxgk key to be returned, and the kvno/enctype
866 * of that key returned to the caller.
868 * @param[in] rock An afsconf_dir* for the configuration directory. This
869 * is a void* just so this can be easily used as a
870 * callback function that uses a void* rock.
871 * @param[inout] avno The requested kvno (if non-zero), or zero to request
872 * the latest key and have its kvno returned in this
874 * @param[inout] enctype The requested enctype (if non-zero), or zero
875 * to request the latest key and have its
876 * enctype returned in this parameter.
877 * @param[out] key The returned rxgk key.
880 afsconf_GetRXGKKey(void *rock, afs_int32 *avno,
881 afs_int32 *enctype, rxgk_key *key)
883 return _afsconf_GetRXGKKey(afsconf_rxgk, rock, avno, enctype, key);
887 afsconf_AddKey(struct afsconf_dir *dir, afs_int32 kvno, char key[8],
890 struct rx_opaque buffer;
891 struct afsconf_typedKey *typedKey;
894 rx_opaque_alloc(&buffer, 8);
895 memcpy(buffer.val, key, 8);
896 typedKey = afsconf_typedKey_new(afsconf_rxkad, kvno, 0, &buffer);
897 if (typedKey == NULL)
898 return AFSCONF_FAILURE;
900 rx_opaque_freeContents(&buffer);
902 code = afsconf_AddTypedKey(dir, typedKey, overwrite);
903 afsconf_typedKey_put(&typedKey);
908 afsconf_DeleteKey(struct afsconf_dir *dir, afs_int32 kvno)
910 return afsconf_DeleteKeyByType(dir, afsconf_rxkad, kvno);
914 afsconf_GetKeysByType(struct afsconf_dir *dir, afsconf_keyType type,
915 int kvno, struct afsconf_typedKeyList **keys)
917 struct kvnoList *kvnoEntry;
922 code = _afsconf_Check(dir);
926 kvnoEntry = findByKvno(dir, type, kvno);
927 if (kvnoEntry == NULL) {
928 code = AFSCONF_NOTFOUND;
932 code = listToArray(kvnoEntry, keys);
940 afsconf_GetAllKeys(struct afsconf_dir *dir, struct afsconf_typedKeyList **keys)
943 struct afsconf_typedKeyList *retval;
944 struct opr_queue *typeCursor;
945 struct keyTypeList *typeEntry;
946 struct opr_queue *kvnoCursor;
947 struct kvnoList *kvnoEntry;
948 struct opr_queue *subCursor;
949 struct subTypeList *subEntry;
954 code = _afsconf_Check(dir);
959 /* First, work out how many keys we have in total */
960 for (opr_queue_Scan(&dir->keyList, typeCursor)) {
961 typeEntry = opr_queue_Entry(typeCursor, struct keyTypeList, link);
962 for (opr_queue_Scan(&typeEntry->kvnoList, kvnoCursor)) {
963 kvnoEntry = opr_queue_Entry(kvnoCursor, struct kvnoList, link);
964 for (opr_queue_Scan(&kvnoEntry->subTypeList, subCursor))
969 /* Allocate space for all of these */
970 retval = malloc(sizeof(struct afsconf_typedKeyList));
971 retval->nkeys = count;
974 retval->keys = calloc(retval->nkeys,
975 sizeof(struct afsconf_typedKey *));
977 /* Populate the key list */
979 for (opr_queue_Scan(&dir->keyList, typeCursor)) {
980 typeEntry = opr_queue_Entry(typeCursor,
981 struct keyTypeList, link);
982 for (opr_queue_Scan(&typeEntry->kvnoList, kvnoCursor)) {
983 kvnoEntry = opr_queue_Entry(kvnoCursor,
984 struct kvnoList, link);
985 for (opr_queue_Scan(&kvnoEntry->subTypeList, subCursor)) {
986 subEntry = opr_queue_Entry(subCursor,
987 struct subTypeList, link);
988 retval->keys[count] = afsconf_typedKey_get(subEntry->key);
1000 UNLOCK_GLOBAL_MUTEX;
1005 afsconf_GetKeyByTypes(struct afsconf_dir *dir, afsconf_keyType type,
1006 int kvno, int subType, struct afsconf_typedKey **key)
1009 struct subTypeList *subTypeEntry;
1013 code = _afsconf_Check(dir);
1017 subTypeEntry = findBySubType(dir, type, kvno, subType);
1018 if (subTypeEntry == NULL) {
1019 code = AFSCONF_NOTFOUND;
1023 *key = afsconf_typedKey_get(subTypeEntry->key);
1026 UNLOCK_GLOBAL_MUTEX;
1030 static struct kvnoList *
1031 pickBestKvno(struct afsconf_dir *dir, afsconf_keyType type)
1033 struct keyTypeList *typeEntry;
1034 struct kvnoList *kvnoEntry;
1036 typeEntry = findByType(dir, type);
1037 if (typeEntry == NULL)
1040 /* We store all of the key lists ordered, so the last entry in the
1041 * kvno list must be the highest kvno. */
1043 kvnoEntry = opr_queue_Last(&typeEntry->kvnoList, struct kvnoList, link);
1045 /* Except, if we're in the rxkad list, we might have a bcrypt entry that
1046 * has a kvno of 999. So we need to skip that one
1048 while (type == afsconf_rxkad && kvnoEntry->kvno == 999) {
1049 kvnoEntry = opr_queue_Prev(&typeEntry->kvnoList, struct kvnoList,
1051 if (opr_queue_IsEnd(&typeEntry->kvnoList, &kvnoEntry->link))
1060 afsconf_GetLatestKeysByType(struct afsconf_dir *dir, afsconf_keyType type,
1061 struct afsconf_typedKeyList **keys)
1064 struct kvnoList *kvnoEntry;
1068 code = _afsconf_Check(dir);
1073 kvnoEntry = pickBestKvno(dir, type);
1074 if (kvnoEntry == NULL) {
1075 code = AFSCONF_NOTFOUND;
1079 code = listToArray(kvnoEntry, keys);
1082 UNLOCK_GLOBAL_MUTEX;
1087 afsconf_GetLatestKeyByTypes(struct afsconf_dir *dir, afsconf_keyType type,
1088 int subType, struct afsconf_typedKey **key)
1091 struct kvnoList *kvnoEntry;
1092 struct subTypeList *subTypeEntry;
1096 code = _afsconf_Check(dir);
1100 kvnoEntry = pickBestKvno(dir, type);
1101 if (kvnoEntry == NULL) {
1102 code = AFSCONF_NOTFOUND;
1106 subTypeEntry = findInKvnoList(kvnoEntry, subType);
1107 if (subTypeEntry == NULL) {
1108 code = AFSCONF_NOTFOUND;
1112 *key = afsconf_typedKey_get(subTypeEntry->key);
1115 UNLOCK_GLOBAL_MUTEX;
1120 afsconf_PutTypedKeyList(struct afsconf_typedKeyList **keys)
1124 if (*keys == NULL) {
1128 for (i=0;i<(*keys)->nkeys;i++)
1129 afsconf_typedKey_put(&((*keys)->keys[i]));
1131 if ((*keys)->keys != NULL)
1132 free((*keys)->keys);
1138 static struct afsconf_typedKey *
1139 afsconf_typedKey_blank(void)
1141 struct afsconf_typedKey *key;
1143 key = calloc(1, sizeof(struct afsconf_typedKey));
1147 rx_atomic_set(&key->refcnt, 1);
1152 struct afsconf_typedKey *
1153 afsconf_typedKey_new(afsconf_keyType type, int kvno, int subType,
1154 struct rx_opaque *keyMaterial)
1156 struct afsconf_typedKey *key;
1159 key = afsconf_typedKey_blank();
1165 key->subType = subType;
1167 code = rx_opaque_copy(&key->key, keyMaterial);
1177 afsconf_typedKey_free(struct afsconf_typedKey **key)
1181 rx_opaque_freeContents(&(*key)->key);
1186 struct afsconf_typedKey *
1187 afsconf_typedKey_get(struct afsconf_typedKey *key)
1189 rx_atomic_inc(&key->refcnt);
1194 afsconf_typedKey_put(struct afsconf_typedKey **key)
1196 if (rx_atomic_dec_and_read(&(*key)->refcnt) == 0)
1197 afsconf_typedKey_free(key);
1203 afsconf_typedKey_values(struct afsconf_typedKey *key, afsconf_keyType *type,
1204 int *kvno, int *subType, struct rx_opaque **material)
1210 if (subType != NULL)
1211 *subType = key->subType;
1212 if (material != NULL)
1213 *material = &key->key;
1217 afsconf_AddTypedKey(struct afsconf_dir *dir,
1218 struct afsconf_typedKey *key,
1225 code = _afsconf_Check(dir);
1229 if (key->type == afsconf_rxkad) {
1230 /* There are restrictions on rxkad keys so that we can still
1231 * return them using the old interface. We only enforce the
1232 * same restrictions as that interface does - that is, we don't
1233 * check that the key we're passed is a valid DES key */
1234 if (key->key.len != 8 || key->subType != 0) {
1235 code = AFSCONF_BADKEY;
1240 code = addMemoryKey(dir, key, overwrite);
1244 code = _afsconf_SaveKeys(dir);
1245 _afsconf_Touch(dir);
1248 UNLOCK_GLOBAL_MUTEX;
1253 afsconf_DeleteKeyByType(struct afsconf_dir *dir,
1254 afsconf_keyType type, int kvno)
1256 struct keyTypeList *typeEntry;
1257 struct kvnoList *kvnoEntry;
1262 code = _afsconf_Check(dir);
1266 typeEntry = findByType(dir, type);
1267 if (typeEntry == NULL) {
1268 code = AFSCONF_NOTFOUND;
1272 kvnoEntry = findInTypeList(typeEntry, kvno);
1273 if (kvnoEntry == NULL) {
1274 code = AFSCONF_NOTFOUND;
1278 deleteKvnoEntry(kvnoEntry);
1280 /* Remove the typeEntry, if it has no sub elements */
1281 if (opr_queue_IsEmpty(&typeEntry->kvnoList)) {
1282 opr_queue_Remove(&typeEntry->link);
1286 code = _afsconf_SaveKeys(dir);
1287 _afsconf_Touch(dir);
1290 UNLOCK_GLOBAL_MUTEX;
1295 afsconf_DeleteKeyBySubType(struct afsconf_dir *dir,
1296 afsconf_keyType type, int kvno, int subType)
1298 struct keyTypeList *typeEntry;
1299 struct kvnoList *kvnoEntry;
1300 struct subTypeList *subTypeEntry;
1305 code = _afsconf_Check(dir);
1309 typeEntry = findByType(dir, type);
1310 if (typeEntry == NULL)
1311 return AFSCONF_NOTFOUND;
1313 kvnoEntry = findInTypeList(typeEntry, kvno);
1314 if (kvnoEntry == NULL)
1315 return AFSCONF_NOTFOUND;
1317 subTypeEntry = findInKvnoList(kvnoEntry, subType);
1318 if (subTypeEntry == NULL)
1319 return AFSCONF_NOTFOUND;
1321 /* Remove the subTypeEntry */
1322 afsconf_typedKey_put(&subTypeEntry->key);
1323 opr_queue_Remove(&subTypeEntry->link);
1326 /* Remove the kvnoEntry, if it has no sub elements */
1327 if (opr_queue_IsEmpty(&kvnoEntry->subTypeList)) {
1328 opr_queue_Remove(&kvnoEntry->link);
1332 /* Remove the typeEntry, if it has no sub elements */
1333 if (opr_queue_IsEmpty(&typeEntry->kvnoList)) {
1334 opr_queue_Remove(&typeEntry->link);
1338 code = _afsconf_SaveKeys(dir);
1339 _afsconf_Touch(dir);
1342 UNLOCK_GLOBAL_MUTEX;
1347 afsconf_DeleteTypedKey(struct afsconf_dir *dir, struct afsconf_typedKey *key)
1349 return afsconf_DeleteKeyBySubType(dir, key->type, key->kvno, key->subType);