Annotation of embedaddon/libpdel/http/servlet/http_servlet_xmlrpc.c, revision 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>