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_rxkad
&& 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
)
1062 rx_opaque_freeContents(&(*key
)->key
);
1067 struct afsconf_typedKey
*
1068 afsconf_typedKey_get(struct afsconf_typedKey
*key
)
1070 rx_atomic_inc(&key
->refcnt
);
1075 afsconf_typedKey_put(struct afsconf_typedKey
**key
)
1077 if (rx_atomic_dec_and_read(&(*key
)->refcnt
) == 0)
1078 afsconf_typedKey_free(key
);
1084 afsconf_typedKey_values(struct afsconf_typedKey
*key
, afsconf_keyType
*type
,
1085 int *kvno
, int *subType
, struct rx_opaque
**material
)
1091 if (subType
!= NULL
)
1092 *subType
= key
->subType
;
1093 if (material
!= NULL
)
1094 *material
= &key
->key
;
1098 afsconf_AddTypedKey(struct afsconf_dir
*dir
,
1099 struct afsconf_typedKey
*key
,
1106 code
= _afsconf_Check(dir
);
1110 if (key
->type
== afsconf_rxkad
) {
1111 /* There are restrictions on rxkad keys so that we can still
1112 * return them using the old interface. We only enforce the
1113 * same restrictions as that interface does - that is, we don't
1114 * check that the key we're passed is a valid DES key */
1115 if (key
->key
.len
!= 8 || key
->subType
!= 0) {
1116 code
= AFSCONF_BADKEY
;
1121 code
= addMemoryKey(dir
, key
, overwrite
);
1125 code
= _afsconf_SaveKeys(dir
);
1126 _afsconf_Touch(dir
);
1129 UNLOCK_GLOBAL_MUTEX
;
1134 afsconf_DeleteKeyByType(struct afsconf_dir
*dir
,
1135 afsconf_keyType type
, int kvno
)
1137 struct keyTypeList
*typeEntry
;
1138 struct kvnoList
*kvnoEntry
;
1143 code
= _afsconf_Check(dir
);
1147 typeEntry
= findByType(dir
, type
);
1148 if (typeEntry
== NULL
) {
1149 code
= AFSCONF_NOTFOUND
;
1153 kvnoEntry
= findInTypeList(typeEntry
, kvno
);
1154 if (kvnoEntry
== NULL
) {
1155 code
= AFSCONF_NOTFOUND
;
1159 deleteKvnoEntry(kvnoEntry
);
1161 /* Remove the typeEntry, if it has no sub elements */
1162 if (opr_queue_IsEmpty(&typeEntry
->kvnoList
)) {
1163 opr_queue_Remove(&typeEntry
->link
);
1167 code
= _afsconf_SaveKeys(dir
);
1168 _afsconf_Touch(dir
);
1171 UNLOCK_GLOBAL_MUTEX
;
1176 afsconf_DeleteKeyBySubType(struct afsconf_dir
*dir
,
1177 afsconf_keyType type
, int kvno
, int subType
)
1179 struct keyTypeList
*typeEntry
;
1180 struct kvnoList
*kvnoEntry
;
1181 struct subTypeList
*subTypeEntry
;
1186 code
= _afsconf_Check(dir
);
1190 typeEntry
= findByType(dir
, type
);
1191 if (typeEntry
== NULL
)
1192 return AFSCONF_NOTFOUND
;
1194 kvnoEntry
= findInTypeList(typeEntry
, kvno
);
1195 if (kvnoEntry
== NULL
)
1196 return AFSCONF_NOTFOUND
;
1198 subTypeEntry
= findInKvnoList(kvnoEntry
, subType
);
1199 if (subTypeEntry
== NULL
)
1200 return AFSCONF_NOTFOUND
;
1202 /* Remove the subTypeEntry */
1203 afsconf_typedKey_put(&subTypeEntry
->key
);
1204 opr_queue_Remove(&subTypeEntry
->link
);
1207 /* Remove the kvnoEntry, if it has no sub elements */
1208 if (opr_queue_IsEmpty(&kvnoEntry
->subTypeList
)) {
1209 opr_queue_Remove(&kvnoEntry
->link
);
1213 /* Remove the typeEntry, if it has no sub elements */
1214 if (opr_queue_IsEmpty(&typeEntry
->kvnoList
)) {
1215 opr_queue_Remove(&typeEntry
->link
);
1219 code
= _afsconf_SaveKeys(dir
);
1220 _afsconf_Touch(dir
);
1223 UNLOCK_GLOBAL_MUTEX
;
1228 afsconf_DeleteTypedKey(struct afsconf_dir
*dir
, struct afsconf_typedKey
*key
)
1230 return afsconf_DeleteKeyBySubType(dir
, key
->type
, key
->kvno
, key
->subType
);