Back to home page

Nginx displayed by LXR

Source navigation ]
Diff markup ]
Identifier search ]
general search ]
 
 
Version: nginx-1.15.12 ]​[ nginx-1.16.0 ]​

0001 
0002 /*
0003  * Copyright (C) Igor Sysoev
0004  * Copyright (C) Nginx, Inc.
0005  */
0006 
0007 
0008 #include <ngx_config.h>
0009 #include <ngx_core.h>
0010 #include <ngx_http.h>
0011 #include <ngx_md5.h>
0012 
0013 
0014 typedef struct {
0015     ngx_http_complex_value_t  *variable;
0016     ngx_http_complex_value_t  *md5;
0017     ngx_str_t                  secret;
0018 } ngx_http_secure_link_conf_t;
0019 
0020 
0021 typedef struct {
0022     ngx_str_t                  expires;
0023 } ngx_http_secure_link_ctx_t;
0024 
0025 
0026 static ngx_int_t ngx_http_secure_link_old_variable(ngx_http_request_t *r,
0027     ngx_http_secure_link_conf_t *conf, ngx_http_variable_value_t *v,
0028     uintptr_t data);
0029 static ngx_int_t ngx_http_secure_link_expires_variable(ngx_http_request_t *r,
0030     ngx_http_variable_value_t *v, uintptr_t data);
0031 static void *ngx_http_secure_link_create_conf(ngx_conf_t *cf);
0032 static char *ngx_http_secure_link_merge_conf(ngx_conf_t *cf, void *parent,
0033     void *child);
0034 static ngx_int_t ngx_http_secure_link_add_variables(ngx_conf_t *cf);
0035 
0036 
0037 static ngx_command_t  ngx_http_secure_link_commands[] = {
0038 
0039     { ngx_string("secure_link"),
0040       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
0041       ngx_http_set_complex_value_slot,
0042       NGX_HTTP_LOC_CONF_OFFSET,
0043       offsetof(ngx_http_secure_link_conf_t, variable),
0044       NULL },
0045 
0046     { ngx_string("secure_link_md5"),
0047       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
0048       ngx_http_set_complex_value_slot,
0049       NGX_HTTP_LOC_CONF_OFFSET,
0050       offsetof(ngx_http_secure_link_conf_t, md5),
0051       NULL },
0052 
0053     { ngx_string("secure_link_secret"),
0054       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
0055       ngx_conf_set_str_slot,
0056       NGX_HTTP_LOC_CONF_OFFSET,
0057       offsetof(ngx_http_secure_link_conf_t, secret),
0058       NULL },
0059 
0060       ngx_null_command
0061 };
0062 
0063 
0064 static ngx_http_module_t  ngx_http_secure_link_module_ctx = {
0065     ngx_http_secure_link_add_variables,    /* preconfiguration */
0066     NULL,                                  /* postconfiguration */
0067 
0068     NULL,                                  /* create main configuration */
0069     NULL,                                  /* init main configuration */
0070 
0071     NULL,                                  /* create server configuration */
0072     NULL,                                  /* merge server configuration */
0073 
0074     ngx_http_secure_link_create_conf,      /* create location configuration */
0075     ngx_http_secure_link_merge_conf        /* merge location configuration */
0076 };
0077 
0078 
0079 ngx_module_t  ngx_http_secure_link_module = {
0080     NGX_MODULE_V1,
0081     &ngx_http_secure_link_module_ctx,      /* module context */
0082     ngx_http_secure_link_commands,         /* module directives */
0083     NGX_HTTP_MODULE,                       /* module type */
0084     NULL,                                  /* init master */
0085     NULL,                                  /* init module */
0086     NULL,                                  /* init process */
0087     NULL,                                  /* init thread */
0088     NULL,                                  /* exit thread */
0089     NULL,                                  /* exit process */
0090     NULL,                                  /* exit master */
0091     NGX_MODULE_V1_PADDING
0092 };
0093 
0094 
0095 static ngx_str_t  ngx_http_secure_link_name = ngx_string("secure_link");
0096 static ngx_str_t  ngx_http_secure_link_expires_name =
0097     ngx_string("secure_link_expires");
0098 
0099 
0100 static ngx_int_t
0101 ngx_http_secure_link_variable(ngx_http_request_t *r,
0102     ngx_http_variable_value_t *v, uintptr_t data)
0103 {
0104     u_char                       *p, *last;
0105     ngx_str_t                     val, hash;
0106     time_t                        expires;
0107     ngx_md5_t                     md5;
0108     ngx_http_secure_link_ctx_t   *ctx;
0109     ngx_http_secure_link_conf_t  *conf;
0110     u_char                        hash_buf[18], md5_buf[16];
0111 
0112     conf = ngx_http_get_module_loc_conf(r, ngx_http_secure_link_module);
0113 
0114     if (conf->secret.data) {
0115         return ngx_http_secure_link_old_variable(r, conf, v, data);
0116     }
0117 
0118     if (conf->variable == NULL || conf->md5 == NULL) {
0119         goto not_found;
0120     }
0121 
0122     if (ngx_http_complex_value(r, conf->variable, &val) != NGX_OK) {
0123         return NGX_ERROR;
0124     }
0125 
0126     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
0127                    "secure link: \"%V\"", &val);
0128 
0129     last = val.data + val.len;
0130 
0131     p = ngx_strlchr(val.data, last, ',');
0132     expires = 0;
0133 
0134     if (p) {
0135         val.len = p++ - val.data;
0136 
0137         expires = ngx_atotm(p, last - p);
0138         if (expires <= 0) {
0139             goto not_found;
0140         }
0141 
0142         ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_secure_link_ctx_t));
0143         if (ctx == NULL) {
0144             return NGX_ERROR;
0145         }
0146 
0147         ngx_http_set_ctx(r, ctx, ngx_http_secure_link_module);
0148 
0149         ctx->expires.len = last - p;
0150         ctx->expires.data = p;
0151     }
0152 
0153     if (val.len > 24) {
0154         goto not_found;
0155     }
0156 
0157     hash.data = hash_buf;
0158 
0159     if (ngx_decode_base64url(&hash, &val) != NGX_OK) {
0160         goto not_found;
0161     }
0162 
0163     if (hash.len != 16) {
0164         goto not_found;
0165     }
0166 
0167     if (ngx_http_complex_value(r, conf->md5, &val) != NGX_OK) {
0168         return NGX_ERROR;
0169     }
0170 
0171     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
0172                    "secure link md5: \"%V\"", &val);
0173 
0174     ngx_md5_init(&md5);
0175     ngx_md5_update(&md5, val.data, val.len);
0176     ngx_md5_final(md5_buf, &md5);
0177 
0178     if (ngx_memcmp(hash_buf, md5_buf, 16) != 0) {
0179         goto not_found;
0180     }
0181 
0182     v->data = (u_char *) ((expires && expires < ngx_time()) ? "0" : "1");
0183     v->len = 1;
0184     v->valid = 1;
0185     v->no_cacheable = 0;
0186     v->not_found = 0;
0187 
0188     return NGX_OK;
0189 
0190 not_found:
0191 
0192     v->not_found = 1;
0193 
0194     return NGX_OK;
0195 }
0196 
0197 
0198 static ngx_int_t
0199 ngx_http_secure_link_old_variable(ngx_http_request_t *r,
0200     ngx_http_secure_link_conf_t *conf, ngx_http_variable_value_t *v,
0201     uintptr_t data)
0202 {
0203     u_char      *p, *start, *end, *last;
0204     size_t       len;
0205     ngx_int_t    n;
0206     ngx_uint_t   i;
0207     ngx_md5_t    md5;
0208     u_char       hash[16];
0209 
0210     p = &r->unparsed_uri.data[1];
0211     last = r->unparsed_uri.data + r->unparsed_uri.len;
0212 
0213     while (p < last) {
0214         if (*p++ == '/') {
0215             start = p;
0216             goto md5_start;
0217         }
0218     }
0219 
0220     goto not_found;
0221 
0222 md5_start:
0223 
0224     while (p < last) {
0225         if (*p++ == '/') {
0226             end = p - 1;
0227             goto url_start;
0228         }
0229     }
0230 
0231     goto not_found;
0232 
0233 url_start:
0234 
0235     len = last - p;
0236 
0237     if (end - start != 32 || len == 0) {
0238         goto not_found;
0239     }
0240 
0241     ngx_md5_init(&md5);
0242     ngx_md5_update(&md5, p, len);
0243     ngx_md5_update(&md5, conf->secret.data, conf->secret.len);
0244     ngx_md5_final(hash, &md5);
0245 
0246     for (i = 0; i < 16; i++) {
0247         n = ngx_hextoi(&start[2 * i], 2);
0248         if (n == NGX_ERROR || n != hash[i]) {
0249             goto not_found;
0250         }
0251     }
0252 
0253     v->len = len;
0254     v->valid = 1;
0255     v->no_cacheable = 0;
0256     v->not_found = 0;
0257     v->data = p;
0258 
0259     return NGX_OK;
0260 
0261 not_found:
0262 
0263     v->not_found = 1;
0264 
0265     return NGX_OK;
0266 }
0267 
0268 
0269 static ngx_int_t
0270 ngx_http_secure_link_expires_variable(ngx_http_request_t *r,
0271     ngx_http_variable_value_t *v, uintptr_t data)
0272 {
0273     ngx_http_secure_link_ctx_t  *ctx;
0274 
0275     ctx = ngx_http_get_module_ctx(r, ngx_http_secure_link_module);
0276 
0277     if (ctx) {
0278         v->len = ctx->expires.len;
0279         v->valid = 1;
0280         v->no_cacheable = 0;
0281         v->not_found = 0;
0282         v->data = ctx->expires.data;
0283 
0284     } else {
0285         v->not_found = 1;
0286     }
0287 
0288     return NGX_OK;
0289 }
0290 
0291 
0292 static void *
0293 ngx_http_secure_link_create_conf(ngx_conf_t *cf)
0294 {
0295     ngx_http_secure_link_conf_t  *conf;
0296 
0297     conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_secure_link_conf_t));
0298     if (conf == NULL) {
0299         return NULL;
0300     }
0301 
0302     /*
0303      * set by ngx_pcalloc():
0304      *
0305      *     conf->variable = NULL;
0306      *     conf->md5 = NULL;
0307      *     conf->secret = { 0, NULL };
0308      */
0309 
0310     return conf;
0311 }
0312 
0313 
0314 static char *
0315 ngx_http_secure_link_merge_conf(ngx_conf_t *cf, void *parent, void *child)
0316 {
0317     ngx_http_secure_link_conf_t *prev = parent;
0318     ngx_http_secure_link_conf_t *conf = child;
0319 
0320     if (conf->secret.data) {
0321         if (conf->variable || conf->md5) {
0322             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
0323                                "\"secure_link_secret\" cannot be mixed with "
0324                                "\"secure_link\" and \"secure_link_md5\"");
0325             return NGX_CONF_ERROR;
0326         }
0327 
0328         return NGX_CONF_OK;
0329     }
0330 
0331     if (conf->variable == NULL) {
0332         conf->variable = prev->variable;
0333     }
0334 
0335     if (conf->md5 == NULL) {
0336         conf->md5 = prev->md5;
0337     }
0338 
0339     if (conf->variable == NULL && conf->md5 == NULL) {
0340         conf->secret = prev->secret;
0341     }
0342 
0343     return NGX_CONF_OK;
0344 }
0345 
0346 
0347 static ngx_int_t
0348 ngx_http_secure_link_add_variables(ngx_conf_t *cf)
0349 {
0350     ngx_http_variable_t  *var;
0351 
0352     var = ngx_http_add_variable(cf, &ngx_http_secure_link_name, 0);
0353     if (var == NULL) {
0354         return NGX_ERROR;
0355     }
0356 
0357     var->get_handler = ngx_http_secure_link_variable;
0358 
0359     var = ngx_http_add_variable(cf, &ngx_http_secure_link_expires_name, 0);
0360     if (var == NULL) {
0361         return NGX_ERROR;
0362     }
0363 
0364     var->get_handler = ngx_http_secure_link_expires_variable;
0365 
0366     return NGX_OK;
0367 }