Line data Source code
1 : /*
2 : *
3 : *
4 : * Distributed under the OpenDDS License.
5 : * See: http://www.opendds.org/license.html
6 : */
7 :
8 : #include "DCPS/DdsDcps_pch.h"
9 :
10 : #include "SecurityRegistry.h"
11 :
12 : #include "SecurityConfig.h"
13 :
14 : #include <dds/DCPS/transport/framework/EntryExit.h>
15 : #include <dds/DCPS/Util.h>
16 : #include <dds/DCPS/Service_Participant.h>
17 : #include <dds/DCPS/EntityImpl.h>
18 : #include <dds/DCPS/ConfigUtils.h>
19 : #include <dds/DCPS/SafetyProfileStreams.h>
20 : #include <dds/DCPS/DomainParticipantImpl.h>
21 :
22 : #include <ace/Singleton.h>
23 : #include <ace/OS_NS_strings.h>
24 : #include <ace/Service_Config.h>
25 :
26 : OPENDDS_BEGIN_VERSIONED_NAMESPACE_DECL
27 :
28 : namespace OpenDDS {
29 : namespace Security {
30 :
31 : const char* SecurityRegistry::DEFAULT_CONFIG_NAME = "_OPENDDS_DEFAULT_CONFIG";
32 : const char* SecurityRegistry::BUILTIN_CONFIG_NAME = "_OPENDDS_BUILTIN_CONFIG";
33 : const char* SecurityRegistry::DEFAULT_INST_PREFIX = "_OPENDDS_";
34 : const char* SecurityRegistry::DEFAULT_PLUGIN_NAME = "BuiltIn";
35 : const char* SecurityRegistry::SECURITY_SECTION_NAME = "security";
36 : const char* SecurityRegistry::ACCESS_CTRL_PLUGIN_NAME = "access_ctrl_plugin";
37 : const char* SecurityRegistry::AUTHENTICATION_PLUGIN_NAME = "auth_plugin";
38 : const char* SecurityRegistry::CRYPTO_PLUGIN_NAME = "crypto_plugin";
39 :
40 :
41 0 : SecurityRegistry::SecurityConfigEntry::SecurityConfigEntry(const OPENDDS_STRING& entryName)
42 0 : : entry_name_(entryName)
43 0 : , auth_name_(DEFAULT_PLUGIN_NAME)
44 0 : , access_ctrl_name_(DEFAULT_PLUGIN_NAME)
45 0 : , crypto_name_(DEFAULT_PLUGIN_NAME)
46 : {
47 0 : }
48 :
49 0 : SecurityRegistry::~SecurityRegistry()
50 : {
51 : DBG_ENTRY_LVL("SecurityRegistry", "~SecurityRegistry", 6);
52 0 : release();
53 0 : }
54 :
55 0 : SecurityRegistry::SecurityConfigEntry::~SecurityConfigEntry()
56 : {
57 0 : }
58 :
59 : void
60 0 : SecurityRegistry::SecurityConfigEntry::add_property(const OPENDDS_STRING& name, const OPENDDS_STRING& value)
61 : {
62 : // Move these up
63 : //static const char* AUTH_CONFIG_PROP_NAME = "auth_config";
64 : //static const char* ACCESS_CTRL_CONFIG_PROP_NAME = "access_ctrl_config";
65 : //static const char* CRYPTO_CONFIG_PROP_NAME = "crypto_config";
66 :
67 : // Config properties can either identity a specific plugin, or
68 : // a configuration property for the security plugins
69 : // TODO - External plugins are not enable yet
70 : //if (0 == name.compare(AUTH_CONFIG_PROP_NAME)) {
71 : // auth_config_name_ = name;
72 : //} else if (0 == name.compare(ACCESS_CTRL_CONFIG_PROP_NAME)) {
73 : // access_ctrl_name_ = name;
74 : //} else if (0 == name.compare(CRYPTO_CONFIG_PROP_NAME)) {
75 : // crypto_name_ = name;
76 : //} else {
77 0 : properties_.push_back(std::make_pair(name, value));
78 : //}
79 0 : }
80 :
81 :
82 : SecurityRegistry*
83 0 : SecurityRegistry::instance()
84 : {
85 0 : return ACE_Unmanaged_Singleton<SecurityRegistry, ACE_Recursive_Thread_Mutex>::instance();
86 : }
87 :
88 : void
89 9 : SecurityRegistry::close()
90 : {
91 9 : ACE_Unmanaged_Singleton<SecurityRegistry, ACE_Recursive_Thread_Mutex>::close();
92 9 : }
93 :
94 0 : SecurityRegistry::SecurityRegistry()
95 : {
96 : DBG_ENTRY_LVL("SecurityRegistry", "SecurityRegistry", 6);
97 0 : lib_directive_map_[DEFAULT_PLUGIN_NAME] = "dynamic OpenDDS_Security Service_Object * OpenDDS_Security:_make_BuiltInPluginLoader()";
98 0 : }
99 :
100 : void
101 0 : SecurityRegistry::release()
102 : {
103 : DBG_ENTRY_LVL("SecurityRegistry", "release", 6);
104 0 : GuardType guard(lock_);
105 :
106 0 : for (InstMap::iterator iter = registered_plugins_.begin(); iter != registered_plugins_.end(); ++iter) {
107 0 : iter->second->shutdown();
108 : }
109 0 : registered_plugins_.clear();
110 0 : config_map_.clear();
111 0 : }
112 :
113 : void
114 0 : SecurityRegistry::register_plugin(const OPENDDS_STRING& plugin_name,
115 : SecurityPluginInst_rch plugin)
116 : {
117 0 : GuardType guard(lock_);
118 :
119 0 : if (registered_plugins_.find(plugin_name) != registered_plugins_.end()) {
120 0 : ACE_ERROR((LM_ERROR,
121 : ACE_TEXT("(%P|%t) SecurityRegistry::register_plugin: ")
122 : ACE_TEXT("plugin=%C already exists.\n"),
123 : plugin_name.c_str()));
124 : } else {
125 0 : registered_plugins_.insert(std::make_pair(plugin_name, plugin));
126 : }
127 0 : }
128 :
129 : SecurityConfig_rch
130 0 : SecurityRegistry::create_config(const OPENDDS_STRING& config_name)
131 : {
132 : // If the configuration instance already exists, then it can be reused.
133 : // Otherwise create a new one and save it for any later needs
134 0 : SecurityConfig_rch existing_config;
135 0 : if (find_config(config_name, existing_config)) {
136 0 : return existing_config;
137 : }
138 :
139 : // This is making an assumption that the entry map is only written
140 : // to in single-threaded operation, and all acess from that point on
141 : // is read-only
142 0 : ConfigEntryMap::const_iterator iEntry = config_entries_.find(config_name);
143 0 : if (iEntry == config_entries_.end()) {
144 0 : ACE_ERROR((LM_ERROR,
145 : ACE_TEXT("(%P|%t) SecurityRegistry::create_config: ")
146 : ACE_TEXT("config=%C does not exist.\n"),
147 : config_name.c_str()));
148 0 : return SecurityConfig_rch();
149 : }
150 :
151 : // This will load any libraries that need to be loaded, and use the
152 : // resulting plugin instance objects to create the concrete implementations
153 0 : const SecurityConfigEntry_rch& entry = iEntry->second;
154 0 : SecurityPluginInst_rch auth_plugin_inst = get_plugin_inst(entry->get_auth_name());
155 0 : if (auth_plugin_inst.is_nil()) {
156 0 : ACE_ERROR((LM_ERROR,
157 : ACE_TEXT("(%P|%t) SecurityRegistry::create_config: ")
158 : ACE_TEXT("Failed to load authentication plugin %C\n"),
159 : entry->get_auth_name().c_str()));
160 0 : return SecurityConfig_rch();
161 : }
162 :
163 0 : SecurityPluginInst_rch ac_plugin_inst = get_plugin_inst(entry->get_access_control_name());
164 0 : if (ac_plugin_inst.is_nil()) {
165 0 : ACE_ERROR((LM_ERROR,
166 : ACE_TEXT("(%P|%t) SecurityRegistry::create_config: ")
167 : ACE_TEXT("Failed to load access control plugin %C\n"),
168 : entry->get_access_control_name().c_str()));
169 0 : return SecurityConfig_rch();
170 : }
171 :
172 0 : SecurityPluginInst_rch crypto_plugin_inst = get_plugin_inst(entry->get_crypto_name());
173 0 : if (crypto_plugin_inst.is_nil()) {
174 0 : ACE_ERROR((LM_ERROR,
175 : ACE_TEXT("(%P|%t) SecurityRegistry::create_config: ")
176 : ACE_TEXT("Failed to load crypto plugin %C\n"),
177 : entry->get_crypto_name().c_str()));
178 0 : return SecurityConfig_rch();
179 : }
180 :
181 : // Create the new config and try to add it to the container
182 : // of existing configs. If this fails for some reason, then
183 : // release the new config and fail
184 : SecurityConfig_rch new_config =
185 : DCPS::make_rch<SecurityConfig>(config_name,
186 : #ifdef OPENDDS_SECURITY
187 0 : auth_plugin_inst->create_authentication(),
188 0 : ac_plugin_inst->create_access_control(),
189 0 : crypto_plugin_inst->create_crypto_key_exchange(),
190 0 : crypto_plugin_inst->create_crypto_key_factory(),
191 0 : crypto_plugin_inst->create_crypto_transform(),
192 0 : DCPS::RcHandle<Utility>(),
193 : #endif
194 0 : entry->get_properties());
195 :
196 0 : if (!add_config(config_name, new_config)) {
197 0 : ACE_ERROR((LM_ERROR,
198 : ACE_TEXT("(%P|%t) SecurityRegistry::create_config: ")
199 : ACE_TEXT("Error storing config instance %C\n"),
200 : config_name.c_str()));
201 0 : return SecurityConfig_rch();
202 : }
203 :
204 0 : return new_config;
205 0 : }
206 :
207 : SecurityConfig_rch
208 0 : SecurityRegistry::create_config(const OPENDDS_STRING& config_name,
209 : SecurityPluginInst_rch plugin)
210 : {
211 : #ifndef OPENDDS_SECURITY
212 : ACE_UNUSED_ARG(plugin);
213 : #endif
214 :
215 0 : SecurityConfig_rch existing_config;
216 0 : if (find_config(config_name, existing_config)) {
217 0 : return existing_config;
218 : }
219 :
220 : SecurityConfig_rch new_config =
221 : DCPS::make_rch<SecurityConfig>(config_name,
222 : #ifdef OPENDDS_SECURITY
223 0 : plugin->create_authentication(),
224 0 : plugin->create_access_control(),
225 0 : plugin->create_crypto_key_exchange(),
226 0 : plugin->create_crypto_key_factory(),
227 0 : plugin->create_crypto_transform(),
228 0 : plugin->create_utility(),
229 : #endif
230 0 : ConfigPropertyList());
231 :
232 0 : if (!add_config(config_name, new_config)) {
233 0 : ACE_ERROR((LM_ERROR,
234 : ACE_TEXT("(%P|%t) SecurityRegistry::create_config: ")
235 : ACE_TEXT("Error storing config instance %C\n"),
236 : config_name.c_str()));
237 0 : return SecurityConfig_rch();
238 : }
239 :
240 0 : return new_config;
241 0 : }
242 :
243 : SecurityConfig_rch
244 0 : SecurityRegistry::get_config(const OPENDDS_STRING& config_name) const
245 : {
246 0 : GuardType guard(lock_);
247 0 : ConfigMap::const_iterator found = config_map_.find(config_name);
248 0 : return found == config_map_.end() ? SecurityConfig_rch() : found->second;
249 0 : }
250 :
251 : SecurityConfig_rch
252 0 : SecurityRegistry::default_config() const
253 : {
254 : #if defined(OPENDDS_SECURITY)
255 0 : GuardType guard(lock_);
256 0 : if (!default_config_ && !TheServiceParticipant->get_security()) {
257 0 : Authentication_var a;
258 0 : AccessControl_var b;
259 0 : CryptoKeyExchange_var c;
260 0 : CryptoKeyFactory_var d;
261 0 : CryptoTransform_var e;
262 0 : default_config_ = DCPS::make_rch<SecurityConfig>("NoPlugins", a, b, c, d, e,
263 0 : DCPS::RcHandle<Utility>(),
264 0 : ConfigPropertyList());
265 0 : }
266 : #endif
267 0 : return default_config_;
268 0 : }
269 :
270 : void
271 0 : SecurityRegistry::default_config(const SecurityConfig_rch& config)
272 : {
273 0 : GuardType guard(lock_);
274 0 : default_config_ = config;
275 0 : }
276 :
277 : SecurityConfig_rch
278 0 : SecurityRegistry::builtin_config() const
279 : {
280 : #if defined(OPENDDS_SECURITY)
281 0 : GuardType g1(default_load_lock_);
282 0 : GuardType guard(lock_);
283 0 : if (!builtin_config_) {
284 : #if !defined(ACE_AS_STATIC_LIBS)
285 : LibDirectiveMap::const_iterator lib_iter = lib_directive_map_.find(DEFAULT_PLUGIN_NAME);
286 : OPENDDS_ASSERT(lib_iter != lib_directive_map_.end());
287 : ACE_TString directive = ACE_TEXT_CHAR_TO_TCHAR(lib_iter->second.c_str());
288 : guard.release();
289 : ACE_Service_Config::process_directive(directive.c_str());
290 : guard.acquire();
291 : #endif
292 : }
293 : #endif
294 0 : return builtin_config_;
295 0 : }
296 :
297 : void
298 0 : SecurityRegistry::builtin_config(const SecurityConfig_rch& config)
299 : {
300 0 : GuardType guard(lock_);
301 0 : builtin_config_ = config;
302 0 : }
303 :
304 : int
305 0 : SecurityRegistry::load_security_configuration(ACE_Configuration_Heap& cf)
306 : {
307 0 : const ACE_Configuration_Section_Key& root = cf.root_section();
308 0 : ACE_TString sect_name;
309 :
310 0 : for (int index = 0; cf.enumerate_sections(root, index, sect_name) == 0; ++index) {
311 0 : if (ACE_OS::strcmp(sect_name.c_str(), ACE_TEXT_CHAR_TO_TCHAR(SECURITY_SECTION_NAME)) == 0) {
312 : // found the section, now iterate through subsections...
313 0 : ACE_Configuration_Section_Key sect;
314 0 : if (cf.open_section(root, sect_name.c_str(), false, sect) != 0) {
315 0 : ACE_ERROR_RETURN((LM_ERROR,
316 : ACE_TEXT("(%P|%t) SecurityRegistry::load_plugin_properties: ")
317 : ACE_TEXT("failed to open section %s\n"),
318 : sect_name.c_str()),
319 : -1);
320 : }
321 :
322 : // Ensure there are no properties in this section
323 0 : DCPS::ValueMap vm;
324 0 : if (DCPS::pullValues(cf, sect, vm) > 0) {
325 : // There are values inside [transport]
326 0 : ACE_ERROR_RETURN((LM_ERROR,
327 : ACE_TEXT("(%P|%t) SecurityRegistry::load_plugin_properties: ")
328 : ACE_TEXT("[%s] sections must have a section name\n"),
329 : sect_name.c_str()),
330 : -1);
331 : }
332 : // Process the subsections of this section
333 0 : DCPS::KeyList keys;
334 0 : if (DCPS::processSections(cf, sect, keys) != 0) {
335 0 : ACE_ERROR_RETURN((LM_ERROR,
336 : ACE_TEXT("(%P|%t) SecurityRegistry::load_plugin_properties: ")
337 : ACE_TEXT("too many nesting layers in [%s] section.\n"),
338 : sect_name.c_str()),
339 : -1);
340 : }
341 :
342 : // Save the properties configured for each security entry
343 0 : for (DCPS::KeyList::const_iterator it = keys.begin(); it != keys.end(); ++it) {
344 0 : const OPENDDS_STRING& entry_name = it->first;
345 : // Duplicate entry check
346 0 : if (config_entries_.find(entry_name) != config_entries_.end()) {
347 0 : ACE_ERROR_RETURN((LM_ERROR,
348 : ACE_TEXT("(%P|%t) SecurityRegistry::load_plugin_properties: ")
349 : ACE_TEXT("duplicate sections named [%s/%C].\n"),
350 : sect_name.c_str(), entry_name.c_str()),
351 : -1);
352 : }
353 :
354 : // Copy any existing properties in the entry and create the SecurityConfigEntry, which
355 : // will be stored until actual plugin instances are needed for this configuration
356 : SecurityConfigEntry_rch newEntry =
357 0 : DCPS::make_rch<SecurityConfigEntry>(it->first);
358 0 : DCPS::ValueMap values;
359 0 : DCPS::pullValues(cf, it->second, values);
360 0 : for (DCPS::ValueMap::const_iterator val = values.begin(); val != values.end(); ++val) {
361 0 : newEntry->add_property(val->first, val->second);
362 : }
363 :
364 0 : config_entries_[it->first] = newEntry;
365 0 : }
366 0 : }
367 : }
368 :
369 0 : return 0;
370 0 : }
371 :
372 : void
373 0 : SecurityRegistry::load_security_plugin_lib(const OPENDDS_STRING& security_plugin_type)
374 : {
375 : ACE_UNUSED_ARG(security_plugin_type);
376 : #if !defined(ACE_AS_STATIC_LIBS)
377 : GuardType guard(lock_);
378 : LibDirectiveMap::iterator lib_iter = lib_directive_map_.find(security_plugin_type);
379 : if (lib_iter != lib_directive_map_.end()) {
380 : ACE_TString directive = ACE_TEXT_CHAR_TO_TCHAR(lib_iter->second.c_str());
381 : guard.release();
382 : ACE_Service_Config::process_directive(directive.c_str());
383 : }
384 : #endif
385 0 : }
386 :
387 : bool
388 0 : SecurityRegistry::find_config(const OPENDDS_STRING& name, SecurityConfig_rch& config)
389 : {
390 0 : GuardType guard(lock_);
391 :
392 0 : bool found_config = false;
393 0 : ConfigMap::iterator iConfig = config_map_.find(name);
394 0 : if (iConfig != config_map_.end()) {
395 0 : config = iConfig->second;
396 0 : found_config = true;
397 : }
398 :
399 0 : return found_config;
400 0 : }
401 :
402 : bool
403 0 : SecurityRegistry::add_config(const OPENDDS_STRING& name, SecurityConfig_rch& config)
404 : {
405 0 : GuardType guard(lock_);
406 :
407 0 : bool added_config = false;
408 0 : ConfigMap::iterator iConfig = config_map_.find(name);
409 0 : if (iConfig == config_map_.end()) {
410 0 : config_map_[name] = config;
411 0 : added_config = true;
412 : } else {
413 : // Someone else added this already. Use it instead
414 0 : config = iConfig->second;
415 0 : added_config = true;
416 : }
417 :
418 0 : return added_config;
419 0 : }
420 :
421 0 : SecurityPluginInst_rch SecurityRegistry::get_plugin_inst(
422 : const OPENDDS_STRING& plugin_name, bool attempt_fix)
423 : {
424 0 : GuardType guard(lock_);
425 :
426 0 : SecurityPluginInst_rch plugin_inst;
427 :
428 0 : if (find(registered_plugins_, plugin_name, plugin_inst) != 0 && attempt_fix) {
429 : #if !defined(ACE_AS_STATIC_LIBS)
430 : guard.release();
431 : // Not present, try to load library
432 : load_security_plugin_lib(plugin_name);
433 : guard.acquire();
434 :
435 : // Try to find it again
436 : find(registered_plugins_, plugin_name, plugin_inst);
437 : #endif
438 : }
439 :
440 0 : return plugin_inst;
441 0 : }
442 :
443 0 : bool SecurityRegistry::has_no_configs() const
444 : {
445 0 : GuardType guard(lock_);
446 0 : return config_map_.empty();
447 0 : }
448 :
449 : } // namespace OpenDDS
450 : } // namespace Security
451 :
452 : OPENDDS_END_VERSIONED_NAMESPACE_DECL
|