Annotation of embedaddon/lighttpd/src/mod_usertrack.c, revision 1.1.1.3
1.1.1.3 ! misho 1: #include "first.h"
! 2:
1.1 misho 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:
1.1.1.3 ! misho 53: if (NULL == s) continue;
! 54:
1.1 misho 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:
1.1.1.2 misho 84: p->config_storage = calloc(1, srv->config_context->used * sizeof(plugin_config *));
1.1 misho 85:
86: for (i = 0; i < srv->config_context->used; i++) {
1.1.1.3 ! misho 87: data_config const* config = (data_config const*)srv->config_context->data[i];
1.1 misho 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:
1.1.1.3 ! misho 101: if (0 != config_insert_values_global(srv, config->value, cv, i == 0 ? T_CONFIG_SCOPE_SERVER : T_CONFIG_SCOPE_CONNECTION)) {
1.1 misho 102: return HANDLER_ERROR;
103: }
104:
1.1.1.3 ! misho 105: if (buffer_string_is_empty(s->cookie_name)) {
1.1 misho 106: buffer_copy_string_len(s->cookie_name, CONST_STR_LEN("TRACKID"));
107: } else {
1.1.1.3 ! misho 108: size_t j, len = buffer_string_length(s->cookie_name);
! 109: for (j = 0; j < len; j++) {
1.1 misho 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:
1.1.1.3 ! misho 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++) {
1.1 misho 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;
1.1.1.3 ! misho 180: char hh[LI_ITOSTRING_LENGTH];
1.1 misho 181:
1.1.1.3 ! misho 182: if (buffer_is_empty(con->uri.path)) return HANDLER_GO_ON;
1.1 misho 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 */
1.1.1.3 ! misho 200: for (nc = g + buffer_string_length(p->conf.cookie_name); *nc == ' ' || *nc == '\t'; nc++);
1.1 misho 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"));
1.1.1.3 ! misho 218: buffer_copy_buffer(ds->value, p->conf.cookie_name);
1.1 misho 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);
1.1.1.3 ! misho 226: li_MD5_Update(&Md5Ctx, CONST_BUF_LEN(con->uri.path));
! 227: li_MD5_Update(&Md5Ctx, CONST_STR_LEN("+"));
1.1 misho 228:
229: /* we assume sizeof(time_t) == 4 here, but if not it ain't a problem at all */
1.1.1.3 ! misho 230: li_itostrn(hh, sizeof(hh), srv->cur_ts);
1.1 misho 231: li_MD5_Update(&Md5Ctx, (unsigned char *)hh, strlen(hh));
232: li_MD5_Update(&Md5Ctx, (unsigned char *)srv->entropy, sizeof(srv->entropy));
1.1.1.3 ! misho 233: li_itostrn(hh, sizeof(hh), rand());
1.1 misho 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:
1.1.1.3 ! misho 242: if (!buffer_string_is_empty(p->conf.cookie_domain)) {
1.1 misho 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="));
1.1.1.3 ! misho 249: buffer_append_int(ds->value, p->conf.cookie_max_age);
1.1 misho 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>