/* ==================================================================== * 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.9 2000/06/09 19:14:06 khera Exp $ */ typedef struct { char *cookieName; int cookieOverrides; int cookieBase64; } 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; m->cookieBase64 = 0; return (void *)m; } 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", ap_set_flag_slot, (void*)XtOffsetOf(cookie_auth_config_rec, cookieOverrides), OR_AUTHCFG, FLAG, "Cookie Auth overrides real Authorization header if On"}, { "AuthCookieBase64", ap_set_flag_slot, (void*)XtOffsetOf(cookie_auth_config_rec, cookieBase64), OR_AUTHCFG, FLAG, "Cookies are Base64 encoded 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); char *decode_buf; 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 ; */ if (sec->cookieBase64) decode_buf = ap_pbase64decode(r->pool, buf); else { ap_unescape_url(buf); /* assume comes in with %xx escapes */ decode_buf = buf; } value = ap_pstrcat(r->pool,"Basic ",uuencode(r->pool,decode_buf),NULL); ap_table_set(r->headers_in, "Authorization", value); #if DEBUG fprintf(stderr,"AuthCookie set `%s'\nas `%s'\n",decode_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 */ NULL, /* header parser */ NULL, /* child_init */ NULL, /* child_exit */ NULL /* post read-request */ };