From: Tomasz Iwanek Date: Fri, 12 Jun 2015 09:01:12 +0000 (+0200) Subject: Save author certificate to pkgmgr database X-Git-Tag: accepted/tizen/mobile/20150630.002712~2 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=refs%2Fchanges%2F49%2F41949%2F3;p=platform%2Fcore%2Fappfw%2Fapp-installers.git Save author certificate to pkgmgr database Registration and unregistation of package was moved to pkgmgr_registration.cc. Change-Id: I80c838983b16302b7bea1d2acfe4d271e8732901 --- diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt index a9ce29d..cbbf1dd 100644 --- a/src/common/CMakeLists.txt +++ b/src/common/CMakeLists.txt @@ -3,6 +3,7 @@ SET(SRCS app_installer.cc context_installer.cc pkgmgr_interface.cc + pkgmgr_registration.cc pkgmgr_signal.cc security_registration.cc step/step_backup_icons.cc diff --git a/src/common/context_installer.h b/src/common/context_installer.h index 55e597a..cd18579 100644 --- a/src/common/context_installer.h +++ b/src/common/context_installer.h @@ -12,6 +12,7 @@ #include #include +#include #include #include @@ -32,6 +33,11 @@ class BackendData { virtual ~BackendData() { } }; +class CertificateInfo { + public: + Property author_certificate; +}; + enum class PrivilegeLevel : int { UNTRUSTED = 0, PUBLIC = 1, @@ -95,6 +101,9 @@ class ContextInstaller { // request privilege level of package Property privilege_level; + + // certificate information + Property certificate_info; }; boost::filesystem::path GetBackupPathForPackagePath( diff --git a/src/common/pkgmgr_registration.cc b/src/common/pkgmgr_registration.cc new file mode 100644 index 0000000..aedebd2 --- /dev/null +++ b/src/common/pkgmgr_registration.cc @@ -0,0 +1,161 @@ +// Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved +// Use of this source code is governed by a apache 2.0 license that can be +// found in the LICENSE file. + +#include "common/pkgmgr_registration.h" + +#include +#include +#include + +#include "common/utils/logging.h" + +namespace bf = boost::filesystem; + +namespace { + +// TODO(sdi2): Check if data->removable is correctly setting +// during parsing step. +// Same check should be done for preload field. + +// Having a specific step to implement a installer commandline tool +// for image build could be usefull also. +const char* const kAppinstTags[] = {"removable=true", nullptr, }; + +bool RegisterAuthorCertificate( + const common_installer::CertificateInfo& cert_info, + const std::string& pkgid, uid_t uid) { + pkgmgr_instcertinfo_h handle; + if (pkgmgr_installer_create_certinfo_set_handle(&handle) < 0) { + LOG(ERROR) << "Cannot create pkgmgr_instcertinfo_h"; + return false; + } + + const auto& cert = cert_info.author_certificate.get(); + pkgmgr_instcert_type inst_cert_type = PM_SET_AUTHOR_ROOT_CERT; + if (cert->isRootCert()) { + inst_cert_type = PM_SET_AUTHOR_ROOT_CERT; + } else if (cert->isCA()) { + inst_cert_type = PM_SET_AUTHOR_INTERMEDIATE_CERT; + } else { + inst_cert_type = PM_SET_AUTHOR_SIGNER_CERT; + } + + if (pkgmgr_installer_set_cert_value(handle, inst_cert_type, + const_cast(cert->getBase64().c_str())) < 0) { + pkgmgr_installer_destroy_certinfo_set_handle(handle); + LOG(ERROR) << "pkgmgrInstallerSetCertValue fail"; + return false; + } + + if (pkgmgr_installer_save_certinfo(pkgid.c_str(), handle, uid) < 0) { + pkgmgr_installer_destroy_certinfo_set_handle(handle); + LOG(ERROR) << "Failed to save certificate information"; + return false; + } + + pkgmgr_installer_destroy_certinfo_set_handle(handle); + return true; +} + +} // anonymous namespace + +namespace common_installer { + +bool RegisterAppInPkgmgr(const bf::path& xml_path, + const std::string& pkgid, + const CertificateInfo& cert_info, uid_t uid) { + int ret = uid != tzplatform_getuid(TZ_SYS_GLOBALAPP_USER) ? + pkgmgr_parser_parse_usr_manifest_for_installation( + xml_path.c_str(), uid, const_cast(kAppinstTags)) : + pkgmgr_parser_parse_manifest_for_installation( + xml_path.c_str(), const_cast(kAppinstTags)); + if (ret) { + LOG(ERROR) << "Failed to unregister package: " << xml_path; + return false; + } + + if (!!cert_info.author_certificate.get()) { + if (!RegisterAuthorCertificate(cert_info, pkgid, uid)) { + return false; + } + } + + return true; +} + +bool UpgradeAppInPkgmgr(const bf::path& xml_path, const std::string& pkgid, + const CertificateInfo& cert_info, uid_t uid) { + int ret = uid != tzplatform_getuid(TZ_SYS_GLOBALAPP_USER) ? + pkgmgr_parser_parse_usr_manifest_for_upgrade( + xml_path.string().c_str(), uid, + const_cast(kAppinstTags)) : + pkgmgr_parser_parse_manifest_for_upgrade( + xml_path.string().c_str(), + const_cast(kAppinstTags)); + + if (ret != 0) { + LOG(ERROR) << "Failed to upgrade package: " << xml_path; + return false; + } + + (void) pkgmgr_installer_delete_certinfo(pkgid.c_str()); + if (!!cert_info.author_certificate.get()) { + if (!RegisterAuthorCertificate(cert_info, pkgid, uid)) { + return false; + } + } + + return true; +} + +bool UnregisterAppInPkgmgr(const bf::path& xml_path, + const std::string& pkgid, uid_t uid) { + int ret = uid != tzplatform_getuid(TZ_SYS_GLOBALAPP_USER) ? + pkgmgr_parser_parse_usr_manifest_for_uninstallation( + xml_path.string().c_str(), uid, + const_cast(kAppinstTags)) : + pkgmgr_parser_parse_manifest_for_uninstallation( + xml_path.string().c_str(), const_cast(kAppinstTags)); + if (ret) { + LOG(ERROR) << "Failed to unregister package: " << xml_path; + return false; + } + + // Certificate info may be not present + (void) pkgmgr_installer_delete_certinfo(pkgid.c_str()); + + return true; +} + +std::string QueryCertificateAuthorCertificate(const std::string& pkgid) { + pkgmgrinfo_certinfo_h handle; + int ret = pkgmgrinfo_pkginfo_create_certinfo(&handle); + if (ret != PMINFO_R_OK) { + LOG(ERROR) << "pkgmgrinfo_pkginfo_create_certinfo failed with error: " + << ret; + return {}; + } + ret = pkgmgrinfo_pkginfo_load_certinfo(pkgid.c_str(), handle, getuid()); + if (ret != PMINFO_R_OK) { + LOG(ERROR) << "pkgmgrinfo_pkginfo_load_certinfo failed with error: " << ret; + pkgmgrinfo_pkginfo_destroy_certinfo(handle); + return {}; + } + const char* author_cert = nullptr; + ret = pkgmgrinfo_pkginfo_get_cert_value(handle, PMINFO_AUTHOR_SIGNER_CERT, + &author_cert); + if (ret != PMINFO_R_OK) { + LOG(ERROR) << "pkgmgrinfo_pkginfo_get_cert_value failed with error: " + << ret; + pkgmgrinfo_pkginfo_destroy_certinfo(handle); + return {}; + } + std::string old_author_certificate; + if (author_cert) + old_author_certificate = author_cert; + pkgmgrinfo_pkginfo_destroy_certinfo(handle); + return old_author_certificate; +} + +} // namespace common_installer diff --git a/src/common/pkgmgr_registration.h b/src/common/pkgmgr_registration.h new file mode 100644 index 0000000..cfa50c9 --- /dev/null +++ b/src/common/pkgmgr_registration.h @@ -0,0 +1,29 @@ +// Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved +// Use of this source code is governed by a apache 2.0 license that can be +// found in the LICENSE file. + +#ifndef COMMON_PKGMGR_REGISTRATION_H_ +#define COMMON_PKGMGR_REGISTRATION_H_ + +#include +#include + +#include + +#include "common/context_installer.h" + +namespace common_installer { + +bool RegisterAppInPkgmgr(const boost::filesystem::path& xml_path, + const std::string& pkgid, + const CertificateInfo& cert_info, uid_t uid); +bool UpgradeAppInPkgmgr(const boost::filesystem::path& xml_path, + const std::string& pkgid, + const CertificateInfo& cert_info, uid_t uid); +bool UnregisterAppInPkgmgr(const boost::filesystem::path& xml_path, + const std::string& pkgid, uid_t uid); +std::string QueryCertificateAuthorCertificate(const std::string& pkgid); + +} // namespace common_installer + +#endif // COMMON_PKGMGR_REGISTRATION_H_ diff --git a/src/common/step/step_check_signature.cc b/src/common/step/step_check_signature.cc index 503bcb2..36f8841 100644 --- a/src/common/step/step_check_signature.cc +++ b/src/common/step/step_check_signature.cc @@ -60,7 +60,8 @@ privilege_manager_visibility_e PrivilegeLevelToVisibility( common_installer::Step::Status ValidateSignatureFile( const bf::path& base_path, const ValidationCore::SignatureFileInfo& file_info, - common_installer::PrivilegeLevel* level) { + common_installer::PrivilegeLevel* level, + common_installer::CertificateInfo* cert_info) { bf::path path = base_path / file_info.getFileName(); LOG(INFO) << "Processing signature: " << path; ValidationCore::SignatureData data(path.string(), file_info.getFileNumber()); @@ -101,6 +102,9 @@ common_installer::Step::Status ValidateSignatureFile( *level == common_installer::PrivilegeLevel::UNTRUSTED) { *level = CertStoreIdToPrivilegeLevel(data.getVisibilityLevel()); } + } else { + // set author certificate to be saved in pkgmgr + cert_info->author_certificate.set(data.getEndEntityCertificatePtr()); } break; }; @@ -162,7 +166,7 @@ namespace common_installer { namespace signature { Step::Status ValidateSignatures(const bf::path& base_path, - PrivilegeLevel* level) { + PrivilegeLevel* level, common_installer::CertificateInfo* cert_info) { ValidationCore::VCoreInit(); // Find signature files ValidationCore::SignatureFileInfoSet signature_files; @@ -177,7 +181,8 @@ Step::Status ValidateSignatures(const bf::path& base_path, // Read xml schema for signatures for (auto& file_info : signature_files) { - Step::Status status = ValidateSignatureFile(base_path, file_info, level); + Step::Status status = ValidateSignatureFile(base_path, file_info, level, + cert_info); if (status != Step::Status::OK) { ValidationCore::VCoreDeinit(); return status; @@ -205,7 +210,8 @@ Step::Status StepCheckSignature::precheck() { Step::Status StepCheckSignature::process() { PrivilegeLevel level = PrivilegeLevel::UNTRUSTED; Status status = - ValidateSignatures(context_->unpacked_dir_path.get(), &level); + ValidateSignatures(context_->unpacked_dir_path.get(), &level, + &context_->certificate_info.get()); if (status != Status::OK) { return status; } diff --git a/src/common/step/step_check_signature.h b/src/common/step/step_check_signature.h index 3743304..8396a49 100644 --- a/src/common/step/step_check_signature.h +++ b/src/common/step/step_check_signature.h @@ -26,7 +26,7 @@ class StepCheckSignature : public Step { // Exposed for tests Step::Status ValidateSignatures(const boost::filesystem::path& base_path, - PrivilegeLevel* level); + PrivilegeLevel* level, common_installer::CertificateInfo* cert_info); } // namespace signature } // namespace common_installer diff --git a/src/common/step/step_register_app.cc b/src/common/step/step_register_app.cc index 1859ea8..2a47c31 100644 --- a/src/common/step/step_register_app.cc +++ b/src/common/step/step_register_app.cc @@ -2,22 +2,15 @@ #include "common/step/step_register_app.h" -#include #include -#include #include #include #include #include +#include "common/pkgmgr_registration.h" #include "common/utils/file_util.h" -namespace { - -const char* const kAppinstTags[] = {"removable=true", nullptr, }; - -} // anonymous namespace - namespace common_installer { namespace register_app { @@ -40,26 +33,13 @@ Step::Status StepRegisterApplication::precheck() { } Step::Status StepRegisterApplication::process() { - // TODO(sdi2): Check if data->removable is correctly setting - // during parsing step. - // Same check should be done for preload field. - - // Having a specific step to implement a installer commandline tool - // for image build could be usefull also. - - int ret = context_->uid.get() != tzplatform_getuid(TZ_SYS_GLOBALAPP_USER) ? - pkgmgr_parser_parse_usr_manifest_for_installation( - context_->xml_path.get().c_str(), context_->uid.get(), - const_cast(kAppinstTags)) : - pkgmgr_parser_parse_manifest_for_installation( - context_->xml_path.get().c_str(), - const_cast(kAppinstTags)); - - if (ret) { + if (!RegisterAppInPkgmgr(context_->xml_path.get(), + context_->pkgid.get().c_str(), + context_->certificate_info.get(), + context_->uid.get())) { LOG(ERROR) << "Failed to register the app"; return Step::Status::ERROR; } - in_registry_ = true; LOG(INFO) << "Successfully registered the app"; return Status::OK; @@ -70,21 +50,9 @@ Step::Status StepRegisterApplication::clean() { } Step::Status StepRegisterApplication::undo() { - if (in_registry_) { - int ret = context_->uid.get() != tzplatform_getuid(TZ_SYS_GLOBALAPP_USER) ? - pkgmgr_parser_parse_usr_manifest_for_uninstallation( - context_->xml_path.get().c_str(), context_->uid.get(), - const_cast(kAppinstTags)) : - pkgmgr_parser_parse_manifest_for_uninstallation( - context_->xml_path.get().c_str(), - const_cast(kAppinstTags)); - - if (ret) { - LOG(ERROR) << "Failed to restore old content pkgmgr database"; - return Step::Status::ERROR; - } - LOG(INFO) << "Successfuly clean database"; - } + UnregisterAppInPkgmgr(context_->xml_path.get(), context_->pkgid.get(), + context_->uid.get()); + LOG(INFO) << "Successfuly clean database"; return Status::OK; } diff --git a/src/common/step/step_register_app.h b/src/common/step/step_register_app.h index 01100cc..13a655c 100644 --- a/src/common/step/step_register_app.h +++ b/src/common/step/step_register_app.h @@ -12,18 +12,13 @@ namespace register_app { class StepRegisterApplication : public Step { public: - explicit StepRegisterApplication(ContextInstaller* context) - : Step(context), - in_registry_(false) { } + using Step::Step; Status process() override; Status clean() override; Status undo() override; Status precheck() override; - private: - bool in_registry_; - SCOPE_LOG_TAG(RegisterApp) }; diff --git a/src/common/step/step_unregister_app.cc b/src/common/step/step_unregister_app.cc index 03f00ea..769e4c9 100755 --- a/src/common/step/step_unregister_app.cc +++ b/src/common/step/step_unregister_app.cc @@ -5,9 +5,11 @@ #include #include +#include #include #include +#include "common/pkgmgr_registration.h" #include "common/step/step_unregister_app.h" #include "common/utils/file_util.h" @@ -38,20 +40,12 @@ Step::Status StepUnregisterApplication::precheck() { } Step::Status StepUnregisterApplication::process() { - const char* const appinst_tags[] = {"removable=true", nullptr, }; - - int ret = context_->uid.get() != tzplatform_getuid(TZ_SYS_GLOBALAPP_USER) ? - pkgmgr_parser_parse_usr_manifest_for_uninstallation( - context_->xml_path.get().c_str(), context_->uid.get(), - const_cast(appinst_tags)) : - pkgmgr_parser_parse_manifest_for_uninstallation( - context_->xml_path.get().c_str(), - const_cast(appinst_tags)); - - if (ret != 0) { + if (!UnregisterAppInPkgmgr(context_->xml_path.get(), context_->pkgid.get(), + context_->uid.get())) { LOG(ERROR) << "Failed to unregister package into database"; return Status::ERROR; } + LOG(DEBUG) << "Successfully unregister the application"; return Status::OK; diff --git a/src/common/step/step_update_app.cc b/src/common/step/step_update_app.cc index d9d767f..57708d0 100644 --- a/src/common/step/step_update_app.cc +++ b/src/common/step/step_update_app.cc @@ -9,32 +9,19 @@ #include #include +#include +#include + #include #include #include #include +#include "common/pkgmgr_registration.h" #include "common/utils/file_util.h" namespace bf = boost::filesystem; -namespace { - -const char* const kAppinstTags[] = {"removable=true", nullptr, }; - -bool UpgradeManifestInformation(uid_t uid, const bf::path& xml_path) { - int ret = uid != tzplatform_getuid(TZ_SYS_GLOBALAPP_USER) ? - pkgmgr_parser_parse_usr_manifest_for_upgrade( - xml_path.string().c_str(), uid, - const_cast(kAppinstTags)) : - pkgmgr_parser_parse_manifest_for_upgrade( - xml_path.string().c_str(), - const_cast(kAppinstTags)); - return !ret; -} - -} // anonymous namespace - namespace common_installer { namespace update_app { @@ -47,8 +34,9 @@ Step::Status StepUpdateApplication::precheck() { } Step::Status StepUpdateApplication::process() { - if (!UpgradeManifestInformation(context_->uid.get(), - context_->xml_path.get())) { + if (!UpgradeAppInPkgmgr(context_->xml_path.get(), + context_->pkgid.get(), context_->certificate_info.get(), + context_->uid.get())) { LOG(ERROR) << "Cannot upgrade manifest for application"; return Status::ERROR; } @@ -62,8 +50,17 @@ Step::Status StepUpdateApplication::clean() { } Step::Status StepUpdateApplication::undo() { - if (!UpgradeManifestInformation(context_->uid.get(), - context_->backup_xml_path.get())) { + // Prepare certification info for revert + ValidationCore::Base64Decoder decoder; + decoder.append(QueryCertificateAuthorCertificate(context_->pkgid.get())); + decoder.finalize(); + CertificateInfo certificate_info; + certificate_info.author_certificate.set(ValidationCore::CertificatePtr( + new ValidationCore::Certificate(decoder.get()))); + + if (!UpgradeAppInPkgmgr(context_->backup_xml_path.get(), + context_->pkgid.get(), certificate_info, + context_->uid.get())) { LOG(ERROR) << "Cannot revert manifest for application"; return Status::ERROR; } diff --git a/src/unit_tests/signature_unittest.cc b/src/unit_tests/signature_unittest.cc index a7e3e33..1e0a032 100644 --- a/src/unit_tests/signature_unittest.cc +++ b/src/unit_tests/signature_unittest.cc @@ -24,7 +24,8 @@ TEST_F(SignatureValidatorTest, HandlesInitializedSignatureDir) { signature_file.reset(new bf::path( "/usr/share/app-installers-ut/test_samples/good_signatures")); PrivilegeLevel level = PrivilegeLevel::UNTRUSTED; - EXPECT_EQ(ValidateSignatures(*signature_file, &level), + common_installer::CertificateInfo cert_info; + EXPECT_EQ(ValidateSignatures(*signature_file, &level, &cert_info), Step::Status::OK); } @@ -33,7 +34,8 @@ TEST_F(SignatureValidatorTest, HandlesBadSignatureDir) { signature_file.reset(new bf::path( "/usr/share/app-installers-ut/test_samples/bad_signatures")); PrivilegeLevel level = PrivilegeLevel::UNTRUSTED; - EXPECT_EQ(ValidateSignatures(*signature_file, &level), + common_installer::CertificateInfo cert_info; + EXPECT_EQ(ValidateSignatures(*signature_file, &level, &cert_info), Step::Status::ERROR); }