/* ====================================================================
* 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 */
};