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_CountKeys(struct afsconf_dir *dir)
943 struct opr_queue *typeCursor;
944 struct keyTypeList *typeEntry;
945 struct opr_queue *kvnoCursor;
946 struct kvnoList *kvnoEntry;
947 struct opr_queue *subCursor;
949 for (opr_queue_Scan(&dir->keyList, typeCursor)) {
950 typeEntry = opr_queue_Entry(typeCursor, struct keyTypeList, link);
951 for (opr_queue_Scan(&typeEntry->kvnoList, kvnoCursor)) {
952 kvnoEntry = opr_queue_Entry(kvnoCursor, struct kvnoList, link);
953 for (opr_queue_Scan(&kvnoEntry->subTypeList, subCursor))
961 afsconf_CountKeys(struct afsconf_dir *dir)
966 count = _afsconf_CountKeys(dir);
973 afsconf_GetAllKeys(struct afsconf_dir *dir, struct afsconf_typedKeyList **keys)
976 struct afsconf_typedKeyList *retval;
977 struct opr_queue *typeCursor;
978 struct keyTypeList *typeEntry;
979 struct opr_queue *kvnoCursor;
980 struct kvnoList *kvnoEntry;
981 struct opr_queue *subCursor;
982 struct subTypeList *subEntry;
987 code = _afsconf_Check(dir);
991 /* First, work out how many keys we have in total */
992 count = _afsconf_CountKeys(dir);
994 /* Allocate space for all of these */
995 retval = malloc(sizeof(struct afsconf_typedKeyList));
996 retval->nkeys = count;
999 retval->keys = calloc(retval->nkeys,
1000 sizeof(struct afsconf_typedKey *));
1002 /* Populate the key list */
1004 for (opr_queue_Scan(&dir->keyList, typeCursor)) {
1005 typeEntry = opr_queue_Entry(typeCursor,
1006 struct keyTypeList, link);
1007 for (opr_queue_Scan(&typeEntry->kvnoList, kvnoCursor)) {
1008 kvnoEntry = opr_queue_Entry(kvnoCursor,
1009 struct kvnoList, link);
1010 for (opr_queue_Scan(&kvnoEntry->subTypeList, subCursor)) {
1011 subEntry = opr_queue_Entry(subCursor,
1012 struct subTypeList, link);
1013 retval->keys[count] = afsconf_typedKey_get(subEntry->key);
1019 retval->keys = NULL;
1025 UNLOCK_GLOBAL_MUTEX;
1030 afsconf_GetKeyByTypes(struct afsconf_dir *dir, afsconf_keyType type,
1031 int kvno, int subType, struct afsconf_typedKey **key)
1034 struct subTypeList *subTypeEntry;
1038 code = _afsconf_Check(dir);
1042 subTypeEntry = findBySubType(dir, type, kvno, subType);
1043 if (subTypeEntry == NULL) {
1044 code = AFSCONF_NOTFOUND;
1048 *key = afsconf_typedKey_get(subTypeEntry->key);
1051 UNLOCK_GLOBAL_MUTEX;
1055 static struct kvnoList *
1056 pickBestKvno(struct afsconf_dir *dir, afsconf_keyType type)
1058 struct keyTypeList *typeEntry;
1059 struct kvnoList *kvnoEntry;
1061 typeEntry = findByType(dir, type);
1062 if (typeEntry == NULL)
1065 /* We store all of the key lists ordered, so the last entry in the
1066 * kvno list must be the highest kvno. */
1068 kvnoEntry = opr_queue_Last(&typeEntry->kvnoList, struct kvnoList, link);
1070 /* Except, if we're in the rxkad list, we might have a bcrypt entry that
1071 * has a kvno of 999. So we need to skip that one
1073 while (type == afsconf_rxkad && kvnoEntry->kvno == 999) {
1074 kvnoEntry = opr_queue_Prev(&typeEntry->kvnoList, struct kvnoList,
1076 if (opr_queue_IsEnd(&typeEntry->kvnoList, &kvnoEntry->link))
1085 afsconf_GetLatestKeysByType(struct afsconf_dir *dir, afsconf_keyType type,
1086 struct afsconf_typedKeyList **keys)
1089 struct kvnoList *kvnoEntry;
1093 code = _afsconf_Check(dir);
1098 kvnoEntry = pickBestKvno(dir, type);
1099 if (kvnoEntry == NULL) {
1100 code = AFSCONF_NOTFOUND;
1104 code = listToArray(kvnoEntry, keys);
1107 UNLOCK_GLOBAL_MUTEX;
1112 afsconf_GetLatestKeyByTypes(struct afsconf_dir *dir, afsconf_keyType type,
1113 int subType, struct afsconf_typedKey **key)
1116 struct kvnoList *kvnoEntry;
1117 struct subTypeList *subTypeEntry;
1121 code = _afsconf_Check(dir);
1125 kvnoEntry = pickBestKvno(dir, type);
1126 if (kvnoEntry == NULL) {
1127 code = AFSCONF_NOTFOUND;
1131 subTypeEntry = findInKvnoList(kvnoEntry, subType);
1132 if (subTypeEntry == NULL) {
1133 code = AFSCONF_NOTFOUND;
1137 *key = afsconf_typedKey_get(subTypeEntry->key);
1140 UNLOCK_GLOBAL_MUTEX;
1145 afsconf_PutTypedKeyList(struct afsconf_typedKeyList **keys)
1149 if (*keys == NULL) {
1153 for (i=0;i<(*keys)->nkeys;i++)
1154 afsconf_typedKey_put(&((*keys)->keys[i]));
1156 if ((*keys)->keys != NULL)
1157 free((*keys)->keys);
1163 static struct afsconf_typedKey *
1164 afsconf_typedKey_blank(void)
1166 struct afsconf_typedKey *key;
1168 key = calloc(1, sizeof(struct afsconf_typedKey));
1172 rx_atomic_set(&key->refcnt, 1);
1177 struct afsconf_typedKey *
1178 afsconf_typedKey_new(afsconf_keyType type, int kvno, int subType,
1179 struct rx_opaque *keyMaterial)
1181 struct afsconf_typedKey *key;
1184 key = afsconf_typedKey_blank();
1190 key->subType = subType;
1192 code = rx_opaque_copy(&key->key, keyMaterial);
1202 afsconf_typedKey_free(struct afsconf_typedKey **key)
1206 rx_opaque_freeContents(&(*key)->key);
1211 struct afsconf_typedKey *
1212 afsconf_typedKey_get(struct afsconf_typedKey *key)
1214 rx_atomic_inc(&key->refcnt);
1219 afsconf_typedKey_put(struct afsconf_typedKey **key)
1221 if (rx_atomic_dec_and_read(&(*key)->refcnt) == 0)
1222 afsconf_typedKey_free(key);
1228 afsconf_typedKey_values(struct afsconf_typedKey *key, afsconf_keyType *type,
1229 int *kvno, int *subType, struct rx_opaque **material)
1235 if (subType != NULL)
1236 *subType = key->subType;
1237 if (material != NULL)
1238 *material = &key->key;
1242 afsconf_AddTypedKey(struct afsconf_dir *dir,
1243 struct afsconf_typedKey *key,
1250 code = _afsconf_Check(dir);
1254 if (key->type == afsconf_rxkad) {
1255 /* There are restrictions on rxkad keys so that we can still
1256 * return them using the old interface. We only enforce the
1257 * same restrictions as that interface does - that is, we don't
1258 * check that the key we're passed is a valid DES key */
1259 if (key->key.len != 8 || key->subType != 0) {
1260 code = AFSCONF_BADKEY;
1265 code = addMemoryKey(dir, key, overwrite);
1269 code = _afsconf_SaveKeys(dir);
1270 _afsconf_Touch(dir);
1273 UNLOCK_GLOBAL_MUTEX;
1278 afsconf_DeleteKeyByType(struct afsconf_dir *dir,
1279 afsconf_keyType type, int kvno)
1281 struct keyTypeList *typeEntry;
1282 struct kvnoList *kvnoEntry;
1287 code = _afsconf_Check(dir);
1291 typeEntry = findByType(dir, type);
1292 if (typeEntry == NULL) {
1293 code = AFSCONF_NOTFOUND;
1297 kvnoEntry = findInTypeList(typeEntry, kvno);
1298 if (kvnoEntry == NULL) {
1299 code = AFSCONF_NOTFOUND;
1303 deleteKvnoEntry(kvnoEntry);
1305 /* Remove the typeEntry, if it has no sub elements */
1306 if (opr_queue_IsEmpty(&typeEntry->kvnoList)) {
1307 opr_queue_Remove(&typeEntry->link);
1311 code = _afsconf_SaveKeys(dir);
1312 _afsconf_Touch(dir);
1315 UNLOCK_GLOBAL_MUTEX;
1320 afsconf_DeleteKeyBySubType(struct afsconf_dir *dir,
1321 afsconf_keyType type, int kvno, int subType)
1323 struct keyTypeList *typeEntry;
1324 struct kvnoList *kvnoEntry;
1325 struct subTypeList *subTypeEntry;
1330 code = _afsconf_Check(dir);
1334 typeEntry = findByType(dir, type);
1335 if (typeEntry == NULL)
1336 return AFSCONF_NOTFOUND;
1338 kvnoEntry = findInTypeList(typeEntry, kvno);
1339 if (kvnoEntry == NULL)
1340 return AFSCONF_NOTFOUND;
1342 subTypeEntry = findInKvnoList(kvnoEntry, subType);
1343 if (subTypeEntry == NULL)
1344 return AFSCONF_NOTFOUND;
1346 /* Remove the subTypeEntry */
1347 afsconf_typedKey_put(&subTypeEntry->key);
1348 opr_queue_Remove(&subTypeEntry->link);
1351 /* Remove the kvnoEntry, if it has no sub elements */
1352 if (opr_queue_IsEmpty(&kvnoEntry->subTypeList)) {
1353 opr_queue_Remove(&kvnoEntry->link);
1357 /* Remove the typeEntry, if it has no sub elements */
1358 if (opr_queue_IsEmpty(&typeEntry->kvnoList)) {
1359 opr_queue_Remove(&typeEntry->link);
1363 code = _afsconf_SaveKeys(dir);
1364 _afsconf_Touch(dir);
1367 UNLOCK_GLOBAL_MUTEX;
1372 afsconf_DeleteTypedKey(struct afsconf_dir *dir, struct afsconf_typedKey *key)
1374 return afsconf_DeleteKeyBySubType(dir, key->type, key->kvno, key->subType);