/* ==================================================================== * 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 . * */ /* ==================================================================== * accessCookie Module * ==================================================================== * Author: Jürgen eT Mangler * eMail: juergen.mangler@univie.ac.at, et@wkv.at * * Version: 0.4 (Clueless) * Date: 27 Sep 2003 * */ #include "httpd.h" #include "http_core.h" #include "http_config.h" #include "http_log.h" #include "http_request.h" #include "mysql.h" typedef struct { int Engine; int Timetrack; int Timetrack_Distance; char *Server; char *Database; char *Table; char *Username; char *Password; char *Name; int Method; char *where; } accessCookie_conf; module MODULE_VAR_EXPORT accessCookie_module; static void *create_accessCookie_dir_config(pool *p, char *dummy) { accessCookie_conf* conf = (accessCookie_conf *) ap_pcalloc(p, sizeof(accessCookie_conf)); conf->Engine = 0; conf->Timetrack = 0; conf->Timetrack_Distance = 0; conf->Server = NULL; conf->Database = NULL; conf->Table = NULL; conf->Username = NULL; conf->Password = NULL; conf->Name = NULL; conf->Method = 0; conf->where = NULL; return (void *) conf; } static const int checkDigit(cmd_parms *cmd, char *eTest) { return (!strcmp(ap_psprintf(cmd->pool,"%i",atoi(eTest)),eTest) ? atoi(eTest) : 0); } static const char *accessCookie_timetrack (cmd_parms *cmd, void *dv, char *arg) { accessCookie_conf *conf = (accessCookie_conf *) dv; switch (*((int *)cmd->info)) { case 1: if (!(strcasecmp(arg, "off"))) { conf->Timetrack = 0; } else if (!(strcasecmp(arg, "static"))) { conf->Timetrack = 1; } else if (!(strcasecmp(arg, "distance"))) { conf->Timetrack = 2; } else { return "accessCookie_Timetrack takes one argument, off|static|distance"; } break; case 2: conf->Timetrack_Distance = checkDigit(cmd,arg); if (!conf->Timetrack_Distance) { return "accessCookie_Timetrack_Distance takes one argument, a digit > 0"; } break; } return NULL; } static const char *accessCookie_engine (cmd_parms *cmd, void *dv, char *arg) { accessCookie_conf *conf = (accessCookie_conf *) dv; if (!(strcasecmp(arg, "on"))) { conf->Engine = 1; } else if (!(strcasecmp(arg, "off"))) { conf->Engine = 0; } else { return "accessCookie_Engine takes one argument, on|off"; } return NULL; } static const char *accessCookie_str (cmd_parms *cmd, void *dv, char *arg) { accessCookie_conf *conf = (accessCookie_conf *) dv; switch (*((int *)cmd->info)) { case 1: conf->Server = arg;break; case 2: conf->Database = arg;break; case 3: conf->Table = arg;break; case 4: conf->Username = arg;break; case 5: conf->Password = arg;break; case 6: conf->Name = arg;break; } return NULL; } static const char *accessCookie_data (cmd_parms *cmd, void *dv, char *arg1, char *arg2) { accessCookie_conf *conf = (accessCookie_conf *) dv; if ((!strcasecmp(arg1, "use")) && (!strcasecmp(arg2, "all"))) { conf->Method = 1; return NULL; } else if ((!strcasecmp(arg1, "use")) && (!strcasecmp(arg2, "none"))) { conf->Method = 2; return NULL; } else if ((!strcasecmp(arg1, "keep")) && (!strcasecmp(arg2, "alive"))) { conf->Method = 4; return NULL; } else if (!strcasecmp(arg1, "where")) { conf->Method = 3; conf->where = arg2; return NULL; } return "allowCookie takes two arguments, [use all|none] | [where mySQL-WHERE-Statement]"; } static int accessCookie_Server = 1; static int accessCookie_Database = 2; static int accessCookie_Table = 3; static int accessCookie_Username = 4; static int accessCookie_Password = 5; static int accessCookie_Name = 6; static int accessCookie_Timetrack = 1; static int accessCookie_Timetrack_Distance = 2; static const command_rec access_cmds[] = { {"accessCookie_Engine", accessCookie_engine, NULL, OR_LIMIT, TAKE1, "on|off"}, {"accessCookie_Server", accessCookie_str, &accessCookie_Server, OR_LIMIT, TAKE1, "Server-Name"}, {"accessCookie_Database", accessCookie_str, &accessCookie_Database, OR_LIMIT, TAKE1, "Database-Name"}, {"accessCookie_Table", accessCookie_str, &accessCookie_Table, OR_LIMIT, TAKE1, "Table-Name"}, {"accessCookie_Username", accessCookie_str, &accessCookie_Username, OR_LIMIT, TAKE1, "Username"}, {"accessCookie_Password", accessCookie_str, &accessCookie_Password, OR_LIMIT, TAKE1, "Password"}, {"accessCookie_Name", accessCookie_str, &accessCookie_Name, OR_LIMIT, TAKE1, "Name of Cookie"}, {"accessCookie_Timetrack", accessCookie_timetrack, &accessCookie_Timetrack, OR_LIMIT, TAKE1, "off|static|distance"}, {"accessCookie_Timetrack_Distance", accessCookie_timetrack, &accessCookie_Timetrack_Distance, OR_LIMIT, TAKE1, "a digit > 0"}, {"allowCookie", accessCookie_data, NULL, OR_LIMIT, TAKE2, "[use all|none] | [keep alive] | [where mySQL-WHERE-Statement]"}, {NULL} }; static void addEnvir (MYSQL_RES *result, table *env, pool *p) { MYSQL_ROW currow = mysql_fetch_row (result); MYSQL_FIELD *curfield; int i = 0; for (i=0; i < mysql_num_fields(result); i++) { curfield = mysql_fetch_field_direct(result,i); if (!strncmp("accessCookie_", curfield->name ,13)) { ap_table_setn (env,ap_pstrdup(p,curfield->name),ap_pstrdup(p,currow[i])); } } } static int getQuery (char *query, accessCookie_conf *conf, table *env, pool *p) { MYSQL connection; MYSQL_RES *results; int ret; mysql_init(&connection); if (!mysql_real_connect (&connection,conf->Server,conf->Username,conf->Password,conf->Database,0,NULL,0)) { ret=1;goto retA; } if (mysql_query (&connection, query)) { ret=2;goto retB; } if (!(results = mysql_store_result (&connection))) { ret=3;goto retB; } if (mysql_num_rows(results) == 0) ret=4; else if (mysql_num_rows(results) > 1) ret=5; else { ret=6; addEnvir(results,env,p); } mysql_free_result(results); retB: mysql_close(&connection); retA: return ret; } static int setDistance (accessCookie_conf *conf, char *eWhere, pool *rPool) { MYSQL connection; char *query = ap_pstrcat(rPool, "update ", conf->Table, " set eTIME=DATE_ADD(NOW(),INTERVAL ", ap_psprintf(rPool, "%i",conf->Timetrack_Distance), " SECOND)", eWhere, ";", NULL); int ret = 0; mysql_init(&connection); if (!mysql_real_connect (&connection,conf->Server,conf->Username,conf->Password,conf->Database,0,NULL,0)) goto retA; if (mysql_query (&connection, query)) goto retB; ret=1; retB: mysql_close(&connection); retA: return ret; } static char *getCookie(request_rec *r,char *name) { char *cookie; char *part; char *value = ""; if (!(cookie = (char *)ap_table_get(r->headers_in, "Cookie"))) { return NULL; } part = ap_pstrcat (r->pool, cookie, ";", NULL); for (part=strtok(part, " ;\n\r\t\f"); (part); part=strtok(NULL, " ;\n\r\t\f")) { while (part && !(value = strchr (part, (int) '='))) { part = strtok (NULL, " ;\n\r\t\f"); } if (++value) { if (!strcasecmp(ap_getword(r->pool,(const char **)&part,'='), name)) { return value; } } } return NULL; } static int check_dir_accessCookie(request_rec *r) { accessCookie_conf *conf = (accessCookie_conf *) ap_get_module_config(r->per_dir_config, &accessCookie_module); char *eQuery = "select * from "; char *eWhere; char *value; char *errText = ""; if (conf->Engine == 0) return OK; if (conf->Method == 2) { errText = "%s: accessCookie - client denied"; goto errOut; } if ((conf->Server == NULL) || (conf->Database == NULL) || (conf->Table == NULL) || (conf->Username == NULL) || (conf->Password == NULL) || (conf->Name == NULL) || (conf->Method == 0)) { errText = "%s: accessCookie - missing parameters"; goto errOut; } /************************************************************************* * inititalize * *************************************************************************/ value = getCookie(r,conf->Name); eQuery = ap_pstrcat(r->pool, eQuery, conf->Table, NULL); eWhere = ap_pstrcat(r->pool, " where COOKIE='", value , "'", NULL); if (conf->Timetrack) { eWhere = ap_pstrcat(r->pool, eWhere, " and eTIME>=NOW()", conf->where, NULL); } /************************************************************************* * keep alive * *************************************************************************/ if (conf->Method == 4) { if (conf->Timetrack == 2) { if (!value) { ap_table_setn (r->subprocess_env,ap_pstrdup(r->pool,"accessCookie_ALIVE"),ap_pstrdup(r->pool,"0")); return OK; } } else { errText = "%s: accessCookie - Works only in Timetrack distance mode"; goto errOut; } } /************************************************************************* * use all, where * *************************************************************************/ if (!value) { errText = "%s: accessCookie - missing cookie"; goto errOut; } if (conf->Method == 3) { eWhere = ap_pstrcat(r->pool, eWhere, " and ", conf->where, NULL); } switch (getQuery(ap_pstrcat(r->pool, eQuery, eWhere, ";", NULL),conf,r->subprocess_env,r->pool)) { case 1: errText = "%s: accessCookie - can't connect to server/database";goto errOut; case 2: errText = "%s: accessCookie - can't execute query";goto errOut; case 3: errText = "%s: accessCookie - can't get results from database";goto errOut; case 4: if (conf->Method == 4) { ap_table_setn (r->subprocess_env,ap_pstrdup(r->pool,"accessCookie_ALIVE"),ap_pstrdup(r->pool,"0")); return OK; } else { errText = "%s: accessCookie - client denied"; goto errOut; } case 5: errText = "%s: accessCookie - holy shit, more than one matching cookie";goto errOut; case 6: if (conf->Timetrack == 2) { if (!conf->Timetrack_Distance) { errText = "%s: accessCookie - Timtrack_Distance not set"; goto errOut; } if (!setDistance(conf,eWhere,r->pool)) { errText = "%s: accessCookie - can't update eTIME"; goto errOut; } if (conf->Method == 4) { ap_table_setn (r->subprocess_env,ap_pstrdup(r->pool,"accessCookie_ALIVE"),ap_pstrdup(r->pool,"1")); } } return OK; } /************************************************************************* * forbidden * *************************************************************************/ errOut: ap_log_rerror(APLOG_MARK, APLOG_NOERRNO|APLOG_ERR, r, errText , r->filename); return FORBIDDEN; } module MODULE_VAR_EXPORT accessCookie_module = { STANDARD_MODULE_STUFF, NULL, /* initializer */ create_accessCookie_dir_config, /* dir config creater */ NULL, /* dir merger --- default is to override */ NULL, /* server config */ NULL, /* merge server config */ access_cmds, /* Command Array */ NULL, /* handlers */ NULL, /* filename translation */ NULL, /* check_user_id */ NULL, /* check auth */ check_dir_accessCookie, /* check access */ NULL, /* type_checker */ NULL, /* fixups */ NULL, /* logger */ NULL, /* header parser */ NULL, /* child_init */ NULL, /* child_exit */ NULL /* post read-request */ };