From f9f6cdaae4c7186d4334ddafe5861871025fad9e Mon Sep 17 00:00:00 2001 From: Benjamin Zeller Date: Wed, 14 Mar 2018 18:02:21 +0100 Subject: [PATCH] Add zypper keys command --- doc/zypper.8.txt | 12 ++++ src/CMakeLists.txt | 2 + src/Command.cc | 2 + src/Command.h | 7 ++- src/Zypper.cc | 41 ++++++++++++++ src/callbacks/keyring.h | 42 +------------- src/keys.cc | 119 ++++++++++++++++++++++++++++++++++++++++ src/keys.h | 23 ++++++++ src/utils/misc.cc | 38 +++++++++++++ src/utils/misc.h | 8 +++ 10 files changed, 252 insertions(+), 42 deletions(-) create mode 100644 src/keys.cc create mode 100644 src/keys.h diff --git a/doc/zypper.8.txt b/doc/zypper.8.txt index b645dd0d06..772f9308d7 100644 --- a/doc/zypper.8.txt +++ b/doc/zypper.8.txt @@ -1420,6 +1420,18 @@ Package locks serve the purpose of preventing changes to the set of installed pa + This command looks for locks that do not currently (with regard to repositories used) lock any package and for each such lock it asks user whether to remove it. + +Key Management +~~~~~~~~~~~~~~ +The *keys* command lists keys from the internal trust database. + +*keys* (*lk*) ['options'] ['key-id'] ['key-filename'] ...:: + List all trusted keys or show detailed information about those specified as arguments, supports also keyfiles as argument. ++ +-- + *-d*, *--detail*:: + Shows the keys in a more detailed multiline output, also shows subkey information +-- Other Commands ~~~~~~~~~~~~~~ diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 49b41a9aee..a488aee25f 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -32,6 +32,7 @@ SET (zypper_HEADERS ps.h SolverRequester.h Summary.h + keys.h callbacks/keyring.h callbacks/media.h callbacks/rpm.h @@ -60,6 +61,7 @@ SET( zypper_SRCS RequestFeedback.cc SolverRequester.cc Summary.cc + keys.cc callbacks/media.cc ${zypper_HEADERS} ) diff --git a/src/Command.cc b/src/Command.cc index 5ea2d74888..c5093c4b89 100644 --- a/src/Command.cc +++ b/src/Command.cc @@ -103,6 +103,8 @@ namespace //_t( RUG_INFO_REQUIREMENTS_e )| "info-obsoletes" | "io"; _t( RUG_PATCH_SEARCH_e ) | "patch-search" | "pse"; _t( RUG_PING_e ) | "ping"; + + _t( KEYS_e ) | "keys" | "lk"; #undef _t } return _table; diff --git a/src/Command.h b/src/Command.h index cfaccb5858..3c11774de8 100644 --- a/src/Command.h +++ b/src/Command.h @@ -93,6 +93,9 @@ struct ZypperCommand static const ZypperCommand RUG_PATCH_SEARCH; static const ZypperCommand RUG_PING; //!@} + //! + + static const ZypperCommand KEYS; enum Command { @@ -167,7 +170,9 @@ struct ZypperCommand //RUG_INFO_OBSOLETES_e, //RUG_INFO_REQUIREMENTS_e, RUG_PATCH_SEARCH_e, - RUG_PING_e + RUG_PING_e, + + KEYS_e, }; ZypperCommand( Command command ) : _command(command) {} diff --git a/src/Zypper.cc b/src/Zypper.cc index 98e6896a44..ac68b80f98 100644 --- a/src/Zypper.cc +++ b/src/Zypper.cc @@ -59,6 +59,7 @@ #include "source-download.h" #include "configtest.h" #include "subcommand.h" +#include "keys.h" #include "output/OutNormal.h" #include "output/OutXML.h" @@ -788,6 +789,12 @@ void print_main_help( Zypper & zypper ) "\tzypper [--command-options] [arguments]\n" ); + static std::string help_keys_commands = _(" Key Management:\n" + "\tkeys, lk\t\tList all keys.\n" + //"\taddkey, as\t\tAdd a new key.\n" + //"\tremovekey, rs\tRemove a key from trust.\n" + ); + zypper.out().info( help_usage, Out::QUIET ); zypper.out().info( help_global_options, Out::QUIET ); zypper.out().info( repo_manager_options, Out::QUIET ); @@ -800,6 +807,7 @@ void print_main_help( Zypper & zypper ) zypper.out().info( help_update_commands, Out::QUIET ); zypper.out().info( help_query_commands, Out::QUIET ); zypper.out().info( help_lock_commands, Out::QUIET ); + zypper.out().info( help_keys_commands, Out::QUIET ); zypper.out().info( help_other_commands, Out::QUIET ); zypper.out().info( help_subcommands, Out::QUIET ); @@ -3464,6 +3472,28 @@ void Zypper::processCommandOptions() break; } + case ZypperCommand::KEYS_e: + { + static struct option list_updates_options[] = { + {"details", no_argument, 0, 'd'}, + {"help", no_argument, 0, 'h'}, + {0, 0, 0, 0} + }; + specific_options = list_updates_options; + + _command_help = CommandHelpFormater() + .synopsis( // translators: command synopsis; do not translate lowercase words + _("keys [OPTIONS] [KEYID] [KEYFILE] ...") + ) + .description(// translators: command description + _("List all trusted keys.") + ) + .optionSectionCommandOptions() + .option(_("-d, --detail" "\n" "Show more details.")) + ; + break; + } + default: { if ( runningHelp() ) @@ -5544,6 +5574,17 @@ void Zypper::doCommand() break; } + case ZypperCommand::KEYS_e: + { + // load system data... + init_target( *this ); + if ( exitCode() != ZYPPER_EXIT_OK ) + return; + + listTrustedKeys(*this); + break; + } + case ZypperCommand::SUBCOMMAND_e: // subcommands are not expected to be executed here! default: // if the program reaches this line, something went wrong diff --git a/src/callbacks/keyring.h b/src/callbacks/keyring.h index bccb47a250..2598991a9d 100644 --- a/src/callbacks/keyring.h +++ b/src/callbacks/keyring.h @@ -19,6 +19,7 @@ #include "Zypper.h" #include "Table.h" +#include "utils/misc.h" /////////////////////////////////////////////////////////////////// namespace zypp @@ -50,47 +51,6 @@ namespace zypp { Zypper::instance().out().warningPar( 4, str::Format(_("This file was modified after it has been signed. This may have been a malicious change, so it might not be trustworthy anymore! You should not continue unless you know it's safe.") ) ); } - - std::ostream & dumpKeyInfo( std::ostream & str, const PublicKeyData & key, const KeyContext & context = KeyContext() ) - { - Zypper & zypper = Zypper::instance(); - if ( zypper.out().type() == Out::TYPE_XML ) - { - { - xmlout::Node parent( str, "gpgkey-info", xmlout::Node::optionalContent ); - - if ( !context.empty() ) - { - dumpAsXmlOn( *parent, context.repoInfo().asUserString(), "repository" ); - } - dumpAsXmlOn( *parent, key.name(), "key-name" ); - dumpAsXmlOn( *parent, key.fingerprint(), "key-fingerprint" ); - dumpAsXmlOn( *parent, key.created(), "key-created" ); - dumpAsXmlOn( *parent, key.expires(), "key-expires" ); - dumpAsXmlOn( *parent, str::Format( "gpg-pubkey-%1%-%2%" ) % key.gpgPubkeyVersion() % key.gpgPubkeyRelease(), "rpm-name" ); - } - return str; - } - - Table t; - t.lineStyle( none ); - if ( !context.empty() ) - { - t << ( TableRow() << "" << _("Repository:") << context.repoInfo().asUserString() ); - } - t << ( TableRow() << "" << _("Key Name:") << key.name() ) - << ( TableRow() << "" << _("Key Fingerprint:") << str::gapify( key.fingerprint(), 8 ) ) - << ( TableRow() << "" << _("Key Created:") << key.created() ) - << ( TableRow() << "" << _("Key Expires:") << key.expiresAsString() ); - for ( const PublicSubkeyData & sub : key.subkeys() ) - t << ( TableRow() << "" << _("Subkey:") << sub.asString() ); - t << ( TableRow() << "" << _("Rpm Name:") << str::Format( "gpg-pubkey-%1%-%2%" ) % key.gpgPubkeyVersion() % key.gpgPubkeyRelease() ); - - return str << t; - } - - inline std::ostream & dumpKeyInfo( std::ostream & str, const PublicKey & key, const KeyContext & context = KeyContext() ) - { return dumpKeyInfo( str, key.keyData(), context ); } } // namespace /////////////////////////////////////////////////////////////////// diff --git a/src/keys.cc b/src/keys.cc new file mode 100644 index 0000000000..ac26ca99e9 --- /dev/null +++ b/src/keys.cc @@ -0,0 +1,119 @@ +/*---------------------------------------------------------------------------*\ + ____ _ _ __ _ __ ___ _ _ + |_ / || | '_ \ '_ \/ -_) '_| + /__|\_, | .__/ .__/\___|_| + |__/|_| |_| +\*---------------------------------------------------------------------------*/ + +#include "Zypper.h" +#include "Table.h" +#include "utils/misc.h" + +#include +#include +#include + + +extern ZYpp::Ptr God; + +template +void dumpKeyList ( Zypper &zypp_r, const std::list &keysFound_r, bool details ) +{ + if ( keysFound_r.empty() ) + { + zypp_r.out().warning(_("No keys found.") ); + } + else + { + zypp_r.out().gap(); + if ( details || zypp_r.globalOpts().machine_readable ) + { + for(const auto &key : keysFound_r) + { + dumpKeyInfo( std::cout , key ); + zypp_r.out().gap(); + } + } else { + Table t; + t << ( TableHeader() + /* translators: Table column header */ << _("ID") + /* translators: Table column header */ << _("Name") + /* translators: Table column header */ << _("Expires")); + + for(const auto &key : keysFound_r) + { + t << ( TableRow() + << key.id() + << key.name() + << key.expires().asString()); + } + t.dumpTo( std::cout ); + zypp_r.out().gap(); + } + } + zypp_r.setExitCode( ZYPPER_EXIT_OK ); +} + +void listTrustedKeys ( Zypper &zypp_r ) +{ + if ( !God || !God->target() || !God->keyRing() ) + return; + + KeyRing_Ptr keyRing = God->keyRing(); + std::list trustedKeys = keyRing->trustedPublicKeyData(); + + if ( zypp_r.arguments().size() ) + { + std::list pubKeys; + for ( const std::string &arg : zypp_r.arguments() ) + { + PublicKeyData foundKey = keyRing->trustedPublicKeyData(arg); + if ( foundKey ) { + //this is a key ID + pubKeys.push_back(foundKey); + } else { + // is the current arg a path or a ID + filesystem::PathInfo path (arg); + if (!path.isExist()) + { + zypp_r.out().warning( str::Format(_("Argument '%1%' is not a trusted ID nor a existing file.")) % arg ); + zypp_r.setExitCode( ZYPPER_EXIT_ERR_INVALID_ARGS ); + return; + } + + KeyManagerCtx::Ptr keyMgr = KeyManagerCtx::createForOpenPGP(); + if (!keyMgr) + { + zypp_r.out().error( "Unable to initialize key manager backend" ); + zypp_r.setExitCode( ZYPPER_EXIT_ERR_ZYPP ); + return; + } + pubKeys.splice( pubKeys.end(), keyMgr->readKeyFromFile( arg )); + } + } + //print always in detail mode here, the user most likely wants to know more about the key + dumpKeyList( zypp_r, pubKeys, true ); + } + else + { + const target::rpm::RpmDb &rpmdb = God->target()->rpmDb(); + dumpKeyList( zypp_r, rpmdb.pubkeys(), zypp_r.cOpts().count("details") ); + } +} + +#if 0 +void removeKey(Zypper &zypp_r ) +{ + +} + +void exportKey( Zypper &zypp_r ) +{ + +} + +void checkKey( Zypper &zypp_r ) +{ + +} +#endif diff --git a/src/keys.h b/src/keys.h new file mode 100644 index 0000000000..efec2e2b1a --- /dev/null +++ b/src/keys.h @@ -0,0 +1,23 @@ +/*---------------------------------------------------------------------------*\ + ____ _ _ __ _ __ ___ _ _ + |_ / || | '_ \ '_ \/ -_) '_| + /__|\_, | .__/ .__/\___|_| + |__/|_| |_| +\*---------------------------------------------------------------------------*/ +#ifndef ZYPPERKEYS_H_ +#define ZYPPERKEYS_H_ + +#include + +class Zypper; + +void listTrustedKeys ( Zypper &zypp_r ); + +#if 0 +void removeKey ( Zypper &zypp_r ); +void exportKey ( Zypper &zypp_r ); +void checkKey ( Zypper &zypp_r ); +#endif + + +#endif diff --git a/src/utils/misc.cc b/src/utils/misc.cc index e688c7672c..07b458d53e 100644 --- a/src/utils/misc.cc +++ b/src/utils/misc.cc @@ -765,3 +765,41 @@ void packagekit_suggest_quit() ExternalProgram pkcall( argv ); pkcall.close(); } + +std::ostream &dumpKeyInfo(std::ostream &str, const PublicKeyData &key, const KeyContext &context) +{ + Zypper & zypper = Zypper::instance(); + if ( zypper.out().type() == Out::TYPE_XML ) + { + { + xmlout::Node parent( str, "gpgkey-info", xmlout::Node::optionalContent ); + + if ( !context.empty() ) + { + dumpAsXmlOn( *parent, context.repoInfo().asUserString(), "repository" ); + } + dumpAsXmlOn( *parent, key.name(), "key-name" ); + dumpAsXmlOn( *parent, key.fingerprint(), "key-fingerprint" ); + dumpAsXmlOn( *parent, key.created(), "key-created" ); + dumpAsXmlOn( *parent, key.expires(), "key-expires" ); + dumpAsXmlOn( *parent, str::Format( "gpg-pubkey-%1%-%2%" ) % key.gpgPubkeyVersion() % key.gpgPubkeyRelease(), "rpm-name" ); + } + return str; + } + + Table t; + t.lineStyle( none ); + if ( !context.empty() ) + { + t << ( TableRow() << "" << _("Repository:") << context.repoInfo().asUserString() ); + } + t << ( TableRow() << "" << _("Key Name:") << key.name() ) + << ( TableRow() << "" << _("Key Fingerprint:") << str::gapify( key.fingerprint(), 8 ) ) + << ( TableRow() << "" << _("Key Created:") << key.created() ) + << ( TableRow() << "" << _("Key Expires:") << key.expiresAsString() ); + for ( const PublicSubkeyData & sub : key.subkeys() ) + t << ( TableRow() << "" << _("Subkey:") << sub.asString() ); + t << ( TableRow() << "" << _("Rpm Name:") << str::Format( "gpg-pubkey-%1%-%2%" ) % key.gpgPubkeyVersion() % key.gpgPubkeyRelease() ); + + return str << t; +} diff --git a/src/utils/misc.h b/src/utils/misc.h index ac5550d8d7..135ace7d6e 100644 --- a/src/utils/misc.h +++ b/src/utils/misc.h @@ -18,6 +18,8 @@ #include #include #include +#include +#include class Zypper; class Table; @@ -173,4 +175,10 @@ bool packagekit_running(); /** Send suggestion to quit to PackageKit via DBus */ void packagekit_suggest_quit(); +/** Dump information about a Key for the current output format */ +std::ostream & dumpKeyInfo( std::ostream & str, const PublicKeyData & key, const KeyContext & context = KeyContext() ); +inline std::ostream & dumpKeyInfo( std::ostream & str, const PublicKey & key, const KeyContext & context = KeyContext() ) +{ return dumpKeyInfo( str, key.keyData(), context ); } + + #endif /*ZYPPER_UTILS_H*/