/* Need rx/rx.h to get working assert(), used by LOCK_GLOBAL_MUTEX */
#include <rx/rx.h>
#include <rx/rx_atomic.h>
+#ifdef AFS_RXGK_ENV
+#include <rx/rxgk.h>
+#endif
+#include <afs/opr.h>
#include <afs/stds.h>
#include <afs/pthread_glock.h>
#include <afs/afsutil.h>
/* Allocate space for the keys we've got stored */
retval = malloc(sizeof(struct afsconf_typedKeyList));
retval->nkeys = opr_queue_Count(&kvnoEntry->subTypeList);
- retval->keys = calloc(retval->nkeys, sizeof(struct afsconf_typedKey *));
- i = 0;
- for(opr_queue_Scan(&kvnoEntry->subTypeList, cursor)) {
- struct subTypeList *entry;
+ if (retval->nkeys > 0) {
+ retval->keys = calloc(retval->nkeys, sizeof(struct afsconf_typedKey *));
- entry = opr_queue_Entry(cursor, struct subTypeList, link);
- retval->keys[i] = afsconf_typedKey_get(entry->key);
- i++;
+ i = 0;
+ for(opr_queue_Scan(&kvnoEntry->subTypeList, cursor)) {
+ struct subTypeList *entry;
+
+ entry = opr_queue_Entry(cursor, struct subTypeList, link);
+ retval->keys[i] = afsconf_typedKey_get(entry->key);
+ i++;
+ }
+ } else {
+ retval->keys = NULL;
}
*keys = retval;
* in the original KeyFile, so that we can continue to be compatible with
* utilities that directly modify that file.
*
- * All other keys are stored in the file KeyFileEx, which has the following
+ * All other keys are stored in the file KeyFileExt, which has the following
* format:
* 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
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
- * | version number |
- * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | number of keys |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Key data ...
* +-+-+-+-+-+-+-+
*
- * The version number is 1 at present. Version numbers higher than 1
- * indicate a keyfile that is not backwards compatible with this
- * specification.
+ * If the format ever needs to chanage incompatibly, a new file name
+ * will be used.
*
* Key data is a sequence of the following records (note that these are
* not word aligned - the next record begins where the previous one ends)
for(i=0; i<nkeys; i++) {
key = afsconf_typedKey_blank();
+ if (key == NULL)
+ goto fail;
key->type = afsconf_rxkad;
key->subType = 0;
return AFSCONF_FAILURE;
typeEntry = findByType(dir, afsconf_rxkad);
- if (typeEntry == NULL)
- goto out;
-
- nkeys = opr_queue_Count(&typeEntry->kvnoList);
+ if (typeEntry)
+ nkeys = opr_queue_Count(&typeEntry->kvnoList);
+ else
+ nkeys = 0;
if (writeWord(fd, nkeys))
goto fail;
+ if (typeEntry == NULL)
+ goto out;
+
for (opr_queue_Scan(&typeEntry->kvnoList, cursor)) {
struct kvnoList *kvnoEntry;
struct subTypeList *subEntry;
{
int fd, i, code;
afs_int32 nkeys;
- struct afsconf_typedKey *key;
+ struct afsconf_typedKey *key = NULL;
fd = open(fileName, O_RDONLY);
if (fd < 0)
afs_int32 reclen;
key = afsconf_typedKey_blank();
+ if (key == NULL)
+ goto fail;
/* The only data version we currently parse has a reclen of 16.
* Anything smaller indicates a corrupt key file. Anything more,
code = read(fd, key->key.val, reclen);
if (code != reclen) {
rx_opaque_freeContents(&key->key);
- free(key);
goto fail;
}
code = addMemoryKey(dir, key, 1);
return 0;
fail:
+ if (key)
+ afsconf_typedKey_put(&key);
+
close(fd);
return EIO;
}
/* XXX - Should check that the key is of the correct length */
/* Copy out the relevant details */
- *kvno = typedKey->kvno;
- memcpy(key, typedKey->key.val, 8);
+ if (kvno != NULL)
+ *kvno = typedKey->kvno;
+
+ if (key != NULL)
+ memcpy(key, typedKey->key.val, 8);
afsconf_typedKey_put(&typedKey);
return 0;
}
+static int
+_afsconf_GetLatestRXGKKey(afsconf_keyType type, struct afsconf_dir *rock,
+ afs_int32 *avno, afs_int32 *enctype, rxgk_key *key)
+{
+#ifdef AFS_RXGK_ENV
+ struct afsconf_typedKeyList *list = NULL;
+ struct afsconf_typedKey *typedKey = NULL;
+ afs_int32 code;
+ int key_i;
+
+ code = afsconf_GetLatestKeysByType(rock, type, &list);
+ if (code != 0)
+ goto done;
+
+ for (key_i = 0; key_i < list->nkeys; key_i++) {
+ if (typedKey == NULL)
+ typedKey = list->keys[key_i];
+ else if (rxgk_enctype_better(typedKey->subType, list->keys[key_i]->subType))
+ typedKey = list->keys[key_i];
+ }
+
+ opr_Assert(typedKey != NULL);
+
+ /* We picked a key; copy to the output parameters */
+ code = rxgk_make_key(key, typedKey->key.val, typedKey->key.len,
+ typedKey->subType);
+ if (code != 0)
+ goto done;
+ if (avno != NULL)
+ *avno = typedKey->kvno;
+ if (enctype != NULL)
+ *enctype = typedKey->subType;
+
+ done:
+ afsconf_PutTypedKeyList(&list);
+ return code;
+#else /* AFS_RXGK_ENV */
+ return AFSCONF_NOTFOUND;
+#endif
+}
+
+/**
+ * Obtain the "best" rxgk key from KeyFileExt
+ *
+ * Return the key and its enctype and kvno, for encrypting outgoing tokens.
+ *
+ * @param[in] rock The configuration directory to be used.
+ * @param[out] avno The key version number of key.
+ * @param[out] enctype The RFC 3961 enctype of key.
+ * @param[out] key The returned rxgk key.
+ */
+int
+afsconf_GetLatestRXGKKey(struct afsconf_dir *rock, afs_int32 *avno,
+ afs_int32 *enctype, rxgk_key *key)
+{
+ return _afsconf_GetLatestRXGKKey(afsconf_rxgk, rock, avno, enctype, key);
+}
+
+static int
+_afsconf_GetRXGKKey(afsconf_keyType type, void *rock, afs_int32 *avno,
+ afs_int32 *enctype, rxgk_key *key)
+{
+#ifdef AFS_RXGK_ENV
+ struct afsconf_dir *dir = rock;
+ struct afsconf_typedKey *typedKey;
+ afs_int32 code;
+
+ /* No information at all means "pick the best/newest one". */
+ if (*avno == 0 && *enctype == 0)
+ return _afsconf_GetLatestRXGKKey(type, dir, avno, enctype, key);
+
+ code = afsconf_GetKeyByTypes(dir, type, *avno, *enctype, &typedKey);
+ if (code != 0)
+ return code;
+
+ code = rxgk_make_key(key, typedKey->key.val, typedKey->key.len,
+ typedKey->subType);
+ afsconf_typedKey_put(&typedKey);
+
+ return code;
+#else /* AFS_RXGK_ENV */
+ return AFSCONF_NOTFOUND;
+#endif
+}
+
+/**
+ * Obtain a particular RXGK key from KeyFileExt
+ *
+ * Use the specified kvno and enctype to fetch an rxgk key from KeyFileExt
+ * and return it as an rxgk_key. Specifying the kvno/enctype pair as both
+ * zeros causes the "best" rxgk key to be returned, and the kvno/enctype
+ * of that key returned to the caller.
+ *
+ * @param[in] rock An afsconf_dir* for the configuration directory. This
+ * is a void* just so this can be easily used as a
+ * callback function that uses a void* rock.
+ * @param[inout] avno The requested kvno (if non-zero), or zero to request
+ * the latest key and have its kvno returned in this
+ * parameter.
+ * @param[inout] enctype The requested enctype (if non-zero), or zero
+ * to request the latest key and have its
+ * enctype returned in this parameter.
+ * @param[out] key The returned rxgk key.
+ */
+int
+afsconf_GetRXGKKey(void *rock, afs_int32 *avno,
+ afs_int32 *enctype, rxgk_key *key)
+{
+ return _afsconf_GetRXGKKey(afsconf_rxgk, rock, avno, enctype, key);
+}
+
int
afsconf_AddKey(struct afsconf_dir *dir, afs_int32 kvno, char key[8],
afs_int32 overwrite)
}
int
+_afsconf_CountKeys(struct afsconf_dir *dir)
+{
+ int count = 0;
+ struct opr_queue *typeCursor;
+ struct keyTypeList *typeEntry;
+ struct opr_queue *kvnoCursor;
+ struct kvnoList *kvnoEntry;
+ struct opr_queue *subCursor;
+
+ for (opr_queue_Scan(&dir->keyList, typeCursor)) {
+ typeEntry = opr_queue_Entry(typeCursor, struct keyTypeList, link);
+ for (opr_queue_Scan(&typeEntry->kvnoList, kvnoCursor)) {
+ kvnoEntry = opr_queue_Entry(kvnoCursor, struct kvnoList, link);
+ for (opr_queue_Scan(&kvnoEntry->subTypeList, subCursor))
+ count++;
+ }
+ }
+ return count;
+}
+
+int
+afsconf_CountKeys(struct afsconf_dir *dir)
+{
+ int count = 0;
+
+ LOCK_GLOBAL_MUTEX;
+ count = _afsconf_CountKeys(dir);
+ UNLOCK_GLOBAL_MUTEX;
+
+ return count;
+}
+
+int
+afsconf_GetAllKeys(struct afsconf_dir *dir, struct afsconf_typedKeyList **keys)
+{
+ int code;
+ struct afsconf_typedKeyList *retval;
+ struct opr_queue *typeCursor;
+ struct keyTypeList *typeEntry;
+ struct opr_queue *kvnoCursor;
+ struct kvnoList *kvnoEntry;
+ struct opr_queue *subCursor;
+ struct subTypeList *subEntry;
+ int count;
+
+ LOCK_GLOBAL_MUTEX;
+
+ code = _afsconf_Check(dir);
+ if (code)
+ goto out;
+
+ /* First, work out how many keys we have in total */
+ count = _afsconf_CountKeys(dir);
+
+ /* Allocate space for all of these */
+ retval = malloc(sizeof(struct afsconf_typedKeyList));
+ retval->nkeys = count;
+
+ if (count > 0) {
+ retval->keys = calloc(retval->nkeys,
+ sizeof(struct afsconf_typedKey *));
+
+ /* Populate the key list */
+ count = 0;
+ for (opr_queue_Scan(&dir->keyList, typeCursor)) {
+ typeEntry = opr_queue_Entry(typeCursor,
+ struct keyTypeList, link);
+ for (opr_queue_Scan(&typeEntry->kvnoList, kvnoCursor)) {
+ kvnoEntry = opr_queue_Entry(kvnoCursor,
+ struct kvnoList, link);
+ for (opr_queue_Scan(&kvnoEntry->subTypeList, subCursor)) {
+ subEntry = opr_queue_Entry(subCursor,
+ struct subTypeList, link);
+ retval->keys[count] = afsconf_typedKey_get(subEntry->key);
+ count++;
+ }
+ }
+ }
+ } else {
+ retval->keys = NULL;
+ }
+
+ *keys = retval;
+
+out:
+ UNLOCK_GLOBAL_MUTEX;
+ return code;
+}
+
+int
afsconf_GetKeyByTypes(struct afsconf_dir *dir, afsconf_keyType type,
int kvno, int subType, struct afsconf_typedKey **key)
{
/* Except, if we're in the rxkad list, we might have a bcrypt entry that
* has a kvno of 999. So we need to skip that one
*/
- while (type == afsconf_rxgk && kvnoEntry->kvno == 999) {
+ while (type == afsconf_rxkad && kvnoEntry->kvno == 999) {
kvnoEntry = opr_queue_Prev(&typeEntry->kvnoList, struct kvnoList,
link);
if (opr_queue_IsEnd(&typeEntry->kvnoList, &kvnoEntry->link))
{
int i;
+ if (*keys == NULL) {
+ return;
+ }
+
for (i=0;i<(*keys)->nkeys;i++)
afsconf_typedKey_put(&((*keys)->keys[i]));
- free((*keys)->keys);
+
+ if ((*keys)->keys != NULL)
+ free((*keys)->keys);
+
free(*keys);
*keys = NULL;
}
{
struct afsconf_typedKey *key;
- key = malloc(sizeof(struct afsconf_typedKey));
+ key = calloc(1, sizeof(struct afsconf_typedKey));
if (key == NULL)
return NULL;
- memset(key, 0, sizeof(struct afsconf_typedKey));
rx_atomic_set(&key->refcnt, 1);
return key;
void
afsconf_typedKey_free(struct afsconf_typedKey **key)
{
+ if (*key == NULL)
+ return;
rx_opaque_freeContents(&(*key)->key);
free(*key);
*key = NULL;
afsconf_typedKey_values(struct afsconf_typedKey *key, afsconf_keyType *type,
int *kvno, int *subType, struct rx_opaque **material)
{
- *type = key->type;
- *kvno = key->kvno;
- *subType = key->subType;
- *material = &key->key;
+ if (type != NULL)
+ *type = key->type;
+ if (kvno != NULL)
+ *kvno = key->kvno;
+ if (subType != NULL)
+ *subType = key->subType;
+ if (material != NULL)
+ *material = &key->key;
}
int