File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / lighttpd / src / mod_usertrack.c
Revision 1.1.1.3 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Wed Nov 2 10:35:00 2016 UTC (7 years, 8 months ago) by misho
Branches: lighttpd, MAIN
CVS tags: v1_4_41p8, HEAD
lighttpd 1.4.41

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

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