Update and clean Tomato RAF files
[tomato.git] / release / src / router / nginx / src / http / modules / ngx_http_secure_link_module.c
blob907ba6ef50c213ed86516f8e8a7cb748b8e9f6a2
2 /*
3 * Copyright (C) Igor Sysoev
4 * Copyright (C) Nginx, Inc.
5 */
8 #include <ngx_config.h>
9 #include <ngx_core.h>
10 #include <ngx_http.h>
11 #include <ngx_md5.h>
14 typedef struct {
15 ngx_http_complex_value_t *variable;
16 ngx_http_complex_value_t *md5;
17 ngx_str_t secret;
18 } ngx_http_secure_link_conf_t;
21 typedef struct {
22 ngx_str_t expires;
23 } ngx_http_secure_link_ctx_t;
26 static ngx_int_t ngx_http_secure_link_old_variable(ngx_http_request_t *r,
27 ngx_http_secure_link_conf_t *conf, ngx_http_variable_value_t *v,
28 uintptr_t data);
29 static ngx_int_t ngx_http_secure_link_expires_variable(ngx_http_request_t *r,
30 ngx_http_variable_value_t *v, uintptr_t data);
31 static void *ngx_http_secure_link_create_conf(ngx_conf_t *cf);
32 static char *ngx_http_secure_link_merge_conf(ngx_conf_t *cf, void *parent,
33 void *child);
34 static ngx_int_t ngx_http_secure_link_add_variables(ngx_conf_t *cf);
37 static ngx_command_t ngx_http_secure_link_commands[] = {
39 { ngx_string("secure_link"),
40 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
41 ngx_http_set_complex_value_slot,
42 NGX_HTTP_LOC_CONF_OFFSET,
43 offsetof(ngx_http_secure_link_conf_t, variable),
44 NULL },
46 { ngx_string("secure_link_md5"),
47 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
48 ngx_http_set_complex_value_slot,
49 NGX_HTTP_LOC_CONF_OFFSET,
50 offsetof(ngx_http_secure_link_conf_t, md5),
51 NULL },
53 { ngx_string("secure_link_secret"),
54 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
55 ngx_conf_set_str_slot,
56 NGX_HTTP_LOC_CONF_OFFSET,
57 offsetof(ngx_http_secure_link_conf_t, secret),
58 NULL },
60 ngx_null_command
64 static ngx_http_module_t ngx_http_secure_link_module_ctx = {
65 ngx_http_secure_link_add_variables, /* preconfiguration */
66 NULL, /* postconfiguration */
68 NULL, /* create main configuration */
69 NULL, /* init main configuration */
71 NULL, /* create server configuration */
72 NULL, /* merge server configuration */
74 ngx_http_secure_link_create_conf, /* create location configuration */
75 ngx_http_secure_link_merge_conf /* merge location configuration */
79 ngx_module_t ngx_http_secure_link_module = {
80 NGX_MODULE_V1,
81 &ngx_http_secure_link_module_ctx, /* module context */
82 ngx_http_secure_link_commands, /* module directives */
83 NGX_HTTP_MODULE, /* module type */
84 NULL, /* init master */
85 NULL, /* init module */
86 NULL, /* init process */
87 NULL, /* init thread */
88 NULL, /* exit thread */
89 NULL, /* exit process */
90 NULL, /* exit master */
91 NGX_MODULE_V1_PADDING
95 static ngx_str_t ngx_http_secure_link_name = ngx_string("secure_link");
96 static ngx_str_t ngx_http_secure_link_expires_name =
97 ngx_string("secure_link_expires");
100 static ngx_int_t
101 ngx_http_secure_link_variable(ngx_http_request_t *r,
102 ngx_http_variable_value_t *v, uintptr_t data)
104 u_char *p, *last;
105 ngx_str_t val, hash;
106 time_t expires;
107 ngx_md5_t md5;
108 ngx_http_secure_link_ctx_t *ctx;
109 ngx_http_secure_link_conf_t *conf;
110 u_char hash_buf[16], md5_buf[16];
112 conf = ngx_http_get_module_loc_conf(r, ngx_http_secure_link_module);
114 if (conf->secret.data) {
115 return ngx_http_secure_link_old_variable(r, conf, v, data);
118 if (conf->variable == NULL || conf->md5 == NULL) {
119 goto not_found;
122 if (ngx_http_complex_value(r, conf->variable, &val) != NGX_OK) {
123 return NGX_ERROR;
126 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
127 "secure link: \"%V\"", &val);
129 last = val.data + val.len;
131 p = ngx_strlchr(val.data, last, ',');
132 expires = 0;
134 if (p) {
135 val.len = p++ - val.data;
137 expires = ngx_atotm(p, last - p);
138 if (expires <= 0) {
139 goto not_found;
142 ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_secure_link_ctx_t));
143 if (ctx == NULL) {
144 return NGX_ERROR;
147 ngx_http_set_ctx(r, ctx, ngx_http_secure_link_module);
149 ctx->expires.len = last - p;
150 ctx->expires.data = p;
153 if (val.len > 24) {
154 goto not_found;
157 hash.len = 16;
158 hash.data = hash_buf;
160 if (ngx_decode_base64url(&hash, &val) != NGX_OK) {
161 goto not_found;
164 if (hash.len != 16) {
165 goto not_found;
168 if (ngx_http_complex_value(r, conf->md5, &val) != NGX_OK) {
169 return NGX_ERROR;
172 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
173 "secure link md5: \"%V\"", &val);
175 ngx_md5_init(&md5);
176 ngx_md5_update(&md5, val.data, val.len);
177 ngx_md5_final(md5_buf, &md5);
179 if (ngx_memcmp(hash_buf, md5_buf, 16) != 0) {
180 goto not_found;
183 v->data = (u_char *) ((expires && expires < ngx_time()) ? "0" : "1");
184 v->len = 1;
185 v->valid = 1;
186 v->no_cacheable = 0;
187 v->not_found = 0;
189 return NGX_OK;
191 not_found:
193 v->not_found = 1;
195 return NGX_OK;
199 static ngx_int_t
200 ngx_http_secure_link_old_variable(ngx_http_request_t *r,
201 ngx_http_secure_link_conf_t *conf, ngx_http_variable_value_t *v,
202 uintptr_t data)
204 u_char *p, *start, *end, *last;
205 size_t len;
206 ngx_int_t n;
207 ngx_uint_t i;
208 ngx_md5_t md5;
209 u_char hash[16];
211 p = &r->unparsed_uri.data[1];
212 last = r->unparsed_uri.data + r->unparsed_uri.len;
214 while (p < last) {
215 if (*p++ == '/') {
216 start = p;
217 goto md5_start;
221 goto not_found;
223 md5_start:
225 while (p < last) {
226 if (*p++ == '/') {
227 end = p - 1;
228 goto url_start;
232 goto not_found;
234 url_start:
236 len = last - p;
238 if (end - start != 32 || len == 0) {
239 goto not_found;
242 ngx_md5_init(&md5);
243 ngx_md5_update(&md5, p, len);
244 ngx_md5_update(&md5, conf->secret.data, conf->secret.len);
245 ngx_md5_final(hash, &md5);
247 for (i = 0; i < 16; i++) {
248 n = ngx_hextoi(&start[2 * i], 2);
249 if (n == NGX_ERROR || n != hash[i]) {
250 goto not_found;
254 v->len = len;
255 v->valid = 1;
256 v->no_cacheable = 0;
257 v->not_found = 0;
258 v->data = p;
260 return NGX_OK;
262 not_found:
264 v->not_found = 1;
266 return NGX_OK;
270 static ngx_int_t
271 ngx_http_secure_link_expires_variable(ngx_http_request_t *r,
272 ngx_http_variable_value_t *v, uintptr_t data)
274 ngx_http_secure_link_ctx_t *ctx;
276 ctx = ngx_http_get_module_ctx(r, ngx_http_secure_link_module);
278 if (ctx) {
279 v->len = ctx->expires.len;
280 v->valid = 1;
281 v->no_cacheable = 0;
282 v->not_found = 0;
283 v->data = ctx->expires.data;
285 } else {
286 v->not_found = 1;
289 return NGX_OK;
293 static void *
294 ngx_http_secure_link_create_conf(ngx_conf_t *cf)
296 ngx_http_secure_link_conf_t *conf;
298 conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_secure_link_conf_t));
299 if (conf == NULL) {
300 return NULL;
304 * set by ngx_pcalloc():
306 * conf->variable = NULL;
307 * conf->md5 = NULL;
308 * conf->secret = { 0, NULL };
311 return conf;
315 static char *
316 ngx_http_secure_link_merge_conf(ngx_conf_t *cf, void *parent, void *child)
318 ngx_http_secure_link_conf_t *prev = parent;
319 ngx_http_secure_link_conf_t *conf = child;
321 if (conf->secret.data) {
322 if (conf->variable || conf->md5) {
323 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
324 "\"secure_link_secret\" cannot be mixed with "
325 "\"secure_link\" and \"secure_link_md5\"");
326 return NGX_CONF_ERROR;
329 return NGX_CONF_OK;
332 if (conf->variable == NULL) {
333 conf->variable = prev->variable;
336 if (conf->md5 == NULL) {
337 conf->md5 = prev->md5;
340 if (conf->variable == NULL && conf->md5 == NULL) {
341 conf->secret = prev->secret;
344 return NGX_CONF_OK;
348 static ngx_int_t
349 ngx_http_secure_link_add_variables(ngx_conf_t *cf)
351 ngx_http_variable_t *var;
353 var = ngx_http_add_variable(cf, &ngx_http_secure_link_name, 0);
354 if (var == NULL) {
355 return NGX_ERROR;
358 var->get_handler = ngx_http_secure_link_variable;
360 var = ngx_http_add_variable(cf, &ngx_http_secure_link_expires_name, 0);
361 if (var == NULL) {
362 return NGX_ERROR;
365 var->get_handler = ngx_http_secure_link_expires_variable;
367 return NGX_OK;