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