const char kRecoveryDeltaString[] = "DELTA";
const char kRecoveryMountInstallString[] = "MOUNTINSTALL";
const char kRecoveryMountUpdateString[] = "MOUNTUPDATE";
+const char kRecoveryReadonlyUpdateInstallString[] = "READONLYUPDATEINSTALL";
const char kRecoveryUnknownString[] = "UNKNOWN";
const std::map<std::string, ci::RequestType> kStringToRequestMap = {
{kRecoveryDeltaString, ci::RequestType::Delta},
{kRecoveryMountInstallString, ci::RequestType::MountInstall},
{kRecoveryMountUpdateString, ci::RequestType::MountUpdate},
+ {kRecoveryReadonlyUpdateInstallString,
+ ci::RequestType::ReadonlyUpdateInstall},
};
std::string TruncateNewLine(const char* data) {
case RequestType::MountUpdate:
fputs(kRecoveryMountUpdateString, handle);
break;
+ case RequestType::ReadonlyUpdateInstall:
+ fputs(kRecoveryReadonlyUpdateInstallString, handle);
+ break;
default:
fputs(kRecoveryUnknownString, handle);
break;
namespace configuration {
ci::Step::Status StepParsePreload::process() {
+ RequestType req_type = context_->request_type.get();
const char* readonly_val = context_->manifest_data.get()->readonly;
if (!readonly_val || (readonly_val && strlen(readonly_val) == 0)) {
if (readonly_val)
if (context_->is_readonly_package.get()) {
context_->manifest_data.get()->readonly = strdup("true");
- if (getuid() != 0) {
+ if (getuid() != 0 && req_type != RequestType::Recovery) {
LOG(ERROR) << "You're not authorized to install readonly app: "
<< context_->pkgid.get().c_str();
return Status::OPERATION_NOT_ALLOWED;
}
PkgQueryInterface pkg_query(context_->pkgid.get(), context_->uid.get());
- RequestType req_type = context_->request_type.get();
const char* preload_val = context_->manifest_data.get()->preload;
if (!preload_val || (preload_val && strlen(preload_val) == 0)) {
if (preload_val)
Status RecoveryNew() override { return Status::OK; };
Status RecoveryUpdate() override;
Status RecoveryMountUpdate() override;
+ Status RecoveryReadonlyUpdateInstall() override { return Status::OK; };
private:
Step::Status ChangeOwnershipIconsAndManifest(const boost::optional<gid_t> gid,
return Status::OK;
}
+Step::Status StepRecoverFiles::RecoveryReadonlyUpdateInstall() {
+ // Remove package directory at RW area
+ bf::path pkg_path =
+ bf::path(GetRootAppPath(false, context_->uid.get())) /
+ context_->pkgid.get();
+ if (!RemoveAll(pkg_path))
+ return Status::RECOVERY_ERROR;
+
+ LOG(INFO) << "Package files recovery done";
+ return Status::OK;
+}
+
bool StepRecoverFiles::SetPackagePath() {
if (context_->pkgid.get().empty())
return false;
Status RecoveryUpdate() override;
Status RecoveryMountNew() override;
Status RecoveryMountUpdate() override;
+ Status RecoveryReadonlyUpdateInstall() override;
private:
bool SetPackagePath();
--- /dev/null
+// Copyright (c) 2018 Samsung Electronics Co., Ltd All Rights Reserved
+// Use of this source code is governed by an apache-2.0 license that can be
+// found in the LICENSE file.
+
+#include "common/step/filesystem/step_recover_globalapp_symlinks.h"
+#include "common/step/filesystem/step_remove_globalapp_symlinks.h"
+
+namespace bf = boost::filesystem;
+
+namespace common_installer {
+namespace filesystem {
+
+Step::Status StepRecoverGlobalAppSymlinks::RecoveryReadonlyUpdateInstall() {
+ StepRemoveGlobalAppSymlinks step(context_);
+ Status status = step.precheck();
+ if (status != Status::OK)
+ return status;
+ return step.process();
+}
+
+} // namespace filesystem
+} // namespace common_installer
--- /dev/null
+// Copyright (c) 2018 Samsung Electronics Co., Ltd All Rights Reserved
+// Use of this source code is governed by an apache-2.0 license that can be
+// found in the LICENSE file.
+
+#ifndef COMMON_STEP_FILESYSTEM_STEP_RECOVER_GLOBALAPP_SYMLINKS_H_
+#define COMMON_STEP_FILESYSTEM_STEP_RECOVER_GLOBALAPP_SYMLINKS_H_
+
+#include <manifest_parser/utils/logging.h>
+
+#include "common/installer_context.h"
+#include "common/step/recovery/step_recovery.h"
+
+namespace common_installer {
+namespace filesystem {
+
+/**
+ * @brief Recovers symlink files of globalapp
+ *
+ * This is the part of Recovery Mode that is responsible for removing
+ * symlink files for read-only files of globalapp for backward compatibility.
+ */
+class StepRecoverGlobalAppSymlinks : public recovery::StepRecovery {
+ public:
+ using StepRecovery::StepRecovery;
+
+ Status RecoveryNew() override { return Status::OK; }
+ Status RecoveryUpdate() override { return Status::OK; }
+ Status RecoveryReadonlyUpdateInstall() override;
+
+ STEP_NAME(RecoverGlobalAppSymlinks)
+};
+
+} // namespace filesystem
+} // namespace common_installer
+
+#endif // COMMON_STEP_FILESYSTEM_STEP_RECOVER_GLOBALAPP_SYMLINKS_H_
namespace filesystem {
Step::Status StepRemoveGlobalAppSymlinks::process() {
- if (context_->is_readonly_package.get())
+ RequestType req_type = context_->request_type.get();
+ if (context_->is_readonly_package.get() && req_type != RequestType::Recovery)
return Step::Status::OK;
if (context_->request_mode.get() != RequestMode::GLOBAL)
std::string package_id = context_->pkgid.get();
- RequestType req_type = context_->request_type.get();
if (req_type == RequestType::Uninstall ||
- req_type == RequestType::ReadonlyUpdateUninstall) {
+ req_type == RequestType::ReadonlyUpdateUninstall ||
+ req_type == RequestType::Recovery) {
LOG(INFO) << "Deleting globalapp symlinks for all user, package: "
<< package_id;
if (!DeleteGlobalAppSymlinksForAllUsers(package_id)) {
return Status::OK;
}
+Step::Status StepRecoverApplication::RecoveryReadonlyUpdateInstall() {
+ // Hmm... this is just-work solution...
+ manifest_x* manifest_data = context_->manifest_data.get();
+ free(manifest_data->system);
+ manifest_data->system = strdup("true");
+ free(manifest_data->preload);
+ manifest_data->preload = strdup("true");
+ free(manifest_data->readonly);
+ manifest_data->readonly = strdup("true");
+ free(manifest_data->removable);
+ manifest_data->removable = strdup("false");
+ return RecoveryUpdate();
+}
+
bool StepRecoverApplication::SetXmlPaths() {
if (context_->pkgid.get().empty())
return false;
using StepRecovery::StepRecovery;
Status RecoveryNew() override;
Status RecoveryUpdate() override;
+ Status RecoveryReadonlyUpdateInstall() override;
+
private:
bool SetXmlPaths();
context_->unpacked_dir_path.set(recovery_file->unpacked_dir());
context_->pkgid.set(recovery_file->pkgid());
switch (recovery_file->type()) {
- case RequestType::Install:
- LOG(INFO) << "Running recovery for new installation";
- break;
- case RequestType::Update:
- LOG(INFO) << "Running recovery for update installation";
- break;
- case RequestType::Delta:
- LOG(INFO) << "Running recovery for delta installation";
- break;
- case RequestType::MountInstall:
- LOG(INFO) << "Running recovery for mount install installation";
- break;
- case RequestType::MountUpdate:
- LOG(INFO) << "Running recovery for mount update installation";
- break;
- default:
- LOG(ERROR) << context_->file_path.get() << " is unknown recovery type ("
- << static_cast<int>(recovery_file->type()) << ")";
- return Status::RECOVERY_ERROR;
+ case RequestType::Install:
+ LOG(INFO) << "Running recovery for new installation";
+ break;
+ case RequestType::Update:
+ LOG(INFO) << "Running recovery for update installation";
+ break;
+ case RequestType::Delta:
+ LOG(INFO) << "Running recovery for delta installation";
+ break;
+ case RequestType::MountInstall:
+ LOG(INFO) << "Running recovery for mount install installation";
+ break;
+ case RequestType::MountUpdate:
+ LOG(INFO) << "Running recovery for mount update installation";
+ break;
+ case RequestType::ReadonlyUpdateInstall:
+ LOG(INFO) << "Running recovery for readonly update installation";
+ context_->is_readonly_package.set(true);
+ context_->root_application_path.set(
+ GetRootAppPath(true, context_->uid.get()));
+ break;
+ default:
+ LOG(ERROR) << context_->file_path.get() << " is unknown recovery type ("
+ << static_cast<int>(recovery_file->type()) << ")";
+ return Status::RECOVERY_ERROR;
}
context_->recovery_info.set(RecoveryInfo(std::move(recovery_file)));
return RecoveryMountNew();
case RequestType::MountUpdate:
return RecoveryMountUpdate();
+ case RequestType::ReadonlyUpdateInstall:
+ return RecoveryReadonlyUpdateInstall();
default:
LOG(ERROR) << "Recovery is not supported for given type of installation";
return Status::RECOVERY_ERROR;
return RecoveryUpdate();
}
+Step::Status StepRecovery::RecoveryReadonlyUpdateInstall() {
+ return RecoveryUpdate();
+}
+
} // namespace recovery
} // namespace common_installer
virtual Status RecoveryDelta();
virtual Status RecoveryMountNew();
virtual Status RecoveryMountUpdate();
+ virtual Status RecoveryReadonlyUpdateInstall();
};
} // namespace recovery
return Status::OK;
}
+Step::Status StepRecoverSecurity::RecoveryReadonlyUpdateInstall() {
+ if (!Check(false)) {
+ LOG(ERROR) << "Invalid parameters";
+ return Status::INVALID_VALUE;
+ }
+ std::string error_message;
+ if (!RegisterSecurityContextForManifest(
+ context_->pkgid.get(), context_->pkg_path.get(), context_->uid.get(),
+ &context_->certificate_info.get(), context_->manifest_data.get(),
+ context_->cross_app_rules.get(), &error_message)) {
+ LOG(ERROR) << "Unsuccessful update";
+ if (!error_message.empty()) {
+ LOG(ERROR) << "error_message: " << error_message;
+ on_error(Status::RECOVERY_ERROR, error_message);
+ }
+ return Status::RECOVERY_ERROR;
+ }
+ return Status::OK;
+}
+
} // namespace security
} // namespace common_installer
Status RecoveryNew() override;
Status RecoveryUpdate() override;
+ Status RecoveryReadonlyUpdateInstall() override;
private:
bool Check(bool is_update);
#include "common/step/security/step_recover_signature.h"
+#include <boost/filesystem/path.hpp>
+
#include <string>
#include "common/certificate_validation.h"
+namespace bf = boost::filesystem;
+
namespace common_installer {
namespace security {
return Status::OK;
}
+Step::Status StepRecoverSignature::RecoveryReadonlyUpdateInstall() {
+ std::string error_message;
+ PrivilegeLevel level;
+ bf::path signature_root =
+ bf::path(GetRootAppPath(context_->is_readonly_package.get(),
+ context_->uid.get())) / context_->pkgid.get();
+ if (!ValidateSignatures(signature_root, &level,
+ &context_->certificate_info.get(), false,
+ &error_message)) {
+ LOG(ERROR) << "Failed to verify signature: " << error_message;
+ return Status::CERT_ERROR;
+ }
+ return Status::OK;
+}
+
} // namespace security
} // namespace common_installer
Status RecoveryNew() override { return Status::OK; }
Status RecoveryUpdate() override;
+ Status RecoveryReadonlyUpdateInstall() override;
private:
virtual boost::filesystem::path GetSignatureRoot() = 0;