From: Michael Tremer Date: Thu, 23 Nov 2017 18:45:52 +0000 (+0100) Subject: libpakfire: Support importing keys X-Git-Tag: 0.9.28~1285^2~1291 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=7b526dd2e1d30a79cdc82d56b61c3c25e502a123;p=pakfire.git libpakfire: Support importing keys Signed-off-by: Michael Tremer --- diff --git a/src/_pakfire/key.c b/src/_pakfire/key.c index 5486e487c..110e63edb 100644 --- a/src/_pakfire/key.c +++ b/src/_pakfire/key.c @@ -37,7 +37,7 @@ static PyObject* Key_new_core(PyTypeObject* type, PakfireObject* pakfire, Pakfir } PyObject* new_key(PakfireObject* pakfire, PakfireKey key) { - return Key_new_core(&KeyType, pakfire, key); + return Key_new_core(&KeyType, pakfire, pakfire_key_ref(key)); } static PyObject* Key_new(PyTypeObject* type, PyObject* args, PyObject* kwds) { @@ -46,7 +46,7 @@ static PyObject* Key_new(PyTypeObject* type, PyObject* args, PyObject* kwds) { static void Key_dealloc(KeyObject* self) { if (self->key) - pakfire_key_free(self->key); + pakfire_key_unref(self->key); if (self->pakfire) Py_DECREF(self->pakfire); diff --git a/src/_pakfire/pakfire.c b/src/_pakfire/pakfire.c index 6449e6b4f..2b45a0799 100644 --- a/src/_pakfire/pakfire.c +++ b/src/_pakfire/pakfire.c @@ -75,23 +75,31 @@ static PyObject* Pakfire_get_arch(PakfireObject* self) { return PyUnicode_FromString(arch); } -static PyObject* Pakfire_get_keys(PakfireObject* self) { +static PyObject* _import_keylist(PakfireObject* pakfire, PakfireKey* keys) { PyObject* list = PyList_New(0); - PakfireKey* keys = pakfire_key_list(self->pakfire); while (keys && *keys) { PakfireKey key = *keys++; - PyObject* object = new_key(self, key); + PyObject* object = new_key(pakfire, key); PyList_Append(list, object); + + // Drop reference to the Python object Py_DECREF(object); - pakfire_key_free(key); + // Drop reference to the key object + pakfire_key_unref(key); } return list; } +static PyObject* Pakfire_get_keys(PakfireObject* self) { + PakfireKey* keys = pakfire_key_list(self->pakfire); + + return _import_keylist(self, keys); +} + static PyObject* Pakfire_get_key(PakfireObject* self, PyObject* args) { const char* pattern = NULL; @@ -117,6 +125,19 @@ static PyObject* Pakfire_generate_key(PakfireObject* self, PyObject* args) { return new_key(self, key); } +static PyObject* Pakfire_import_key(PakfireObject* self, PyObject* args) { + const char* data = NULL; + + if (!PyArg_ParseTuple(args, "s", &data)) + return NULL; + + PakfireKey* keys = pakfire_key_import(self->pakfire, data); + if (!keys) + return NULL; // TODO Raise error from errno + + return _import_keylist(self, keys); +} + static struct PyMethodDef Pakfire_methods[] = { { "generate_key", @@ -130,6 +151,12 @@ static struct PyMethodDef Pakfire_methods[] = { METH_VARARGS, NULL }, + { + "import_key", + (PyCFunction)Pakfire_import_key, + METH_VARARGS, + NULL + }, { NULL }, }; diff --git a/src/libpakfire/include/pakfire/errno.h b/src/libpakfire/include/pakfire/errno.h index dbb5ce714..f112d8129 100644 --- a/src/libpakfire/include/pakfire/errno.h +++ b/src/libpakfire/include/pakfire/errno.h @@ -33,6 +33,7 @@ enum _pakfire_errors { PAKFIRE_E_SOLV_NOT_SOLV, // SOLV file in not in SOLV format PAKFIRE_E_SOLV_UNSUPPORTED, // SOLV file is in an unsupported format PAKFIRE_E_SOLV_CORRUPTED, // SOLV file is corrupted + PAKFIRE_E_INVALID_INPUT, }; extern __thread int pakfire_errno; diff --git a/src/libpakfire/include/pakfire/key.h b/src/libpakfire/include/pakfire/key.h index 47be3866d..27073cee9 100644 --- a/src/libpakfire/include/pakfire/key.h +++ b/src/libpakfire/include/pakfire/key.h @@ -33,12 +33,14 @@ typedef enum pakfire_key_export_mode { PakfireKey* pakfire_key_list(Pakfire pakfire); PakfireKey pakfire_key_create(Pakfire pakfire, gpgme_key_t gpgkey); -void pakfire_key_free(PakfireKey key); +PakfireKey pakfire_key_ref(PakfireKey key); +void pakfire_key_unref(PakfireKey key); PakfireKey pakfire_key_get(Pakfire pakfire, const char* fingerprint); const char* pakfire_key_get_fingerprint(PakfireKey key); PakfireKey pakfire_key_generate(Pakfire pakfire, const char* userid); char* pakfire_key_export(PakfireKey key, pakfire_key_export_mode_t mode); +PakfireKey* pakfire_key_import(Pakfire pakfire, const char* data); #ifdef PAKFIRE_PRIVATE diff --git a/src/libpakfire/key.c b/src/libpakfire/key.c index f0d6d8e53..7c42a360c 100644 --- a/src/libpakfire/key.c +++ b/src/libpakfire/key.c @@ -20,7 +20,9 @@ #include #include +#include +#include #include #include #include @@ -112,6 +114,7 @@ PakfireKey pakfire_key_create(Pakfire pakfire, gpgme_key_t gpgkey) { PakfireKey key = pakfire_calloc(1, sizeof(*key)); if (key) { + key->nrefs = 1; key->pakfire = pakfire_ref(pakfire); key->gpgkey = gpgkey; @@ -121,13 +124,26 @@ PakfireKey pakfire_key_create(Pakfire pakfire, gpgme_key_t gpgkey) { return key; } -void pakfire_key_free(PakfireKey key) { +static void pakfire_key_free(PakfireKey key) { pakfire_unref(key->pakfire); gpgme_key_unref(key->gpgkey); pakfire_free(key); } +PakfireKey pakfire_key_ref(PakfireKey key) { + ++key->nrefs; + + return key; +} + +void pakfire_key_unref(PakfireKey key) { + if (--key->nrefs > 0) + return; + + pakfire_key_free(key); +} + PakfireKey pakfire_key_get(Pakfire pakfire, const char* fingerprint) { gpgme_ctx_t gpgctx = pakfire_get_gpgctx(pakfire); assert(gpgctx); @@ -231,3 +247,64 @@ FAIL: return NULL; } + +PakfireKey* pakfire_key_import(Pakfire pakfire, const char* data) { + gpgme_error_t error; + gpgme_data_t keydata; + + gpgme_ctx_t gpgctx = pakfire_get_gpgctx(pakfire); + assert(gpgctx); + + // Form a data object out of the input without copying data + error = gpgme_data_new_from_mem(&keydata, data, strlen(data), 0); + if (error != GPG_ERR_NO_ERROR) + goto FAIL; + + // Try importing the key(s) + error = gpgme_op_import(gpgctx, keydata); + + gpgme_import_result_t result; + switch (error) { + // Everything went fine + case GPG_ERR_NO_ERROR: + result = gpgme_op_import_result(gpgctx); + + PakfireKey* head = pakfire_calloc(result->imported + 1, sizeof(*head)); + PakfireKey* list = head; + + // Retrieve all imported keys + gpgme_import_status_t status = result->imports; + while (status) { + PakfireKey key = pakfire_key_get(pakfire, status->fpr); + if (key) { + // Append key to list + *list++ = key; + } + + status = status->next; + } + + // Terminate list + *list = NULL; + + gpgme_data_release(keydata); + gpgme_release(gpgctx); + + return head; + + // Input was invalid + case GPG_ERR_INV_VALUE: + pakfire_errno = PAKFIRE_E_INVALID_INPUT; + break; + + // Fall through for any other errors + default: + break; + } + +FAIL: + gpgme_data_release(keydata); + gpgme_release(gpgctx); + + return NULL; +} diff --git a/src/libpakfire/libpakfire.sym b/src/libpakfire/libpakfire.sym index abd048723..bea1d07e7 100644 --- a/src/libpakfire/libpakfire.sym +++ b/src/libpakfire/libpakfire.sym @@ -72,11 +72,13 @@ global: # key pakfire_key_create; pakfire_key_export; - pakfire_key_free; pakfire_key_generate; pakfire_key_get; pakfire_key_get_fingerprint; + pakfire_key_import; pakfire_key_list; + pakfire_key_ref; + pakfire_key_unref; # package pakfire_package_add_conflicts; diff --git a/src/pakfire/cli.py b/src/pakfire/cli.py index caa124606..9f8115f40 100644 --- a/src/pakfire/cli.py +++ b/src/pakfire/cli.py @@ -775,6 +775,20 @@ class CliKey(Cli): # Add common arguments self._add_common_arguments(parser) + # export + export = subparsers.add_parser("export", help=_("Export a key to a file")) + export.add_argument("fingerprint", nargs=1, + help=_("The fingerprint of the key to export")) + export.add_argument("--filename", nargs="*", help=_("Write the key to this file")) + export.add_argument("--secret", action="store_true", + help=_("Export the secret key")) + export.set_defaults(func=self.handle_export) + + # import + _import = subparsers.add_parser("import", help=_("Import a key from file")) + _import.add_argument("filename", nargs="+", help=_("Filename of that key to import")) + _import.set_defaults(func=self.handle_import) + # generate generate = subparsers.add_parser("generate", help=_("Import a key from file")) generate.add_argument("--realname", nargs=1, @@ -787,35 +801,8 @@ class CliKey(Cli): list = subparsers.add_parser("list", help=_("List all imported keys")) list.set_defaults(func=self.handle_list) - # export - export = subparsers.add_parser("export", help=_("Export a key to a file")) - export.add_argument("fingerprint", nargs=1, - help=_("The fingerprint of the key to export")) - export.add_argument("--filename", nargs="*", help=_("Write the key to this file")) - export.add_argument("--secret", action="store_true", - help=_("Export the secret key")) - export.set_defaults(func=self.handle_export) - return parser.parse_args() - def parse_command_generate(self): - # Parse "generate" command. - sub_gen = self.sub_commands.add_parser("generate", - help=_("Import a key from file.")) - sub_gen.add_argument("--realname", nargs=1, - help=_("The real name of the owner of this key.")) - sub_gen.add_argument("--email", nargs=1, - help=_("The email address of the owner of this key.")) - sub_gen.set_defaults(func=self.handle_generate) - - def parse_command_import(self): - # Parse "import" command. - sub_import = self.sub_commands.add_parser("import", - help=_("Import a key from file.")) - sub_import.add_argument("filename", nargs=1, - help=_("Filename of that key to import.")) - sub_import.add_argument("action", action="store_const", const="import") - def parse_command_delete(self): # Parse "delete" command. sub_del = self.sub_commands.add_parser("delete", @@ -875,12 +862,15 @@ class CliKey(Cli): else: print(data) - def handle_import(self): - filename = self.args.filename[0] + def handle_import(self, ns): + p = self.pakfire(ns) - # Simply import the file. - p = self.create_pakfire() - p.keyring.import_key(filename) + for filename in ns.filename: + with open(filename) as f: + data = f.read() + + key = p.import_key(data) + print(key) def handle_delete(self): keyid = self.args.keyid[0]