sbkeysync: Refactor signature database data structures
Rather than having three sets of (firmware, filesystem) key databases, refactor into two sets of (kdk, db, dbx) databases. This allows us to add the PK later. Signed-off-by: Jeremy Kerr <jeremy.kerr@canonical.com>
This commit is contained in:
parent
b4773c902a
commit
74153741c4
1 changed files with 138 additions and 168 deletions
256
src/sbkeysync.c
256
src/sbkeysync.c
|
@ -109,8 +109,13 @@ struct cert_type {
|
||||||
|
|
||||||
struct key_database {
|
struct key_database {
|
||||||
const struct key_database_type *type;
|
const struct key_database_type *type;
|
||||||
struct list_head firmware_keys;
|
struct list_head keys;
|
||||||
struct list_head filesystem_keys;
|
};
|
||||||
|
|
||||||
|
struct keyset {
|
||||||
|
struct key_database kek;
|
||||||
|
struct key_database db;
|
||||||
|
struct key_database dbx;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct fs_keystore_entry {
|
struct fs_keystore_entry {
|
||||||
|
@ -129,9 +134,8 @@ struct fs_keystore {
|
||||||
|
|
||||||
struct sync_context {
|
struct sync_context {
|
||||||
const char *efivars_dir;
|
const char *efivars_dir;
|
||||||
struct key_database *kek;
|
struct keyset *filesystem_keys;
|
||||||
struct key_database *db;
|
struct keyset *firmware_keys;
|
||||||
struct key_database *dbx;
|
|
||||||
struct fs_keystore *fs_keystore;
|
struct fs_keystore *fs_keystore;
|
||||||
const char **keystore_dirs;
|
const char **keystore_dirs;
|
||||||
unsigned int n_keystore_dirs;
|
unsigned int n_keystore_dirs;
|
||||||
|
@ -140,6 +144,7 @@ struct sync_context {
|
||||||
bool dry_run;
|
bool dry_run;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
#define GUID_STRLEN (8 + 1 + 4 + 1 + 4 + 1 + 4 + 1 + 12 + 1)
|
#define GUID_STRLEN (8 + 1 + 4 + 1 + 4 + 1 + 4 + 1 + 12 + 1)
|
||||||
static void guid_to_str(const EFI_GUID *guid, char *str)
|
static void guid_to_str(const EFI_GUID *guid, char *str)
|
||||||
{
|
{
|
||||||
|
@ -295,42 +300,63 @@ static int sigdb_iterate(void *db_data, size_t len,
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int sigdb_add_key(EFI_SIGNATURE_DATA *sigdata, int len,
|
struct keydb_add_ctx {
|
||||||
|
struct fs_keystore_entry *ke;
|
||||||
|
struct key_database *kdb;
|
||||||
|
struct keyset *keyset;
|
||||||
|
};
|
||||||
|
|
||||||
|
static int keydb_add_key(EFI_SIGNATURE_DATA *sigdata, int len,
|
||||||
const EFI_GUID *type, void *arg)
|
const EFI_GUID *type, void *arg)
|
||||||
{
|
{
|
||||||
struct key_database *kdb = arg;
|
struct keydb_add_ctx *add_ctx = arg;
|
||||||
struct key *key;
|
struct key *key;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
key = talloc(kdb, struct key);
|
key = talloc(add_ctx->keyset, struct key);
|
||||||
|
|
||||||
rc = key_parse(key, type, sigdata->SignatureData,
|
rc = key_parse(key, type, sigdata->SignatureData,
|
||||||
len - sizeof(*sigdata));
|
len - sizeof(*sigdata));
|
||||||
|
|
||||||
if (rc)
|
if (rc) {
|
||||||
talloc_free(key);
|
talloc_free(key);
|
||||||
else
|
return 0;
|
||||||
list_add(&kdb->firmware_keys, &key->list);
|
}
|
||||||
|
key->keystore_entry = add_ctx->ke;
|
||||||
|
key->type = *type;
|
||||||
|
|
||||||
|
/* add a reference to the keystore entry: we don't want it to be
|
||||||
|
* deallocated if the keystore is deallocated before the
|
||||||
|
* struct key. */
|
||||||
|
if (key->keystore_entry)
|
||||||
|
talloc_reference(key, key->keystore_entry);
|
||||||
|
|
||||||
|
list_add(&add_ctx->kdb->keys, &key->list);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int read_firmware_key_database(struct key_database *kdb,
|
static int read_firmware_keydb(struct sync_context *ctx,
|
||||||
const char *dir)
|
struct key_database *kdb)
|
||||||
{
|
{
|
||||||
|
struct keydb_add_ctx add_ctx;
|
||||||
char guid_str[GUID_STRLEN];
|
char guid_str[GUID_STRLEN];
|
||||||
char *filename;
|
char *filename;
|
||||||
uint8_t *buf;
|
uint8_t *buf;
|
||||||
int rc = -1;
|
int rc = -1;
|
||||||
size_t len;
|
size_t len;
|
||||||
|
|
||||||
|
add_ctx.keyset = ctx->firmware_keys;
|
||||||
|
add_ctx.kdb = kdb;
|
||||||
|
add_ctx.ke = NULL;
|
||||||
|
|
||||||
guid_to_str(&kdb->type->guid, guid_str);
|
guid_to_str(&kdb->type->guid, guid_str);
|
||||||
|
|
||||||
filename = talloc_asprintf(kdb, "%s/%s-%s", dir,
|
filename = talloc_asprintf(ctx->firmware_keys, "%s/%s-%s",
|
||||||
kdb->type->name, guid_str);
|
ctx->efivars_dir, kdb->type->name, guid_str);
|
||||||
|
|
||||||
buf = NULL;
|
buf = NULL;
|
||||||
rc = fileio_read_file_noerror(kdb, filename, &buf, &len);
|
rc = fileio_read_file_noerror(ctx->firmware_keys, filename, &buf, &len);
|
||||||
if (rc)
|
if (rc)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
|
@ -342,7 +368,7 @@ static int read_firmware_key_database(struct key_database *kdb,
|
||||||
len -= sizeof(uint32_t);
|
len -= sizeof(uint32_t);
|
||||||
|
|
||||||
rc = 0;
|
rc = 0;
|
||||||
sigdb_iterate(buf, len, sigdb_add_key, kdb);
|
sigdb_iterate(buf, len, keydb_add_key, &add_ctx);
|
||||||
|
|
||||||
out:
|
out:
|
||||||
if (rc)
|
if (rc)
|
||||||
|
@ -352,40 +378,6 @@ out:
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct keystore_add_ctx {
|
|
||||||
struct fs_keystore *keystore;
|
|
||||||
struct fs_keystore_entry *ke;
|
|
||||||
struct key_database *kdb;
|
|
||||||
};
|
|
||||||
|
|
||||||
static int keystore_add_key(EFI_SIGNATURE_DATA *sigdata, int len,
|
|
||||||
const EFI_GUID *type, void *arg)
|
|
||||||
{
|
|
||||||
struct keystore_add_ctx *add_ctx = arg;
|
|
||||||
struct key *key;
|
|
||||||
int rc;
|
|
||||||
|
|
||||||
key = talloc(add_ctx->kdb, struct key);
|
|
||||||
key->keystore_entry = add_ctx->ke;
|
|
||||||
key->type = *type;
|
|
||||||
|
|
||||||
rc = key_parse(key, type, sigdata->SignatureData,
|
|
||||||
len - sizeof(*sigdata));
|
|
||||||
|
|
||||||
if (rc) {
|
|
||||||
talloc_free(key);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* add a reference to the data: we don't want it to be
|
|
||||||
* deallocated if the keystore is deallocated before the
|
|
||||||
* struct key. */
|
|
||||||
talloc_reference(key, add_ctx->ke->data);
|
|
||||||
list_add(&add_ctx->kdb->filesystem_keys, &key->list);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void __attribute__((format(printf, 2, 3))) print_keystore_key_error(
|
static void __attribute__((format(printf, 2, 3))) print_keystore_key_error(
|
||||||
struct fs_keystore_entry *ke, const char *fmt, ...)
|
struct fs_keystore_entry *ke, const char *fmt, ...)
|
||||||
{
|
{
|
||||||
|
@ -402,19 +394,19 @@ static void __attribute__((format(printf, 2, 3))) print_keystore_key_error(
|
||||||
va_end(ap);
|
va_end(ap);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int read_keystore_key_database(struct key_database *kdb,
|
static int read_filesystem_keydb(struct sync_context *ctx,
|
||||||
struct fs_keystore *keystore)
|
struct key_database *kdb)
|
||||||
{
|
{
|
||||||
EFI_GUID cert_type_pkcs7 = EFI_CERT_TYPE_PKCS7_GUID;
|
EFI_GUID cert_type_pkcs7 = EFI_CERT_TYPE_PKCS7_GUID;
|
||||||
EFI_VARIABLE_AUTHENTICATION_2 *auth;
|
EFI_VARIABLE_AUTHENTICATION_2 *auth;
|
||||||
struct keystore_add_ctx add_ctx;
|
struct keydb_add_ctx add_ctx;
|
||||||
struct fs_keystore_entry *ke;
|
struct fs_keystore_entry *ke;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
add_ctx.keystore = keystore;
|
add_ctx.keyset = ctx->filesystem_keys;
|
||||||
add_ctx.kdb = kdb;
|
add_ctx.kdb = kdb;
|
||||||
|
|
||||||
list_for_each(&keystore->keys, ke, keystore_list) {
|
list_for_each(&ctx->fs_keystore->keys, ke, keystore_list) {
|
||||||
unsigned int len;
|
unsigned int len;
|
||||||
void *buf;
|
void *buf;
|
||||||
|
|
||||||
|
@ -462,7 +454,7 @@ static int read_keystore_key_database(struct key_database *kdb,
|
||||||
auth->AuthInfo.Hdr.dwLength;
|
auth->AuthInfo.Hdr.dwLength;
|
||||||
|
|
||||||
add_ctx.ke = ke;
|
add_ctx.ke = ke;
|
||||||
rc = sigdb_iterate(buf, len, keystore_add_key, &add_ctx);
|
rc = sigdb_iterate(buf, len, keydb_add_key, &add_ctx);
|
||||||
if (rc) {
|
if (rc) {
|
||||||
print_keystore_key_error(ke, "error parsing "
|
print_keystore_key_error(ke, "error parsing "
|
||||||
"EFI_SIGNATURE_LIST");
|
"EFI_SIGNATURE_LIST");
|
||||||
|
@ -474,49 +466,39 @@ static int read_keystore_key_database(struct key_database *kdb,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int read_key_databases(struct sync_context *ctx)
|
static int read_keysets(struct sync_context *ctx)
|
||||||
{
|
{
|
||||||
struct key_database *kdbs[] = {
|
read_firmware_keydb(ctx, &ctx->firmware_keys->kek);
|
||||||
ctx->kek,
|
read_firmware_keydb(ctx, &ctx->firmware_keys->db);
|
||||||
ctx->db,
|
read_firmware_keydb(ctx, &ctx->firmware_keys->dbx);
|
||||||
ctx->dbx,
|
|
||||||
};
|
|
||||||
unsigned int i;
|
|
||||||
|
|
||||||
for (i = 0; i < ARRAY_SIZE(kdbs); i++) {
|
read_filesystem_keydb(ctx, &ctx->filesystem_keys->kek);
|
||||||
struct key_database *kdb = kdbs[i];
|
read_filesystem_keydb(ctx, &ctx->filesystem_keys->db);
|
||||||
read_firmware_key_database(kdb, ctx->efivars_dir);
|
read_filesystem_keydb(ctx, &ctx->filesystem_keys->dbx);
|
||||||
read_keystore_key_database(kdb, ctx->fs_keystore);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void print_key_database(struct key_database *kdb)
|
static void print_keyset(struct keyset *keyset, const char *name)
|
||||||
{
|
{
|
||||||
|
struct key_database *kdbs[] =
|
||||||
|
{ &keyset->kek, &keyset->db, &keyset->dbx };
|
||||||
struct key *key;
|
struct key *key;
|
||||||
|
unsigned int i;
|
||||||
|
|
||||||
printf(" %s (firmware)\n", kdb->type->name);
|
printf("%s keys:\n", name);
|
||||||
|
|
||||||
list_for_each(&kdb->firmware_keys, key, list)
|
for (i = 0; i < ARRAY_SIZE(kdbs); i++) {
|
||||||
printf(" %s\n", key->description);
|
printf(" %s:\n", kdbs[i]->type->name);
|
||||||
|
|
||||||
printf(" %s (filesystem)\n", kdb->type->name);
|
list_for_each(&kdbs[i]->keys, key, list) {
|
||||||
|
|
||||||
list_for_each(&kdb->filesystem_keys, key, list) {
|
|
||||||
printf(" %s\n", key->description);
|
printf(" %s\n", key->description);
|
||||||
|
if (key->keystore_entry)
|
||||||
printf(" from %s/%s\n",
|
printf(" from %s/%s\n",
|
||||||
key->keystore_entry->root,
|
key->keystore_entry->root,
|
||||||
key->keystore_entry->name);
|
key->keystore_entry->name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void print_key_databases(struct sync_context *ctx)
|
|
||||||
{
|
|
||||||
printf("EFI key databases:\n");
|
|
||||||
print_key_database(ctx->kek);
|
|
||||||
print_key_database(ctx->db);
|
|
||||||
print_key_database(ctx->dbx);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int check_efivars_mount(const char *mountpoint)
|
static int check_efivars_mount(const char *mountpoint)
|
||||||
|
@ -534,13 +516,6 @@ static int check_efivars_mount(const char *mountpoint)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* for each root directory, top-level first:
|
|
||||||
* for each db/dbx/KEK:
|
|
||||||
* for each file:
|
|
||||||
* if file exists in keystore, skip
|
|
||||||
* add file to keystore
|
|
||||||
*/
|
|
||||||
|
|
||||||
static int keystore_entry_read(struct fs_keystore_entry *ke)
|
static int keystore_entry_read(struct fs_keystore_entry *ke)
|
||||||
{
|
{
|
||||||
const char *path;
|
const char *path;
|
||||||
|
@ -570,10 +545,11 @@ static bool keystore_contains_file(struct fs_keystore *keystore,
|
||||||
|
|
||||||
static int update_keystore(struct fs_keystore *keystore, const char *root)
|
static int update_keystore(struct fs_keystore *keystore, const char *root)
|
||||||
{
|
{
|
||||||
|
struct fs_keystore_entry *ke;
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
|
|
||||||
for (i = 0; i < ARRAY_SIZE(keydb_types); i++) {
|
for (i = 0; i < ARRAY_SIZE(keydb_types); i++) {
|
||||||
const char *dirname, *filename;
|
const char *filename, *dirname;
|
||||||
struct dirent *dirent;
|
struct dirent *dirent;
|
||||||
DIR *dir;
|
DIR *dir;
|
||||||
|
|
||||||
|
@ -585,7 +561,6 @@ static int update_keystore(struct fs_keystore *keystore, const char *root)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
for (dirent = readdir(dir); dirent; dirent = readdir(dir)) {
|
for (dirent = readdir(dir); dirent; dirent = readdir(dir)) {
|
||||||
struct fs_keystore_entry *ke;
|
|
||||||
|
|
||||||
if (dirent->d_name[0] == '.')
|
if (dirent->d_name[0] == '.')
|
||||||
continue;
|
continue;
|
||||||
|
@ -612,6 +587,7 @@ static int update_keystore(struct fs_keystore *keystore, const char *root)
|
||||||
closedir(dir);
|
closedir(dir);
|
||||||
talloc_free(dirname);
|
talloc_free(dirname);
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -650,17 +626,31 @@ static int key_cmp(struct key *a, struct key *b)
|
||||||
return memcmp(a->id, b->id, a->id_len);
|
return memcmp(a->id, b->id, a->id_len);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int find_new_keys_in_kdb(struct sync_context *ctx,
|
/**
|
||||||
struct key_database *kdb)
|
* Finds the set-difference of the filesystem and firmware keys, and
|
||||||
|
* populates ctx->new_keys with the keystore_entries that should be
|
||||||
|
* inserted into firmware
|
||||||
|
*/
|
||||||
|
static int find_new_keys(struct sync_context *ctx)
|
||||||
{
|
{
|
||||||
|
struct {
|
||||||
|
struct key_database *fs_kdb, *fw_kdb;
|
||||||
|
} kdbs[] = {
|
||||||
|
{ &ctx->filesystem_keys->kek, &ctx->firmware_keys->kek },
|
||||||
|
{ &ctx->filesystem_keys->db, &ctx->firmware_keys->db },
|
||||||
|
{ &ctx->filesystem_keys->dbx, &ctx->firmware_keys->dbx },
|
||||||
|
};
|
||||||
|
unsigned int i;
|
||||||
|
int n = 0;
|
||||||
|
|
||||||
|
for (i = 0; i < ARRAY_SIZE(kdbs); i++ ) {
|
||||||
struct fs_keystore_entry *ke;
|
struct fs_keystore_entry *ke;
|
||||||
struct key *fs_key, *fw_key;
|
struct key *fs_key, *fw_key;
|
||||||
bool found;
|
bool found;
|
||||||
int n = 0;
|
|
||||||
|
|
||||||
list_for_each(&kdb->filesystem_keys, fs_key, list) {
|
list_for_each(&kdbs[i].fs_kdb->keys, fs_key, list) {
|
||||||
found = false;
|
found = false;
|
||||||
list_for_each(&kdb->firmware_keys, fw_key, list) {
|
list_for_each(&kdbs[i].fw_kdb->keys, fw_key, list) {
|
||||||
if (!key_cmp(fs_key, fw_key)) {
|
if (!key_cmp(fs_key, fw_key)) {
|
||||||
found = true;
|
found = true;
|
||||||
break;
|
break;
|
||||||
|
@ -681,36 +671,10 @@ static int find_new_keys_in_kdb(struct sync_context *ctx,
|
||||||
if (found)
|
if (found)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
list_add(&ctx->new_keys, &fs_key->keystore_entry->new_list);
|
list_add(&ctx->new_keys,
|
||||||
|
&fs_key->keystore_entry->new_list);
|
||||||
n++;
|
n++;
|
||||||
}
|
}
|
||||||
|
|
||||||
return n;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Find the keys that are present in the filesystem, but not the firmware.
|
|
||||||
* Returns:
|
|
||||||
* 0 if there are no new keys to add
|
|
||||||
* >0 if there are keys to add
|
|
||||||
* -1 on error
|
|
||||||
*/
|
|
||||||
static int find_new_keys(struct sync_context *ctx)
|
|
||||||
{
|
|
||||||
struct key_database *kdbs[] = {
|
|
||||||
ctx->kek,
|
|
||||||
ctx->db,
|
|
||||||
ctx->dbx,
|
|
||||||
};
|
|
||||||
unsigned int n, i;
|
|
||||||
int rc;
|
|
||||||
|
|
||||||
n = 0;
|
|
||||||
|
|
||||||
for (i = 0; i < ARRAY_SIZE(kdbs); i++) {
|
|
||||||
rc = find_new_keys_in_kdb(ctx, kdbs[i]);
|
|
||||||
if (rc < 0)
|
|
||||||
return rc;
|
|
||||||
n += rc;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return n;
|
return n;
|
||||||
|
@ -800,19 +764,22 @@ static int insert_new_keys(struct sync_context *ctx)
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void init_key_database(struct sync_context *ctx,
|
static struct keyset *init_keyset(struct sync_context *ctx)
|
||||||
struct key_database **kdb_p,
|
|
||||||
const struct key_database_type *type)
|
|
||||||
{
|
{
|
||||||
struct key_database *kdb;
|
struct keyset *keyset;
|
||||||
|
|
||||||
kdb = talloc(ctx, struct key_database);
|
keyset = talloc(ctx, struct keyset);
|
||||||
|
|
||||||
list_head_init(&kdb->firmware_keys);
|
list_head_init(&keyset->kek.keys);
|
||||||
list_head_init(&kdb->filesystem_keys);
|
keyset->kek.type = &keydb_types[0];
|
||||||
kdb->type = type;
|
|
||||||
|
|
||||||
*kdb_p = kdb;
|
list_head_init(&keyset->db.keys);
|
||||||
|
keyset->db.type = &keydb_types[1];
|
||||||
|
|
||||||
|
list_head_init(&keyset->dbx.keys);
|
||||||
|
keyset->dbx.type = &keydb_types[2];
|
||||||
|
|
||||||
|
return keyset;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct option options[] = {
|
static struct option options[] = {
|
||||||
|
@ -904,14 +871,13 @@ int main(int argc, char **argv)
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
init_key_database(ctx, &ctx->kek, &keydb_types[0]);
|
|
||||||
init_key_database(ctx, &ctx->db, &keydb_types[1]);
|
|
||||||
init_key_database(ctx, &ctx->dbx, &keydb_types[2]);
|
|
||||||
|
|
||||||
ERR_load_crypto_strings();
|
ERR_load_crypto_strings();
|
||||||
OpenSSL_add_all_digests();
|
OpenSSL_add_all_digests();
|
||||||
OpenSSL_add_all_ciphers();
|
OpenSSL_add_all_ciphers();
|
||||||
|
|
||||||
|
ctx->filesystem_keys = init_keyset(ctx);
|
||||||
|
ctx->firmware_keys = init_keyset(ctx);
|
||||||
|
|
||||||
if (!ctx->efivars_dir) {
|
if (!ctx->efivars_dir) {
|
||||||
ctx->efivars_dir = EFIVARS_MOUNTPOINT;
|
ctx->efivars_dir = EFIVARS_MOUNTPOINT;
|
||||||
if (check_efivars_mount(ctx->efivars_dir)) {
|
if (check_efivars_mount(ctx->efivars_dir)) {
|
||||||
|
@ -933,9 +899,11 @@ int main(int argc, char **argv)
|
||||||
if (ctx->verbose)
|
if (ctx->verbose)
|
||||||
print_keystore(ctx->fs_keystore);
|
print_keystore(ctx->fs_keystore);
|
||||||
|
|
||||||
read_key_databases(ctx);
|
read_keysets(ctx);
|
||||||
if (ctx->verbose)
|
if (ctx->verbose) {
|
||||||
print_key_databases(ctx);
|
print_keyset(ctx->firmware_keys, "firmware");
|
||||||
|
print_keyset(ctx->filesystem_keys, "filesystem");
|
||||||
|
}
|
||||||
|
|
||||||
find_new_keys(ctx);
|
find_new_keys(ctx);
|
||||||
|
|
||||||
|
@ -945,5 +913,7 @@ int main(int argc, char **argv)
|
||||||
if (!ctx->dry_run)
|
if (!ctx->dry_run)
|
||||||
insert_new_keys(ctx);
|
insert_new_keys(ctx);
|
||||||
|
|
||||||
|
talloc_free(ctx);
|
||||||
|
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue