Rework sockname, and add sockacl.
[shibboleth/sp.git] / shib-target / shib-config.cpp
1 /*
2  * The Shibboleth License, Version 1.
3  * Copyright (c) 2002
4  * University Corporation for Advanced Internet Development, Inc.
5  * All rights reserved
6  *
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions are met:
10  *
11  * Redistributions of source code must retain the above copyright notice, this
12  * list of conditions and the following disclaimer.
13  *
14  * Redistributions in binary form must reproduce the above copyright notice,
15  * this list of conditions and the following disclaimer in the documentation
16  * and/or other materials provided with the distribution, if any, must include
17  * the following acknowledgment: "This product includes software developed by
18  * the University Corporation for Advanced Internet Development
19  * <http://www.ucaid.edu>Internet2 Project. Alternately, this acknowledegement
20  * may appear in the software itself, if and wherever such third-party
21  * acknowledgments normally appear.
22  *
23  * Neither the name of Shibboleth nor the names of its contributors, nor
24  * Internet2, nor the University Corporation for Advanced Internet Development,
25  * Inc., nor UCAID may be used to endorse or promote products derived from this
26  * software without specific prior written permission. For written permission,
27  * please contact shibboleth@shibboleth.org
28  *
29  * Products derived from this software may not be called Shibboleth, Internet2,
30  * UCAID, or the University Corporation for Advanced Internet Development, nor
31  * may Shibboleth appear in their name, without prior written permission of the
32  * University Corporation for Advanced Internet Development.
33  *
34  *
35  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
36  * AND WITH ALL FAULTS. ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
37  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
38  * PARTICULAR PURPOSE, AND NON-INFRINGEMENT ARE DISCLAIMED AND THE ENTIRE RISK
39  * OF SATISFACTORY QUALITY, PERFORMANCE, ACCURACY, AND EFFORT IS WITH LICENSEE.
40  * IN NO EVENT SHALL THE COPYRIGHT OWNER, CONTRIBUTORS OR THE UNIVERSITY
41  * CORPORATION FOR ADVANCED INTERNET DEVELOPMENT, INC. BE LIABLE FOR ANY DIRECT,
42  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
43  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
44  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
45  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
46  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
47  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
48  */
49
50 /*
51  * shib-config.cpp -- ShibTarget initialization and finalization routines
52  *
53  * Created By:  Derek Atkins <derek@ihtfp.com>
54  *
55  * $Id$
56  */
57
58 #include "internal.h"
59
60 #include <shib/shib-threads.h>
61
62 #include <log4cpp/PropertyConfigurator.hh>
63 #include <log4cpp/Category.hh>
64
65 #ifndef SHIBTARGET_INIFILE
66 #define SHIBTARGET_INIFILE "/opt/shibboleth/etc/shibboleth/shibboleth.ini"
67 #endif
68
69 class STConfig : public ShibTargetConfig
70 {
71 public:
72   STConfig(const char* app_name, const char* inifile);
73   ~STConfig();
74   void shutdown();
75   void init();
76   ShibINI& getINI() { return *ini; }
77
78   Iterator<const XMLCh*> getPolicies() { return Iterator<const XMLCh*>(policies); }
79
80   void ref();
81 private:
82   SAMLConfig& samlConf;
83   ShibConfig& shibConf;
84   ShibINI* ini;
85   string m_app_name;
86   int refcount;
87   vector<const XMLCh*> policies;
88   string m_SocketName;
89 #ifdef WANT_TCP_SHAR
90   vector<string> m_SocketACL;
91 #endif
92   friend ShibSockName shib_target_sockname();
93   friend ShibSockName shib_target_sockacl(unsigned int);
94 };
95
96 namespace {
97   STConfig * g_Config = NULL;
98   Mutex * g_lock = NULL;
99 }
100
101 CCache* shibtarget::g_shibTargetCCache = NULL;
102
103 /****************************************************************************/
104 // External Interface
105
106
107 void ShibTargetConfig::preinit()
108 {
109   if (g_lock) return;
110   g_lock = Mutex::create();
111 }
112
113 ShibTargetConfig& ShibTargetConfig::init(const char* app_name, const char* inifile)
114 {
115   if (!g_lock)
116     throw runtime_error ("ShibTargetConfig not pre-initialized");
117
118   if (!app_name)
119     throw runtime_error ("No Application name");
120   Lock lock(g_lock);
121
122   if (g_Config) {
123     g_Config->ref();
124     return *g_Config;
125   }
126
127   g_Config = new STConfig(app_name, inifile);
128   g_Config->init();
129   return *g_Config;
130 }
131
132 ShibTargetConfig& ShibTargetConfig::getConfig()
133 {
134     if (!g_Config)
135         throw SAMLException("ShibTargetConfig::getConfig() called with NULL configuration");
136     return *g_Config;
137 }
138
139 /****************************************************************************/
140 // STConfig
141
142 STConfig::STConfig(const char* app_name, const char* inifile)
143   :  samlConf(SAMLConfig::getConfig()), shibConf(ShibConfig::getConfig()),
144      m_app_name(app_name)
145 {
146   try {
147     ini = new ShibINI((inifile ? inifile : SHIBTARGET_INIFILE));
148   } catch (...) {
149     cerr << "Unable to load the INI file: " << 
150       (inifile ? inifile : SHIBTARGET_INIFILE) << endl;
151     throw;
152   }
153 }
154
155 void STConfig::init()
156 {
157   string app = m_app_name;
158   string tag;
159
160   // Initialize Log4cpp
161   if (ini->get_tag (app, SHIBTARGET_TAG_LOGGER, true, &tag)) {
162     cerr << "Trying to load logger configuration: " << tag << "\n";
163     try {
164       PropertyConfigurator::configure(tag);
165     } catch (ConfigureFailure& e) {
166       cerr << "Error reading configuration: " << e.what() << "\n";
167     }
168   } else {
169     Category& category = Category::getRoot();
170     category.setPriority(log4cpp::Priority::DEBUG);
171     cerr << "No logger configuration found\n";
172   }
173
174   Category& log = Category::getInstance("shibtarget.STConfig");
175
176   saml::NDC ndc("STConfig::init");
177
178   // Init SAML Configuration
179   if (ini->get_tag (app, SHIBTARGET_TAG_SAMLCOMPAT, true, &tag))
180     samlConf.compatibility_mode = ShibINI::boolean(tag);
181   if (ini->get_tag (app, SHIBTARGET_TAG_SCHEMAS, true, &tag))
182     samlConf.schema_dir = tag;
183
184   // Init SAML Binding Configuration
185   if (ini->get_tag (app, SHIBTARGET_TAG_AATIMEOUT, true, &tag))
186     samlConf.binding_defaults.timeout = atoi(tag.c_str());
187   if (ini->get_tag (app, SHIBTARGET_TAG_AACONNECTTO, true, &tag))
188     samlConf.binding_defaults.conn_timeout = atoi(tag.c_str());
189   if (ini->get_tag (app, SHIBTARGET_TAG_CERTFILE, true, &tag))
190     samlConf.binding_defaults.ssl_certfile = tag;
191   if (ini->get_tag (app, SHIBTARGET_TAG_KEYFILE, true, &tag))
192     samlConf.binding_defaults.ssl_keyfile = tag;
193   if (ini->get_tag (app, SHIBTARGET_TAG_KEYPASS, true, &tag))
194     samlConf.binding_defaults.ssl_keypass = tag;
195   if (ini->get_tag (app, SHIBTARGET_TAG_CALIST, true, &tag))
196     samlConf.binding_defaults.ssl_calist = tag;
197
198   try {
199     if (!samlConf.init()) {
200       log.fatal ("Failed to initialize SAML Library");
201       throw runtime_error ("Failed to initialize SAML Library");
202     } else
203       log.debug ("SAML Initialized");
204   } catch (...) {
205     log.crit ("Died initializing SAML Library");
206     throw;    
207   }
208
209   // Init Shib
210   try { 
211     if (!shibConf.init()) {
212       log.fatal ("Failed to initialize Shib library");
213       throw runtime_error ("Failed to initialize Shib Library");
214     } else
215       log.debug ("Shib Initialized");
216   } catch (...) {
217     log.crit ("Failed initializing Shib library.");
218     throw;
219   }
220
221   // Load any SAML extensions
222   string ext = "extensions:saml";
223   if (ini->exists(ext)) {
224     saml::NDC ndc("load_extensions");
225     ShibINI::Iterator* iter = ini->tag_iterator(ext);
226
227     for (const string* str = iter->begin(); str; str = iter->next()) {
228       string file = ini->get(ext, *str);
229       try
230       {
231         samlConf.saml_register_extension(file.c_str(),ini);
232         log.debug("%s: loading %s", str->c_str(), file.c_str());
233       }
234       catch (SAMLException& e)
235       {
236         log.crit("%s: %s", str->c_str(), e.what());
237       }
238     }
239     delete iter;
240   }
241
242   // Load the specified metadata.
243   if (ini->get_tag(app, SHIBTARGET_TAG_METADATA, true, &tag) && ini->exists(tag))
244   {
245     ShibINI::Iterator* iter=ini->tag_iterator(tag);
246     for (const string* prov=iter->begin(); prov; prov=iter->next())
247     {
248         const string source=ini->get(tag,*prov);
249         log.info("registering metadata provider: type=%s, source=%s",prov->c_str(),source.c_str());
250         if (!shibConf.addMetadata(prov->c_str(),source.c_str()))
251         {
252             log.crit("error adding metadata provider: type=%s, source=%s",prov->c_str(),source.c_str());
253             if (!strcmp(app.c_str(), SHIBTARGET_SHAR))
254                 throw runtime_error("error adding metadata provider");
255         }
256     }
257     delete iter;
258   }
259   
260   // Load SAML policies.
261   if (ini->exists(SHIBTARGET_POLICIES)) {
262     log.info("loading SAML policies");
263     ShibINI::Iterator* iter = ini->tag_iterator(SHIBTARGET_POLICIES);
264
265     for (const string* str = iter->begin(); str; str = iter->next()) {
266         policies.push_back(XMLString::transcode(ini->get(SHIBTARGET_POLICIES, *str).c_str()));
267     }
268     delete iter;
269   }
270   
271   // Initialize the SHAR Cache
272   if (!strcmp (app.c_str(), SHIBTARGET_SHAR)) {
273     const char * cache_type = NULL;
274     if (ini->get_tag (app, SHIBTARGET_TAG_CACHETYPE, true, &tag))
275       cache_type = tag.c_str();
276
277     g_shibTargetCCache = CCache::getInstance(cache_type);
278   }
279
280   // Process socket settings.
281   m_SocketName=ini->get(SHIBTARGET_GENERAL, "sharsocket");
282   if (m_SocketName.empty())
283     m_SocketName=SHIB_SHAR_SOCKET;
284
285 #ifdef WANT_TCP_SHAR
286   string sockacl=ini->get(SHIBTARGET_SHAR, "sharacl");
287   if (sockacl.length()>0)
288   {
289     int j = 0;
290     for (int i = 0;  i < sockacl.length();  i++)
291     {
292         if (sockacl.at(i)==' ')
293         {
294             string addr=sockacl.substr(j, i-j);
295             j = i+1;
296             m_SocketACL.push_back(addr);
297         }
298     }
299     string addr=sockacl.substr(j, sockacl.length()-j);
300     m_SocketACL.push_back(addr);
301   }
302   else
303     m_SocketACL.push_back("127.0.0.1");
304 #endif
305
306   ref();
307   log.debug("finished");
308 }
309
310 STConfig::~STConfig()
311 {
312   for (vector<const XMLCh*>::iterator i=policies.begin(); i!=policies.end(); i++)
313     delete const_cast<XMLCh*>(*i);
314   
315   if (ini) delete ini;
316   
317   if (g_shibTargetCCache)
318     delete g_shibTargetCCache;
319
320   shibConf.term();
321   samlConf.term();
322 }
323
324 void STConfig::ref()
325 {
326   refcount++;
327 }
328
329 void STConfig::shutdown()
330 {
331   refcount--;
332   if (!refcount) {
333     delete g_Config;
334     g_Config = NULL;
335   }
336 }
337
338 extern "C" ShibSockName shib_target_sockname(void)
339 {
340     return (g_Config ? g_Config->m_SocketName.c_str() : (ShibSockName)0);
341 }
342
343 extern "C" ShibSockName shib_target_sockacl(unsigned int index)
344 {
345 #ifdef WANT_TCP_SHAR
346     if (g_Config && index<g_Config->m_SocketACL.size())
347         return g_Config->m_SocketACL[index].c_str();
348 #endif
349     return (ShibSockName)0;
350 }