Groonga 3.0.9 Source Code Document
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
ngx_http_secure_link_module.c
Go to the documentation of this file.
1 
2 /*
3  * Copyright (C) Igor Sysoev
4  * Copyright (C) Nginx, Inc.
5  */
6 
7 
8 #include <ngx_config.h>
9 #include <ngx_core.h>
10 #include <ngx_http.h>
11 #include <ngx_md5.h>
12 
13 
14 typedef struct {
19 
20 
21 typedef struct {
24 
25 
26 static ngx_int_t ngx_http_secure_link_old_variable(ngx_http_request_t *r,
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);
35 
36 
37 static ngx_command_t ngx_http_secure_link_commands[] = {
38 
39  { ngx_string("secure_link"),
43  offsetof(ngx_http_secure_link_conf_t, variable),
44  NULL },
45 
46  { ngx_string("secure_link_md5"),
50  offsetof(ngx_http_secure_link_conf_t, md5),
51  NULL },
52 
53  { ngx_string("secure_link_secret"),
57  offsetof(ngx_http_secure_link_conf_t, secret),
58  NULL },
59 
61 };
62 
63 
64 static ngx_http_module_t ngx_http_secure_link_module_ctx = {
65  ngx_http_secure_link_add_variables, /* preconfiguration */
66  NULL, /* postconfiguration */
67 
68  NULL, /* create main configuration */
69  NULL, /* init main configuration */
70 
71  NULL, /* create server configuration */
72  NULL, /* merge server configuration */
73 
74  ngx_http_secure_link_create_conf, /* create location configuration */
75  ngx_http_secure_link_merge_conf /* merge location configuration */
76 };
77 
78 
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 */
92 };
93 
94 
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");
98 
99 
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)
103 {
104  u_char *p, *last;
105  ngx_str_t val, hash;
106  time_t expires;
107  ngx_md5_t md5;
110  u_char hash_buf[16], md5_buf[16];
111 
112  conf = ngx_http_get_module_loc_conf(r, ngx_http_secure_link_module);
113 
114  if (conf->secret.data) {
115  return ngx_http_secure_link_old_variable(r, conf, v, data);
116  }
117 
118  if (conf->variable == NULL || conf->md5 == NULL) {
119  goto not_found;
120  }
121 
122  if (ngx_http_complex_value(r, conf->variable, &val) != NGX_OK) {
123  return NGX_ERROR;
124  }
125 
127  "secure link: \"%V\"", &val);
128 
129  last = val.data + val.len;
130 
131  p = ngx_strlchr(val.data, last, ',');
132  expires = 0;
133 
134  if (p) {
135  val.len = p++ - val.data;
136 
137  expires = ngx_atotm(p, last - p);
138  if (expires <= 0) {
139  goto not_found;
140  }
141 
142  ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_secure_link_ctx_t));
143  if (ctx == NULL) {
144  return NGX_ERROR;
145  }
146 
147  ngx_http_set_ctx(r, ctx, ngx_http_secure_link_module);
148 
149  ctx->expires.len = last - p;
150  ctx->expires.data = p;
151  }
152 
153  if (val.len > 24) {
154  goto not_found;
155  }
156 
157  hash.len = 16;
158  hash.data = hash_buf;
159 
160  if (ngx_decode_base64url(&hash, &val) != NGX_OK) {
161  goto not_found;
162  }
163 
164  if (hash.len != 16) {
165  goto not_found;
166  }
167 
168  if (ngx_http_complex_value(r, conf->md5, &val) != NGX_OK) {
169  return NGX_ERROR;
170  }
171 
173  "secure link md5: \"%V\"", &val);
174 
175  ngx_md5_init(&md5);
176  ngx_md5_update(&md5, val.data, val.len);
177  ngx_md5_final(md5_buf, &md5);
178 
179  if (ngx_memcmp(hash_buf, md5_buf, 16) != 0) {
180  goto not_found;
181  }
182 
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;
188 
189  return NGX_OK;
190 
191 not_found:
192 
193  v->not_found = 1;
194 
195  return NGX_OK;
196 }
197 
198 
199 static ngx_int_t
200 ngx_http_secure_link_old_variable(ngx_http_request_t *r,
202  uintptr_t data)
203 {
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];
210 
211  p = &r->unparsed_uri.data[1];
212  last = r->unparsed_uri.data + r->unparsed_uri.len;
213 
214  while (p < last) {
215  if (*p++ == '/') {
216  start = p;
217  goto md5_start;
218  }
219  }
220 
221  goto not_found;
222 
223 md5_start:
224 
225  while (p < last) {
226  if (*p++ == '/') {
227  end = p - 1;
228  goto url_start;
229  }
230  }
231 
232  goto not_found;
233 
234 url_start:
235 
236  len = last - p;
237 
238  if (end - start != 32 || len == 0) {
239  goto not_found;
240  }
241 
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);
246 
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;
251  }
252  }
253 
254  v->len = len;
255  v->valid = 1;
256  v->no_cacheable = 0;
257  v->not_found = 0;
258  v->data = p;
259 
260  return NGX_OK;
261 
262 not_found:
263 
264  v->not_found = 1;
265 
266  return NGX_OK;
267 }
268 
269 
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)
273 {
275 
276  ctx = ngx_http_get_module_ctx(r, ngx_http_secure_link_module);
277 
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;
284 
285  } else {
286  v->not_found = 1;
287  }
288 
289  return NGX_OK;
290 }
291 
292 
293 static void *
294 ngx_http_secure_link_create_conf(ngx_conf_t *cf)
295 {
297 
298  conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_secure_link_conf_t));
299  if (conf == NULL) {
300  return NULL;
301  }
302 
303  /*
304  * set by ngx_pcalloc():
305  *
306  * conf->variable = NULL;
307  * conf->md5 = NULL;
308  * conf->secret = { 0, NULL };
309  */
310 
311  return conf;
312 }
313 
314 
315 static char *
316 ngx_http_secure_link_merge_conf(ngx_conf_t *cf, void *parent, void *child)
317 {
318  ngx_http_secure_link_conf_t *prev = parent;
319  ngx_http_secure_link_conf_t *conf = child;
320 
321  if (conf->secret.data) {
322  if (conf->variable || conf->md5) {
324  "\"secure_link_secret\" cannot be mixed with "
325  "\"secure_link\" and \"secure_link_md5\"");
326  return NGX_CONF_ERROR;
327  }
328 
329  return NGX_CONF_OK;
330  }
331 
332  if (conf->variable == NULL) {
333  conf->variable = prev->variable;
334  }
335 
336  if (conf->md5 == NULL) {
337  conf->md5 = prev->md5;
338  }
339 
340  if (conf->variable == NULL && conf->md5 == NULL) {
341  conf->secret = prev->secret;
342  }
343 
344  return NGX_CONF_OK;
345 }
346 
347 
348 static ngx_int_t
349 ngx_http_secure_link_add_variables(ngx_conf_t *cf)
350 {
351  ngx_http_variable_t *var;
352 
353  var = ngx_http_add_variable(cf, &ngx_http_secure_link_name, 0);
354  if (var == NULL) {
355  return NGX_ERROR;
356  }
357 
358  var->get_handler = ngx_http_secure_link_variable;
359 
360  var = ngx_http_add_variable(cf, &ngx_http_secure_link_expires_name, 0);
361  if (var == NULL) {
362  return NGX_ERROR;
363  }
364 
365  var->get_handler = ngx_http_secure_link_expires_variable;
366 
367  return NGX_OK;
368 }