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>