4433ef16f695b47e4575f6ce7fd3e746b8e7357c
[platform/core/security/cynara.git] / src / common / plugin / PluginManager.cpp
1 /*
2  * Copyright (c) 2014-2015 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        src/common/plugin/PluginManager.cpp
18  * @author      Zofia Abramowska <z.abramowska@samsung.com>
19  * @author      Lukasz Wojciechowski <l.wojciechow@partner.samsung.com>
20  * @version     1.0
21  * @brief       Definition of PluginManager class
22  */
23
24 #define _BSD_SOURCE_
25
26 #include <cinttypes>
27 #include <cstdlib>
28 #include <cstring>
29 #include <dirent.h>
30 #include <dlfcn.h>
31 #include <functional>
32
33 #include <exceptions/UnknownPolicyTypeException.h>
34 #include <log/log.h>
35
36 #include "PluginManager.h"
37
38
39 namespace {
40     int pluginFilter(const struct dirent *ent) {
41 #ifdef _DIRENT_HAVE_D_TYPE
42         if (ent->d_type != DT_REG) {
43             return 0;
44         }
45 #endif
46         if (ent->d_name[0] == '.') {
47             return 0;
48         }
49         return 1;
50     }
51 }
52
53 namespace Cynara {
54
55 PluginManager::PluginManager(const std::string &pluginDir) : m_dir(pluginDir) {
56 }
57
58 PluginManager::~PluginManager(void) {
59     // We have to be sure, that external objects will be destroyed
60     // before handles to libraries are closed.
61     for (auto &plugin : m_plugins) {
62         plugin.second.reset();
63     }
64 }
65
66 ExternalPluginPtr PluginManager::getPlugin(PolicyType pType) {
67     return m_plugins[pType];
68 }
69
70 std::vector<PolicyDescription> PluginManager::getPolicyDescriptions(void) const {
71     std::vector<PolicyDescription> descriptions;
72     descriptions.reserve(m_plugins.size());
73     for (auto &plugin : m_plugins) {
74         descriptions.push_back(plugin.first);
75     }
76     return descriptions;
77 }
78
79 void PluginManager::invalidateAll(void) {
80     for (auto &plugin : m_plugins) {
81         plugin.second->invalidate();
82     }
83 }
84
85 void PluginManager::checkPolicyType(PolicyType pType) const {
86     const auto it = m_plugins.find(pType);
87     if (it == m_plugins.end() || it->second == nullptr)
88         throw UnknownPolicyTypeException(pType);
89 }
90
91 void PluginManager::loadPlugins(void) {
92     struct dirent **nameList = NULL;
93     int fileAmount = scandir(m_dir.c_str(), &nameList, pluginFilter, alphasort);
94
95     if (fileAmount < 0) {
96         auto error = strerror(errno);
97         LOGE("Couldn't scan for plugins in <%s> : <%s>", m_dir.c_str(), error);
98         return;
99     }
100
101     std::unique_ptr<dirent*, std::function<void(dirent**)>> direntPtr(nameList,
102             [fileAmount](dirent** dirs) {
103                 for (int i = 0; i < fileAmount; i++) {
104                     free(dirs[i]);
105                 }
106                 free(dirs);
107             });
108     for (int i = 0; i < fileAmount; i++) {
109         openPlugin(m_dir + nameList[i]->d_name);
110     }
111 }
112
113 void PluginManager::openPlugin(const std::string &path) {
114     LOGD("Loading plugin: <%s>", path.c_str());
115
116     void *handle = dlopen(path.c_str(), RTLD_LAZY);
117
118     if (!handle) {
119         LOGW("File could not be dlopened <%s> : <%s>", path.c_str(), dlerror());
120         return;
121     }
122     PluginLibPtr handlePtr(handle, std::ptr_fun(dlclose));
123
124     //Flush any previous errors
125     dlerror();
126     create_t creator = reinterpret_cast<create_t>(dlsym(handle, "create"));
127
128     char *error;
129     if ((error = dlerror()) != NULL) {
130         LOGE("Couldn't resolve symbol <create> from lib <%s> : <%s>", path.c_str(), error);
131         return;
132     }
133
134     destroy_t destroyer = reinterpret_cast<destroy_t>(dlsym(handle, "destroy"));
135     if ((error = dlerror()) != NULL) {
136         LOGE("Couldn't resolve symbol <destroy> from lib <%s> : <%s>", path.c_str(), error);
137         return;
138     }
139
140     ExternalPluginPtr pluginPtr(creator(), destroyer);
141
142     if (!pluginPtr) {
143         LOGE("Couldn't create plugin for <%s>", path.c_str());
144         return;
145     }
146
147     auto policies = pluginPtr->getSupportedPolicyDescr();
148     if (policies.empty()) {
149         LOGE("Plugin <%s> does not support any type!", path.c_str());
150         return;
151     }
152     for (auto &desc : policies) {
153         if (!m_plugins.insert(std::make_pair(desc, pluginPtr)).second) {
154             LOGW("Policy: type [%" PRIu16 "] name <%s> was already supported.",
155                  desc.type, desc.name.c_str());
156         } else {
157             LOGD("Supported policy: type [%" PRIu16 "] name <%s>", desc.type, desc.name.c_str());
158         }
159     }
160
161     m_pluginLibs.push_back(std::move(handlePtr));
162 }
163
164 } // namespace Cynara
165