526d62492804dcad2070c94ca54528d543fdb6a5
[shibboleth/sp.git] / shibd / shibd.cpp
1 /*\r
2  *  Copyright 2001-2007 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  * shar.cpp -- the shibd "main" code.  All the functionality is elsewhere\r
19  *\r
20  * Created By:  Derek Atkins <derek@ihtfp.com>\r
21  *\r
22  * $Id: shar.cpp 2164 2007-02-11 05:26:18 +0000 (Sun, 11 Feb 2007) cantor $\r
23  */\r
24 \r
25 \r
26 // eventually we might be able to support autoconf via cygwin...\r
27 #if defined (_MSC_VER) || defined(__BORLANDC__)\r
28 # include "config_win32.h"\r
29 #else\r
30 # include "config.h"\r
31 #endif\r
32 \r
33 #ifdef WIN32\r
34 # define _CRT_NONSTDC_NO_DEPRECATE 1\r
35 # define _CRT_SECURE_NO_DEPRECATE 1\r
36 #endif\r
37 \r
38 #include <shibsp/SPConfig.h>\r
39 \r
40 #ifdef HAVE_UNISTD_H\r
41 #include <unistd.h>\r
42 #include <sys/select.h>\r
43 #endif\r
44 \r
45 #include <stdio.h>\r
46 #include <signal.h>\r
47 #include <shibsp/ServiceProvider.h>\r
48 #include <shibsp/remoting/ListenerService.h>\r
49 #include <xercesc/util/XMLUniDefs.hpp>\r
50 #include <xmltooling/XMLToolingConfig.h>\r
51 #include <xmltooling/util/XMLConstants.h>\r
52 #include <xmltooling/util/XMLHelper.h>\r
53 \r
54 using namespace shibsp;\r
55 using namespace xmltooling;\r
56 using namespace std;\r
57 \r
58 bool shibd_shutdown = false;\r
59 const char* shar_config = NULL;\r
60 const char* shar_schemadir = NULL;\r
61 bool shar_checkonly = false;\r
62 bool shar_version = false;\r
63 static int unlink_socket = 0;\r
64 const char* pidfile = NULL;\r
65 \r
66 #ifdef WIN32\r
67 \r
68 //#include <CRTDBG.H>\r
69 \r
70 #define nNoMansLandSize 4\r
71 typedef struct _CrtMemBlockHeader\r
72 {\r
73         struct _CrtMemBlockHeader * pBlockHeaderNext;\r
74         struct _CrtMemBlockHeader * pBlockHeaderPrev;\r
75         char *                      szFileName;\r
76         int                         nLine;\r
77         size_t                      nDataSize;\r
78         int                         nBlockUse;\r
79         long                        lRequest;\r
80         unsigned char               gap[nNoMansLandSize];\r
81         /* followed by:\r
82          *  unsigned char           data[nDataSize];\r
83          *  unsigned char           anotherGap[nNoMansLandSize];\r
84          */\r
85 } _CrtMemBlockHeader;\r
86 \r
87 /*\r
88 int MyAllocHook(int nAllocType, void *pvData,\r
89       size_t nSize, int nBlockUse, long lRequest,\r
90       const unsigned char * szFileName, int nLine)\r
91 {\r
92     if ( nBlockUse == _CRT_BLOCK )\r
93       return( TRUE );\r
94     if (nAllocType == _HOOK_FREE) {\r
95         _CrtMemBlockHeader* ptr = (_CrtMemBlockHeader*)(((_CrtMemBlockHeader *)pvData)-1);\r
96         if (ptr->nDataSize == 8192)\r
97             fprintf(stderr,"free  request %u size %u\n", ptr->lRequest, ptr->nDataSize);\r
98     }\r
99     else if (nAllocType == _HOOK_ALLOC && nSize == 8192)\r
100         fprintf(stderr,"%s request %u size %u\n", ((nAllocType == _HOOK_ALLOC) ? "alloc" : "realloc"), lRequest, nSize);\r
101     return (TRUE);\r
102 }\r
103 */\r
104 \r
105 int real_main(int preinit)\r
106 {\r
107     SPConfig& conf=SPConfig::getConfig();\r
108     if (preinit) {\r
109 \r
110         // Initialize the SP library.\r
111         conf.setFeatures(\r
112             SPConfig::Listener |\r
113             SPConfig::Caching |\r
114             SPConfig::Metadata |\r
115             SPConfig::Trust |\r
116             SPConfig::Credentials |\r
117             SPConfig::AttributeResolution |\r
118             SPConfig::Handlers |\r
119             SPConfig::OutOfProcess |\r
120             (shar_checkonly ? SPConfig::RequestMapping : SPConfig::Logging)\r
121             );\r
122         if (!shar_config)\r
123             shar_config=getenv("SHIBSP_CONFIG");\r
124         if (!shar_schemadir)\r
125             shar_schemadir=getenv("SHIBSP_SCHEMAS");\r
126         if (!shar_schemadir)\r
127             shar_schemadir=SHIBSP_SCHEMAS;\r
128         if (!shar_config)\r
129             shar_config=SHIBSP_CONFIG;\r
130         if (!conf.init(shar_schemadir)) {\r
131             fprintf(stderr, "configuration is invalid, see console for specific problems\n");\r
132             return -1;\r
133         }\r
134         \r
135         try {\r
136             static const XMLCh path[] = UNICODE_LITERAL_4(p,a,t,h);\r
137             static const XMLCh validate[] = UNICODE_LITERAL_8(v,a,l,i,d,a,t,e);\r
138             xercesc::DOMDocument* dummydoc=XMLToolingConfig::getConfig().getParser().newDocument();\r
139             XercesJanitor<xercesc::DOMDocument> docjanitor(dummydoc);\r
140             xercesc::DOMElement* dummy = dummydoc->createElementNS(NULL,path);\r
141             auto_ptr_XMLCh src(shar_config);\r
142             dummy->setAttributeNS(NULL,path,src.get());\r
143             dummy->setAttributeNS(NULL,validate,xmlconstants::XML_ONE);\r
144     \r
145             conf.setServiceProvider(conf.ServiceProviderManager.newPlugin(XML_SERVICE_PROVIDER,dummy));\r
146             conf.getServiceProvider()->init();\r
147         }\r
148         catch (exception& ex) {\r
149             fprintf(stderr, "caught exception while loading configuration: %s\n", ex.what());\r
150             conf.term();\r
151             return -2;\r
152         }\r
153 \r
154         // If just a test run, bail.\r
155         if (shar_checkonly) {\r
156             fprintf(stdout, "overall configuration is loadable, check console for non-fatal problems\n");\r
157             return 0;\r
158         }\r
159     }\r
160     else {\r
161 \r
162         //_CrtSetAllocHook(MyAllocHook);\r
163 \r
164         // Run the listener\r
165         if (!shar_checkonly) {\r
166 \r
167             // Run the listener.\r
168             if (!conf.getServiceProvider()->getListenerService()->run(&shibd_shutdown)) {\r
169                 fprintf(stderr, "listener failed to enter listen loop\n");\r
170                 return -3;\r
171             }\r
172         }\r
173 \r
174         conf.term();\r
175     }\r
176     return 0;\r
177 }\r
178 \r
179 #else\r
180 \r
181 static void term_handler(int arg)\r
182 {\r
183     shibd_shutdown = true;\r
184 }\r
185 \r
186 static int setup_signals(void)\r
187 {\r
188     struct sigaction sa;\r
189     memset(&sa, 0, sizeof (sa));\r
190     sa.sa_handler = SIG_IGN;\r
191     sa.sa_flags = SA_RESTART;\r
192 \r
193     if (sigaction(SIGPIPE, &sa, NULL) < 0) {\r
194         return -1;\r
195     }\r
196 \r
197     memset(&sa, 0, sizeof (sa));\r
198     sa.sa_handler = term_handler;\r
199     sa.sa_flags = SA_RESTART;\r
200 \r
201     if (sigaction(SIGHUP, &sa, NULL) < 0) {\r
202         return -1;\r
203     }\r
204     if (sigaction(SIGINT, &sa, NULL) < 0) {\r
205         return -1;\r
206     }\r
207     if (sigaction(SIGQUIT, &sa, NULL) < 0) {\r
208         return -1;\r
209     }\r
210     if (sigaction(SIGTERM, &sa, NULL) < 0) {\r
211         return -1;\r
212     }\r
213     return 0;\r
214 }\r
215 \r
216 static void usage(char* whoami)\r
217 {\r
218     fprintf(stderr, "usage: %s [-fcdt]\n", whoami);\r
219     fprintf(stderr, "  -c\tconfig file to use.\n");\r
220     fprintf(stderr, "  -x\tXML schema catalogs to use.\n");\r
221     fprintf(stderr, "  -t\tcheck configuration file for problems.\n");\r
222     fprintf(stderr, "  -f\tforce removal of listener socket.\n");\r
223     fprintf(stderr, "  -p\tpid file to use.\n");\r
224     fprintf(stderr, "  -v\tprint software version.\n");\r
225     fprintf(stderr, "  -h\tprint this help message.\n");\r
226     exit(1);\r
227 }\r
228 \r
229 static int parse_args(int argc, char* argv[])\r
230 {\r
231     int opt;\r
232 \r
233     while ((opt = getopt(argc, argv, "c:x:p:ftvh")) > 0) {\r
234         switch (opt) {\r
235             case 'c':\r
236                 shar_config=optarg;\r
237                 break;\r
238             case 'x':\r
239                 shar_schemadir=optarg;\r
240                 break;\r
241             case 'f':\r
242                 unlink_socket = 1;\r
243                 break;\r
244             case 't':\r
245                 shar_checkonly=true;\r
246                 break;\r
247             case 'v':\r
248                 shar_version=true;\r
249                 break;\r
250             case 'p':\r
251                 pidfile=optarg;\r
252                 break;\r
253             default:\r
254                 return -1;\r
255         }\r
256     }\r
257     return 0;\r
258 }\r
259 \r
260 int main(int argc, char *argv[])\r
261 {\r
262     if (parse_args(argc, argv) != 0)\r
263         usage(argv[0]);\r
264     else if (shar_version) {\r
265         fprintf(stdout, PACKAGE_STRING);\r
266         return 0;\r
267     }\r
268 \r
269     if (setup_signals() != 0)\r
270         return -1;\r
271 \r
272     if (!shar_config)\r
273         shar_config=getenv("SHIBSP_CONFIG");\r
274     if (!shar_schemadir)\r
275         shar_schemadir=getenv("SHIBSP_SCHEMAS");\r
276     if (!shar_schemadir)\r
277         shar_schemadir=SHIBSP_SCHEMAS;\r
278     if (!shar_config)\r
279         shar_config=SHIBSP_CONFIG;\r
280 \r
281     // initialize the shib-target library\r
282     SPConfig& conf=SPConfig::getConfig();\r
283     conf.setFeatures(\r
284         SPConfig::Listener |\r
285         SPConfig::Caching |\r
286         SPConfig::Metadata |\r
287         SPConfig::Trust |\r
288         SPConfig::Credentials |\r
289         SPConfig::AttributeResolution |\r
290         SPConfig::Handlers |\r
291         SPConfig::OutOfProcess |\r
292         (shar_checkonly ? SPConfig::RequestMapping : SPConfig::Logging)\r
293         );\r
294     if (!conf.init(shar_schemadir)) {\r
295         fprintf(stderr, "configuration is invalid, check console for specific problems\n");\r
296         return -1;\r
297     }\r
298 \r
299     try {\r
300         static const XMLCh path[] = UNICODE_LITERAL_4(p,a,t,h);\r
301         static const XMLCh validate[] = UNICODE_LITERAL_8(v,a,l,i,d,a,t,e);\r
302         xercesc::DOMDocument* dummydoc=XMLToolingConfig::getConfig().getParser().newDocument();\r
303         XercesJanitor<xercesc::DOMDocument> docjanitor(dummydoc);\r
304         xercesc::DOMElement* dummy = dummydoc->createElementNS(NULL,path);\r
305         auto_ptr_XMLCh src(shar_config);\r
306         dummy->setAttributeNS(NULL,path,src.get());\r
307         dummy->setAttributeNS(NULL,validate,xmlconstants::XML_ONE);\r
308 \r
309         conf.setServiceProvider(conf.ServiceProviderManager.newPlugin(XML_SERVICE_PROVIDER,dummy));\r
310         conf.getServiceProvider()->init();\r
311     }\r
312     catch (exception& ex) {\r
313         fprintf(stderr, "caught exception while loading configuration: %s\n", ex.what());\r
314         conf.term();\r
315         return -2;\r
316     }\r
317 \r
318     if (shar_checkonly)\r
319         fprintf(stderr, "overall configuration is loadable, check console for non-fatal problems\n");\r
320     else {\r
321 \r
322         // Write the pid file\r
323         if (pidfile) {\r
324             FILE* pidf = fopen(pidfile, "w");\r
325             if (pidf) {\r
326                 fprintf(pidf, "%d\n", getpid());\r
327                 fclose(pidf);\r
328             } else {\r
329                 perror(pidfile);  // keep running though\r
330             }\r
331         }\r
332     \r
333         // Run the listener\r
334         if (!conf.getServiceProvider()->getListenerService()->run(&shibd_shutdown)) {\r
335             fprintf(stderr, "listener failed to enter listen loop\n");\r
336             return -3;\r
337         }\r
338     }\r
339 \r
340     conf.term();\r
341     if (pidfile)\r
342         unlink(pidfile);\r
343     return 0;\r
344 }\r
345 \r
346 #endif\r