Annotation of embedaddon/libpdel/http/servlet/http_servlet_cookieauth.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: 
                     43: #include <netinet/in.h>
                     44: 
                     45: #include <stdlib.h>
                     46: #include <stddef.h>
                     47: #include <stdio.h>
                     48: #include <string.h>
                     49: #include <stdarg.h>
                     50: #include <syslog.h>
                     51: #include <errno.h>
                     52: #include <ctype.h>
                     53: #include <assert.h>
                     54: #include <pthread.h>
                     55: 
                     56: #include <openssl/ssl.h>
                     57: #include <openssl/md5.h>
                     58: 
                     59: #include "structs/structs.h"
                     60: #include "structs/type/array.h"
                     61: #include "structs/type/boolean.h"
                     62: #include "structs/type/data.h"
                     63: #include "structs/type/int.h"
                     64: #include "structs/type/null.h"
                     65: #include "structs/type/string.h"
                     66: #include "structs/type/struct.h"
                     67: #include "structs/type/time.h"
                     68: #include "structs/xml.h"
                     69: 
                     70: #include "http/http_defs.h"
                     71: #include "http/http_server.h"
                     72: #include "http/http_servlet.h"
                     73: #include "http/servlet/redirect.h"
                     74: #include "http/servlet/cookieauth.h"
                     75: 
                     76: #include "sys/alog.h"
                     77: #include "io/string_fp.h"
                     78: #include "util/rsa_util.h"
                     79: #include "util/typed_mem.h"
                     80: #include "debug/debug.h"
                     81: 
                     82: #ifndef __FreeBSD__
                     83: #define __printflike(x,y)
                     84: #endif
                     85: 
                     86: /*
                     87:  * Ref: http://home.netscape.com/newsref/std/cookie_spec.html
                     88:  */
                     89: 
                     90: #define MEM_TYPE               "http_servlet_cookieauth"
                     91: #define DATA_MEM_TYPE          "http_servlet_cookieauth.data"
                     92: #define COOKIE_TIME_FMT                "%a, %d-%b-%Y %T GMT"
                     93: #define COOKIE_LINGER_TIME     (30 * 60)               /* 30 minutes */
                     94: 
                     95: /* Per-servlet private info */
                     96: struct cookieauth_private {
                     97:        struct http_servlet     *redirect;      /* private redirect servlet */
                     98:        http_servlet_cookieauth_reqd_t
                     99:                                *authreqd;      /* checks if auth required */
                    100:        void                    *arg;           /* argument for authreqd() */
                    101:        void                    (*destroy)(void *);     /* destructor for arg */
                    102:        char                    *privkey;       /* rsa private key file */
                    103:        char                    *cookiename;    /* name of cookie */
                    104:        struct structs_data     id;             /* unique system id */
                    105: };
                    106: 
                    107: /* Structure of the cookie data */
                    108: struct cookieauth {
                    109:        char                    *username;      /* login username */
                    110:        char                    *path;          /* cookie path */
                    111:        char                    *domain;        /* cookie domain */
                    112:        u_char                  secure;         /* cookie 'secure' bit */
                    113:        u_char                  session_only;   /* this browser session only */
                    114:        time_t                  timestamp;      /* time cookie was set */
                    115:        time_t                  expire;         /* expiration time, or zero */
                    116:        u_int32_t               linger;         /* max linger time, or zero */
                    117:        struct structs_data     id;             /* unique system id */
                    118:        struct structs_data     sig;            /* rsa signature */
                    119: };
                    120: 
                    121: /* Internal functions */
                    122: static http_servlet_run_t      http_servlet_cookieauth_run;
                    123: static http_servlet_destroy_t  http_servlet_cookieauth_destroy;
                    124: 
                    125: static int     http_servlet_cookieauth_get(const char *privkey,
                    126:                        const struct structs_data *id, const char *cookiename,
                    127:                        struct http_request *req, struct cookieauth *auth);
                    128: static int     http_servlet_cookieauth_md5(const struct cookieauth *auth,
                    129:                        u_char *md5);
                    130: 
                    131: #if PDEL_DEBUG
                    132: static void    dump_data(const void *data, u_int plen, const char *fmt, ...)
                    133:                        __printflike(3, 4);
                    134: #endif
                    135: 
                    136: /* Internal variables */
                    137: static const struct structs_type authcookie_data_type
                    138:        = STRUCTS_DATA_TYPE(NULL, DATA_MEM_TYPE);
                    139: 
                    140: static const struct structs_field cookieauth_fields[] = {
                    141:        STRUCTS_STRUCT_FIELD(cookieauth, username, &structs_type_string),
                    142:        STRUCTS_STRUCT_FIELD(cookieauth, path, &structs_type_string_null),
                    143:        STRUCTS_STRUCT_FIELD(cookieauth, domain, &structs_type_string_null),
                    144:        STRUCTS_STRUCT_FIELD(cookieauth, secure, &structs_type_boolean_char),
                    145:        STRUCTS_STRUCT_FIELD(cookieauth,
                    146:            session_only, &structs_type_boolean_char),
                    147:        STRUCTS_STRUCT_FIELD(cookieauth, timestamp, &structs_type_time_gmt),
                    148:        STRUCTS_STRUCT_FIELD(cookieauth, expire, &structs_type_time_gmt),
                    149:        STRUCTS_STRUCT_FIELD(cookieauth, linger, &structs_type_uint32),
                    150:        STRUCTS_STRUCT_FIELD(cookieauth, id, &authcookie_data_type),
                    151:        STRUCTS_STRUCT_FIELD(cookieauth, sig, &authcookie_data_type),
                    152:        STRUCTS_STRUCT_FIELD_END
                    153: };
                    154: static const struct structs_type cookieauth_type
                    155:        = STRUCTS_STRUCT_TYPE(cookieauth, &cookieauth_fields);
                    156: 
                    157: /*
                    158:  * Create a new cookieauth servlet.
                    159:  */
                    160: struct http_servlet *
                    161: http_servlet_cookieauth_create(const char *redirect, int append,
                    162:        http_servlet_cookieauth_reqd_t *authreqd, void *arg,
                    163:        void (*destroy)(void *), const char *privkey,
                    164:        const void *id, size_t idlen, const char *cookiename)
                    165: {
                    166:        struct http_servlet *servlet;
                    167:        struct cookieauth_private *priv;
                    168:        struct structs_data id_data;
                    169:        const char *s;
                    170: 
                    171:        /* Validate cookiename */
                    172:        for (s = cookiename; *s != '\0'; s++) {
                    173:                if (!isgraph((u_char)*s) || strchr(",;=", *s) != NULL)
                    174:                        break;
                    175:        }
                    176:        if (s == cookiename || *s != '\0') {
                    177:                errno = EINVAL;
                    178:                return (NULL);
                    179:        }
                    180: 
                    181:        /* Create new servlet */
                    182:        if ((servlet = MALLOC(MEM_TYPE, sizeof(*servlet))) == NULL)
                    183:                return (NULL);
                    184:        memset(servlet, 0, sizeof(*servlet));
                    185:        servlet->run = http_servlet_cookieauth_run;
                    186:        servlet->destroy = http_servlet_cookieauth_destroy;
                    187: 
                    188:        /* Set up private info */
                    189:        if ((priv = MALLOC(MEM_TYPE, sizeof(*priv))) == NULL)
                    190:                goto fail;
                    191:        memset(priv, 0, sizeof(*priv));
                    192:        if ((priv->redirect
                    193:            = http_servlet_redirect_create(redirect, append)) == NULL)
                    194:                goto fail;
                    195:        priv->authreqd = authreqd;
                    196:        priv->arg = arg;
                    197:        priv->destroy = destroy;
                    198:        if ((priv->privkey = STRDUP(MEM_TYPE, privkey)) == NULL)
                    199:                goto fail;
                    200:        if ((priv->cookiename = STRDUP(MEM_TYPE, cookiename)) == NULL)
                    201:                goto fail;
                    202:        id_data.data = (u_char *)id;
                    203:        id_data.length = idlen;
                    204:        if (structs_get(&authcookie_data_type, NULL, &id_data, &priv->id) == -1)
                    205:                goto fail;
                    206:        servlet->arg = priv;
                    207: 
                    208:        /* Done */
                    209:        return (servlet);
                    210: 
                    211: fail:
                    212:        /* Clean up after failure */
                    213:        if (priv != NULL) {
                    214:                structs_free(&authcookie_data_type, NULL, &priv->id);
                    215:                FREE(MEM_TYPE, priv->cookiename);
                    216:                FREE(MEM_TYPE, priv->privkey);
                    217:                http_server_destroy_servlet(&priv->redirect);
                    218:                FREE(MEM_TYPE, priv);
                    219:        }
                    220:        FREE(MEM_TYPE, servlet);
                    221:        return (NULL);
                    222: }
                    223: 
                    224: /*
                    225:  * Execute cookie authorization servlet.
                    226:  */
                    227: static int
                    228: http_servlet_cookieauth_run(struct http_servlet *servlet,
                    229:        struct http_request *req, struct http_response *resp)
                    230: {
                    231:        struct cookieauth_private *const priv = servlet->arg;
                    232:        struct cookieauth auth;
                    233: 
                    234:        /* Always allow access to the logon page */
                    235:        if (priv->authreqd != NULL && !(*priv->authreqd)(priv->arg, req))
                    236:                goto allow;
                    237: 
                    238:        /* Get valid authorization structure, if there is one */
                    239:        if (http_servlet_cookieauth_get(priv->privkey,
                    240:            &priv->id, priv->cookiename, req, &auth) == -1) {
                    241: 
                    242:                /* Invalid authorization -> redirect to logon page */
                    243:                if (errno == EACCES) {
                    244:                        return ((*priv->redirect->run)(priv->redirect,
                    245:                            req, resp));
                    246:                }
                    247: 
                    248:                /* Other errors -> generate server error */
                    249:                http_response_send_errno_error(resp);
                    250:                return (1);
                    251:        }
                    252: 
                    253:        /* Update cookie for linger timer */
                    254:        if (auth.linger != 0) {
                    255:                (void)http_servlet_cookieauth_login(resp, priv->privkey,
                    256:                    auth.username, auth.linger, auth.expire, auth.session_only,
                    257:                    priv->id.data, priv->id.length, priv->cookiename, auth.path,
                    258:                    auth.domain, auth.secure);
                    259:        }
                    260: 
                    261:        /* Free authorization info */
                    262:        structs_free(&cookieauth_type, NULL, &auth);
                    263: 
                    264: allow:
                    265:        /* Allow request to continue */
                    266:        return (0);
                    267: }
                    268: 
                    269: /*
                    270:  * Destroy an auth servlet.
                    271:  */
                    272: static void
                    273: http_servlet_cookieauth_destroy(struct http_servlet *servlet)
                    274: {
                    275:        struct cookieauth_private *const priv = servlet->arg;
                    276: 
                    277:        if (priv->destroy != NULL)
                    278:                (*priv->destroy)(priv->arg);
                    279:        structs_free(&authcookie_data_type, NULL, &priv->id);
                    280:        FREE(MEM_TYPE, priv->privkey);
                    281:        FREE(MEM_TYPE, priv->cookiename);
                    282:        http_server_destroy_servlet(&priv->redirect);
                    283:        FREE(MEM_TYPE, priv);
                    284:        FREE(MEM_TYPE, servlet);
                    285: }
                    286: 
                    287: /*
                    288:  * Add a cookie that will cause the servlet to not redirect.
                    289:  */
                    290: int
                    291: http_servlet_cookieauth_login(struct http_response *resp,
                    292:        const char *privkey, const char *username, u_int max_linger,
                    293:        time_t expire, int session_only, const u_char *id, size_t idlen,
                    294:        const char *cookiename, const char *path, const char *domain,
                    295:        int secure)
                    296: {
                    297:        struct structs_data data;       /* binary encoding of "auth" */
                    298:        struct cookieauth auth;         /* authorization info struct */
                    299:        u_char md5[MD5_DIGEST_LENGTH];
                    300:        u_char sigbuf[1024];
                    301:        char ebuf[128];
                    302:        int siglen;
                    303:        char *hval;
                    304:        FILE *sb;
                    305: 
                    306:        /* Build auth structure */
                    307:        if (structs_init(&cookieauth_type, NULL, &auth) == -1)
                    308:                return (-1);
                    309:        if (structs_set_string(&cookieauth_type,
                    310:            "username", username, &auth, ebuf, sizeof(ebuf)) == -1) {
                    311:                alogf(LOG_ERR, "%s: %s", "structs_set_string", ebuf);
                    312:                structs_free(&cookieauth_type, NULL, &auth);
                    313:                return (-1);
                    314:        }
                    315:        if (path != NULL
                    316:            && structs_set_string(&cookieauth_type,
                    317:              "path", path, &auth, ebuf, sizeof(ebuf)) == -1) {
                    318:                alogf(LOG_ERR, "%s: %s", "structs_set_string", ebuf);
                    319:                structs_free(&cookieauth_type, NULL, &auth);
                    320:                return (-1);
                    321:        }
                    322:        if (domain != NULL
                    323:            && structs_set_string(&cookieauth_type,
                    324:              "domain", domain, &auth, ebuf, sizeof(ebuf)) == -1) {
                    325:                alogf(LOG_ERR, "%s: %s", "structs_set_string", ebuf);
                    326:                structs_free(&cookieauth_type, NULL, &auth);
                    327:                return (-1);
                    328:        }
                    329:        auth.secure = !!secure;
                    330:        auth.session_only = !!session_only;
                    331:        auth.timestamp = time(NULL);
                    332:        auth.linger = max_linger;
                    333:        auth.expire = expire;
                    334:        data.data = (u_char *)id;
                    335:        data.length = idlen;
                    336:        if (structs_get(&authcookie_data_type, NULL, &data, &auth.id) == -1) {
                    337:                alogf(LOG_ERR, "%s: %m", "structs_get");
                    338:                structs_free(&cookieauth_type, NULL, &auth);
                    339:                return (-1);
                    340:        }
                    341: 
                    342:        /* Add RSA signature */
                    343:        if (http_servlet_cookieauth_md5(&auth, md5) == -1) {
                    344:                alogf(LOG_ERR, "%s: %m", "http_servlet_cookieauth_md5");
                    345:                structs_free(&cookieauth_type, NULL, &auth);
                    346:                return (-1);
                    347:        }
                    348:        if ((siglen = rsa_util_sign(privkey,
                    349:            md5, sigbuf, sizeof(sigbuf))) == -1) {
                    350:                alogf(LOG_ERR, "%s: %m", "rsa_util_sign");
                    351:                structs_free(&cookieauth_type, NULL, &auth);
                    352:                return (-1);
                    353:        }
                    354:        data.data = sigbuf;
                    355:        data.length = siglen;
                    356:        if (structs_get(&authcookie_data_type, NULL, &data, &auth.sig) == -1) {
                    357:                alogf(LOG_ERR, "%s: %m", "structs_get");
                    358:                structs_free(&cookieauth_type, NULL, &auth);
                    359:                return (-1);
                    360:        }
                    361: 
                    362:        /* Encode auth structure into binary */
                    363:        if (structs_get_binary(&cookieauth_type,
                    364:            NULL, &auth, DATA_MEM_TYPE, &data) == -1) {
                    365:                alogf(LOG_ERR, "%s: %m", "structs_get_binary");
                    366:                structs_free(&cookieauth_type, NULL, &auth);
                    367:                return (-1);
                    368:        }
                    369: 
                    370: #if PDEL_DEBUG
                    371:        if (PDEL_DEBUG_ENABLED(HTTP_SERVLET_COOKIEAUTH)) {
                    372:                printf("COOKIE AUTH STRUCTURE\n");
                    373:                structs_xml_output(&cookieauth_type,
                    374:                    "auth", NULL, &auth, stdout, NULL, STRUCTS_XML_FULL);
                    375:                dump_data(data.data, data.length, "COOKIE DATA");
                    376:        }
                    377: #endif
                    378: 
                    379:        structs_free(&cookieauth_type, NULL, &auth);
                    380: 
                    381:        /* Base64 encode it */
                    382:        if ((hval = structs_get_string(&authcookie_data_type,
                    383:            NULL, &data, TYPED_MEM_TEMP)) == NULL) {
                    384:                alogf(LOG_ERR, "%s: %m", "structs_get_string");
                    385:                structs_free(&authcookie_data_type, NULL, &data);
                    386:                return (-1);
                    387:        }
                    388:        structs_free(&authcookie_data_type, NULL, &data);
                    389: 
                    390:        /* Create string output buffer */
                    391:        if ((sb = string_buf_output(TYPED_MEM_TEMP)) == NULL) {
                    392:                FREE(TYPED_MEM_TEMP, hval);
                    393:                return (-1);
                    394:        }
                    395: 
                    396:        /* Construct cookie header value */
                    397:        fprintf(sb, "%s=%s", cookiename, hval);
                    398:        FREE(TYPED_MEM_TEMP, hval);
                    399:        if (!session_only) {
                    400:                char tbuf[64];
                    401:                struct tm tm;
                    402: 
                    403:                strftime(tbuf, sizeof(tbuf),
                    404:                    COOKIE_TIME_FMT, gmtime_r(&expire, &tm));
                    405:                fprintf(sb, "; expires=%s", tbuf);
                    406:        }
                    407:        if (domain != NULL)
                    408:                fprintf(sb, "; domain=%s", domain);
                    409:        if (path != NULL)
                    410:                fprintf(sb, "; path=%s", path);
                    411:        if (secure)
                    412:                fprintf(sb, "; secure");
                    413:        hval = string_buf_content(sb, 1);
                    414:        fclose(sb);
                    415:        if (hval == NULL)
                    416:                return (-1);
                    417: 
                    418:        /* Set cookie header value */
                    419:        if (http_response_set_header(resp,
                    420:            0, HTTP_HEADER_SET_COOKIE, "%s", hval) == -1) {
                    421:                FREE(TYPED_MEM_TEMP, hval);
                    422:                return (-1);
                    423:        }
                    424:        FREE(TYPED_MEM_TEMP, hval);
                    425: 
                    426:        /* Done */
                    427:        return (0);
                    428: }
                    429: 
                    430: /*
                    431:  * Remove authorization cookie.
                    432:  */
                    433: int
                    434: http_servlet_cookieauth_logout(const char *cookiename, const char *path,
                    435:        const char *domain, struct http_response *resp)
                    436: {
                    437:        static const time_t past = 0;
                    438:        char tbuf[64];
                    439:        struct tm tm;
                    440:        char *hval;
                    441:        FILE *sb;
                    442: 
                    443:        /* Create string output buffer */
                    444:        if ((sb = string_buf_output(TYPED_MEM_TEMP)) == NULL)
                    445:                return (-1);
                    446: 
                    447:        /* Construct cookie header value */
                    448:        strftime(tbuf, sizeof(tbuf), COOKIE_TIME_FMT, gmtime_r(&past, &tm));
                    449:        fprintf(sb, "%s=x; expires=%s", cookiename, tbuf);
                    450:        if (domain != NULL)
                    451:                fprintf(sb, "; domain=%s", domain);
                    452:        if (path != NULL)
                    453:                fprintf(sb, "; path=%s", path);
                    454:        hval = string_buf_content(sb, 1);
                    455:        fclose(sb);
                    456:        if (hval == NULL)
                    457:                return (-1);
                    458: 
                    459:        /* Set cookie header value */
                    460:        if (http_response_set_header(resp, 0,
                    461:            HTTP_HEADER_SET_COOKIE, "%s", hval) == -1) {
                    462:                FREE(TYPED_MEM_TEMP, hval);
                    463:                return (-1);
                    464:        }
                    465:        FREE(TYPED_MEM_TEMP, hval);
                    466: 
                    467:        /* Done */
                    468:        return (0);
                    469: }
                    470: 
                    471: /*
                    472:  * Get username.
                    473:  */
                    474: char *
                    475: http_servlet_cookieauth_user(const char *privkey, const void *id, size_t idlen,
                    476:        const char *cookiename, struct http_request *req, const char *mtype)
                    477: {
                    478:        struct cookieauth auth;
                    479:        struct structs_data idd;
                    480:        char *username;
                    481: 
                    482:        /* Get valid authorization structure, if there is one */
                    483:        idd.data = (u_char *)id;
                    484:        idd.length = idlen;
                    485:        if (http_servlet_cookieauth_get(privkey,
                    486:            &idd, cookiename, req, &auth) == -1)
                    487:                return (NULL);
                    488: 
                    489:        /* Get copy of username */
                    490:        if ((username = structs_get_string(&cookieauth_type,
                    491:            "username", &auth, mtype)) == NULL)
                    492:                alogf(LOG_ERR, "%s: %m", "structs_get_string");
                    493: 
                    494:        /* Free auth structure */
                    495:        structs_free(&cookieauth_type, NULL, &auth);
                    496: 
                    497:        /* Return username */
                    498:        return (username);
                    499: }
                    500: 
                    501: /*
                    502:  * Get valid authorization structure if there is one.
                    503:  */
                    504: static int
                    505: http_servlet_cookieauth_get(const char *privkey, const struct structs_data *id,
                    506:        const char *cookiename, struct http_request *req,
                    507:        struct cookieauth *auth)
                    508: {
                    509:        const int namelen = strlen(cookiename);
                    510:        const time_t now = time(NULL);
                    511:        const char *hval;
                    512:        const char *next;
                    513: 
                    514:        /* Get cookie header */
                    515:        if ((hval = http_request_get_header(req, HTTP_HEADER_COOKIE)) == NULL)
                    516:                goto invalid;
                    517: 
                    518:        /* Find our cookie */
                    519:        for ( ; *hval != '\0'; hval = next) {
                    520:                u_char md5[MD5_DIGEST_LENGTH];
                    521:                struct structs_data data;
                    522:                char valbuf[512];
                    523:                const char *eq;
                    524:                char ebuf[128];
                    525:                int vallen;
                    526: 
                    527:                /* Get next cookie and compare name */
                    528:                while (isspace((u_char)*hval))
                    529:                        hval++;
                    530:                if ((eq = strchr(hval, '=')) == NULL)
                    531:                        break;
                    532:                if ((next = strchr(eq + 1, ';')) == NULL) {
                    533:                        next = eq + strlen(eq);
                    534:                        vallen = strlen(eq + 1);
                    535:                } else {
                    536:                        vallen = next - (eq + 1);
                    537:                        next++;
                    538:                }
                    539:                if (strncmp(hval, cookiename, namelen) != 0
                    540:                    || hval + namelen != eq)
                    541:                        continue;
                    542: 
                    543:                /* Isolate cookie value */
                    544:                if (vallen > sizeof(valbuf) - 1) {
                    545:                        DBG(HTTP_SERVLET_COOKIEAUTH, "cookie too long");
                    546:                        continue;
                    547:                }
                    548:                memcpy(valbuf, hval + namelen + 1, vallen);
                    549:                valbuf[vallen] = '\0';
                    550: 
                    551:                /* Decode base64 data into binary data */
                    552:                if (structs_init(&authcookie_data_type, NULL, &data) == -1) {
                    553:                        alogf(LOG_ERR, "%s: %m", "structs_init");
                    554:                        continue;
                    555:                }
                    556:                if (structs_set_string(&authcookie_data_type,
                    557:                    NULL, valbuf, &data, NULL, 0) == -1) {
                    558:                        DBG(HTTP_SERVLET_COOKIEAUTH,
                    559:                            "error decoding base64: %s", ebuf);
                    560:                        structs_free(&authcookie_data_type, NULL, &data);
                    561:                        continue;
                    562:                }
                    563: 
                    564: #if PDEL_DEBUG
                    565:                if (PDEL_DEBUG_ENABLED(HTTP_SERVLET_COOKIEAUTH))
                    566:                        dump_data(data.data, data.length, "COOKIE DATA");
                    567: #endif
                    568: 
                    569:                /* Initialize the struct cookieauth */
                    570:                if (structs_init(&cookieauth_type, NULL, auth) == -1) {
                    571:                        alogf(LOG_ERR, "%s: %m", "structs_init");
                    572:                        continue;
                    573:                }
                    574: 
                    575:                /* Decode binary data into the struct cookieauth */
                    576:                if (structs_set_binary(&cookieauth_type, NULL, &data,
                    577:                    auth, ebuf, sizeof(ebuf)) == -1) {
                    578:                        DBG(HTTP_SERVLET_COOKIEAUTH,
                    579:                            "error decoding auth data: %s", ebuf);
                    580:                        structs_free(&cookieauth_type, NULL, auth);
                    581:                        structs_free(&authcookie_data_type, NULL, &data);
                    582:                        continue;
                    583:                }
                    584:                structs_free(&authcookie_data_type, NULL, &data);
                    585: 
                    586: #if PDEL_DEBUG
                    587:                if (PDEL_DEBUG_ENABLED(HTTP_SERVLET_COOKIEAUTH)) {
                    588:                        printf("COOKIE AUTH STRUCTURE\n");
                    589:                        structs_xml_output(&cookieauth_type,
                    590:                            "auth", NULL, auth, stdout, NULL, STRUCTS_XML_FULL);
                    591:                }
                    592: #endif
                    593: 
                    594:                /* Validate auth cookie timestamp and expiration */
                    595:                if (auth->timestamp > now
                    596:                    || (auth->expire != 0 && now >= auth->expire)
                    597:                    || (auth->linger != 0
                    598:                      && now >= auth->timestamp + auth->linger)) {
                    599:                        DBG(HTTP_SERVLET_COOKIEAUTH, "expired cookie");
                    600:                        structs_free(&cookieauth_type, NULL, auth);
                    601:                        continue;
                    602:                }
                    603: 
                    604:                /* Validate auth cookie identifier */
                    605:                if (structs_equal(&authcookie_data_type,
                    606:                    NULL, &auth->id, id) != 1) {
                    607:                        DBG(HTTP_SERVLET_COOKIEAUTH, "wrong system id");
                    608:                        structs_free(&cookieauth_type, NULL, auth);
                    609:                        continue;
                    610:                }
                    611: 
                    612:                /* Validate auth cookie RSA signature */
                    613:                if (http_servlet_cookieauth_md5(auth, md5) == -1) {
                    614:                        alogf(LOG_ERR, "%s: %m", "http_servlet_cookieauth_md5");
                    615:                        structs_free(&cookieauth_type, NULL, auth);
                    616:                        return (-1);
                    617:                }
                    618:                if (!rsa_util_verify_priv(privkey, md5,
                    619:                    auth->sig.data, auth->sig.length)) {
                    620:                        DBG(HTTP_SERVLET_COOKIEAUTH, "invalid RSA signature");
                    621:                        structs_free(&cookieauth_type, NULL, auth);
                    622:                        continue;
                    623:                }
                    624: 
                    625:                /* OK */
                    626:                return (0);
                    627:        }
                    628: 
                    629: invalid:
                    630:        /* No valid cookie found */
                    631:        errno = EACCES;
                    632:        return (-1);
                    633: }
                    634: 
                    635: /*
                    636:  * Compute MD5 for RSA signature.
                    637:  */
                    638: static int
                    639: http_servlet_cookieauth_md5(const struct cookieauth *auth, u_char *md5)
                    640: {
                    641:        struct structs_data data;
                    642:        struct cookieauth copy;
                    643:        MD5_CTX ctx;
                    644: 
                    645:        /* Copy supplied auth structure */
                    646:        if (structs_get(&cookieauth_type, NULL, auth, &copy) == -1)
                    647:                return (-1);
                    648: 
                    649:        /* Zero out the 'sig' field */
                    650:        FREE(DATA_MEM_TYPE, copy.sig.data);
                    651:        memset(&copy.sig, 0, sizeof(copy.sig));
                    652: 
                    653:        /* Create binary encoding of 'copy' */
                    654:        if (structs_get_binary(&cookieauth_type,
                    655:            NULL, &copy, DATA_MEM_TYPE, &data) == -1) {
                    656:                alogf(LOG_ERR, "%s: %m", "structs_get_binary");
                    657:                structs_free(&cookieauth_type, NULL, &copy);
                    658:                return (-1);
                    659:        }
                    660:        structs_free(&cookieauth_type, NULL, &copy);
                    661: 
                    662:        /* Compute MD5 of that */
                    663:        MD5_Init(&ctx);
                    664:        MD5_Update(&ctx, data.data, data.length);
                    665:        MD5_Final(md5, &ctx);
                    666: 
                    667:        /* Done */
                    668:        structs_free(&authcookie_data_type, NULL, &data);
                    669:        return (0);
                    670: }
                    671: 
                    672: #if PDEL_DEBUG
                    673: /*
                    674:  * Dump some data.
                    675:  */
                    676: static void
                    677: dump_data(const void *data, u_int plen, const char *fmt, ...)
                    678: {
                    679:        const u_char *pkt = data;
                    680:        const int num = 16;
                    681:        va_list args;
                    682:        int i, j;
                    683: 
                    684:        va_start(args, fmt);
                    685:        vprintf(fmt, args);
                    686:        printf("\n");
                    687:        va_end(args);
                    688:        for (i = 0; i < ((plen + num - 1) / num) * num; i += num) {
                    689:                printf("0x%04x  ", i);
                    690:                for (j = i; j < i + num; j++) {
                    691:                        if (j < plen)
                    692:                                printf("%02x", pkt[j]);
                    693:                        else
                    694:                                printf("  ");
                    695:                        if ((j % 2) == 1)
                    696:                                printf(" ");
                    697:                }
                    698:                printf("       ");
                    699:                for (j = i; j < i + num; j++) {
                    700:                        if (j < plen) {
                    701:                                printf("%c", isprint((u_char)pkt[j]) ?
                    702:                                    pkt[j] : '.');
                    703:                        }
                    704:                }
                    705:                printf("\n");
                    706:        }
                    707: }
                    708: #endif
                    709: 

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>