1 /*
2 * Copyright 1999-2006 University of Chicago
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "globus_i_service_engine.h"
18 #include "globus_soap_message.h"
19 #include "globus_soap_message_attrs.h"
20 #include "globus_xio_tcp_driver.h"
21 #include "globus_xio_http.h"
22 #include "globus_xio_gsi.h"
23 #include "globus_ws_addressing.h"
24 #include "globus_handler.h"
25 #include "globus_i_soap_message.h"
26 #include "globus_flavor.h"
27 #include "openssl/rand.h"
28 #include <syslog.h>
29
30 static
31 globus_bool_t
32 globus_l_service_engine_timeout_callback(
33 globus_xio_handle_t handle,
34 globus_xio_operation_type_t type,
35 void * user_arg);
36
37 /**
38 * Initialize a service engine
39 * @ingroup globus_service_engine
40 *
41 * Creates a new service engine. The service engine will be created on a
42 * new TCP port, but will not accept connections until either
43 * globus_service_engine_register_session() or
44 * globus_service_engine_register_start() is called.
45 *
46 * @param new_engine
47 * Pointer to a <code>globus_service_engine_t</code> which will contain
48 * the handle to the new engine after this function returns successfully.
49 * @param attrs
50 * Default @ref globus_soap_message_attrs "SOAP Message attributes" to
51 * use when this engine processes SOAP requests. This parameter may be
52 * NULL.
53 * @param port_contact
54 * String containing the TCP port number to use for this service engine.
55 * This parameter may be NULL. If the string "0" is used, then a port will
56 * be chosen automatically.
57 * @param handlers
58 * Chain of message handlers to use. If this is NULL, the handler chain
59 * will be derived from the default attributes. Experts only!
60 * @param enable_https
61 * Use transport-level security (TLS) to authenticate and protect messages
62 * sent and received by this engine.
63 *
64 * @retval GLOBUS_SUCCESS
65 * Engine initialized successfully.
66 * @retval GLOBUS_SERVICE_ENGINE_ERROR_TYPE_OUT_OF_MEMORY
67 * Insufficient memory to initialized the engine.
68 * @retval GLOBUS_SOAP_MESSAGE_ERROR_TYPE_NULL_PARAM
69 * The @a new_engine parameter is NULL.
70 * @retval GLOBUS_SERVICE_ENGINE_ERROR_TYPE_INIT_FAILED
71 * Internal error initializing the engine. The causal error will
72 * be generated by either
73 * - Globus XIO
74 * - Globus SOAP Message Attributes
75 * - Globus Handler Chain
76 * @retval GLOBUS_SERVICE_ENGINE_ERROR_TYPE_INVALID_CONTACT
77 * Invalid @a port_contact string.
78 *
79 */
80 globus_result_t
81 globus_service_engine_init(
82 globus_service_engine_t * new_engine,
83 globus_soap_message_attr_t attrs,
84 const char * port_contact,
85 globus_handler_chain_t handlers,
86 globus_bool_t enable_https)
87 308 {
88 308 globus_result_t result = GLOBUS_SUCCESS;
89 308 int port = 0;
90 308 globus_i_service_engine_t * engine = NULL;
91 308 globus_xio_attr_t server_attr = NULL;
92 308 char * contact = NULL;
93 308 void * timeout = NULL;
94 globus_soap_message_auth_method_t secattr;
95 int rc;
96 unsigned short randbytes;
97 GlobusFuncName(globus_service_engine_init);
98 308 GlobusServiceEngineDebugEnter();
99
100 308 if (new_engine == NULL)
101 {
102 0 result = GlobusSoapMessageErrorNullParam;
103
104 0 goto out;
105 }
106 308 engine = calloc(1, sizeof(globus_i_service_engine_t));
107 308 if(!engine)
108 {
109 0 result = GlobusServiceEngineErrorOutOfMemory;
110 0 goto out;
111 }
112 308 rc = globus_hashtable_init(
113 &engine->services,
114 13,
115 globus_hashtable_string_hash,
116 globus_hashtable_string_keyeq);
117 308 if (rc != GLOBUS_SUCCESS)
118 {
119 0 goto free_engine_out;
120 }
121 308 if(!attrs)
122 {
123 58 result = globus_soap_message_attr_init(&engine->attrs);
124 58 if(result != GLOBUS_SUCCESS)
125 {
126 0 result = GlobusServiceEngineErrorInitFailed(result);
127 0 goto free_engine_services_out;
128 }
129 }
130 else
131 {
132 250 result = globus_soap_message_attr_copy(
133 &engine->attrs, attrs);
134 250 if(result != GLOBUS_SUCCESS)
135 {
136 0 result = GlobusServiceEngineErrorInitFailed(result);
137 0 goto free_engine_services_out;
138 }
139 }
140
141 308 result = globus_xio_attr_init(&server_attr);
142 308 if(result != GLOBUS_SUCCESS)
143 {
144 0 result = GlobusServiceEngineErrorInitFailed(result);
145 0 goto free_engine_attrs_out;
146 }
147
148 308 if(port_contact)
149 {
150 238 port = atoi(port_contact);
151 238 if(port < 0)
152 {
153 0 result = GlobusServiceEngineErrorInvalidContact(port_contact);
154 0 goto free_server_attr_out;
155 }
156
157 238 result = globus_xio_attr_cntl(server_attr,
158 globus_i_soap_message_tcp_driver,
159 GLOBUS_XIO_TCP_SET_PORT, port);
160 238 if(result != GLOBUS_SUCCESS)
161 {
162 0 result = GlobusServiceEngineErrorInitFailed(result);
163 0 goto free_server_attr_out;
164 }
165
166 238 result = globus_xio_attr_cntl(server_attr,
167 globus_i_soap_message_tcp_driver,
168 GLOBUS_XIO_TCP_SET_REUSEADDR,
169 GLOBUS_TRUE);
170 238 if(result != GLOBUS_SUCCESS)
171 {
172 0 result = GlobusServiceEngineErrorInitFailed(result);
173 0 goto free_server_attr_out;
174 }
175 }
176 308 result = globus_xio_attr_cntl(server_attr,
177 globus_i_soap_message_tcp_driver,
178 GLOBUS_XIO_TCP_SET_NODELAY,
179 GLOBUS_TRUE);
180
181 308 if(result != GLOBUS_SUCCESS)
182 {
183 0 result = GlobusServiceEngineErrorInitFailed(result);
184
185 0 goto free_server_attr_out;
186 }
187
188
189 308 timeout = globus_soap_message_attr_get(
190 engine->attrs, GLOBUS_SOAP_MESSAGE_TIMEOUT_KEY);
191 308 if(timeout)
192 {
193 0 result = globus_xio_attr_cntl(
194 server_attr,
195 GLOBUS_NULL,
196 GLOBUS_XIO_ATTR_SET_TIMEOUT_ALL,
197 globus_l_service_engine_timeout_callback,
198 timeout,
199 GLOBUS_NULL);
200 0 if(result != GLOBUS_SUCCESS)
201 {
202 0 result = GlobusServiceEngineErrorInitFailed(result);
203 0 goto free_server_attr_out;
204 }
205 }
206 308 engine->logger = globus_soap_message_attr_get(
207 engine->attrs, GLOBUS_SOAP_MESSAGE_LOGGER_KEY);
208 308 if(enable_https)
209 {
210 6 engine->https = GLOBUS_TRUE;
211 6 result = globus_i_soap_message_setup_transport_security(
212 engine->attrs,
213 server_attr);
214 6 if(result != GLOBUS_SUCCESS)
215 {
216 0 result = GlobusServiceEngineErrorInitFailed(result);
217
218 0 goto free_server_attr_out;
219 }
220
221 6 result = globus_xio_server_create(
222 &engine->server,
223 server_attr,
224 globus_i_soap_message_xio_https_stack);
225 6 if(result != GLOBUS_SUCCESS)
226 {
227 0 result = GlobusServiceEngineErrorInitFailed(result);
228
229 0 goto free_server_attr_out;
230 }
231 }
232 else
233 {
234 302 result = globus_xio_server_create(&engine->server,
235 server_attr,
236 globus_i_soap_message_xio_stack);
237 302 if(result != GLOBUS_SUCCESS)
238 {
239 0 result = GlobusServiceEngineErrorInitFailed(result);
240
241 0 goto free_server_attr_out;
242 }
243 }
244
245 308 globus_mutex_init(&engine->mutex, NULL);
246
247 308 result = globus_xio_server_get_contact_string(engine->server, &contact);
248 308 if (result != GLOBUS_SUCCESS)
249 {
250 0 result = GlobusServiceEngineErrorInitFailed(result);
251
252 0 goto destroy_mutex_out;
253 }
254 308 engine->contact = globus_common_create_string(
255 "http%s://%s/",
256 (enable_https ? "s" : ""),
257 contact);
258 308 free(contact);
259 308 if (engine->contact == NULL)
260 {
261 0 result = GlobusServiceEngineErrorOutOfMemory;
262
263 0 goto destroy_mutex_out;
264 }
265
266 308 if(!handlers)
267 {
268 308 result = globus_handler_chain_init(&engine->handlers);
269 308 if (result != GLOBUS_SUCCESS)
270 {
271 0 result = GlobusServiceEngineErrorInitFailed(result);
272
273 0 goto free_engine_contact_out;
274 }
275
276 308 result = globus_handler_chain_push(
277 engine->handlers,
278 GLOBUS_HANDLER_TYPE_REQUEST_ALL,
279 GLOBUS_HANDLER_WS_ADDRESSING_SERVER);
280 308 if(result != GLOBUS_SUCCESS)
281 {
282 0 result = GlobusServiceEngineErrorInitFailed(result);
283
284 0 goto destroy_engine_handlers_out;
285 }
286
287 308 result = globus_handler_chain_push(
288 engine->handlers,
289 GLOBUS_HANDLER_TYPE_RESPONSE_ALL,
290 GLOBUS_HANDLER_WS_ADDRESSING_SERVER);
291 308 if(result != GLOBUS_SUCCESS)
292 {
293 0 result = GlobusServiceEngineErrorInitFailed(result);
294
295 0 goto destroy_engine_handlers_out;
296 }
297
298 308 secattr = (globus_soap_message_auth_method_t)
299 globus_soap_message_attr_get(
300 engine->attrs,
301 GLOBUS_SOAP_MESSAGE_AUTHENTICATION_METHOD_KEY);
302
303 308 if ((!enable_https) &&
304 (secattr == GLOBUS_SOAP_MESSAGE_AUTH_SECURE ||
305 secattr == GLOBUS_SOAP_MESSAGE_AUTH_SECURE_MESSAGE))
306 {
307 0 result = globus_handler_chain_push(
308 engine->handlers,
309 GLOBUS_HANDLER_TYPE_REQUEST,
310 "globus_handler_ws_secure_message_server");
311 0 if(result != GLOBUS_SUCCESS)
312 {
313 0 result = GlobusServiceEngineErrorInitFailed(result);
314
315 0 goto destroy_engine_handlers_out;
316 }
317
318 0 result = globus_handler_chain_push(
319 engine->handlers,
320 GLOBUS_HANDLER_TYPE_RESPONSE_ALL,
321 "globus_handler_ws_secure_message_server");
322 0 if(result != GLOBUS_SUCCESS)
323 {
324 0 result = GlobusServiceEngineErrorInitFailed(result);
325
326 0 goto destroy_engine_handlers_out;
327 }
328 }
329 }
330 else
331 {
332 0 result = globus_handler_chain_copy(&engine->handlers, handlers);
333 0 if (result != GLOBUS_SUCCESS)
334 {
335 0 result = GlobusServiceEngineErrorInitFailed(result);
336
337 0 goto free_engine_contact_out;
338 }
339 }
340
341 308 GlobusServiceEngineExtensionLock();
342 308 rc = globus_list_insert(&globus_i_service_engine_instances, engine);
343 308 GlobusServiceEngineExtensionUnlock();
344 308 if (rc != 0)
345 {
346 0 result = GlobusServiceEngineErrorOutOfMemory;
347
348 0 goto destroy_engine_handlers_out;
349 }
350
351 308 RAND_pseudo_bytes(&randbytes, sizeof(randbytes));
352 308 sprintf(engine->id, "%hu", randbytes);
353
354 308 globus_usage_stats_send(globus_i_service_engine_usage,
355 3,
356 "ID",
357 engine->id,
358 "EVENT",
359 "1",
360 "SERVICES",
361 globus_i_service_engine_service_list);
362
363 308 *new_engine = engine;
364
365 308 globus_logging_write(
366 engine->logger,
367 LOG_INFO,
368 "event=globus_service_engine.start "
369 "engine_id=%s "
370 "contact=%s\n",
371 engine->id,
372 engine->contact);
373
374 308 if (result != GLOBUS_SUCCESS)
375 {
376 0 destroy_engine_handlers_out:
377 0 globus_handler_chain_destroy(engine->handlers);
378 0 free_engine_contact_out:
379 0 free(engine->contact);
380 0 destroy_mutex_out:
381 0 globus_mutex_destroy(&engine->mutex);
382 0 globus_xio_server_close(engine->server);
383 0 free_server_attr_out:
384 0 globus_xio_attr_destroy(server_attr);
385 0 free_engine_attrs_out:
386 0 globus_soap_message_attr_destroy(engine->attrs);
387 0 free_engine_services_out:
388 0 globus_hashtable_destroy(&engine->services);
389 0 free_engine_out:
390 0 free(engine);
391 }
392 308 out:
393 308 GlobusServiceEngineDebugExit();
394 308 return result;
395 }
396 /* globus_service_engine_init() */
397
398 static
399 globus_bool_t
400 globus_l_service_engine_timeout_callback(
401 globus_xio_handle_t handle,
402 globus_xio_operation_type_t type,
403 void * user_arg)
404 0 {
405 0 return GLOBUS_TRUE;
406 }