Commit 25cd4bcb authored by Jan Včelák's avatar Jan Včelák 🚀
Browse files

keymgr, unify key searching code

parent a3948283
......@@ -186,6 +186,143 @@ static int print_list(dnssec_list_t *list, const char *filter)
return found_match ? DNSSEC_EOK : DNSSEC_NOT_FOUND;
}
/* -- key matching --------------------------------------------------------- */
/*!
* Key match callback function prototype.
*/
typedef int (*key_match_cb)(dnssec_kasp_key_t *key, void *data);
/*!
* Convert search string to keytag value.
*
* \return Keytag or -1 if the search string is not a keytag value.
*/
static int search_str_to_keytag(const char *search)
{
assert(search);
errno = 0;
char *end = NULL;
long value = strtol(search, &end, 10);
if (*end == '\0' && errno == 0 && 0 <= value && value <= UINT16_MAX) {
return value;
} else {
return -1;
}
}
/*!
* Check if key matches search string or search keytag.
*
* \param key DNSSEC key to test.
* \param keytag Key tag to match (ignored if negative).
* \param search Key ID to match (prefix based match).
*
* \return DNSSEC key matches key tag or key ID.
*/
static bool key_match(const dnssec_key_t *key, int keytag, const char *keyid)
{
assert(key);
assert(keyid);
// key tag
if (keytag > 0 && dnssec_key_get_keytag(key) == keytag) {
return true;
}
// key ID
const char *id = dnssec_key_get_id(key);
size_t id_len = strlen(id);
size_t keyid_len = strlen(keyid);
return (keyid_len <= id_len && strncasecmp(id, keyid, keyid_len) == 0);
}
/*!
* Call a function for each key matching the search string.
*
* \param list List of \ref dnssec_kasp_key_t keys.
* \param search Search string, can be key tag or key ID prefix.
* \param match Callback function.
* \param data Custom data passed to callback function.
*
* \return Error code propagated from callback function.
*/
static int search_key(dnssec_list_t *list, const char *search,
key_match_cb match, void *data)
{
assert(list);
assert(search);
assert(match);
int keytag = search_str_to_keytag(search);
bool found = false;
dnssec_list_foreach(item, list) {
dnssec_kasp_key_t *key = dnssec_item_get(item);
if (key_match(key->key, keytag, search)) {
found = true;
int r = match(key, data);
if (r != DNSSEC_EOK) {
return r;
}
}
}
return DNSSEC_EOK;
}
/*!
* Callback for \ref search_key assuring the found key is unique.
*/
static int assure_unique(dnssec_kasp_key_t *key, void *data)
{
assert(key);
assert(data);
dnssec_kasp_key_t **unique_ptr = data;
if (*unique_ptr) {
return DNSSEC_ERROR;
}
*unique_ptr = key;
return DNSSEC_EOK;
}
/*!
* Search for a unique key.
*
* \param[in] list List of \ref dnssec_kasp_key_t keys.
* \param[in] search Search string, can be key tag or key ID prefix.
* \param[out] key_ptr Found key.
*
* \return Error code.
*/
static int search_unique_key(dnssec_list_t *list, const char *search,
dnssec_kasp_key_t **key_ptr)
{
assert(list);
assert(search);
assert(key_ptr);
dnssec_kasp_key_t *match = NULL;
int r = search_key(list, search, assure_unique, &match);
if (r == DNSSEC_ERROR) {
error("Multiple matching keys found.");
return DNSSEC_ERROR;
}
if (match == NULL) {
error("No matching key found.");
return DNSSEC_ERROR;
}
*key_ptr = match;
return DNSSEC_EOK;
}
/* -- actions implementation ----------------------------------------------- */
/*
......@@ -442,29 +579,6 @@ static int cmd_zone_key_list(int argc, char *argv[])
return 0;
}
/*!
* Match key by keytag or key ID prefix.
*/
static bool key_match(const dnssec_key_t *key, const char *search)
{
// keytag exact match
char keytag[10] = { 0 };
int len = snprintf(keytag, sizeof(keytag), "%d", dnssec_key_get_keytag(key));
if (len > 0 && strcmp(search, keytag) == 0) {
return true;
}
// key ID prefix match
const char *keyid = dnssec_key_get_id(key);
size_t keyid_len = strlen(keyid);
size_t search_len = strlen(search);
return (search_len <= keyid_len && strncasecmp(search, keyid, search_len) == 0);
}
/*
* keymgr zone key show <zone> <key-spec>
*/
......@@ -490,37 +604,24 @@ static int cmd_zone_key_show(int argc, char *argv[])
return 1;
}
bool found = false;
dnssec_list_t *zone_keys = dnssec_kasp_zone_get_keys(zone);
dnssec_list_foreach(item, zone_keys) {
const dnssec_kasp_key_t *key = dnssec_item_get(item);
if (!key_match(key->key, search)) {
continue;
}
if (found) {
printf("\n");
}
printf("id %s\n", dnssec_key_get_id(key->key));
printf("keytag %d\n", dnssec_key_get_keytag(key->key));
printf("algorithm %d\n", dnssec_key_get_algorithm(key->key));
printf("size %u\n", dnssec_key_get_size(key->key));
printf("flags %d\n", dnssec_key_get_flags(key->key));
printf("publish %ld\n", key->timing.publish);
printf("active %ld\n", key->timing.active);
printf("retire %ld\n", key->timing.retire);
printf("remove %ld\n", key->timing.remove);
found = true;
}
dnssec_list_t *keys = dnssec_kasp_zone_get_keys(zone);
if (!found) {
error("No matching key found.");
dnssec_kasp_key_t *key = NULL;
int r = search_unique_key(keys, search, &key);
if (r != DNSSEC_EOK) {
return 1;
}
printf("id %s\n", dnssec_key_get_id(key->key));
printf("keytag %d\n", dnssec_key_get_keytag(key->key));
printf("algorithm %d\n", dnssec_key_get_algorithm(key->key));
printf("size %u\n", dnssec_key_get_size(key->key));
printf("flags %d\n", dnssec_key_get_flags(key->key));
printf("publish %ld\n", key->timing.publish);
printf("active %ld\n", key->timing.active);
printf("retire %ld\n", key->timing.retire);
printf("remove %ld\n", key->timing.remove);
return 0;
}
......@@ -680,22 +781,10 @@ static int cmd_zone_key_set(int argc, char *argv[])
return 1;
}
dnssec_list_t *keys = dnssec_kasp_zone_get_keys(zone);
dnssec_kasp_key_t *match = NULL;
dnssec_list_t *zone_keys = dnssec_kasp_zone_get_keys(zone);
dnssec_list_foreach(item, zone_keys) {
dnssec_kasp_key_t *key = dnssec_item_get(item);
if (key_match(key->key, search)) {
if (match) {
error("Multiple matching keys found.");
return 1;
}
match = key;
}
}
if (!match) {
error("No matching key found.");
int r = search_unique_key(keys, search, &match);
if (r != DNSSEC_EOK) {
return 1;
}
......@@ -704,7 +793,7 @@ static int cmd_zone_key_set(int argc, char *argv[])
if (new_timing.retire >= 0) { match->timing.retire = new_timing.retire; }
if (new_timing.remove >= 0) { match->timing.remove = new_timing.remove; }
int r = dnssec_kasp_zone_save(kasp, zone);
r = dnssec_kasp_zone_save(kasp, zone);
if (r != DNSSEC_EOK) {
error("Failed to save updated zone (%s).", dnssec_strerror(r));
return 1;
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment