tizen 2.4 release
[framework/web/wrt-installer.git] / src / jobs / widget_install / task_smack.cpp
1 /*
2  * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved
3  *
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
7  *
8  *        http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16 /*
17  * @file    task_smack.cpp
18  * @author  Piotr Kozbial (p.kozbial@samsung.com)
19  * @version 1.0
20  * @brief   Implementation file for installer task smack
21  */
22
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>
38 #include <sstream>
39 #include <dpl/log/secure_log.h>
40 #include <boost/filesystem.hpp>
41
42 using namespace WrtDB;
43 using namespace ValidationCore;
44
45 namespace bf = boost::filesystem;
46
47 namespace {
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";
52 #endif
53 const int MAX_BUF_SIZE = 128;
54 void freeList(const char** list) {
55     for (int i = 0; list[i] != NULL; i++)
56     {
57         delete(list[i]);
58     }
59     delete[] list;
60 }
61 }
62
63 namespace Jobs {
64 namespace WidgetInstall {
65 TaskSmack::TaskSmack(JobWidgetInstall * const &jobContext) :
66     DPL::TaskDecl<TaskSmack>(this),
67     m_jobContext(jobContext)
68 {
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);
76 #endif
77     AddStep(&TaskSmack::EndStep);
78
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);
85
86     AddAbortStep(&TaskSmack::StepAbortSmack);
87 }
88
89 void TaskSmack::StepSetInstall()
90 {
91     _D("----------------> SMACK: StepStartSetSmack()");
92
93     m_pkgId = DPL::ToUTF8String(m_jobContext->m_installerContext.widgetConfig.tzPkgid);
94
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.");
98     }
99
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");
105         }
106     }
107 }
108
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()
112 {
113     _D("----------------> SMACK:\
114             Jobs::WidgetInstall::TaskSmack::StepSmackAppPrivilegeVersion()");
115
116     DPL::OptionalString minVersion = m_jobContext->m_installerContext.widgetConfig.configInfo.tizenMinVersionRequired;
117     std::string version;
118     if (!minVersion || minVersion->empty()) {
119         _W("setting app privilege version - default");
120         return;
121     } else {
122         version = DPL::ToUTF8String(*minVersion);
123     }
124
125     if (PC_OPERATION_SUCCESS != perm_app_set_privilege_version(m_pkgId.c_str(),
126         version.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.");
129     } else {
130         _D("Success in setting app privilege version for version %s", version.c_str());
131     }
132 }
133
134 void TaskSmack::StepSmackFolderLabeling()
135 {
136     _D("----------------> SMACK:\
137             Jobs::WidgetInstall::TaskSmack::SmackFolderLabelingStep()");
138
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());
144     }
145
146     /* for prelaod */
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, "_")) {
151         }
152     }
153
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());
159         }
160     }
161
162     /* res directory */
163     std::string resDir = m_jobContext->m_installerContext.locations->getPackageInstallationDir() +
164         "/res";
165
166     if (PC_OPERATION_SUCCESS != perm_app_setup_path(m_pkgId.c_str(), resDir.c_str(),
167                 APP_PATH_PRIVATE)) {
168         _W("Add label to %s", resDir.c_str());
169     }
170
171     /* data directory */
172     if (PC_OPERATION_SUCCESS != perm_app_setup_path(m_pkgId.c_str(),
173                 m_jobContext->m_installerContext.locations->getPrivateStorageDir().c_str(),
174                 APP_PATH_PRIVATE)) {
175         _W("Add label to %s", m_jobContext->m_installerContext.locations->getPrivateStorageDir().c_str());
176     }
177
178     /* tmp directory */
179     if (PC_OPERATION_SUCCESS != perm_app_setup_path(m_pkgId.c_str(),
180                 m_jobContext->m_installerContext.locations->getPrivateTempStorageDir().c_str(),
181                 APP_PATH_PRIVATE))
182     {
183         _W("Add label to %s", m_jobContext->m_installerContext.locations->getPrivateTempStorageDir().c_str());
184     }
185
186     /* bin directory */
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(),
190                     APP_PATH_PRIVATE)) {
191            _W("Add label to %s", m_jobContext->m_installerContext.locations->getBinaryDir().c_str());
192         }
193     } else {
194         // for hybrid webapp
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());
200         }
201         // webapp executable
202         if (PC_OPERATION_SUCCESS != perm_app_setup_path(m_pkgId.c_str(),
203                 m_jobContext->m_installerContext.locations->getExecFile().c_str(),
204                 APP_PATH_PRIVATE)) {
205            _W("Failed to Add label to %s", m_jobContext->m_installerContext.locations->getExecFile().c_str());
206         }
207 #ifdef SERVICE_ENABLED
208         // Service app
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());
213             }
214         }
215 #endif
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());
222             }
223         }
224 #endif
225     }
226
227     if(!setLabelForSharedDir(m_pkgId.c_str())) {
228         _W("Add label to shared directory");
229     }
230
231     /* TODO : set label at wrt-client */
232 }
233
234 void TaskSmack::StepSmackPrivilege()
235 {
236     _D("----------------> SMACK:\
237         Jobs::WidgetInstall::TaskSmack::SmackPrivilegeStep()");
238
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;
243             break;
244         case Jobs::WidgetInstall::TaskCertify::Level::PARTNER:
245             app_type = PERM_APP_TYPE_WRT_PARTNER;
246             break;
247     }
248
249     std::string id = DPL::ToUTF8String(m_jobContext->m_installerContext.widgetConfig.tzPkgid);
250     char* appId = NULL;
251     appId = (char*)calloc(1, id.length() + 1);
252     if (appId == NULL) {
253         ThrowMsg(Exceptions::NotAllowed, "Failure in calloc");
254     }
255     snprintf(appId, id.length() + 1, "%s", id.c_str());
256
257     WrtDB::ConfigParserData::PrivilegeList privileges =
258         m_jobContext->m_installerContext.widgetConfig.configInfo.privilegeList;
259
260     char** perm_list = new char*[privileges.size() + 1];
261     int index = 0;
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;
269     }
270     perm_list[index] = NULL;
271
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");
275     }
276
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");
282         } else {
283             _D("privilege succeeded for debug_mode.");
284         }
285     }
286
287     free(appId);
288     index = 0;
289     while (NULL != perm_list[index]) {
290         delete [] perm_list[index++];
291     }
292     delete [] perm_list;
293
294     m_jobContext->UpdateProgress(
295         InstallerContext::INSTALL_SMACK_ENABLE,
296         "Widget SMACK Enabled");
297 }
298
299 void TaskSmack::StepAddLabelNPRuntime()
300 {
301     _D("----------------> SMACK:\
302             Jobs::WidgetInstall::TaskSmack::StepAddLabelNPRuntime()");
303
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());
311         }
312     }
313 }
314
315
316 void TaskSmack::StepLabelSignatureFiles()
317 {
318     _D("----------------> SMACK:\
319             Jobs::WidgetInstall::TaskSmack::StepLabelSignatureFiles()");
320
321     bf::path widgetPath(m_jobContext->m_installerContext.locations->getPackageInstallationDir());
322     widgetPath /= WrtDB::GlobalConfig::GetWidgetSrcPath();
323
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.");
329     }
330
331     for (auto it = signatureFiles.cbegin(); it != signatureFiles.cend(); ++it) {
332         auto sigPath = widgetPath / it->getFileName();
333
334         _D("Setting label to %s", sigPath.c_str());
335         if (PC_OPERATION_SUCCESS != perm_app_setup_path(m_pkgId.c_str(),
336                     sigPath.c_str(),
337                     APP_PATH_ANY_LABEL, "_")) {
338             _W("Failed to set label to %s", sigPath.c_str());
339         }
340     }
341 }
342
343 #if USE(UI_GADGET_SMACK_EXCEPTION)
344 void TaskSmack::StepSecurityOriginDB()
345 {
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;
351
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());
356     }
357
358     bf::path securityOriginDBJournalPath(m_jobContext->m_installerContext.locations->getPrivateStorageDir());
359     securityOriginDBJournalPath /= securityOriginDBJournal;
360
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());
365     }
366 }
367 #endif
368
369 void TaskSmack::StepRevokeForUpdate()
370 {
371     _D("----------------> SMACK:\
372         Jobs::WidgetInstall::TaskSmack::StepRevokePrivilegeForUpdate()");
373
374     if (PC_OPERATION_SUCCESS != perm_app_revoke_permissions(m_pkgId.c_str())) {
375         _W("failure in revoking smack permissions");
376     }
377 }
378
379 void TaskSmack::StepAbortSmack()
380 {
381     _D("----------------> SMACK:\
382             Jobs::WidgetInstall::TaskSmack::StepAbortSmack()");
383
384     if (PC_OPERATION_SUCCESS != perm_app_revoke_permissions(m_pkgId.c_str())) {
385         _W("failure in revoking smack permissions");
386     }
387
388     if (PC_OPERATION_SUCCESS != perm_app_uninstall(m_pkgId.c_str())) {
389         _W("failure in removing smack rules file");
390     }
391 }
392
393 bool TaskSmack::setLabelForSharedDir(const char* pkgId)
394 {
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());
400     }
401
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());
407     }
408
409     /* /shared/trusted directory */
410     CertificatePtr rootCert = m_jobContext->m_installerContext.widgetSecurity.getAuthorCertificatePtr();
411     if (!!rootCert) {
412         ValidationCore::Crypto::Hash::SHA1 sha1;
413
414         /*  ValidationCore::Crypto::Hash throws non-dpl namespace exception
415          *  to remove dpl dependency of cert-svc
416          *
417          *  [changed] Validation::Crypto::Hash can throws
418          *  - ValidationCore::Crypto::Hash::OutOfSequence
419          *  - ValidationCore::Crypto::Hash::AppendFailed
420          *
421          *  [from]    Validation::Crypto::Hash could throws
422          *  - DPL::Exception::OutOfSequence
423          *  - DPL::Exception::AppendFailed
424          */
425         sha1.Append(rootCert->getDER());
426         sha1.Finish();
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("/");
432         }
433
434         _D("sha1 label string : %s", sha1String.c_str());
435
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());
440         }
441     }
442
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());
448     }
449
450     return true;
451 }
452
453 void TaskSmack::StartStep()
454 {
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");
459     }
460 }
461
462 void TaskSmack::EndStep()
463 {
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");
468     }
469 }
470
471 void TaskSmack::StartStep2()
472 {
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");
477     }
478 }
479
480 void TaskSmack::EndStep2()
481 {
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");
486     }
487 }
488
489 } //namespace WidgetInstall
490 } //namespace Jobs