/* ==================================================================== * Copyright (c) 1995 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 . * */ /* Netscape Cookies Access control * This module allows access, and pretends to the rest of the * system that the user used BasicAuth to get in. In the very * near future we will have to use some encryption to make * second-guess spoofing harder. * * (c) Dirk-Willem van Gulik, June 1996, for * http://ewse.ceo.org/. and http://enrm.ceo.org/. * a http://www.ceo.org/ CEO Programme Project. * * Example: * Cookie_Access on * Cookie_AuthFile * Cookie_Authorative off * Cookie_MustGive off * Cookie_EncryptedCookies on * * * require user name... * or * require valid-user * * * Person to contact/blame * Dirk.vanGulik@jrc.it * * Revision History * 0.0 First version * */ #include "httpd.h" #include "http_log.h" /* log reason */ #include "http_config.h" /* config read stuff */ #include "http_protocol.h" /* basic auth */ #ifndef HAS_NO_CRYPT_H #include #endif /* Arbitrary limit for the length of the * value of the cookie name and the cookie * value */ #define MAX_USER_NAME_LEN (32) #define MAX_COOKIE_VALUE_LEN (32) /* Do you really want to keep the connection open ?? */ #undef KEEP_MSQL_CONNECTION_OPEN module cookie_file_access_module; typedef struct { int cookie_file_active; /* on/off flag */ char *cookie_file_auth_file; /* .htpasswd like file */ int cookie_file_auth_authorative;/* do we have a final say ? */ int cookie_file_auth_encrypted; /* security ? */ int cookie_file_auth_must; /* Enforce cookie eating ? */ } cookie_file_auth_config_rec; void * create_cookie_file_access_config (pool * p, char *d) { cookie_file_auth_config_rec *sec = (cookie_file_auth_config_rec *) pcalloc (p, sizeof (cookie_file_auth_config_rec)); /* Just to illustrate the defaults forcefully */ sec->cookie_file_active = 0; /* not active */ sec->cookie_file_auth_file=NULL; /* no file.. */ sec->cookie_file_auth_authorative = 0; /* do we have a final say ? */ sec->cookie_file_auth_encrypted = 1; /* security ? */ sec->cookie_file_auth_must = 0; /* Forcefull cooky eating */ return sec; } char * cookie_file_set_string_slot (cmd_parms * cmd, char *struct_ptr, char *arg) { *(char **) (struct_ptr + ((int) cmd->info)) = pstrdup (cmd->pool, arg); return NULL; } char * cookie_file_set_flag_slot (cmd_parms * cmd, char *struct_ptr, int arg) { (int) *(char **) (struct_ptr + ((int) cmd->info)) = arg; return NULL; } command_rec cookie_file_access_cmds[] = { {"Cookie_Access", cookie_file_set_flag_slot, (void *) XtOffsetOf (cookie_file_auth_config_rec, cookie_file_active), OR_AUTHCFG, FLAG, "Switch cookie access on/off"}, {"Cookie_AccFile", cookie_file_set_string_slot, (void *) XtOffsetOf (cookie_file_auth_config_rec, cookie_file_auth_file), OR_AUTHCFG, TAKE1, "'.htpasswd' like file with cookie name/value pairs and the userid"}, {"Cookie_Authorative", cookie_file_set_flag_slot, (void *) XtOffsetOf (cookie_file_auth_config_rec, cookie_file_auth_authorative), OR_AUTHCFG, FLAG, "When 'on' the Cookie is taken to be authorative and access control is not passed."}, {"Cookie_MustGive", cookie_file_set_flag_slot, (void *) XtOffsetOf (cookie_file_auth_config_rec, cookie_file_auth_must), OR_AUTHCFG, FLAG, "When 'on' the client must present a cookie."}, {"Cookie_EncryptedCookies", cookie_file_set_flag_slot, (void *) XtOffsetOf (cookie_file_auth_config_rec, cookie_file_auth_encrypted), OR_AUTHCFG, FLAG, "When 'on' the cookie values in the table are taken to be crypt()ed using your machines crypt() function."}, {NULL} }; int get_userid_and_cookie(request_rec *r, cookie_file_auth_config_rec *sec, char *cookie_file_name, /* in - cookie to look for */ char *cookie_file_value, /* out - (encrypted) cookie value to check */ char *userid /* out - UID to set if all is OK */ ) { FILE *f; char l[MAX_STRING_LEN]; char *u, *v,*w; if (!(sec -> cookie_file_auth_file)) { log_reason("No cookie-password file specified","",r); return 0; }; if(!(f=pfopen(r->pool, sec -> cookie_file_auth_file, "r"))) { log_reason ("Could not open cookie-password file", sec -> cookie_file_auth_file, r); return 0; } while(!(cfg_getline(l,MAX_STRING_LEN,f))) { if((l[0] == '#') || (!l[0])) continue; /* Format of the file is userID:name:value */ w = l; u = getword(r->pool, &w, ':'); /* u->userID */ v = getword(r->pool, &w, ':'); /* v->cookie name */ /* w->cookie value */ if(!strcmp(cookie_file_name,v)) { pfclose(r->pool, f); if (strlen(u)>=MAX_USER_NAME_LEN) { log_reason("Could not cope with a UserName in the cookie file, too long","",r); return 0; }; if (strlen(v)>=MAX_COOKIE_VALUE_LEN) { log_reason("Could not cope with a CookieValue in the cookie file, too long","",r); return 0; }; strcpy (cookie_file_value, v); strcpy (userid, u); return 1; } } pfclose(r->pool, f); return 0; } int cookie_file_authenticate (request_rec * r) { cookie_file_auth_config_rec *sec = (cookie_file_auth_config_rec *) get_module_config (r->per_dir_config, &cookie_file_access_module); conn_rec *c = r->connection; char *cookie, *sent_pw, *ptr; char *value, real_value[MAX_USER_NAME_LEN], real_uname[MAX_COOKIE_VALUE_LEN]; /* are we configured ? */ if (!(sec->cookie_file_active)) return DECLINED; /* Is there a cookie we can act on ? */ if (!(ptr = table_get (r->headers_in, "Cookie"))) { if (sec->cookie_file_auth_must) return AUTH_REQUIRED; return DECLINED; }; /* We do NOT have to use cookie access, the client * already gave us that stuff. */ if ((OK == get_basic_auth_pw (r, &sent_pw)) && (sent_pw)) return DECLINED; /* make a copy which we can destroy, keep room for the \0 and ; */ if (!(cookie = palloc (r->pool, 2 + strlen (ptr)))) { log_reason ("CookieAuth: Could not claim memory for a cookie", r->uri, r); return SERVER_ERROR; }; strcpy (cookie, ptr); /* Place the elephant in egypt. */ cookie[0 + strlen (ptr)] = ';'; cookie[1 + strlen (ptr)] = '\0'; /* Run Through The Cookies, (White)Space Or ; Separated ? */ for (cookie = strtok (cookie, " ;\n\r\t\f"); (cookie); cookie = strtok (NULL, " ;\n\r\t\f") ) { /* The cookie looks something like 'Blah=Bloh' where * Blah & Bloh are in the cookie_file_name and cookie_file_value * fields of the table. */ while ((!(value = strchr (cookie, (int) '='))) && (cookie)) { /* Misbaked cookie, should we log this, ignore or just give up ? */ cookie = strtok (NULL, " ;\n\r\t\f"); }; if (!(cookie)) break; *value = '\0'; value++; /* now look up, for the cookie name, which is pointed * to by 'cookie', the username and the real_value * of the cookie as stored in the db/file. */ real_value[0] = '\0'; real_uname[0] = '\0'; if (get_userid_and_cookie (r, sec, cookie, real_uname, real_value)) { /* Now do we have to crypt the incoming cookie * (for the second time!) to avoid having * usable cookies in the database. */ if (sec->cookie_file_auth_encrypted) { /* anyone know where the prototype for crypt is? * PLEASE NOTE: * The crypt function (at least under FreeBSD 2.0.5) returns * a ptr to a *static* array (max 120 chars) and does *not* * modify the string pointed at by sent_pw ! */ value = (char *) crypt (value, real_value); }; if (!(strcmp (value, real_value))) { /* Jup, this looks real good */ c->user = real_uname; c->auth_type ="COOKIE"; return OK; }; /* else ... we could log illegal cookies attempts here ?!*/ }; /* else we could log unfound cookies here ?!*/ }; /* end of for loop */ if (sec->cookie_file_auth_authorative) { note_basic_auth_failure (r); log_reason ("CookieAuth: No valid Cookie(s)", r->filename, r); return AUTH_REQUIRED; }; return DECLINED; } module cookie_file_access_module = { STANDARD_MODULE_STUFF, NULL, /* initializer */ create_cookie_file_access_config, /* dir config creater */ NULL, /* dir merger */ NULL, /* server config */ NULL, /* merge server configs */ cookie_file_access_cmds, /* command table */ NULL, /* handlers */ NULL, /* filename translation */ cookie_file_authenticate, /* check_user_id */ NULL, /* check auth */ NULL, /* check access */ NULL, /* type_checker */ NULL, /* fixups */ NULL, /* logger */ };