comparison src/http/modules/ngx_http_userid_filter_module.c @ 88:e916a291e9aa NGINX_0_1_44

nginx 0.1.44 *) Feature: the IMAP/POP3 proxy supports SSL. *) Feature: the "proxy_timeout" directive of the ngx_imap_proxy_module. *) Feature: the "userid_mark" directive. *) Feature: the $remote_user variable value is determined independently of authorization use.
author Igor Sysoev <http://sysoev.ru>
date Tue, 06 Sep 2005 00:00:00 +0400
parents b55cbf18157e
children 71c46860eb55
comparison
equal deleted inserted replaced
87:5b7ec80c3c40 88:e916a291e9aa
24 ngx_int_t service; 24 ngx_int_t service;
25 25
26 ngx_str_t name; 26 ngx_str_t name;
27 ngx_str_t domain; 27 ngx_str_t domain;
28 ngx_str_t path; 28 ngx_str_t path;
29 ngx_str_t p3p;
30
29 time_t expires; 31 time_t expires;
30 ngx_str_t p3p; 32
33 u_char mark;
31 } ngx_http_userid_conf_t; 34 } ngx_http_userid_conf_t;
32 35
33 36
34 typedef struct { 37 typedef struct {
35 uint32_t uid_got[4]; 38 uint32_t uid_got[4];
36 uint32_t uid_set[4]; 39 uint32_t uid_set[4];
40 ngx_str_t cookie;
37 } ngx_http_userid_ctx_t; 41 } ngx_http_userid_ctx_t;
38 42
39 43
40 static ngx_int_t ngx_http_userid_get_uid(ngx_http_request_t *r, 44 static void ngx_http_userid_get_uid(ngx_http_request_t *r,
41 ngx_http_userid_ctx_t *ctx, ngx_http_userid_conf_t *conf); 45 ngx_http_userid_ctx_t *ctx, ngx_http_userid_conf_t *conf);
42 static ngx_int_t ngx_http_userid_set_uid(ngx_http_request_t *r, 46 static ngx_int_t ngx_http_userid_set_uid(ngx_http_request_t *r,
43 ngx_http_userid_ctx_t *ctx, ngx_http_userid_conf_t *conf); 47 ngx_http_userid_ctx_t *ctx, ngx_http_userid_conf_t *conf);
44 48
45 static size_t ngx_http_userid_log_uid_got_getlen(ngx_http_request_t *r, 49 static size_t ngx_http_userid_log_uid_got_getlen(ngx_http_request_t *r,
59 static char *ngx_http_userid_domain(ngx_conf_t *cf, void *post, void *data); 63 static char *ngx_http_userid_domain(ngx_conf_t *cf, void *post, void *data);
60 static char *ngx_http_userid_path(ngx_conf_t *cf, void *post, void *data); 64 static char *ngx_http_userid_path(ngx_conf_t *cf, void *post, void *data);
61 static char *ngx_http_userid_expires(ngx_conf_t *cf, ngx_command_t *cmd, 65 static char *ngx_http_userid_expires(ngx_conf_t *cf, ngx_command_t *cmd,
62 void *conf); 66 void *conf);
63 static char *ngx_http_userid_p3p(ngx_conf_t *cf, void *post, void *data); 67 static char *ngx_http_userid_p3p(ngx_conf_t *cf, void *post, void *data);
68 static char *ngx_http_userid_mark(ngx_conf_t *cf, ngx_command_t *cmd,
69 void *conf);
70
64 71
65 72
66 static uint32_t sequencer_v1 = 1; 73 static uint32_t sequencer_v1 = 1;
67 static uint32_t sequencer_v2 = 0x03030302; 74 static uint32_t sequencer_v2 = 0x03030302;
68 75
82 }; 89 };
83 90
84 91
85 static ngx_conf_post_handler_pt ngx_http_userid_domain_p = 92 static ngx_conf_post_handler_pt ngx_http_userid_domain_p =
86 ngx_http_userid_domain; 93 ngx_http_userid_domain;
87
88 static ngx_conf_post_handler_pt ngx_http_userid_path_p = ngx_http_userid_path; 94 static ngx_conf_post_handler_pt ngx_http_userid_path_p = ngx_http_userid_path;
89 static ngx_conf_post_handler_pt ngx_http_userid_p3p_p = ngx_http_userid_p3p; 95 static ngx_conf_post_handler_pt ngx_http_userid_p3p_p = ngx_http_userid_p3p;
90 96
91 97
92 static ngx_command_t ngx_http_userid_commands[] = { 98 static ngx_command_t ngx_http_userid_commands[] = {
97 NGX_HTTP_LOC_CONF_OFFSET, 103 NGX_HTTP_LOC_CONF_OFFSET,
98 offsetof(ngx_http_userid_conf_t, enable), 104 offsetof(ngx_http_userid_conf_t, enable),
99 ngx_http_userid_state }, 105 ngx_http_userid_state },
100 106
101 { ngx_string("userid_service"), 107 { ngx_string("userid_service"),
102 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, 108 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
103 ngx_conf_set_num_slot, 109 ngx_conf_set_num_slot,
104 NGX_HTTP_LOC_CONF_OFFSET, 110 NGX_HTTP_LOC_CONF_OFFSET,
105 offsetof(ngx_http_userid_conf_t, service), 111 offsetof(ngx_http_userid_conf_t, service),
106 NULL }, 112 NULL },
107 113
108 { ngx_string("userid_name"), 114 { ngx_string("userid_name"),
109 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, 115 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
110 ngx_conf_set_str_slot, 116 ngx_conf_set_str_slot,
111 NGX_HTTP_LOC_CONF_OFFSET, 117 NGX_HTTP_LOC_CONF_OFFSET,
112 offsetof(ngx_http_userid_conf_t, name), 118 offsetof(ngx_http_userid_conf_t, name),
113 NULL }, 119 NULL },
114 120
115 { ngx_string("userid_domain"), 121 { ngx_string("userid_domain"),
116 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, 122 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
117 ngx_conf_set_str_slot, 123 ngx_conf_set_str_slot,
118 NGX_HTTP_LOC_CONF_OFFSET, 124 NGX_HTTP_LOC_CONF_OFFSET,
119 offsetof(ngx_http_userid_conf_t, domain), 125 offsetof(ngx_http_userid_conf_t, domain),
120 &ngx_http_userid_domain_p }, 126 &ngx_http_userid_domain_p },
121 127
122 { ngx_string("userid_path"), 128 { ngx_string("userid_path"),
123 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, 129 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
124 ngx_conf_set_str_slot, 130 ngx_conf_set_str_slot,
125 NGX_HTTP_LOC_CONF_OFFSET, 131 NGX_HTTP_LOC_CONF_OFFSET,
126 offsetof(ngx_http_userid_conf_t, path), 132 offsetof(ngx_http_userid_conf_t, path),
127 &ngx_http_userid_path_p }, 133 &ngx_http_userid_path_p },
128 134
137 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, 143 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
138 ngx_conf_set_str_slot, 144 ngx_conf_set_str_slot,
139 NGX_HTTP_LOC_CONF_OFFSET, 145 NGX_HTTP_LOC_CONF_OFFSET,
140 offsetof(ngx_http_userid_conf_t, p3p), 146 offsetof(ngx_http_userid_conf_t, p3p),
141 &ngx_http_userid_p3p_p }, 147 &ngx_http_userid_p3p_p },
148
149 { ngx_string("userid_mark"),
150 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
151 ngx_http_userid_mark,
152 NGX_HTTP_LOC_CONF_OFFSET,
153 0,
154 NULL },
142 155
143 ngx_null_command 156 ngx_null_command
144 }; 157 };
145 158
146 159
203 return NGX_ERROR; 216 return NGX_ERROR;
204 } 217 }
205 218
206 ngx_http_set_ctx(r, ctx, ngx_http_userid_filter_module); 219 ngx_http_set_ctx(r, ctx, ngx_http_userid_filter_module);
207 220
208 221 ngx_http_userid_get_uid(r, ctx, conf);
209 rc = ngx_http_userid_get_uid(r, ctx, conf); 222
223 if (conf->enable == NGX_HTTP_USERID_LOG) {
224 return ngx_http_next_header_filter(r);
225 }
226
227 if (ctx->uid_got[3] != 0) {
228 if (conf->mark == '\0') {
229 return ngx_http_next_header_filter(r);
230
231 } else {
232 if (ctx->cookie.len > 23
233 && ctx->cookie.data[22] == conf->mark
234 && ctx->cookie.data[23] == '=')
235 {
236 return ngx_http_next_header_filter(r);
237 }
238 }
239 }
240
241 rc = ngx_http_userid_set_uid(r, ctx, conf);
210 242
211 if (rc != NGX_OK) { 243 if (rc != NGX_OK) {
212 return rc; 244 return rc;
213 } 245 }
214 246
215 if (conf->enable == NGX_HTTP_USERID_LOG || ctx->uid_got[3] != 0) {
216 return ngx_http_next_header_filter(r);
217 }
218
219 rc = ngx_http_userid_set_uid(r, ctx, conf);
220
221 if (rc != NGX_OK) {
222 return rc;
223 }
224
225 return ngx_http_next_header_filter(r); 247 return ngx_http_next_header_filter(r);
226 } 248 }
227 249
228 250
229 static ngx_int_t 251 static void
230 ngx_http_userid_get_uid(ngx_http_request_t *r, ngx_http_userid_ctx_t *ctx, 252 ngx_http_userid_get_uid(ngx_http_request_t *r, ngx_http_userid_ctx_t *ctx,
231 ngx_http_userid_conf_t *conf) 253 ngx_http_userid_conf_t *conf)
232 { 254 {
233 ngx_int_t n; 255 ngx_int_t n;
234 ngx_str_t src, dst; 256 ngx_str_t src, dst;
235 ngx_table_elt_t **cookies; 257 ngx_table_elt_t **cookies;
236 258
237 n = ngx_http_parse_multi_header_lines(&r->headers_in.cookies, &conf->name, 259 n = ngx_http_parse_multi_header_lines(&r->headers_in.cookies, &conf->name,
238 &src); 260 &ctx->cookie);
239 if (n == NGX_DECLINED) { 261 if (n == NGX_DECLINED) {
240 return NGX_OK; 262 return;
241 } 263 }
242 264
243 if (src.len < 22) { 265 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
266 "uid cookie: \"%V\"", &ctx->cookie);
267
268 if (ctx->cookie.len < 22) {
244 cookies = r->headers_in.cookies.elts; 269 cookies = r->headers_in.cookies.elts;
245 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, 270 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
246 "client sent too short userid cookie \"%V\"", 271 "client sent too short userid cookie \"%V\"",
247 &cookies[n]->value); 272 &cookies[n]->value);
248 return NGX_OK; 273 return;
249 } 274 }
275
276 src = ctx->cookie;
250 277
251 /* 278 /*
252 * we have to limit encoded string to 22 characters 279 * we have to limit the encoded string to 22 characters because
253 * because there are already the millions cookies with a garbage 280 * 1) cookie may be marked by "userid_mark",
254 * instead of the correct base64 trail "==" 281 * 2) and there are already the millions cookies with a garbage
282 * instead of the correct base64 trail "=="
255 */ 283 */
256 284
257 src.len = 22; 285 src.len = 22;
258 286
259 dst.data = (u_char *) ctx->uid_got; 287 dst.data = (u_char *) ctx->uid_got;
261 if (ngx_decode_base64(&dst, &src) == NGX_ERROR) { 289 if (ngx_decode_base64(&dst, &src) == NGX_ERROR) {
262 cookies = r->headers_in.cookies.elts; 290 cookies = r->headers_in.cookies.elts;
263 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, 291 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
264 "client sent invalid userid cookie \"%V\"", 292 "client sent invalid userid cookie \"%V\"",
265 &cookies[n]->value); 293 &cookies[n]->value);
266 return NGX_OK; 294 return;
267 } 295 }
268 296
269 ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, 297 ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
270 "uid: %08XD%08XD%08XD%08XD", 298 "uid: %08XD%08XD%08XD%08XD",
271 ctx->uid_got[0], ctx->uid_got[1], 299 ctx->uid_got[0], ctx->uid_got[1],
272 ctx->uid_got[2], ctx->uid_got[3]); 300 ctx->uid_got[2], ctx->uid_got[3]);
273
274 return NGX_OK;
275 } 301 }
276 302
277 303
278 static ngx_int_t 304 static ngx_int_t
279 ngx_http_userid_set_uid(ngx_http_request_t *r, ngx_http_userid_ctx_t *ctx, 305 ngx_http_userid_set_uid(ngx_http_request_t *r, ngx_http_userid_ctx_t *ctx,
284 socklen_t slen; 310 socklen_t slen;
285 struct sockaddr_in sin; 311 struct sockaddr_in sin;
286 ngx_str_t src, dst; 312 ngx_str_t src, dst;
287 ngx_table_elt_t *set_cookie, *p3p; 313 ngx_table_elt_t *set_cookie, *p3p;
288 314
289 /* TODO: mutex for sequencers */ 315 /*
290 316 * TODO: in the threaded mode the sequencers should be in TLS and their
291 if (conf->enable == NGX_HTTP_USERID_V1) { 317 * ranges should be divided between threads
292 if (conf->service == NGX_CONF_UNSET) { 318 */
293 ctx->uid_set[0] = 0; 319
320 if (ctx->uid_got[3] == 0) {
321
322 if (conf->enable == NGX_HTTP_USERID_V1) {
323 if (conf->service == NGX_CONF_UNSET) {
324 ctx->uid_set[0] = 0;
325 } else {
326 ctx->uid_set[0] = conf->service;
327 }
328 ctx->uid_set[1] = ngx_time();
329 ctx->uid_set[2] = ngx_pid;
330 ctx->uid_set[3] = sequencer_v1;
331 sequencer_v1 += 0x100;
332
294 } else { 333 } else {
295 ctx->uid_set[0] = htonl(conf->service); 334 if (conf->service == NGX_CONF_UNSET) {
335 if (r->in_addr == 0) {
336 slen = sizeof(struct sockaddr_in);
337 if (getsockname(r->connection->fd,
338 (struct sockaddr *) &sin, &slen) == -1)
339 {
340 ngx_log_error(NGX_LOG_CRIT, r->connection->log,
341 ngx_socket_errno, "getsockname() failed");
342 }
343
344 r->in_addr = sin.sin_addr.s_addr;
345 }
346
347 ctx->uid_set[0] = htonl(r->in_addr);
348
349 } else {
350 ctx->uid_set[0] = htonl(conf->service);
351 }
352
353 ctx->uid_set[1] = htonl(ngx_time());
354 ctx->uid_set[2] = htonl(ngx_pid);
355 ctx->uid_set[3] = htonl(sequencer_v2);
356 sequencer_v2 += 0x100;
357 if (sequencer_v2 < 0x03030302) {
358 sequencer_v2 = 0x03030302;
359 }
296 } 360 }
297 361
298 ctx->uid_set[1] = ngx_time();
299 ctx->uid_set[2] = ngx_pid;
300 ctx->uid_set[3] = sequencer_v1;
301 sequencer_v1 += 0x100;
302
303 } else { 362 } else {
304 if (conf->service == NGX_CONF_UNSET) { 363 ctx->uid_set[0] = ctx->uid_got[0];
305 if (r->in_addr == 0) { 364 ctx->uid_set[1] = ctx->uid_got[1];
306 slen = sizeof(struct sockaddr_in); 365 ctx->uid_set[2] = ctx->uid_got[2];
307 if (getsockname(r->connection->fd, 366 ctx->uid_set[3] = ctx->uid_got[3];
308 (struct sockaddr *) &sin, &slen) == -1)
309 {
310 ngx_log_error(NGX_LOG_CRIT, r->connection->log,
311 ngx_socket_errno, "getsockname() failed");
312 }
313
314 r->in_addr = sin.sin_addr.s_addr;
315 }
316
317 ctx->uid_set[0] = htonl(r->in_addr);
318
319 } else {
320 ctx->uid_set[0] = htonl(conf->service);
321 }
322
323 ctx->uid_set[1] = htonl(ngx_time());
324 ctx->uid_set[2] = htonl(ngx_pid);
325 ctx->uid_set[3] = htonl(sequencer_v2);
326 sequencer_v2 += 0x100;
327 if (sequencer_v2 < 0x03030302) {
328 sequencer_v2 = 0x03030302;
329 }
330 } 367 }
331 368
332 len = conf->name.len + 1 + ngx_base64_encoded_length(16) + conf->path.len; 369 len = conf->name.len + 1 + ngx_base64_encoded_length(16) + conf->path.len;
333 370
334 if (conf->expires) { 371 if (conf->expires) {
345 } 382 }
346 383
347 p = ngx_cpymem(cookie, conf->name.data, conf->name.len); 384 p = ngx_cpymem(cookie, conf->name.data, conf->name.len);
348 *p++ = '='; 385 *p++ = '=';
349 386
350 src.len = 16; 387 if (ctx->uid_got[3] == 0) {
351 src.data = (u_char *) ctx->uid_set; 388 src.len = 16;
352 dst.data = p; 389 src.data = (u_char *) ctx->uid_set;
353 390 dst.data = p;
354 ngx_encode_base64(&dst, &src); 391
355 392 ngx_encode_base64(&dst, &src);
356 p += dst.len; 393
394 p += dst.len;
395
396 if (conf->mark) {
397 *(p - 2) = conf->mark;
398 }
399
400 } else {
401 p = ngx_cpymem(p, ctx->cookie.data, 22);
402 *p++ = conf->mark;
403 *p++ = '=';
404 }
357 405
358 if (conf->expires == NGX_HTTP_USERID_MAX_EXPIRES) { 406 if (conf->expires == NGX_HTTP_USERID_MAX_EXPIRES) {
359 p = ngx_cpymem(p, expires, sizeof(expires) - 1); 407 p = ngx_cpymem(p, expires, sizeof(expires) - 1);
360 408
361 } else if (conf->expires) { 409 } else if (conf->expires) {
543 */ 591 */
544 592
545 conf->enable = NGX_CONF_UNSET_UINT; 593 conf->enable = NGX_CONF_UNSET_UINT;
546 conf->service = NGX_CONF_UNSET; 594 conf->service = NGX_CONF_UNSET;
547 conf->expires = NGX_CONF_UNSET; 595 conf->expires = NGX_CONF_UNSET;
596 conf->mark = (u_char) '\xFF';
548 597
549 return conf; 598 return conf;
550 } 599 }
551 600
552 601
565 ngx_conf_merge_str_value(conf->p3p, prev->p3p, ""); 614 ngx_conf_merge_str_value(conf->p3p, prev->p3p, "");
566 615
567 ngx_conf_merge_value(conf->service, prev->service, NGX_CONF_UNSET); 616 ngx_conf_merge_value(conf->service, prev->service, NGX_CONF_UNSET);
568 ngx_conf_merge_sec_value(conf->expires, prev->expires, 0); 617 ngx_conf_merge_sec_value(conf->expires, prev->expires, 0);
569 618
619 if (conf->mark == (u_char) '\xFF') {
620 if (prev->mark == (u_char) '\xFF') {
621 conf->mark = '\0';
622 } else {
623 conf->mark = prev->mark;
624 }
625 }
626
570 return NGX_CONF_OK; 627 return NGX_CONF_OK;
571 } 628 }
572 629
573 630
574 static char * 631 static char *
625 static char * 682 static char *
626 ngx_http_userid_expires(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) 683 ngx_http_userid_expires(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
627 { 684 {
628 ngx_http_userid_conf_t *ucf = conf; 685 ngx_http_userid_conf_t *ucf = conf;
629 686
630 ngx_str_t *value; 687 ngx_str_t *value;
631 688
632 if (ucf->expires != NGX_CONF_UNSET) { 689 if (ucf->expires != NGX_CONF_UNSET) {
633 return "is duplicate"; 690 return "is duplicate";
634 } 691 }
635 692
668 p3p->data = (u_char *) ""; 725 p3p->data = (u_char *) "";
669 } 726 }
670 727
671 return NGX_CONF_OK; 728 return NGX_CONF_OK;
672 } 729 }
730
731
732 static char *
733 ngx_http_userid_mark(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
734 {
735 ngx_http_userid_conf_t *ucf = conf;
736
737 ngx_str_t *value;
738
739 if (ucf->mark != (u_char) '\xFF') {
740 return "is duplicate";
741 }
742
743 value = cf->args->elts;
744
745 if (ngx_strcmp(value[1].data, "off") == 0) {
746 ucf->mark = '\0';
747 return NGX_CONF_OK;
748 }
749
750 if (value[1].len != 1
751 || !((value[1].data[0] >= '0' && value[1].data[0] <= '9')
752 || (value[1].data[0] >= 'A' && value[1].data[0] <= 'Z')
753 || (value[1].data[0] >= 'a' && value[1].data[0] <= 'z')
754 || value[1].data[0] == '='))
755 {
756 return "value must be \"off\" or a single letter, digit or \"=\"";
757 }
758
759 ucf->mark = value[1].data[0];
760
761 return NGX_CONF_OK;
762 }