/* ==================================================================== * Copyright (c) 1996 The Apache Group. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * 3. All advertising materials mentioning features or use of this * software must display the following acknowledgment: * "This product includes software developed by the Apache Group * for use in the Apache HTTP server project (http://www.apache.org/)." * * 4. The names "Apache Server" and "Apache Group" must not be used to * endorse or promote products derived from this software without * prior written permission. * * 5. Redistributions of any form whatsoever must retain the following * acknowledgment: * "This product includes software developed by the Apache Group * for use in the Apache HTTP server project (http://www.apache.org/)." * * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR * IT'S CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED * OF THE POSSIBILITY OF SUCH DAMAGE. * ==================================================================== * * This software consists of voluntary contributions made by many * individuals on behalf of the Apache Group and was originally based * on public domain software written at the National Center for * Supercomputing Applications, University of Illinois, Urbana-Champaign. * For more information on the Apache Group and the Apache HTTP server * project, please see . * */ #include "httpd.h" #include "http_config.h" /* * cookieName is the name of the cookie we look for to convert to an * Authorization header. * * The config command AuthCookieName sets this value. If it is not set, * we do no Cookie->Authorization conversion. * * cookieOverrides determines if the cookie value takes precedence over a * real Authorization header. If the AuthCookieOverride config option is * "On", then we always use the Cookie version if available. If it is "Off" * then we let any existing "Authorization" header remain unaltered. The * default is "Off" if it is not specified. If you turn this function on, * then you better make sure the password in the cookie matches that in your * database or your users will be seriously confused why they can't get in * even after properly typing their password. * * We assume the Cookie header comes to us as UserID:password with special * characters escaped using the standard %xx escapes. Notably, spaces * and semicolons need to be escaped. It doesn't hurt to escape all of * the characters, as this helps obscure the meaning of the Cookie to * the casual observer. It is up to the web site to initially set this * cookie in the user's browser. A good place to do that is when the * password is assigned. * * In order for this clever trick to work, we must ensure that this code * runs prior to any other authorization module. To do this, the config * line for this module must appear below any other auth module in the * Apache Configuration file. * * $Id: mod_auth_cookie.c,v 1.6 1996/12/19 19:25:05 khera Exp $ */ typedef struct { char *cookieName; int cookieOverrides; } cookie_auth_config_rec; static void *create_cookie_auth_dir_config(pool * p, char *d) { cookie_auth_config_rec *m = ap_pcalloc(p, sizeof(cookie_auth_config_rec)); if (!m) return NULL; /* failure to get memory is a bad thing */ m->cookieName = NULL; m->cookieOverrides = 0; return (void *)m; } static const char *set_override(cmd_parms *cmd, void *mrec, int arg) { ((cookie_auth_config_rec *)mrec)->cookieOverrides = arg; return NULL; } static command_rec cookie_auth_cmds[] = { { "AuthCookieName", ap_set_string_slot, (void *) XtOffsetOf(cookie_auth_config_rec, cookieName), OR_AUTHCFG, TAKE1, "Name of cookie to convert to Authorization record" }, { "AuthCookieOverride", set_override, NULL, OR_AUTHCFG, FLAG, "Cookie Auth overrides real Authorization header if On" }, { NULL } }; module cookie_auth_module; /* * This uuencode function and the idea for faking the basic authentication * was taken from the apache_ssl.c code by Ben Laurie and then modified for * use here. */ static const char six2pr[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; /* return the string in uuencoded form */ static char * uuencode(pool * p, const char *szFrom) { const unsigned char *s; int rlen = (strlen(szFrom) + 1) * 4 / 3 + 3; char *result = ap_palloc(p, rlen); char *szTo = result; for (s = (const unsigned char *) szFrom; *s; s += 3) { *szTo++ = six2pr[s[0] >> 2]; *szTo++ = six2pr[(s[0] << 4 | s[1] >> 4) & 0x3f]; if (!s[0]) break; *szTo++ = six2pr[(s[1] << 2 | s[2] >> 6) & 0x3f]; if (!s[1]) break; *szTo++ = six2pr[s[2] & 0x3f]; if (!s[2]) break; } *szTo++ = '\0'; #if DEBUG fprintf(stderr, "UUencoded `%s' as `%s'\n", szFrom, result); #endif return result; } /* * this doesn't really authenticate the user, but creates a fake * Authorization header based on the provided cookie */ static int cookie_authenticate_basic_user(request_rec * r) { cookie_auth_config_rec *sec = (cookie_auth_config_rec *) ap_get_module_config(r->per_dir_config, &cookie_auth_module); const char *cookie; if (!sec->cookieName) return DECLINED; /* we're not configured */ if (r->connection->user) return DECLINED; /* too late for us to run */ /* * if user supplied Authorization info, let it take precedence unless * we are overriding it. this is potentially confusing to users to * override it. */ if (!sec->cookieOverrides && ap_table_get(r->headers_in, "Authorization")) return DECLINED; /* * now check if there is a cookie set by the name specified. if so, * then convert it into an Authorization header. */ if ((cookie = ap_table_get(r->headers_in, "Cookie"))) { char buf[MAX_STRING_LEN]; char *value = strstr(cookie, sec->cookieName); if (!value) /* our cookie was not found */ return DECLINED; value += strlen(sec->cookieName) + 1; /* get past the "=" sign */ strncpy(buf, value, MAX_STRING_LEN - 1); buf[MAX_STRING_LEN - 1] = '\0'; value = strchr(buf, ';'); if (value) *value = '\0'; /* Ignore anything after a ; */ ap_unescape_url(buf); /* assume comes in with %xx escapes */ value = ap_pstrcat(r->pool, "Basic ", uuencode(r->pool, buf), NULL); ap_table_set(r->headers_in, "Authorization", value); #if DEBUG fprintf(stderr, "AuthCookie set `%s'\nas `%s'\n", buf, value); #endif } return DECLINED; /* let the "real" authentication happen */ } module cookie_auth_module = { STANDARD_MODULE_STUFF, NULL, /* initializer */ create_cookie_auth_dir_config, /* dir config creater */ NULL, /* dir merger --- default is to override */ NULL, /* server config */ NULL, /* merge server config */ cookie_auth_cmds, /* command table */ NULL, /* handlers */ NULL, /* filename translation */ cookie_authenticate_basic_user, /* check_user_id */ NULL, /* check auth */ NULL, /* check access */ NULL, /* type_checker */ NULL, /* fixups */ NULL /* logger */ };