* "id:<id>" - request a key matching the ID
* "<subtype>:<id>" - request a key of a subtype
*/
-static int asymmetric_key_match(const struct key *key, const void *description)
+static int asymmetric_key_match(const struct key *key,
+ const struct key_match_data *match_data)
{
const struct asymmetric_key_subtype *subtype = asymmetric_key_subtype(key);
+ const char *description = match_data->raw_data;
const char *spec = description;
const char *id;
ptrdiff_t speclen;
return 0;
}
+/*
+ * Preparse the match criterion. If we don't set lookup_type and cmp,
+ * the default will be an exact match on the key description.
+ *
+ * There are some specifiers for matching key IDs rather than by the key
+ * description:
+ *
+ * "id:<id>" - request a key by any available ID
+ *
+ * These have to be searched by iteration rather than by direct lookup because
+ * the key is hashed according to its description.
+ */
+static int asymmetric_key_match_preparse(struct key_match_data *match_data)
+{
+ match_data->lookup_type = KEYRING_SEARCH_LOOKUP_ITERATE;
+ return 0;
+}
+
+/*
+ * Free the preparsed the match criterion.
+ */
+static void asymmetric_key_match_free(struct key_match_data *match_data)
+{
+}
+
/*
* Describe the asymmetric key
*/
.preparse = asymmetric_key_preparse,
.free_preparse = asymmetric_key_free_preparse,
.instantiate = generic_key_instantiate,
+ .match_preparse = asymmetric_key_match_preparse,
.match = asymmetric_key_match,
+ .match_free = asymmetric_key_match_free,
.destroy = asymmetric_key_destroy,
.describe = asymmetric_key_describe,
.def_lookup_type = KEYRING_SEARCH_LOOKUP_ITERATE,
extern struct key_type key_type_logon;
struct key_preparsed_payload;
+struct key_match_data;
extern int user_preparse(struct key_preparsed_payload *prep);
extern void user_free_preparse(struct key_preparsed_payload *prep);
extern int user_update(struct key *key, struct key_preparsed_payload *prep);
-extern int user_match(const struct key *key, const void *criterion);
+extern int user_match(const struct key *key,
+ const struct key_match_data *match_data);
extern void user_revoke(struct key *key);
extern void user_destroy(struct key *key);
extern void user_describe(const struct key *user, struct seq_file *m);
typedef int (*request_key_actor_t)(struct key_construction *key,
const char *op, void *aux);
+/*
+ * Preparsed matching criterion.
+ */
+struct key_match_data {
+ /* Comparison function, defaults to type->match, but can be replaced by
+ * type->match_preparse(). */
+ int (*cmp)(const struct key *key,
+ const struct key_match_data *match_data);
+
+ const void *raw_data; /* Raw match data */
+ void *preparsed; /* For ->match_preparse() to stash stuff */
+ unsigned lookup_type; /* Type of lookup for this search. */
+#define KEYRING_SEARCH_LOOKUP_DIRECT 0x0000 /* Direct lookup by description. */
+#define KEYRING_SEARCH_LOOKUP_ITERATE 0x0001 /* Iterative search. */
+};
+
/*
* kernel managed key type definition
*/
/* Default key search algorithm. */
unsigned def_lookup_type;
-#define KEYRING_SEARCH_LOOKUP_DIRECT 0x0000 /* Direct lookup by description. */
-#define KEYRING_SEARCH_LOOKUP_ITERATE 0x0001 /* Iterative search. */
/* vet a description */
int (*vet_description)(const char *description);
*/
int (*update)(struct key *key, struct key_preparsed_payload *prep);
+ /* Preparse the data supplied to ->match() (optional). The
+ * data to be preparsed can be found in match_data->raw_data.
+ * The lookup type can also be set by this function.
+ */
+ int (*match_preparse)(struct key_match_data *match_data);
+
/* match a key against a description */
- int (*match)(const struct key *key, const void *desc);
+ int (*match)(const struct key *key,
+ const struct key_match_data *match_data);
+
+ /* Free preparsed match data (optional). This should be supplied it
+ * ->match_preparse() is supplied. */
+ void (*match_free)(struct key_match_data *match_data);
/* clear some of the data from a key on revokation (optional)
* - the key's semaphore will be write-locked by the caller
* should end with a period). The domain name is case-independent.
*/
static int
-dns_resolver_match(const struct key *key, const void *description)
+dns_resolver_match(const struct key *key,
+ const struct key_match_data *match_data)
{
int slen, dlen, ret = 0;
- const char *src = key->description, *dsp = description;
+ const char *src = key->description, *dsp = match_data->raw_data;
kenter("%s,%s", src, dsp);
int (*func)(const struct key *key, void *data),
void *data);
-typedef int (*key_match_func_t)(const struct key *, const void *);
-
struct keyring_search_context {
struct keyring_index_key index_key;
const struct cred *cred;
- key_match_func_t match;
- const void *match_data;
+ struct key_match_data match_data;
unsigned flags;
#define KEYRING_SEARCH_LOOKUP_TYPE 0x0001 /* [as type->def_lookup_type] */
#define KEYRING_SEARCH_NO_STATE_CHECK 0x0002 /* Skip state checks */
struct key *dest_keyring,
unsigned long flags);
-extern int lookup_user_key_possessed(const struct key *key, const void *target);
+extern int lookup_user_key_possessed(const struct key *key,
+ const struct key_match_data *match_data);
extern key_ref_t lookup_user_key(key_serial_t id, unsigned long flags,
key_perm_t perm);
#define KEY_LOOKUP_CREATE 0x01
}
/* keys that don't match */
- if (!ctx->match(key, ctx->match_data)) {
+ if (!ctx->match_data.cmp(key, &ctx->match_data)) {
kleave(" = 0 [!match]");
return 0;
}
*/
static int search_keyring(struct key *keyring, struct keyring_search_context *ctx)
{
- if ((ctx->flags & KEYRING_SEARCH_LOOKUP_TYPE) ==
- KEYRING_SEARCH_LOOKUP_DIRECT) {
+ if (ctx->match_data.lookup_type == KEYRING_SEARCH_LOOKUP_DIRECT) {
const void *object;
object = assoc_array_find(&keyring->keys,
/* Check to see if this top-level keyring is what we are looking for
* and whether it is valid or not.
*/
- if (ctx->flags & KEYRING_SEARCH_LOOKUP_ITERATE ||
+ if (ctx->match_data.lookup_type == KEYRING_SEARCH_LOOKUP_ITERATE ||
keyring_compare_object(keyring, &ctx->index_key)) {
ctx->skipped_ret = 2;
ctx->flags |= KEYRING_SEARCH_DO_STATE_CHECK;
.index_key.type = type,
.index_key.description = description,
.cred = current_cred(),
- .match = type->match,
- .match_data = description,
- .flags = (type->def_lookup_type |
- KEYRING_SEARCH_DO_STATE_CHECK),
+ .match_data.cmp = type->match,
+ .match_data.raw_data = description,
+ .match_data.lookup_type = KEYRING_SEARCH_LOOKUP_DIRECT,
+ .flags = KEYRING_SEARCH_DO_STATE_CHECK,
};
+ key_ref_t key;
+ int ret;
- if (!ctx.match)
+ if (!ctx.match_data.cmp)
return ERR_PTR(-ENOKEY);
- return keyring_search_aux(keyring, &ctx);
+ if (type->match_preparse) {
+ ret = type->match_preparse(&ctx.match_data);
+ if (ret < 0)
+ return ERR_PTR(ret);
+ }
+
+ key = keyring_search_aux(keyring, &ctx);
+
+ if (type->match_free)
+ type->match_free(&ctx.match_data);
+ return key;
}
EXPORT_SYMBOL(keyring_search);
/* We might get a keyring with matching index-key that is nonetheless a
* different keyring. */
- if (key != ctx->match_data)
+ if (key != ctx->match_data.raw_data)
return 0;
ctx->result = ERR_PTR(-EDEADLK);
static int keyring_detect_cycle(struct key *A, struct key *B)
{
struct keyring_search_context ctx = {
- .index_key = A->index_key,
- .match_data = A,
- .iterator = keyring_detect_cycle_iterator,
- .flags = (KEYRING_SEARCH_LOOKUP_DIRECT |
- KEYRING_SEARCH_NO_STATE_CHECK |
- KEYRING_SEARCH_NO_UPDATE_TIME |
- KEYRING_SEARCH_NO_CHECK_PERM |
- KEYRING_SEARCH_DETECT_TOO_DEEP),
+ .index_key = A->index_key,
+ .match_data.raw_data = A,
+ .match_data.lookup_type = KEYRING_SEARCH_LOOKUP_DIRECT,
+ .iterator = keyring_detect_cycle_iterator,
+ .flags = (KEYRING_SEARCH_NO_STATE_CHECK |
+ KEYRING_SEARCH_NO_UPDATE_TIME |
+ KEYRING_SEARCH_NO_CHECK_PERM |
+ KEYRING_SEARCH_DETECT_TOO_DEEP),
};
rcu_read_lock();
.index_key.type = key->type,
.index_key.description = key->description,
.cred = current_cred(),
- .match = lookup_user_key_possessed,
- .match_data = key,
- .flags = (KEYRING_SEARCH_NO_STATE_CHECK |
- KEYRING_SEARCH_LOOKUP_DIRECT),
+ .match_data.cmp = lookup_user_key_possessed,
+ .match_data.raw_data = key,
+ .match_data.lookup_type = KEYRING_SEARCH_LOOKUP_DIRECT,
+ .flags = KEYRING_SEARCH_NO_STATE_CHECK,
};
key_ref = make_key_ref(key, 0);
/*
* See if the key we're looking at is the target key.
*/
-int lookup_user_key_possessed(const struct key *key, const void *target)
+int lookup_user_key_possessed(const struct key *key,
+ const struct key_match_data *match_data)
{
- return key == target;
+ return key == match_data->raw_data;
}
/*
key_perm_t perm)
{
struct keyring_search_context ctx = {
- .match = lookup_user_key_possessed,
- .flags = (KEYRING_SEARCH_NO_STATE_CHECK |
- KEYRING_SEARCH_LOOKUP_DIRECT),
+ .match_data.cmp = lookup_user_key_possessed,
+ .match_data.lookup_type = KEYRING_SEARCH_LOOKUP_DIRECT,
+ .flags = KEYRING_SEARCH_NO_STATE_CHECK,
};
struct request_key_auth *rka;
struct key *key;
ctx.index_key.type = key->type;
ctx.index_key.description = key->description;
ctx.index_key.desc_len = strlen(key->description);
- ctx.match_data = key;
+ ctx.match_data.raw_data = key;
kdebug("check possessed");
skey_ref = search_process_keyrings(&ctx);
kdebug("possessed=%p", skey_ref);
.index_key.type = type,
.index_key.description = description,
.cred = current_cred(),
- .match = type->match,
- .match_data = description,
- .flags = KEYRING_SEARCH_LOOKUP_DIRECT,
+ .match_data.cmp = type->match,
+ .match_data.raw_data = description,
+ .match_data.lookup_type = KEYRING_SEARCH_LOOKUP_DIRECT,
};
struct key *key;
key_ref_t key_ref;
ctx.index_key.type->name, ctx.index_key.description,
callout_info, callout_len, aux, dest_keyring, flags);
+ if (type->match_preparse) {
+ ret = type->match_preparse(&ctx.match_data);
+ if (ret < 0) {
+ key = ERR_PTR(ret);
+ goto error;
+ }
+ }
+
/* search all the process keyrings for a key */
key_ref = search_process_keyrings(&ctx);
if (ret < 0) {
key_put(key);
key = ERR_PTR(ret);
- goto error;
+ goto error_free;
}
}
} else if (PTR_ERR(key_ref) != -EAGAIN) {
* should consult userspace if we can */
key = ERR_PTR(-ENOKEY);
if (!callout_info)
- goto error;
+ goto error_free;
key = construct_key_and_link(&ctx, callout_info, callout_len,
aux, dest_keyring, flags);
}
+error_free:
+ if (type->match_free)
+ type->match_free(&ctx.match_data);
error:
kleave(" = %p", key);
return key;
.index_key.type = &key_type_request_key_auth,
.index_key.description = description,
.cred = current_cred(),
- .match = user_match,
- .match_data = description,
- .flags = KEYRING_SEARCH_LOOKUP_DIRECT,
+ .match_data.cmp = user_match,
+ .match_data.raw_data = description,
+ .match_data.lookup_type = KEYRING_SEARCH_LOOKUP_DIRECT,
};
struct key *authkey;
key_ref_t authkey_ref;
/*
* match users on their name
*/
-int user_match(const struct key *key, const void *description)
+int user_match(const struct key *key, const struct key_match_data *match_data)
{
- return strcmp(key->description, description) == 0;
+ return strcmp(key->description, match_data->raw_data) == 0;
}
EXPORT_SYMBOL_GPL(user_match);