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