File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / lighttpd / src / mod_usertrack.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Mon Oct 14 10:32:48 2013 UTC (10 years, 8 months ago) by misho
Branches: lighttpd, MAIN
CVS tags: v1_4_33, HEAD
1.4.33

    1: #include "base.h"
    2: #include "log.h"
    3: #include "buffer.h"
    4: 
    5: #include "plugin.h"
    6: 
    7: #include <ctype.h>
    8: #include <stdlib.h>
    9: #include <string.h>
   10: 
   11: #include "md5.h"
   12: 
   13: /* plugin config for all request/connections */
   14: 
   15: typedef struct {
   16: 	buffer *cookie_name;
   17: 	buffer *cookie_domain;
   18: 	unsigned int cookie_max_age;
   19: } plugin_config;
   20: 
   21: typedef struct {
   22: 	PLUGIN_DATA;
   23: 
   24: 	plugin_config **config_storage;
   25: 
   26: 	plugin_config conf;
   27: } plugin_data;
   28: 
   29: /* init the plugin data */
   30: INIT_FUNC(mod_usertrack_init) {
   31: 	plugin_data *p;
   32: 
   33: 	p = calloc(1, sizeof(*p));
   34: 
   35: 	return p;
   36: }
   37: 
   38: /* detroy the plugin data */
   39: FREE_FUNC(mod_usertrack_free) {
   40: 	plugin_data *p = p_d;
   41: 
   42: 	UNUSED(srv);
   43: 
   44: 	if (!p) return HANDLER_GO_ON;
   45: 
   46: 	if (p->config_storage) {
   47: 		size_t i;
   48: 		for (i = 0; i < srv->config_context->used; i++) {
   49: 			plugin_config *s = p->config_storage[i];
   50: 
   51: 			buffer_free(s->cookie_name);
   52: 			buffer_free(s->cookie_domain);
   53: 
   54: 			free(s);
   55: 		}
   56: 		free(p->config_storage);
   57: 	}
   58: 
   59: 	free(p);
   60: 
   61: 	return HANDLER_GO_ON;
   62: }
   63: 
   64: /* handle plugin config and check values */
   65: 
   66: SETDEFAULTS_FUNC(mod_usertrack_set_defaults) {
   67: 	plugin_data *p = p_d;
   68: 	size_t i = 0;
   69: 
   70: 	config_values_t cv[] = {
   71: 		{ "usertrack.cookie-name",       NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },       /* 0 */
   72: 		{ "usertrack.cookie-max-age",    NULL, T_CONFIG_INT, T_CONFIG_SCOPE_CONNECTION },          /* 1 */
   73: 		{ "usertrack.cookie-domain",     NULL, T_CONFIG_STRING, T_CONFIG_SCOPE_CONNECTION },       /* 2 */
   74: 
   75: 		{ "usertrack.cookiename",        NULL, T_CONFIG_DEPRECATED, T_CONFIG_SCOPE_CONNECTION },
   76: 		{ NULL,                          NULL, T_CONFIG_UNSET, T_CONFIG_SCOPE_UNSET }
   77: 	};
   78: 
   79: 	if (!p) return HANDLER_ERROR;
   80: 
   81: 	p->config_storage = calloc(1, srv->config_context->used * sizeof(specific_config *));
   82: 
   83: 	for (i = 0; i < srv->config_context->used; i++) {
   84: 		plugin_config *s;
   85: 
   86: 		s = calloc(1, sizeof(plugin_config));
   87: 		s->cookie_name    = buffer_init();
   88: 		s->cookie_domain  = buffer_init();
   89: 		s->cookie_max_age = 0;
   90: 
   91: 		cv[0].destination = s->cookie_name;
   92: 		cv[1].destination = &(s->cookie_max_age);
   93: 		cv[2].destination = s->cookie_domain;
   94: 
   95: 		p->config_storage[i] = s;
   96: 
   97: 		if (0 != config_insert_values_global(srv, ((data_config *)srv->config_context->data[i])->value, cv)) {
   98: 			return HANDLER_ERROR;
   99: 		}
  100: 
  101: 		if (buffer_is_empty(s->cookie_name)) {
  102: 			buffer_copy_string_len(s->cookie_name, CONST_STR_LEN("TRACKID"));
  103: 		} else {
  104: 			size_t j;
  105: 			for (j = 0; j < s->cookie_name->used - 1; j++) {
  106: 				char c = s->cookie_name->ptr[j] | 32;
  107: 				if (c < 'a' || c > 'z') {
  108: 					log_error_write(srv, __FILE__, __LINE__, "sb",
  109: 							"invalid character in usertrack.cookie-name:",
  110: 							s->cookie_name);
  111: 
  112: 					return HANDLER_ERROR;
  113: 				}
  114: 			}
  115: 		}
  116: 
  117: 		if (!buffer_is_empty(s->cookie_domain)) {
  118: 			size_t j;
  119: 			for (j = 0; j < s->cookie_domain->used - 1; j++) {
  120: 				char c = s->cookie_domain->ptr[j];
  121: 				if (c <= 32 || c >= 127 || c == '"' || c == '\\') {
  122: 					log_error_write(srv, __FILE__, __LINE__, "sb",
  123: 							"invalid character in usertrack.cookie-domain:",
  124: 							s->cookie_domain);
  125: 
  126: 					return HANDLER_ERROR;
  127: 				}
  128: 			}
  129: 		}
  130: 	}
  131: 
  132: 	return HANDLER_GO_ON;
  133: }
  134: 
  135: #define PATCH(x) \
  136: 	p->conf.x = s->x;
  137: static int mod_usertrack_patch_connection(server *srv, connection *con, plugin_data *p) {
  138: 	size_t i, j;
  139: 	plugin_config *s = p->config_storage[0];
  140: 
  141: 	PATCH(cookie_name);
  142: 	PATCH(cookie_domain);
  143: 	PATCH(cookie_max_age);
  144: 
  145: 	/* skip the first, the global context */
  146: 	for (i = 1; i < srv->config_context->used; i++) {
  147: 		data_config *dc = (data_config *)srv->config_context->data[i];
  148: 		s = p->config_storage[i];
  149: 
  150: 		/* condition didn't match */
  151: 		if (!config_check_cond(srv, con, dc)) continue;
  152: 
  153: 		/* merge config */
  154: 		for (j = 0; j < dc->value->used; j++) {
  155: 			data_unset *du = dc->value->data[j];
  156: 
  157: 			if (buffer_is_equal_string(du->key, CONST_STR_LEN("usertrack.cookie-name"))) {
  158: 				PATCH(cookie_name);
  159: 			} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("usertrack.cookie-max-age"))) {
  160: 				PATCH(cookie_max_age);
  161: 			} else if (buffer_is_equal_string(du->key, CONST_STR_LEN("usertrack.cookie-domain"))) {
  162: 				PATCH(cookie_domain);
  163: 			}
  164: 		}
  165: 	}
  166: 
  167: 	return 0;
  168: }
  169: #undef PATCH
  170: 
  171: URIHANDLER_FUNC(mod_usertrack_uri_handler) {
  172: 	plugin_data *p = p_d;
  173: 	data_string *ds;
  174: 	unsigned char h[16];
  175: 	li_MD5_CTX Md5Ctx;
  176: 	char hh[32];
  177: 
  178: 	if (con->uri.path->used == 0) return HANDLER_GO_ON;
  179: 
  180: 	mod_usertrack_patch_connection(srv, con, p);
  181: 
  182: 	if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "Cookie"))) {
  183: 		char *g;
  184: 		/* we have a cookie, does it contain a valid name ? */
  185: 
  186: 		/* parse the cookie
  187: 		 *
  188: 		 * check for cookiename + (WS | '=')
  189: 		 *
  190: 		 */
  191: 
  192: 		if (NULL != (g = strstr(ds->value->ptr, p->conf.cookie_name->ptr))) {
  193: 			char *nc;
  194: 
  195: 			/* skip WS */
  196: 			for (nc = g + p->conf.cookie_name->used-1; *nc == ' ' || *nc == '\t'; nc++);
  197: 
  198: 			if (*nc == '=') {
  199: 				/* ok, found the key of our own cookie */
  200: 
  201: 				if (strlen(nc) > 32) {
  202: 					/* i'm lazy */
  203: 					return HANDLER_GO_ON;
  204: 				}
  205: 			}
  206: 		}
  207: 	}
  208: 
  209: 	/* set a cookie */
  210: 	if (NULL == (ds = (data_string *)array_get_unused_element(con->response.headers, TYPE_STRING))) {
  211: 		ds = data_response_init();
  212: 	}
  213: 	buffer_copy_string_len(ds->key, CONST_STR_LEN("Set-Cookie"));
  214: 	buffer_copy_string_buffer(ds->value, p->conf.cookie_name);
  215: 	buffer_append_string_len(ds->value, CONST_STR_LEN("="));
  216: 
  217: 
  218: 	/* taken from mod_auth.c */
  219: 
  220: 	/* generate shared-secret */
  221: 	li_MD5_Init(&Md5Ctx);
  222: 	li_MD5_Update(&Md5Ctx, (unsigned char *)con->uri.path->ptr, con->uri.path->used - 1);
  223: 	li_MD5_Update(&Md5Ctx, (unsigned char *)"+", 1);
  224: 
  225: 	/* we assume sizeof(time_t) == 4 here, but if not it ain't a problem at all */
  226: 	LI_ltostr(hh, srv->cur_ts);
  227: 	li_MD5_Update(&Md5Ctx, (unsigned char *)hh, strlen(hh));
  228: 	li_MD5_Update(&Md5Ctx, (unsigned char *)srv->entropy, sizeof(srv->entropy));
  229: 	LI_ltostr(hh, rand());
  230: 	li_MD5_Update(&Md5Ctx, (unsigned char *)hh, strlen(hh));
  231: 
  232: 	li_MD5_Final(h, &Md5Ctx);
  233: 
  234: 	buffer_append_string_encoded(ds->value, (char *)h, 16, ENCODING_HEX);
  235: 	buffer_append_string_len(ds->value, CONST_STR_LEN("; Path=/"));
  236: 	buffer_append_string_len(ds->value, CONST_STR_LEN("; Version=1"));
  237: 
  238: 	if (!buffer_is_empty(p->conf.cookie_domain)) {
  239: 		buffer_append_string_len(ds->value, CONST_STR_LEN("; Domain="));
  240: 		buffer_append_string_encoded(ds->value, CONST_BUF_LEN(p->conf.cookie_domain), ENCODING_REL_URI);
  241: 	}
  242: 
  243: 	if (p->conf.cookie_max_age) {
  244: 		buffer_append_string_len(ds->value, CONST_STR_LEN("; max-age="));
  245: 		buffer_append_long(ds->value, p->conf.cookie_max_age);
  246: 	}
  247: 
  248: 	array_insert_unique(con->response.headers, (data_unset *)ds);
  249: 
  250: 	return HANDLER_GO_ON;
  251: }
  252: 
  253: /* this function is called at dlopen() time and inits the callbacks */
  254: 
  255: int mod_usertrack_plugin_init(plugin *p);
  256: int mod_usertrack_plugin_init(plugin *p) {
  257: 	p->version     = LIGHTTPD_VERSION_ID;
  258: 	p->name        = buffer_init_string("usertrack");
  259: 
  260: 	p->init        = mod_usertrack_init;
  261: 	p->handle_uri_clean  = mod_usertrack_uri_handler;
  262: 	p->set_defaults  = mod_usertrack_set_defaults;
  263: 	p->cleanup     = mod_usertrack_free;
  264: 
  265: 	p->data        = NULL;
  266: 
  267: 	return 0;
  268: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>