First cut at signing support.
[shibboleth/cpp-xmltooling.git] / xmltooling / XMLToolingConfig.cpp
1 /*\r
2  *  Copyright 2001-2006 Internet2\r
3  * \r
4  * Licensed under the Apache License, Version 2.0 (the "License");\r
5  * you may not use this file except in compliance with the License.\r
6  * You may obtain a copy of the License at\r
7  *\r
8  *     http://www.apache.org/licenses/LICENSE-2.0\r
9  *\r
10  * Unless required by applicable law or agreed to in writing, software\r
11  * distributed under the License is distributed on an "AS IS" BASIS,\r
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
13  * See the License for the specific language governing permissions and\r
14  * limitations under the License.\r
15  */\r
16 \r
17 /**\r
18  * XMLToolingConfig.cpp\r
19  * \r
20  * Library configuration \r
21  */\r
22 \r
23 #include "internal.h"\r
24 #include "XMLToolingConfig.h"\r
25 #include "impl/UnknownElement.h"\r
26 #include "signature/impl/XMLSecSignature.h"\r
27 #include "util/NDC.h"\r
28 \r
29 #ifdef HAVE_DLFCN_H\r
30 # include <dlfcn.h>\r
31 #endif\r
32 \r
33 #include <log4cpp/Category.hh>\r
34 #include <log4cpp/PropertyConfigurator.hh>\r
35 #include <log4cpp/OstreamAppender.hh>\r
36 #include <xercesc/util/PlatformUtils.hpp>\r
37 #ifndef XMLTOOLING_NO_XMLSEC\r
38     #include <xsec/framework/XSECProvider.hpp>\r
39 #endif\r
40 \r
41 #include <stdexcept>\r
42 \r
43 using namespace log4cpp;\r
44 using namespace xmltooling;\r
45 using namespace std;\r
46 \r
47 namespace {\r
48    XMLToolingInternalConfig g_config;\r
49 }\r
50 \r
51 XMLToolingConfig& XMLToolingConfig::getConfig()\r
52 {\r
53     return g_config;\r
54 }\r
55 \r
56 XMLToolingInternalConfig& XMLToolingInternalConfig::getInternalConfig()\r
57 {\r
58     return g_config;\r
59 }\r
60 \r
61 bool XMLToolingInternalConfig::log_config(const char* config)\r
62 {\r
63     try {\r
64         if (!config || !*config)\r
65             config=getenv("XMLTOOLING_LOG_CONFIG");\r
66         if (!config || !*config)\r
67             config="WARN";\r
68         \r
69         bool level=false;\r
70         Category& root = Category::getRoot();\r
71         if (!strcmp(config,"DEBUG")) {\r
72             root.setPriority(Priority::DEBUG);\r
73             level=true;\r
74         }\r
75         else if (!strcmp(config,"INFO")) {\r
76             root.setPriority(Priority::INFO);\r
77             level=true;\r
78         }\r
79         else if (!strcmp(config,"NOTICE")) {\r
80             root.setPriority(Priority::NOTICE);\r
81             level=true;\r
82         }\r
83         else if (!strcmp(config,"WARN")) {\r
84             root.setPriority(Priority::WARN);\r
85             level=true;\r
86         }\r
87         else if (!strcmp(config,"ERROR")) {\r
88             root.setPriority(Priority::ERROR);\r
89             level=true;\r
90         }\r
91         else if (!strcmp(config,"CRIT")) {\r
92             root.setPriority(Priority::CRIT);\r
93             level=true;\r
94         }\r
95         else if (!strcmp(config,"ALERT")) {\r
96             root.setPriority(Priority::ALERT);\r
97             level=true;\r
98         }\r
99         else if (!strcmp(config,"EMERG")) {\r
100             root.setPriority(Priority::EMERG);\r
101             level=true;\r
102         }\r
103         else if (!strcmp(config,"FATAL")) {\r
104             root.setPriority(Priority::FATAL);\r
105             level=true;\r
106         }\r
107         if (level)\r
108             root.setAppender(new OstreamAppender("default",&cerr));\r
109         else\r
110             PropertyConfigurator::configure(config);\r
111     }\r
112     catch (const ConfigureFailure& e) {\r
113         Category::getInstance(XMLTOOLING_LOGCAT".Logging").crit("failed to initialize log4cpp: %s", e.what());\r
114         return false;\r
115     }\r
116     \r
117     return true;\r
118 }\r
119 \r
120 bool XMLToolingInternalConfig::init()\r
121 {\r
122 #ifdef _DEBUG\r
123     xmltooling::NDC ndc("init");\r
124 #endif\r
125     Category& log=Category::getInstance(XMLTOOLING_LOGCAT".XMLToolingConfig");\r
126     try {\r
127         log.debug("library initialization started");\r
128 \r
129         xercesc::XMLPlatformUtils::Initialize();\r
130         log.debug("Xerces initialization complete");\r
131 \r
132 #ifndef XMLTOOLING_NO_XMLSEC\r
133         XSECPlatformUtils::Initialise();\r
134         m_xsecProvider=new XSECProvider();\r
135         log.debug("XMLSec initialization complete");\r
136 #endif\r
137 \r
138         m_parserPool=new ParserPool();\r
139         m_lock=xercesc::XMLPlatformUtils::makeMutex();\r
140 \r
141         // default registrations\r
142         XMLObjectBuilder::registerDefaultBuilder(new UnknownElementBuilder());\r
143         Marshaller::registerDefaultMarshaller(new UnknownElementMarshaller());\r
144         Unmarshaller::registerDefaultUnmarshaller(new UnknownElementUnmarshaller());\r
145         \r
146         QName dsig(XMLConstants::XMLSIG_NS,Signature::LOCAL_NAME);\r
147         XMLObjectBuilder::registerBuilder(dsig,new XMLSecSignatureBuilder());\r
148         Marshaller::registerMarshaller(dsig,new XMLSecSignatureMarshaller());\r
149         Unmarshaller::registerUnmarshaller(dsig,new XMLSecSignatureUnmarshaller());\r
150     }\r
151     catch (const xercesc::XMLException&) {\r
152         log.fatal("caught exception while initializing Xerces");\r
153         return false;\r
154     }\r
155 \r
156     log.info("library initialization complete");\r
157     return true;\r
158 }\r
159 \r
160 void XMLToolingInternalConfig::term()\r
161 {\r
162     XMLObjectBuilder::destroyBuilders();\r
163     Marshaller::destroyMarshallers();\r
164     Unmarshaller::destroyUnmarshallers();\r
165 \r
166     for (vector<void*>::reverse_iterator i=m_libhandles.rbegin(); i!=m_libhandles.rend(); i++) {\r
167 #if defined(WIN32)\r
168         FARPROC fn=GetProcAddress(static_cast<HMODULE>(*i),"xmltooling_extension_term");\r
169         if (fn)\r
170             fn();\r
171         FreeLibrary(static_cast<HMODULE>(*i));\r
172 #elif defined(HAVE_DLFCN_H)\r
173         void (*fn)()=(void (*)())dlsym(*i,"xmltooling_extension_term");\r
174         if (fn)\r
175             fn();\r
176         dlclose(*i);\r
177 #else\r
178 # error "Don't know about dynamic loading on this platform!"\r
179 #endif\r
180     }\r
181     m_libhandles.clear();\r
182     \r
183     delete m_parserPool;\r
184     m_parserPool=NULL;\r
185 \r
186 #ifndef XMLTOOLING_NO_XMLSEC\r
187     delete m_xsecProvider;\r
188     m_xsecProvider=NULL;\r
189     XSECPlatformUtils::Terminate();\r
190 #endif\r
191 \r
192     xercesc::XMLPlatformUtils::closeMutex(m_lock);\r
193     m_lock=NULL;\r
194     xercesc::XMLPlatformUtils::Terminate();\r
195 \r
196  #ifdef _DEBUG\r
197     xmltooling::NDC ndc("term");\r
198 #endif\r
199    Category::getInstance(XMLTOOLING_LOGCAT".XMLToolingConfig").info("library shutdown complete");\r
200 }\r
201 \r
202 ILockable& XMLToolingInternalConfig::lock()\r
203 {\r
204     xercesc::XMLPlatformUtils::lockMutex(m_lock);\r
205     return *this;\r
206 }\r
207 \r
208 void XMLToolingInternalConfig::unlock()\r
209 {\r
210     xercesc::XMLPlatformUtils::unlockMutex(m_lock);\r
211 }\r
212 \r
213 bool XMLToolingInternalConfig::load_library(const char* path, void* context)\r
214 {\r
215 #ifdef _DEBUG\r
216     xmltooling::NDC ndc("LoadLibrary");\r
217 #endif\r
218     Category& log=Category::getInstance(XMLTOOLING_LOGCAT".XMLToolingConfig");\r
219     log.info("loading extension: %s", path);\r
220 \r
221     Locker locker(this);\r
222 \r
223 #if defined(WIN32)\r
224     HMODULE handle=NULL;\r
225     char* fixed=const_cast<char*>(path);\r
226     if (strchr(fixed,'/')) {\r
227         fixed=strdup(path);\r
228         char* p=fixed;\r
229         while (p=strchr(p,'/'))\r
230             *p='\\';\r
231     }\r
232 \r
233     UINT em=SetErrorMode(SEM_FAILCRITICALERRORS);\r
234     try {\r
235         handle=LoadLibraryEx(fixed,NULL,LOAD_WITH_ALTERED_SEARCH_PATH);\r
236         if (!handle)\r
237              handle=LoadLibraryEx(fixed,NULL,0);\r
238         if (!handle)\r
239             throw runtime_error(string("unable to load extension library: ") + fixed);\r
240         FARPROC fn=GetProcAddress(handle,"xmltooling_extension_init");\r
241         if (!fn)\r
242             throw runtime_error(string("unable to locate xmltooling_extension_init entry point: ") + fixed);\r
243         if (reinterpret_cast<int(*)(void*)>(fn)(context)!=0)\r
244             throw runtime_error(string("detected error in xmltooling_extension_init: ") + fixed);\r
245         if (fixed!=path)\r
246             free(fixed);\r
247         SetErrorMode(em);\r
248     }\r
249     catch(runtime_error& e) {\r
250         log.error(e.what());\r
251         if (handle)\r
252             FreeLibrary(handle);\r
253         SetErrorMode(em);\r
254         if (fixed!=path)\r
255             free(fixed);\r
256         return false;\r
257     }\r
258 \r
259 #elif defined(HAVE_DLFCN_H)\r
260     void* handle=dlopen(path,RTLD_LAZY);\r
261     if (!handle)\r
262         throw runtime_error(string("unable to load extension library '") + path + "': " + dlerror());\r
263     int (*fn)(void*)=(int (*)(void*))(dlsym(handle,"xmltooling_extension_init"));\r
264     if (!fn) {\r
265         dlclose(handle);\r
266         throw runtime_error(\r
267             string("unable to locate xmltooling_extension_init entry point in '") + path + "': " +\r
268                 (dlerror() ? dlerror() : "unknown error")\r
269             );\r
270     }\r
271     try {\r
272         if (fn(context)!=0)\r
273             throw runtime_error(string("detected error in xmltooling_extension_init in ") + path);\r
274     }\r
275     catch(runtime_error& e) {\r
276         log.error(e.what());\r
277         if (handle)\r
278             dlclose(handle);\r
279         return false;\r
280     }\r
281 #else\r
282 # error "Don't know about dynamic loading on this platform!"\r
283 #endif\r
284     m_libhandles.push_back(handle);\r
285     log.info("loaded extension: %s", path);\r
286     return true;\r
287 }\r