implement step for use user extension 28/75028/5 accepted/tizen/common/20160707.171532 accepted/tizen/ivi/20160707.043119 accepted/tizen/mobile/20160707.043137 accepted/tizen/tv/20160707.043001 accepted/tizen/wearable/20160707.043135 submit/tizen/20160707.013535
authorInhwan Lee <ideal.lee@samsung.com>
Thu, 16 Jun 2016 10:14:55 +0000 (19:14 +0900)
committerTomasz Iwanek <t.iwanek@samsung.com>
Wed, 6 Jul 2016 13:19:37 +0000 (06:19 -0700)
Change-Id: Ie5442f543f6e4dc3dbf78685716db2b113c021d0

src/wgt/CMakeLists.txt [changed mode: 0644->0755]
src/wgt/extension_config_parser.cc [new file with mode: 0755]
src/wgt/extension_config_parser.h [new file with mode: 0755]
src/wgt/step/security/step_check_extension_privileges.cc [new file with mode: 0755]
src/wgt/step/security/step_check_extension_privileges.h [new file with mode: 0755]
src/wgt/wgt_installer.cc [changed mode: 0644->0755]

old mode 100644 (file)
new mode 100755 (executable)
index f45acc5..2e70267
@@ -18,8 +18,10 @@ SET(SRCS
   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)
diff --git a/src/wgt/extension_config_parser.cc b/src/wgt/extension_config_parser.cc
new file mode 100755 (executable)
index 0000000..4813d72
--- /dev/null
@@ -0,0 +1,190 @@
+// 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
diff --git a/src/wgt/extension_config_parser.h b/src/wgt/extension_config_parser.h
new file mode 100755 (executable)
index 0000000..c5cd454
--- /dev/null
@@ -0,0 +1,36 @@
+// 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_
diff --git a/src/wgt/step/security/step_check_extension_privileges.cc b/src/wgt/step/security/step_check_extension_privileges.cc
new file mode 100755 (executable)
index 0000000..f75c832
--- /dev/null
@@ -0,0 +1,132 @@
+// 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
diff --git a/src/wgt/step/security/step_check_extension_privileges.h b/src/wgt/step/security/step_check_extension_privileges.h
new file mode 100755 (executable)
index 0000000..0c27abc
--- /dev/null
@@ -0,0 +1,55 @@
+// 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_
old mode 100644 (file)
new mode 100755 (executable)
index 7abd4e2..ee5f62c
@@ -82,6 +82,7 @@
 #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;
 
@@ -118,6 +119,7 @@ WgtInstaller::WgtInstaller(ci::PkgMgrPtr pkgrmgr)
       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>(
@@ -157,6 +159,7 @@ WgtInstaller::WgtInstaller(ci::PkgMgrPtr pkgrmgr)
       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>(
@@ -202,6 +205,7 @@ WgtInstaller::WgtInstaller(ci::PkgMgrPtr pkgrmgr)
       AddStep<ci::rds::StepRDSParse>();
       AddStep<ci::filesystem::StepUpdateTep>();
       AddStep<wgt::rds::StepWgtRDSModify>();
+      AddStep<wgt::security::StepCheckExtensionPrivileges>();
       AddStep<ci::security::StepUpdateSecurity>();
       break;
     }
@@ -241,6 +245,7 @@ WgtInstaller::WgtInstaller(ci::PkgMgrPtr pkgrmgr)
       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>(
@@ -301,6 +306,7 @@ WgtInstaller::WgtInstaller(ci::PkgMgrPtr pkgrmgr)
       AddStep<ci::pkgmgr::StepRunParserPlugin>(
           ci::Plugin::ActionType::Install);
       AddStep<ci::filesystem::StepCreatePerUserStorageDirectories>();
+      AddStep<wgt::security::StepCheckExtensionPrivileges>();
       AddStep<ci::security::StepRegisterSecurity>();
       break;
     }
@@ -332,6 +338,7 @@ WgtInstaller::WgtInstaller(ci::PkgMgrPtr pkgrmgr)
       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>(