2 * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 * @file task_smack.cpp
18 * @author Piotr Kozbial (p.kozbial@samsung.com)
20 * @brief Implementation file for installer task smack
23 #include <widget_install/task_smack.h>
24 #include <widget_install/task_certify.h>
25 #include <widget_install/widget_install_context.h>
26 #include <widget_install/widget_install_errors.h>
27 #include <dpl/wrt-dao-ro/common_dao_types.h>
28 #include <dpl/foreach.h>
29 #include <dpl/wrt-dao-ro/global_config.h>
30 #include <dpl/wrt-dao-ro/widget_dao_read_only.h>
31 #include <dpl/platform.h>
32 #include <vcore/Certificate.h>
33 #include <vcore/CryptoHash.h>
34 #include <vcore/SignatureFinder.h>
35 #include <privilege-control.h>
36 #include <security-server.h>
37 #include <sys/smack.h>
39 #include <dpl/log/secure_log.h>
40 #include <boost/filesystem.hpp>
42 using namespace WrtDB;
43 using namespace ValidationCore;
45 namespace bf = boost::filesystem;
48 #if USE(UI_GADGET_SMACK_EXCEPTION)
49 const char* smackLabelOriginDB = "wrt::db_origin";
50 const char* securityOriginDB = ".security_origin.db";
51 const char* securityOriginDBJournal = ".security_origin.db-journal";
53 const int MAX_BUF_SIZE = 128;
54 void freeList(const char** list) {
55 for (int i = 0; list[i] != NULL; i++)
64 namespace WidgetInstall {
65 TaskSmack::TaskSmack(JobWidgetInstall * const &jobContext) :
66 DPL::TaskDecl<TaskSmack>(this),
67 m_jobContext(jobContext)
69 AddStep(&TaskSmack::StartStep);
70 AddStep(&TaskSmack::StepSetInstall);
71 AddStep(&TaskSmack::StepSmackAppPrivilegeVersion);
72 AddStep(&TaskSmack::StepSmackFolderLabeling);
73 AddStep(&TaskSmack::StepSmackPrivilege);
74 #if USE(UI_GADGET_SMACK_EXCEPTION)
75 AddStep(&TaskSmack::StepSecurityOriginDB);
77 AddStep(&TaskSmack::EndStep);
79 // Seperate steps to guarantee transaction of smack rule db.
80 // perm_end() API should be called to load newly added rules to memory
81 AddStep(&TaskSmack::StartStep2);
82 AddStep(&TaskSmack::StepAddLabelNPRuntime);
83 AddStep(&TaskSmack::StepLabelSignatureFiles);
84 AddStep(&TaskSmack::EndStep2);
86 AddAbortStep(&TaskSmack::StepAbortSmack);
89 void TaskSmack::StepSetInstall()
91 _D("----------------> SMACK: StepStartSetSmack()");
93 m_pkgId = DPL::ToUTF8String(m_jobContext->m_installerContext.widgetConfig.tzPkgid);
95 if (PC_OPERATION_SUCCESS != perm_app_install(m_pkgId.c_str())) {
96 ThrowMsg(Exceptions::NotAllowed, "Instalation failure. "
97 "failure in creating smack rules file.");
100 /*pkgid should not be same with SMACK label used by system*/
101 if (!m_jobContext->m_installerContext.isUpdateMode) {
102 if (SECURITY_SERVER_API_SUCCESS == security_server_check_domain_name(m_pkgId.c_str())) {
103 _W("Cannot install this pkg[%s] : It has invalid pkg name", m_pkgId.c_str());
104 ThrowMsg(Exceptions::NotAllowed, "Cannot install this packageID. It has invalid packageID");
109 //Note: perm_app_set_privilege_version calling order is important.
110 //perm_app_install->perm_app_set_privilege_version->perm_app_setup_path/perm_app_enable_permissions
111 void TaskSmack::StepSmackAppPrivilegeVersion()
113 _D("----------------> SMACK:\
114 Jobs::WidgetInstall::TaskSmack::StepSmackAppPrivilegeVersion()");
116 DPL::OptionalString minVersion = m_jobContext->m_installerContext.widgetConfig.configInfo.tizenMinVersionRequired;
118 if (!minVersion || minVersion->empty()) {
119 _W("setting app privilege version - default");
122 version = DPL::ToUTF8String(*minVersion);
125 if (PC_OPERATION_SUCCESS != perm_app_set_privilege_version(m_pkgId.c_str(),
127 _W("failure in setting app privilege version for version %s", version.c_str());
128 ThrowMsg(Exceptions::NotAllowed, "Failure in setting app privilege version.");
130 _D("Success in setting app privilege version for version %s", version.c_str());
134 void TaskSmack::StepSmackFolderLabeling()
136 _D("----------------> SMACK:\
137 Jobs::WidgetInstall::TaskSmack::SmackFolderLabelingStep()");
139 /* /opt/usr/apps/[pkgid] directory's label is "_" */
140 if (PC_OPERATION_SUCCESS != perm_app_setup_path(m_pkgId.c_str(),
141 m_jobContext->m_installerContext.locations->getPackageInstallationDir().c_str(),
142 APP_PATH_ANY_LABEL, "_")) {
143 _W("Add label to %s", m_jobContext->m_installerContext.locations->getPackageInstallationDir().c_str());
147 if (m_jobContext->m_installerContext.mode.installTime == InstallMode::InstallTime::PRELOAD) {
148 if (PC_OPERATION_SUCCESS != perm_app_setup_path(m_pkgId.c_str(),
149 m_jobContext->m_installerContext.locations->getUserDataRootDir().c_str(),
150 APP_PATH_ANY_LABEL, "_")) {
154 /* .mmc directory for sdcard /opt/usr/apps/[pkgId]/.mmc */
155 if (m_jobContext->m_installerContext.locationType == INSTALL_LOCATION_TYPE_PREFER_EXTERNAL) {
156 std::string mmcDir = m_jobContext->m_installerContext.locations->getPackageInstallationDir() + "/.mmc";
157 if (PC_OPERATION_SUCCESS != perm_app_setup_path(m_pkgId.c_str(), mmcDir.c_str(), APP_PATH_PRIVATE)) {
158 _W("Add label to %s", mmcDir.c_str());
163 std::string resDir = m_jobContext->m_installerContext.locations->getPackageInstallationDir() +
166 if (PC_OPERATION_SUCCESS != perm_app_setup_path(m_pkgId.c_str(), resDir.c_str(),
168 _W("Add label to %s", resDir.c_str());
172 if (PC_OPERATION_SUCCESS != perm_app_setup_path(m_pkgId.c_str(),
173 m_jobContext->m_installerContext.locations->getPrivateStorageDir().c_str(),
175 _W("Add label to %s", m_jobContext->m_installerContext.locations->getPrivateStorageDir().c_str());
179 if (PC_OPERATION_SUCCESS != perm_app_setup_path(m_pkgId.c_str(),
180 m_jobContext->m_installerContext.locations->getPrivateTempStorageDir().c_str(),
183 _W("Add label to %s", m_jobContext->m_installerContext.locations->getPrivateTempStorageDir().c_str());
187 if( m_jobContext->m_installerContext.widgetConfig.packagingType != PKG_TYPE_HYBRID_WEB_APP){
188 if (PC_OPERATION_SUCCESS != perm_app_setup_path(m_pkgId.c_str(),
189 m_jobContext->m_installerContext.locations->getBinaryDir().c_str(),
191 _W("Add label to %s", m_jobContext->m_installerContext.locations->getBinaryDir().c_str());
195 std::string native_label = m_pkgId + ".native";
196 if (PC_OPERATION_SUCCESS != perm_app_setup_path(m_pkgId.c_str(),
197 m_jobContext->m_installerContext.locations->getBinaryDir().c_str(),
198 APP_PATH_ANY_LABEL, native_label.c_str())) {
199 _W("Failed to Add label to %s", m_jobContext->m_installerContext.locations->getBinaryDir().c_str());
202 if (PC_OPERATION_SUCCESS != perm_app_setup_path(m_pkgId.c_str(),
203 m_jobContext->m_installerContext.locations->getExecFile().c_str(),
205 _W("Failed to Add label to %s", m_jobContext->m_installerContext.locations->getExecFile().c_str());
207 #ifdef SERVICE_ENABLED
209 FOREACH(it, m_jobContext->m_installerContext.widgetConfig.configInfo.serviceAppInfoList) {
210 std::string serviceExec = m_jobContext->m_installerContext.locations->getBinaryDir() + "/" + DPL::ToUTF8String(it->serviceId);
211 if (PC_OPERATION_SUCCESS != perm_app_setup_path(m_pkgId.c_str(), serviceExec.c_str(), APP_PATH_PRIVATE)) {
212 _W("Failed to Add label to %s", serviceExec.c_str());
216 #if USE(WEB_PROVIDER)
217 ConfigParserData::LiveboxList& liveboxList = m_jobContext->m_installerContext.widgetConfig.configInfo.m_livebox;
218 if (!liveboxList.empty()) {
219 std::string dBoxExec = m_jobContext->m_installerContext.locations->getExecFile() + ".d-box";
220 if (PC_OPERATION_SUCCESS != perm_app_setup_path(m_pkgId.c_str(), dBoxExec.c_str(), APP_PATH_PRIVATE)) {
221 _W("Failed to Add label to %s", dBoxExec.c_str());
227 if(!setLabelForSharedDir(m_pkgId.c_str())) {
228 _W("Add label to shared directory");
231 /* TODO : set label at wrt-client */
234 void TaskSmack::StepSmackPrivilege()
236 _D("----------------> SMACK:\
237 Jobs::WidgetInstall::TaskSmack::SmackPrivilegeStep()");
239 app_type_t app_type = PERM_APP_TYPE_WRT;
240 switch(m_jobContext->m_installerContext.certLevel) {
241 case Jobs::WidgetInstall::TaskCertify::Level::PLATFORM:
242 app_type = PERM_APP_TYPE_WRT_PLATFORM;
244 case Jobs::WidgetInstall::TaskCertify::Level::PARTNER:
245 app_type = PERM_APP_TYPE_WRT_PARTNER;
249 std::string id = DPL::ToUTF8String(m_jobContext->m_installerContext.widgetConfig.tzPkgid);
251 appId = (char*)calloc(1, id.length() + 1);
253 ThrowMsg(Exceptions::NotAllowed, "Failure in calloc");
255 snprintf(appId, id.length() + 1, "%s", id.c_str());
257 WrtDB::ConfigParserData::PrivilegeList privileges =
258 m_jobContext->m_installerContext.widgetConfig.configInfo.privilegeList;
260 char** perm_list = new char*[privileges.size() + 1];
262 FOREACH(it, privileges) {
263 _D("Permission : %ls", it->name.c_str());
264 int length = DPL::ToUTF8String(it->name).length();
265 char *priv = new char[length + 1];
266 snprintf(priv, length + 1, "%s",
267 DPL::ToUTF8String(it->name).c_str());
268 perm_list[index++] = priv;
270 perm_list[index] = NULL;
272 if (PC_OPERATION_SUCCESS != perm_app_enable_permissions(appId, app_type,
273 const_cast<const char **>(perm_list), true)) {
274 _W("failure in contructing smack rules based on perm_list");
277 /* apply privilege for debug_mode */
278 const char *perm_debug[] = {"http://tizen.org/privilege/appdebugging", NULL};
279 if (m_jobContext->m_installerContext.mode.command == InstallMode::Command::DEBUGINSTALL) {
280 if (PC_OPERATION_SUCCESS != perm_app_enable_permissions(appId, app_type, perm_debug, true)) {
281 _W("failure in contructing smack rules based on debug_mode privilege");
283 _D("privilege succeeded for debug_mode.");
289 while (NULL != perm_list[index]) {
290 delete [] perm_list[index++];
294 m_jobContext->UpdateProgress(
295 InstallerContext::INSTALL_SMACK_ENABLE,
296 "Widget SMACK Enabled");
299 void TaskSmack::StepAddLabelNPRuntime()
301 _D("----------------> SMACK:\
302 Jobs::WidgetInstall::TaskSmack::StepAddLabelNPRuntime()");
304 if (0 == access(m_jobContext->m_installerContext.locations->getNPPluginsDir().c_str(), F_OK)) {
305 if (PC_OPERATION_SUCCESS !=
306 perm_app_setup_path(DPL::ToUTF8String(m_jobContext->m_installerContext.widgetConfig.tzPkgid).c_str(),
307 m_jobContext->m_installerContext.locations->getNPPluginsExecFile().c_str(),
308 PERM_APP_PATH_NPRUNTIME)) {
309 _E("failed to set smack execute label to %s",
310 m_jobContext->m_installerContext.locations->getNPPluginsExecFile().c_str());
316 void TaskSmack::StepLabelSignatureFiles()
318 _D("----------------> SMACK:\
319 Jobs::WidgetInstall::TaskSmack::StepLabelSignatureFiles()");
321 bf::path widgetPath(m_jobContext->m_installerContext.locations->getPackageInstallationDir());
322 widgetPath /= WrtDB::GlobalConfig::GetWidgetSrcPath();
324 SignatureFileInfoSet signatureFiles;
325 SignatureFinder signatureFinder(widgetPath.string());
326 if (SignatureFinder::NO_ERROR != signatureFinder.find(signatureFiles)) {
327 ThrowMsg(Exceptions::SignatureNotFound,
328 "Error while discovering signature files.");
331 for (auto it = signatureFiles.cbegin(); it != signatureFiles.cend(); ++it) {
332 auto sigPath = widgetPath / it->getFileName();
334 _D("Setting label to %s", sigPath.c_str());
335 if (PC_OPERATION_SUCCESS != perm_app_setup_path(m_pkgId.c_str(),
337 APP_PATH_ANY_LABEL, "_")) {
338 _W("Failed to set label to %s", sigPath.c_str());
343 #if USE(UI_GADGET_SMACK_EXCEPTION)
344 void TaskSmack::StepSecurityOriginDB()
346 _D("----------------> SMACK:\
347 Jobs::WidgetInstall::TaskSmack::StepSecurityOriginDB()");
348 /* security Origin DB Path */
349 bf::path securityOriginDBPath(m_jobContext->m_installerContext.locations->getPrivateStorageDir());
350 securityOriginDBPath /= securityOriginDB;
352 if (PC_OPERATION_SUCCESS != perm_app_setup_path(m_pkgId.c_str(),
353 securityOriginDBPath.c_str(),
354 APP_PATH_ANY_LABEL,smackLabelOriginDB)) {
355 _W("Add label to %s", securityOriginDBPath.c_str());
358 bf::path securityOriginDBJournalPath(m_jobContext->m_installerContext.locations->getPrivateStorageDir());
359 securityOriginDBJournalPath /= securityOriginDBJournal;
361 if (PC_OPERATION_SUCCESS != perm_app_setup_path(m_pkgId.c_str(),
362 securityOriginDBJournalPath.c_str(),
363 APP_PATH_ANY_LABEL,smackLabelOriginDB)) {
364 _W("Add label to %s", securityOriginDBJournalPath.c_str());
369 void TaskSmack::StepRevokeForUpdate()
371 _D("----------------> SMACK:\
372 Jobs::WidgetInstall::TaskSmack::StepRevokePrivilegeForUpdate()");
374 if (PC_OPERATION_SUCCESS != perm_app_revoke_permissions(m_pkgId.c_str())) {
375 _W("failure in revoking smack permissions");
379 void TaskSmack::StepAbortSmack()
381 _D("----------------> SMACK:\
382 Jobs::WidgetInstall::TaskSmack::StepAbortSmack()");
384 if (PC_OPERATION_SUCCESS != perm_app_revoke_permissions(m_pkgId.c_str())) {
385 _W("failure in revoking smack permissions");
388 if (PC_OPERATION_SUCCESS != perm_app_uninstall(m_pkgId.c_str())) {
389 _W("failure in removing smack rules file");
393 bool TaskSmack::setLabelForSharedDir(const char* pkgId)
395 /* /shared directory */
396 if (PC_OPERATION_SUCCESS != perm_app_setup_path(pkgId,
397 m_jobContext->m_installerContext.locations->getSharedRootDir().c_str(),
398 APP_PATH_ANY_LABEL, "_")) {
399 _W("Add label to %s", m_jobContext->m_installerContext.locations->getUserDataRootDir().c_str());
402 /* /shared/res directory */
403 if (PC_OPERATION_SUCCESS != perm_app_setup_path(pkgId,
404 m_jobContext->m_installerContext.locations->getSharedResourceDir().c_str(),
405 APP_PATH_ANY_LABEL, "_")) {
406 _W("Add label to %s", m_jobContext->m_installerContext.locations->getSharedResourceDir().c_str());
409 /* /shared/trusted directory */
410 CertificatePtr rootCert = m_jobContext->m_installerContext.widgetSecurity.getAuthorCertificatePtr();
412 ValidationCore::Crypto::Hash::SHA1 sha1;
414 /* ValidationCore::Crypto::Hash throws non-dpl namespace exception
415 * to remove dpl dependency of cert-svc
417 * [changed] Validation::Crypto::Hash can throws
418 * - ValidationCore::Crypto::Hash::OutOfSequence
419 * - ValidationCore::Crypto::Hash::AppendFailed
421 * [from] Validation::Crypto::Hash could throws
422 * - DPL::Exception::OutOfSequence
423 * - DPL::Exception::AppendFailed
425 sha1.Append(rootCert->getDER());
427 std::string sha1String = sha1.ToBase64String();
428 size_t iPos = sha1String.find("/");
429 while(iPos < std::string::npos) {
430 sha1String.replace(iPos, 1, "#");
431 iPos = sha1String.find("/");
434 _D("sha1 label string : %s", sha1String.c_str());
436 if (PC_OPERATION_SUCCESS != perm_app_setup_path(pkgId,
437 m_jobContext->m_installerContext.locations->getSharedTrustedDir().c_str(),
438 APP_PATH_GROUP_RW, sha1String.c_str())) {
439 _W("Add label to %s", m_jobContext->m_installerContext.locations->getBinaryDir().c_str());
443 /* /shared/data directory */
444 if (PC_OPERATION_SUCCESS != perm_app_setup_path(pkgId,
445 m_jobContext->m_installerContext.locations->getSharedDataDir().c_str(),
446 APP_PATH_PUBLIC_RO)) {
447 _W("Add label to %s", m_jobContext->m_installerContext.locations->getSharedDataDir().c_str());
453 void TaskSmack::StartStep()
455 LOGI("--------- <TaskSmack> : START ----------");
456 if (PC_OPERATION_SUCCESS != perm_begin()) {
457 LOGE("Failed to smack transaction begin.");
458 ThrowMsg(Exceptions::SmackTransactionFailed, "Failed to smack transaction begin");
462 void TaskSmack::EndStep()
464 LOGI("--------- <TaskSmack> : END ----------");
465 if (PC_OPERATION_SUCCESS != perm_end()) {
466 LOGE("Failed to smack transaction end.");
467 ThrowMsg(Exceptions::SmackTransactionFailed, "Failed to smack transaction end");
471 void TaskSmack::StartStep2()
473 LOGI("--------- <TaskSmack> : START2 ----------");
474 if (PC_OPERATION_SUCCESS != perm_begin()) {
475 LOGE("Failed to smack transaction begin.");
476 ThrowMsg(Exceptions::SmackTransactionFailed, "Failed to smack transaction begin");
480 void TaskSmack::EndStep2()
482 LOGI("--------- <TaskSmack> : END2 ----------");
483 if (PC_OPERATION_SUCCESS != perm_end()) {
484 LOGE("Failed to smack transaction end.");
485 ThrowMsg(Exceptions::SmackTransactionFailed, "Failed to smack transaction end");
489 } //namespace WidgetInstall