Annotation of embedaddon/libpdel/http/servlet/http_servlet_xmlrpc.c, revision 1.1.1.1
1.1 misho 1:
2: /*
3: * Copyright (c) 2001-2002 Packet Design, LLC.
4: * All rights reserved.
5: *
6: * Subject to the following obligations and disclaimer of warranty,
7: * use and redistribution of this software, in source or object code
8: * forms, with or without modifications are expressly permitted by
9: * Packet Design; provided, however, that:
10: *
11: * (i) Any and all reproductions of the source or object code
12: * must include the copyright notice above and the following
13: * disclaimer of warranties; and
14: * (ii) No rights are granted, in any manner or form, to use
15: * Packet Design trademarks, including the mark "PACKET DESIGN"
16: * on advertising, endorsements, or otherwise except as such
17: * appears in the above copyright notice or in the software.
18: *
19: * THIS SOFTWARE IS BEING PROVIDED BY PACKET DESIGN "AS IS", AND
20: * TO THE MAXIMUM EXTENT PERMITTED BY LAW, PACKET DESIGN MAKES NO
21: * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING
22: * THIS SOFTWARE, INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED
23: * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE,
24: * OR NON-INFRINGEMENT. PACKET DESIGN DOES NOT WARRANT, GUARANTEE,
25: * OR MAKE ANY REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS
26: * OF THE USE OF THIS SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY,
27: * RELIABILITY OR OTHERWISE. IN NO EVENT SHALL PACKET DESIGN BE
28: * LIABLE FOR ANY DAMAGES RESULTING FROM OR ARISING OUT OF ANY USE
29: * OF THIS SOFTWARE, INCLUDING WITHOUT LIMITATION, ANY DIRECT,
30: * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, PUNITIVE, OR CONSEQUENTIAL
31: * DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, LOSS OF
32: * USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY THEORY OF
33: * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
34: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
35: * THE USE OF THIS SOFTWARE, EVEN IF PACKET DESIGN IS ADVISED OF
36: * THE POSSIBILITY OF SUCH DAMAGE.
37: *
38: * Author: Archie Cobbs <archie@freebsd.org>
39: */
40:
41: #include <sys/types.h>
42: #include <sys/param.h>
43: #include <sys/stat.h>
44:
45: #include <netinet/in_systm.h>
46: #include <netinet/in.h>
47:
48: #include <stdlib.h>
49: #include <stdio.h>
50: #include <string.h>
51: #include <stdarg.h>
52: #include <syslog.h>
53: #include <errno.h>
54: #include <assert.h>
55:
56: #include <openssl/ssl.h>
57:
58: #include "structs/structs.h"
59: #include "structs/type/array.h"
60: #include "structs/type/struct.h"
61: #include "structs/type/union.h"
62: #include "structs/xml.h"
63: #include "structs/xmlrpc.h"
64:
65: #include "http/http_defs.h"
66: #include "http/http_server.h"
67: #include "http/http_servlet.h"
68: #include "http/servlet/xml.h"
69: #include "http/servlet/xmlrpc.h"
70: #include "util/typed_mem.h"
71:
72: #define MEM_TYPE "http_servlet_xmlrpc"
73:
74: #define BOGUS_RTYPE ((const struct structs_type *)0x1832f0ad)
75:
76: struct xmlrpc_state {
77: struct http_servlet *servlet; /* servlet */
78: struct http_servlet_xmlrpc_method *methods; /* methods */
79: void *arg;
80: void (*destroy)(void *);
81: http_logger_t *logger;
82: };
83:
84: /* Internal functions */
85: static http_servlet_run_t http_servlet_xmlrpc_run;
86: static http_servlet_destroy_t http_servlet_xmlrpc_destroy;
87:
88: static struct http_servlet_xmlrpc_method *http_servlet_xmlrpc_copy_methods(
89: const struct http_servlet_xmlrpc_method *methods);
90: static void http_servlet_xmlrpc_free_methods(
91: struct http_servlet_xmlrpc_method *methods);
92:
93: static http_servlet_xml_handler_t http_servlet_xmlrpc_handler;
94:
95: /*
96: * Create a new http_servlet_xmlrpc servlet.
97: */
98: struct http_servlet *
99: http_servlet_xmlrpc_create(const struct http_servlet_xmlrpc_info *info,
100: void *arg, void (*destroy)(void *))
101: {
102: struct http_servlet_xml_info xinfo;
103: struct http_servlet *servlet;
104: struct xmlrpc_state *state;
105:
106: /* Create servlet */
107: if ((servlet = MALLOC(MEM_TYPE, sizeof(*servlet))) == NULL)
108: return (NULL);
109: memset(servlet, 0, sizeof(*servlet));
110: servlet->run = http_servlet_xmlrpc_run;
111: servlet->destroy = http_servlet_xmlrpc_destroy;
112:
113: /* Create servlet state structure */
114: if ((state = MALLOC(MEM_TYPE, sizeof(*state))) == NULL)
115: goto fail;
116: memset(state, 0, sizeof(*state));
117: state->arg = arg;
118: state->destroy = destroy;
119: state->logger = info->logger;
120:
121: /* Copy method list */
122: if ((state->methods
123: = http_servlet_xmlrpc_copy_methods(info->methods)) == NULL)
124: goto fail;
125:
126: /* Set up info for the more general http_servlet_xml servlet */
127: memset(&xinfo, 0, sizeof(xinfo));
128: xinfo.handler = http_servlet_xmlrpc_handler;
129: xinfo.ptag = XML_RPC_REQUEST_TAG;
130: xinfo.ptype = &structs_type_xmlrpc_request;
131: xinfo.rtag = XML_RPC_REPLY_TAG;
132: xinfo.rtype = &structs_type_xmlrpc_response;
133: xinfo.allow_post = 1;
134: xinfo.allow_get = 0;
135: xinfo.logger = info->logger;
136: xinfo.flags = STRUCTS_XML_FULL;
137:
138: /* Create "inner" XML servlet using 'xinfo' */
139: if ((state->servlet = http_servlet_xml_create(&xinfo,
140: state, NULL)) == NULL)
141: goto fail;
142:
143: /* Done */
144: servlet->arg = state;
145: return (servlet);
146:
147: fail:
148: /* Clean up after failure */
149: if (state != NULL) {
150: if (state->methods != NULL)
151: http_servlet_xmlrpc_free_methods(state->methods);
152: FREE(MEM_TYPE, state);
153: }
154: FREE(MEM_TYPE, servlet);
155: return (NULL);
156: }
157:
158: static int
159: http_servlet_xmlrpc_run(struct http_servlet *servlet,
160: struct http_request *req, struct http_response *resp)
161: {
162: struct xmlrpc_state *const state = servlet->arg;
163:
164: return ((*state->servlet->run)(state->servlet, req, resp));
165: }
166:
167: static void
168: http_servlet_xmlrpc_destroy(struct http_servlet *servlet)
169: {
170: struct xmlrpc_state *const state = servlet->arg;
171:
172: /* Destroy 'inner' servlet */
173: http_server_destroy_servlet(&state->servlet);
174:
175: /* Destroy 'outer' servlet */
176: if (state->destroy != NULL)
177: (*state->destroy)(state->arg);
178: http_servlet_xmlrpc_free_methods(state->methods);
179: FREE(MEM_TYPE, state);
180: FREE(MEM_TYPE, servlet);
181: }
182:
183: /*
184: * Our "wrapper" handler that converts an XML-RPC request/reply
185: * into a more normal request/reply.
186: */
187: static void *
188: http_servlet_xmlrpc_handler(void *arg, struct http_request *req,
189: const void *payload, const char *pattrs, char **rattrsp,
190: const char *mtype)
191: {
192: const struct xmlrpc_state *const state = arg;
193: const struct structs_type *const xrept = &structs_type_xmlrpc_response;
194: const struct http_servlet_xmlrpc_method *method;
195: const struct xmlrpc_request *const xreq = payload; /* XML-RPC request */
196: void **params = NULL; /* parameter list for handler */
197: void *reply = NULL; /* reply returned by handler */
198: struct xmlrpc_response_union *xreply = NULL; /* XML-RPC reply */
199: const struct structs_type *rtype = NULL;/* handlers' reply type */
200: void *ret = NULL; /* this func's return value */
201: int faulted = 0; /* handler returned fault */
202: char *errbuf = NULL; /* error message, if any */
203: int exploded_params = 0; /* exploded parameters */
204: int exploded_response = 0; /* exploded response */
205: int errno_save; /* saved errno value */
206: u_int i;
207:
208: /* Find method */
209: for (method = state->methods; method->name != NULL
210: && *method->name != '\0'
211: && strcmp(method->name, xreq->methodName) != 0; method++);
212: if (method->name == NULL) {
213: ASPRINTF(TYPED_MEM_TEMP, &errbuf,
214: "method name \"%s\" not recognized", xreq->methodName);
215: if (errbuf == NULL)
216: goto fail;
217: (*state->logger)(LOG_ERR, "XML-RPC: %s", errbuf);
218: errno = ENOSYS;
219: goto null_reply;
220: }
221: exploded_params = (method->ptypes == NULL);
222:
223: /* Check number of arguments */
224: if (xreq->params.length < method->min_params
225: || xreq->params.length > method->max_params) {
226: ASPRINTF(TYPED_MEM_TEMP, &errbuf,
227: "%d parameter(s) present for method \"%s\" which takes"
228: " between %u and %u parameter(s)", xreq->params.length,
229: xreq->methodName, method->min_params, method->max_params);
230: if (errbuf == NULL)
231: goto fail;
232: (*state->logger)(LOG_ERR, "XML-RPC: %s", errbuf);
233: errno = EINVAL;
234: goto null_reply;
235: }
236:
237: /* Get parameters from the XML-RPC request */
238: if ((params = MALLOC(TYPED_MEM_TEMP,
239: xreq->params.length * sizeof(*params))) == NULL)
240: goto null_reply;
241: memset(params, 0, xreq->params.length * sizeof(*params));
242: for (i = 0; i < xreq->params.length; i++) {
243: char ebuf[256];
244:
245: /* Optionally leave parameter list "exploded" */
246: if (exploded_params) {
247: params[i] = &xreq->params.elems[i].value;
248: continue;
249: }
250:
251: /* "Compact" this parameter using structs_xmlrpc2struct() */
252: if ((params[i] = MALLOC(TYPED_MEM_TEMP,
253: method->ptypes[i]->size)) == NULL)
254: break;
255: if (structs_init(method->ptypes[i], NULL, params[i]) == -1) {
256: FREE(TYPED_MEM_TEMP, params[i]);
257: params[i] = NULL;
258: break;
259: }
260: if (structs_xmlrpc2struct(&structs_type_xmlrpc_value,
261: &xreq->params.elems[i].value, NULL, method->ptypes[i],
262: params[i], NULL, ebuf, sizeof(ebuf)) == -1) {
263: errno_save = errno;
264: ASPRINTF(TYPED_MEM_TEMP, &errbuf, "parameter #%d of"
265: " method \"%s\" has an invalid type or value: %s",
266: i + 1, xreq->methodName, ebuf);
267: if (errbuf == NULL)
268: goto fail;
269: (*state->logger)(LOG_ERR, "XML-RPC: %s", errbuf);
270: errno = errno_save;
271: break;
272: }
273: }
274: if (i < xreq->params.length)
275: goto null_reply;
276:
277: /* Invoke our simplified handler */
278: rtype = BOGUS_RTYPE;
279: reply = (*method->handler)(state->arg, xreq->methodName, req,
280: xreq->params.length, (const void **)params, TYPED_MEM_TEMP,
281: &rtype, &faulted);
282: if (reply == NULL) {
283: errno_save = errno;
284: (*state->logger)(LOG_ERR,
285: "XML-RPC: handler for \"%s\" failed: %s",
286: xreq->methodName, strerror(errno));
287: errno = errno_save;
288: goto null_reply;
289: }
290:
291: /* Sanity check returned reply type */
292: if (rtype == BOGUS_RTYPE) {
293: ASPRINTF(TYPED_MEM_TEMP, &errbuf, "handler didn't set 'rtype'");
294: if (errbuf == NULL)
295: goto fail;
296: (*state->logger)(LOG_ERR, "XML-RPC: handler for"
297: " \"%s\" failed: %s", xreq->methodName, errbuf);
298: errno = ECONNABORTED;
299: goto null_reply;
300: }
301: if (faulted && rtype != &structs_type_xmlrpc_compact_fault) {
302: ASPRINTF(TYPED_MEM_TEMP, &errbuf, "handler returned a fault"
303: " but didn't set 'rtype' to"
304: " &structs_type_xmlrpc_compact_fault");
305: if (errbuf == NULL)
306: goto fail;
307: (*state->logger)(LOG_ERR, "XML-RPC: handler for"
308: " \"%s\" failed: %s", xreq->methodName, errbuf);
309: errno = ECONNABORTED;
310: goto null_reply;
311: }
312:
313: /* Check for "exploded" return value */
314: if (rtype == NULL) {
315: rtype = &structs_type_xmlrpc_value;
316: exploded_response = 1;
317: }
318:
319: null_reply:
320: /* Save errno (used to create the fault when/if reply == NULL) */
321: errno_save = errno;
322:
323: /* Create the XML-RPC reply */
324: if ((xreply = MALLOC(mtype, sizeof(*xreply))) == NULL)
325: goto fail;
326: if (structs_init(xrept, NULL, xreply) == -1) {
327: FREE(mtype, xreply);
328: xreply = NULL;
329: goto fail;
330: }
331:
332: /* If handler returned NULL, create a fault structure using errno */
333: if (reply == NULL) {
334: struct xmlrpc_compact_fault *fault;
335:
336: /* Create an initialize fault structure from error string */
337: if ((fault = MALLOC(TYPED_MEM_TEMP, sizeof(*fault))) == NULL)
338: goto fail;
339: if (structs_init(&structs_type_xmlrpc_compact_fault,
340: NULL, fault) == -1) {
341: FREE(TYPED_MEM_TEMP, fault);
342: goto fail;
343: }
344: fault->faultCode = errno;
345: if (structs_set_string(&structs_type_xmlrpc_compact_fault,
346: "faultString", errbuf != NULL ? errbuf :
347: strerror(errno_save), fault, NULL, 0) == -1)
348: ; /* too bad, just ignore error */
349:
350: /* Now pretend like handler() itself returned the fault */
351: reply = fault;
352: rtype = &structs_type_xmlrpc_compact_fault;
353: faulted = 1;
354: }
355:
356: /* Set fault if error, otherwise set reply as XML-RPC reply parameter */
357: if (faulted) {
358: if (structs_struct2xmlrpc(rtype, reply,
359: NULL, xrept, xreply, "fault.value") == -1)
360: goto fail;
361: } else {
362: if (structs_array_insert(xrept, "params", 0, xreply) == -1)
363: goto fail;
364: if (exploded_response) {
365: if (structs_set(xrept, reply,
366: "params.0.value", xreply) == -1)
367: goto fail;
368: } else if (structs_struct2xmlrpc(rtype, reply, NULL,
369: xrept, xreply, "params.0.value") == -1)
370: goto fail;
371: }
372:
373: /* Done, so return reply */
374: ret = xreply;
375: xreply = NULL;
376:
377: fail:
378: /* Cleanup and exit */
379: errno_save = errno;
380: if (params != NULL) {
381: if (!exploded_params) {
382: for (i = 0; i < xreq->params.length; i++) {
383: if (params[i] != NULL) {
384: structs_free(method->ptypes[i],
385: NULL, params[i]);
386: FREE(TYPED_MEM_TEMP, params[i]);
387: }
388: }
389: }
390: FREE(TYPED_MEM_TEMP, params);
391: }
392: if (reply != NULL) {
393: structs_free(rtype, NULL, reply);
394: FREE(TYPED_MEM_TEMP, reply);
395: }
396: if (xreply != NULL) {
397: structs_free(xrept, NULL, xreply);
398: FREE(mtype, xreply);
399: }
400: if (errbuf != NULL)
401: FREE(TYPED_MEM_TEMP, errbuf);
402: errno = errno_save;
403: return (ret);
404: }
405:
406: /*
407: * Copy an XML-RPC method list
408: */
409: static struct http_servlet_xmlrpc_method *
410: http_servlet_xmlrpc_copy_methods(
411: const struct http_servlet_xmlrpc_method *const methods)
412: {
413: const struct http_servlet_xmlrpc_method *method;
414: struct http_servlet_xmlrpc_method *mcopy;
415: int num;
416: int i;
417:
418: /* Count the number of methods */
419: for (num = 0, method = methods; method->name != NULL; num++, method++);
420:
421: /* Allocate an array */
422: if ((mcopy = MALLOC(MEM_TYPE, (num + 1) * sizeof(*mcopy))) == NULL)
423: return (NULL);
424: memset(mcopy, 0, (num + 1) * sizeof(*mcopy));
425:
426: /* Make a 'deep' copy (except for structs types XXX) */
427: for (i = 0; i < num; i++) {
428: const struct http_servlet_xmlrpc_method *const orig
429: = &methods[i];
430: struct http_servlet_xmlrpc_method *const copy = &mcopy[i];
431:
432: /* Copy all except the malloc'd stuff */
433: *copy = *orig;
434: copy->name = NULL;
435: copy->ptypes = NULL;
436:
437: /* Copy types array */
438: if (orig->ptypes != NULL) {
439: if ((copy->ptypes = MALLOC(MEM_TYPE, copy->max_params
440: * sizeof(*copy->ptypes))) == NULL) {
441: http_servlet_xmlrpc_free_methods(mcopy);
442: return (NULL);
443: }
444: memcpy(copy->ptypes, orig->ptypes,
445: copy->max_params * sizeof(*copy->ptypes));
446: }
447:
448: /* Copy name */
449: if ((copy->name = STRDUP(MEM_TYPE, orig->name)) == NULL) {
450: FREE(MEM_TYPE, copy->ptypes);
451: http_servlet_xmlrpc_free_methods(mcopy);
452: return (NULL);
453: }
454: }
455:
456: /* Done */
457: return (mcopy);
458: }
459:
460: static void
461: http_servlet_xmlrpc_free_methods(struct http_servlet_xmlrpc_method *methods)
462: {
463: const struct http_servlet_xmlrpc_method *method;
464: int i;
465:
466: for (i = 0, method = methods; method->name != NULL; i++, method++) {
467: FREE(MEM_TYPE, (char *)method->name);
468: FREE(MEM_TYPE, method->ptypes);
469: }
470: FREE(MEM_TYPE, methods);
471: }
472:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>