Annotation of embedaddon/libpdel/http/servlet/http_servlet_cookieauth.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:
! 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, ©) == -1)
! 647: return (-1);
! 648:
! 649: /* Zero out the 'sig' field */
! 650: FREE(DATA_MEM_TYPE, copy.sig.data);
! 651: memset(©.sig, 0, sizeof(copy.sig));
! 652:
! 653: /* Create binary encoding of 'copy' */
! 654: if (structs_get_binary(&cookieauth_type,
! 655: NULL, ©, DATA_MEM_TYPE, &data) == -1) {
! 656: alogf(LOG_ERR, "%s: %m", "structs_get_binary");
! 657: structs_free(&cookieauth_type, NULL, ©);
! 658: return (-1);
! 659: }
! 660: structs_free(&cookieauth_type, NULL, ©);
! 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>