step/security/step_check_wgt_notification_category.cc
step/security/step_check_wgt_ime_privilege.cc
step/security/step_direct_manifest_check_signature.cc
+ step/security/step_check_extension_privileges.cc
wgt_app_query_interface.cc
wgt_installer.cc
+ extension_config_parser.cc
)
IF(WRT_LAUNCHER)
--- /dev/null
+// Copyright (c) 2016 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 "wgt/extension_config_parser.h"
+#include <manifest_parser/utils/string_util.h>
+#include <manifest_parser/manifest_handler.h>
+
+#include <cassert>
+#include <utility>
+
+namespace wgt {
+
+namespace {
+const xmlChar kExtensionNodeKey[] = "extension";
+const xmlChar kNamePrivilegeKey[] = "privilege";
+const xmlChar kPrivigeNameAttributeKey[] = "name";
+const char kAttributePrefix[] = "@";
+const xmlChar kDirAttributeKey[] = "dir";
+const char kXmlTextKey[] = "#text";
+const char kNamespaceKey[] = "@namespace";
+const char kExtensionPath[] = "extension.privilege";
+const char kExtensionNameKey[] = "@name";
+} // namespace
+
+ExtensionConfigParser::ExtensionConfigParser(std::string config_xml) {
+ config_xml_ = config_xml;
+}
+
+std::unique_ptr<parser::DictionaryValue>
+ ExtensionConfigParser::LoadExtensionConfig(const std::string& config_xml) {
+ xmlDoc *doc = nullptr;
+ xmlNode* root_node = nullptr;
+ doc = xmlReadFile(config_xml.c_str(), nullptr, XML_PARSE_NOENT);
+ if (!doc) {
+ LOG(ERROR) << "Failed to read xml document model from" << config_xml;
+ return nullptr;
+ }
+ root_node = xmlDocGetRootElement(doc);
+ std::unique_ptr<parser::DictionaryValue> dv = LoadXMLNode(root_node);
+ std::unique_ptr<parser::DictionaryValue> result(new parser::DictionaryValue);
+ if (dv)
+ result->Set(reinterpret_cast<const char*>(root_node->name), dv.release());
+ return result;
+}
+
+std::string ExtensionConfigParser::GetNodeDir(
+ xmlNode* node, const std::string& inherit_dir) {
+ std::string dir(inherit_dir);
+ for (xmlAttr* prop = node->properties; prop; prop = prop->next) {
+ if (xmlStrEqual(prop->name, kDirAttributeKey)) {
+ char* prop_value = reinterpret_cast<char*>(xmlNodeListGetString(
+ node->doc, prop->children, 1));
+ dir = prop_value;
+ xmlFree(prop_value);
+ break;
+ }
+ }
+ return dir;
+}
+std::string ExtensionConfigParser::GetNodeText(
+ xmlNode* root, const std::string& inherit_dir) {
+ if (root->type != XML_ELEMENT_NODE)
+ return std::string();
+ std::string current_dir(GetNodeDir(root, inherit_dir));
+ std::string text;
+ if (!current_dir.empty())
+ text += parser::utils::GetDirUTF8Start(current_dir);
+ for (xmlNode* node = root->children; node; node = node->next) {
+ if (node->type == XML_TEXT_NODE || node->type == XML_CDATA_SECTION_NODE)
+ text = text + std::string(reinterpret_cast<char*>(node->content));
+ else
+ text += GetNodeText(node, current_dir);
+ }
+ if (!current_dir.empty())
+ text += parser::utils::GetDirUTF8End();
+ return text;
+}
+bool ExtensionConfigParser::IsPropSupportDir(xmlNode* root, xmlAttr* prop) {
+ if (xmlStrEqual(root->name, kNamePrivilegeKey)
+ && xmlStrEqual(prop->name, kPrivigeNameAttributeKey)) {
+ return true;
+ }
+ return false;
+}
+bool ExtensionConfigParser::IsTrimRequiredForElement(xmlNode* root) {
+ if (xmlStrEqual(root->name, kNamePrivilegeKey)) {
+ return true;
+ }
+ return false;
+}
+bool ExtensionConfigParser::IsTrimRequiredForProp(
+ xmlNode* root, xmlAttr* prop) {
+ if (xmlStrEqual(root->name, kNamePrivilegeKey) &&
+ xmlStrEqual(prop->name, kPrivigeNameAttributeKey)) {
+ return true;
+ }
+ return false;
+}
+std::unique_ptr<parser::DictionaryValue>
+ ExtensionConfigParser::LoadXMLNode(
+ xmlNode* root, const std::string& inherit_dir) {
+ std::unique_ptr<parser::DictionaryValue> value(new parser::DictionaryValue());
+ if (root->type != XML_ELEMENT_NODE)
+ return nullptr;
+
+ std::string current_dir(GetNodeDir(root, inherit_dir));
+
+ xmlAttr* prop = nullptr;
+ for (prop = root->properties; prop; prop = prop->next) {
+ xmlChar* value_ptr = xmlNodeListGetString(root->doc, prop->children, 1);
+ std::string prop_value(reinterpret_cast<char*>(value_ptr));
+ xmlFree(value_ptr);
+ if (IsPropSupportDir(root, prop))
+ prop_value = parser::utils::GetDirTextUTF8(prop_value, current_dir);
+
+ if (IsTrimRequiredForProp(root, prop))
+ prop_value = parser::utils::CollapseWhitespaceUTF8(prop_value);
+
+ value->SetString(
+ std::string(kAttributePrefix)
+ + reinterpret_cast<const char*>(prop->name),
+ prop_value);
+ }
+
+ if (root->ns)
+ value->SetString(kNamespaceKey,
+ reinterpret_cast<const char*>(root->ns->href));
+
+ for (xmlNode* node = root->children; node; node = node->next) {
+ std::string sub_node_name(reinterpret_cast<const char*>(node->name));
+ std::unique_ptr<parser::DictionaryValue> sub_value =
+ LoadXMLNode(node, current_dir);
+
+ if (!sub_value) {
+ continue;
+ }
+ if (!value->HasKey(sub_node_name)) {
+ value->Set(sub_node_name, sub_value.release());
+ continue;
+ }
+
+ parser::Value* temp;
+ value->Get(sub_node_name, &temp);
+
+ if (temp->IsType(parser::Value::TYPE_LIST)) {
+ parser::ListValue* list;
+ temp->GetAsList(&list);
+ list->Append(sub_value.release());
+ } else {
+ assert(temp->IsType(parser::Value::TYPE_DICTIONARY));
+ parser::DictionaryValue* dict;
+ temp->GetAsDictionary(&dict);
+ parser::DictionaryValue* prev_value = dict->DeepCopy();
+
+ parser::ListValue* list = new parser::ListValue();
+ list->Append(prev_value);
+ list->Append(sub_value.release());
+ value->Set(sub_node_name, list);
+ }
+ }
+
+ std::string text;
+ xmlChar* text_ptr = xmlNodeListGetString(root->doc, root->children, 1);
+ if (text_ptr) {
+ text = reinterpret_cast<char*>(text_ptr);
+ xmlFree(text_ptr);
+ }
+ if (IsTrimRequiredForElement(root))
+ text = parser::utils::CollapseWhitespaceUTF8(text);
+ if (!text.empty())
+ value->SetString(kXmlTextKey, text);
+
+ return value;
+}
+std::vector<std::string> ExtensionConfigParser::GetExtensionPrivilegeList() {
+ std::unique_ptr<parser::DictionaryValue> dic
+ = LoadExtensionConfig(config_xml_);
+ std::vector<std::string> privilege_list;
+
+ for (auto& item : parser::GetOneOrMany(dic.get(), kExtensionPath, "")) {
+ std::string privilege;
+ if (item->GetString(kExtensionNameKey, &privilege)) {
+ LOG(DEBUG) << "User defined extra privilege: " << privilege;
+ privilege_list.push_back(privilege);
+ }
+ }
+ return privilege_list;
+}
+} // namespace wgt
--- /dev/null
+// Copyright (c) 2016 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 WGT_EXTENSION_CONFIG_PARSER_H_
+#define WGT_EXTENSION_CONFIG_PARSER_H_
+
+#include <libxml2/libxml/tree.h>
+#include <manifest_parser/utils/logging.h>
+#include <manifest_parser/values.h>
+#include <manifest_parser/manifest_util.h>
+
+#include <string>
+#include <map>
+#include <vector>
+
+namespace wgt {
+class ExtensionConfigParser {
+ public:
+ explicit ExtensionConfigParser(std::string config_xml);
+ std::vector<std::string> GetExtensionPrivilegeList();
+ private:
+ std::unique_ptr<parser::DictionaryValue> LoadExtensionConfig(
+ const std::string& config_xml);
+ std::string GetNodeDir(xmlNode* node, const std::string& inherit_dir);
+ std::string GetNodeText(xmlNode* root, const std::string& inherit_dir);
+ bool IsPropSupportDir(xmlNode* root, xmlAttr* prop);
+ bool IsTrimRequiredForElement(xmlNode* root);
+ bool IsTrimRequiredForProp(xmlNode* root, xmlAttr* prop);
+ std::unique_ptr<parser::DictionaryValue> LoadXMLNode(
+ xmlNode* root, const std::string& inherit_dir = "");
+ std::string config_xml_;
+};
+} // namespace wgt
+
+#endif // WGT_EXTENSION_CONFIG_PARSER_H_
--- /dev/null
+// Copyright (c) 2016 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 "wgt/step/security/step_check_extension_privileges.h"
+#include <pkgmgrinfo_basic.h>
+#include <glob.h>
+#include <sys/utsname.h>
+
+#include <set>
+#include <vector>
+#include <cstdlib>
+#include <string>
+#include <memory>
+
+#include "wgt/extension_config_parser.h"
+#include "manifest_parser/values.h"
+#include "common/certificate_validation.h"
+#include "common/utils/glist_range.h"
+
+namespace {
+const char kPluginsDirectory[] = "/res/wgt/plugin/";
+const char kArchArmv7l[] = "armv7l";
+const char kArchI586[] = "i586";
+const char kArchDefault[] = "default";
+}
+
+namespace wgt {
+namespace security {
+
+common_installer::Step::Status StepCheckExtensionPrivileges::precheck() {
+ if (!context_->manifest_data.get()) {
+ LOG(ERROR) << "Manifest data is not set";
+ return Status::ERROR;
+ }
+ return Status::OK;
+}
+common_installer::Step::Status StepCheckExtensionPrivileges::process() {
+ std::string app_ext_config_pattern(GetExtensionPath());
+
+ manifest_x* m = context_->manifest_data.get();
+ std::set<std::string> current_privileges;
+ for (const char* priv : GListRange<char*>(m->privileges)) {
+ current_privileges.insert(priv);
+ }
+
+ std::set<std::string> xmlFiles;
+ {
+ glob_t glob_result;
+ glob(app_ext_config_pattern.c_str(), GLOB_TILDE, NULL, &glob_result);
+ for (unsigned int i = 0; i < glob_result.gl_pathc; ++i) {
+ xmlFiles.insert(glob_result.gl_pathv[i]);
+ }
+ }
+ std::set<std::string> privileges;
+ for (auto it = xmlFiles.begin(); it != xmlFiles.end(); ++it) {
+ LOG(DEBUG) << "start to parse extension xml : " << *it;
+ ExtensionConfigParser extensionParser(*it);
+ std::vector<std::string> list = extensionParser.GetExtensionPrivilegeList();
+ for (int i = 0 ; i < list.size() ; i++) {
+ if (current_privileges.find(list[i]) == current_privileges.end()) {
+ privileges.insert(list[i]);
+ }
+ }
+ }
+
+ if (!privileges.empty()) {
+ if (!CheckPriviligeLevel(privileges)) {
+ LOG(DEBUG) << "Fail to validation of privilege";
+ return Status::ERROR;
+ }
+ for (auto it = privileges.begin(); it != privileges.end(); ++it) {
+ LOG(DEBUG) << "set list privilege : " << *it;
+ m->privileges = g_list_append(m->privileges, strdup((*it).c_str()));
+ }
+ }
+ return Status::OK;
+}
+
+std::string StepCheckExtensionPrivileges::GetExtensionPath() {
+ std::string app_ext_config_pattern(context_->pkg_path.get().string());
+ app_ext_config_pattern.append(kPluginsDirectory);
+ struct utsname u;
+ if (0 == uname(&u)) {
+ std::string machine = u.machine;
+ LOG(DEBUG) << "Machine archicture for user defined plugins: " << machine;
+ if (!machine.empty()) {
+ if (machine == kArchArmv7l) {
+ app_ext_config_pattern.append(kArchArmv7l);
+ } else if (machine == kArchI586) {
+ app_ext_config_pattern.append(kArchI586);
+ } else {
+ app_ext_config_pattern.append(kArchDefault);
+ }
+ } else {
+ LOG(ERROR) << "cannot get machine info";
+ app_ext_config_pattern.append(kArchDefault);
+ }
+ app_ext_config_pattern.append("/");
+ }
+ app_ext_config_pattern.append("*");
+ app_ext_config_pattern.append(".xml");
+ return app_ext_config_pattern;
+}
+
+bool StepCheckExtensionPrivileges::CheckPriviligeLevel(
+ std::set<std::string> priv_set) {
+ GList* privileges = nullptr;
+ for (auto it = priv_set.begin(); it != priv_set.end(); ++it) {
+ privileges = g_list_append(privileges, strdup((*it).c_str()));
+ }
+ guint size = g_list_length(privileges);
+ if (size == 0) return true;
+
+ std::string error_message;
+ if (!common_installer::ValidatePrivilegeLevel(
+ context_->privilege_level.get(),
+ false,
+ context_->manifest_data.get()->api_version,
+ privileges,
+ &error_message)) {
+ if (!error_message.empty()) {
+ LOG(ERROR) << "error_message: " << error_message;
+ return false;
+ }
+ return false;
+ }
+ return true;
+}
+
+} // namespace security
+} // namespace wgt
--- /dev/null
+// 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.
+// Copyright (c) 2016 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 WGT_STEP_SECURITY_STEP_CHECK_EXTENSION_PRIVILEGES_H_
+#define WGT_STEP_SECURITY_STEP_CHECK_EXTENSION_PRIVILEGES_H_
+
+#include <common/app_installer.h>
+#include <common/installer_context.h>
+#include <common/step/step.h>
+#include <manifest_parser/utils/logging.h>
+#include <manifest_parser/values.h>
+
+#include <vector>
+#include <string>
+#include <set>
+
+namespace wgt {
+namespace security {
+
+/**
+ * \brief Step that add user extension privileges during installation
+ */
+class StepCheckExtensionPrivileges : public common_installer::Step {
+ public:
+ using Step::Step;
+
+ /**
+ * \Adds extra package privileges defined by extension manifest.
+ *
+ * \return Status::OK
+ */
+ Status process() override;
+ Status clean() override { return Status::OK; }
+ Status undo() override { return Status::OK; }
+ /**
+ * \brief Check requirements for this step
+ *
+ * \return Status::ERROR when rmanifest data are missing,
+ * Status::OK otherwise
+ */
+ Status precheck() override;
+ private:
+ std::string GetExtensionPath();
+ bool CheckPriviligeLevel(std::set<std::string> priv_set);
+ STEP_NAME(CheckExtensionPrivileges)
+};
+
+} // namespace security
+} // namespace wgt
+
+#endif // WGT_STEP_SECURITY_STEP_CHECK_EXTENSION_PRIVILEGES_H_
#include "wgt/step/security/step_check_wgt_notification_category.h"
#include "wgt/step/security/step_check_wgt_ime_privilege.h"
#include "wgt/step/security/step_direct_manifest_check_signature.h"
+#include "wgt/step/security/step_check_extension_privileges.h"
namespace ci = common_installer;
AddStep<wgt::filesystem::StepWgtPatchIcons>();
AddStep<ci::filesystem::StepCreateIcons>();
AddStep<wgt::filesystem::StepCopyPreviewIcons>();
+ AddStep<wgt::security::StepCheckExtensionPrivileges>();
AddStep<wgt::pkgmgr::StepGenerateXml>();
AddStep<ci::pkgmgr::StepRegisterApplication>();
AddStep<ci::pkgmgr::StepRunParserPlugin>(
AddStep<ci::filesystem::StepCreateIcons>();
AddStep<wgt::filesystem::StepCopyPreviewIcons>();
AddStep<ci::filesystem::StepCopyStorageDirectories>();
+ AddStep<wgt::security::StepCheckExtensionPrivileges>();
AddStep<ci::security::StepUpdateSecurity>();
AddStep<wgt::pkgmgr::StepGenerateXml>();
AddStep<ci::pkgmgr::StepRunParserPlugin>(
AddStep<ci::rds::StepRDSParse>();
AddStep<ci::filesystem::StepUpdateTep>();
AddStep<wgt::rds::StepWgtRDSModify>();
+ AddStep<wgt::security::StepCheckExtensionPrivileges>();
AddStep<ci::security::StepUpdateSecurity>();
break;
}
AddStep<ci::filesystem::StepCreateIcons>();
AddStep<wgt::filesystem::StepCopyPreviewIcons>();
AddStep<ci::filesystem::StepCopyStorageDirectories>();
+ AddStep<wgt::security::StepCheckExtensionPrivileges>();
AddStep<ci::security::StepUpdateSecurity>();
AddStep<wgt::pkgmgr::StepGenerateXml>();
AddStep<ci::pkgmgr::StepRunParserPlugin>(
AddStep<ci::pkgmgr::StepRunParserPlugin>(
ci::Plugin::ActionType::Install);
AddStep<ci::filesystem::StepCreatePerUserStorageDirectories>();
+ AddStep<wgt::security::StepCheckExtensionPrivileges>();
AddStep<ci::security::StepRegisterSecurity>();
break;
}
AddStep<wgt::filesystem::StepWgtPatchIcons>();
AddStep<ci::filesystem::StepCreateIcons>();
AddStep<wgt::filesystem::StepCopyPreviewIcons>();
+ AddStep<wgt::security::StepCheckExtensionPrivileges>();
AddStep<ci::security::StepUpdateSecurity>();
AddStep<wgt::pkgmgr::StepGenerateXml>();
AddStep<ci::pkgmgr::StepRunParserPlugin>(