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>