Redirect based on php-set cookies
tqvn2004
nginx-forum at nginx.us
Thu Feb 10 15:11:35 MSK 2011
[b]For someone who is interested in using this module[/b]
To compile with nginx, do the following steps:
1. Download Nginx source code from http://wiki.nginx.org/NginxInstall,
and put them in, let's say, folder 'nginx'
2. Install OpenSSL for your Linux.
3. You need also to download OpenSSL source code, and copy folder
openssl/crypto/sha to nginx/src. This step is important, as the
secret_cookie module depends on OpenSSL at compile time.
4. Copy sha/sha.h in openssl/crypto/sha into nginx/src/core. You will
get compilation error if not doing this.
5. Now create a folder name nginx/src/secret_cookie to store the
secret_cookie module. Put the config and ngx_http_secret_cookie_module.c
(described below) in this folder.
7. Go to folder nginx and now you can configure the make:
./configure --prefix=/usr/local/nginx-proxy/ --with-http_ssl_module
--add-module=src/secret_cookie --with-sha1=src/sha
Please change the directory as per your server configuration.
8. Run make, if everything is ok, you should now be able to compile
nginx with the secret_cookie module.
Content of the config file:
[code]ngx_addon_name=ngx_http_secret_cookie_module
HTTP_MODULES="$HTTP_MODULES ngx_http_secret_cookie_module"
NGX_ADDON_SRCS="$NGX_ADDON_SRCS
$ngx_addon_dir/ngx_http_secret_cookie_module.c"
[/code]
Content of the ngx_http_secret_cookie_module.c file:
[code]
/*
* Copyright (C) Huan Cong Nguyen
* Version 1.0.6
*/
#include
#include
#include
#include
/*
* This module set the $secret_cookie_value variable
* to the names of valid secret cookies set at client.
* Based on the variable, user can be classified
* into verified and non-verified one.
*/
#define NGX_HTTP_SECRET_COOKIE_OFF 0 // Default state
#define NGX_HTTP_SECRET_COOKIE_ON 1
#define NGX_HTTP_SECRET_COOKIE_NOT_SET 0
#define NGX_HTTP_SECRET_COOKIE_MINIMUM_DURATION 600 // 10
minutes
#define NGX_HTTP_SECRET_COOKIE_MINIMUM_UA_LIMIT 10 // 10
characters
#define NGX_HTTP_SECRET_COOKIE_MAX_SHORT_STR_SIZE 12 // Allow only
12 characters in name, salt and rule
// Rule elements
#define NGX_HTTP_SECRET_COOKIE_RULE_SALT 's'
#define NGX_HTTP_SECRET_COOKIE_RULE_ADDRESS 'a'
#define NGX_HTTP_SECRET_COOKIE_RULE_TIME 't'
#define NGX_HTTP_SECRET_COOKIE_RULE_USER_AGENT 'u'
#define NGX_HTTP_SECRET_COOKIE_DIVIDER ' '
// Record for each secret cookie
typedef struct {
ngx_flag_t status;
ngx_flag_t log;
ngx_uint_t duration;
ngx_str_t name;
ngx_str_t rule;
ngx_str_t salt;
ngx_uint_t ua_limit;
} ngx_http_secret_cookie_t;
// Record for Location configuration
typedef struct {
ngx_flag_t status;
ngx_array_t *secret_cookies;
ngx_http_variable_value_t *secret_cookie_value_disabled;
} ngx_http_secret_cookie_conf_t;
// Context variable: This alive for request's duration
typedef struct {
ngx_http_variable_value_t *secret_cookie_value;
} ngx_http_secret_cookie_ctx_t;
// Return variable structure
typedef struct {
ngx_str_t name;
ngx_http_get_variable_pt handler;
uintptr_t data;
} ngx_http_secret_cookie_variable_t;
static void *ngx_http_secret_cookie_create_conf(ngx_conf_t *cf);
static char *ngx_http_secret_cookie_merge_conf(ngx_conf_t *cf, void
*parent,
void *child);
static ngx_int_t ngx_http_secret_cookie_add_variable(ngx_conf_t *cf);
static ngx_int_t ngx_http_secret_cookie_variable(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data);
static ngx_http_secret_cookie_ctx_t *
ngx_http_secret_cookie_handler(ngx_http_request_t *r,
ngx_http_secret_cookie_conf_t *cf);
static char *ngx_http_secret_cookie_def(ngx_conf_t *cf, ngx_command_t
*cmd, void *conf);
static u_char * ngx_num2str(u_char *buf, u_char *last, uint64_t ui64);
static ngx_int_t ngx_raw_vs_hex(u_char *rawbuf, size_t rlen, u_char
*hexbuf, size_t hlen);
static ngx_command_t ngx_http_secret_cookie_commands[] = {
/* Define secret_cookie directive (on or off).
* Location: Main, HTTP
* Take: 1 parameter, a Flag
*/
{ ngx_string("secret_cookie"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1,
ngx_conf_set_flag_slot, // Convert on/off to value
NGX_HTTP_LOC_CONF_OFFSET, // Instruct value to be written to
Location Config,
offsetof(ngx_http_secret_cookie_conf_t, status), // with this
offset
NULL }, // No post-handler is necessary.
/* Define secret_cookie_def directive ([off] name=xyz salt=abc
rule=mnk duration=8323)
* Location: Main, HTTP
* Taking: 4 or 5 parameters
*/
{ ngx_string("secret_cookie_def"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE4|NGX_CONF_TAKE5|NGX_CONF_TAKE6|NGX_CONF_TAKE7,
ngx_http_secret_cookie_def,
NGX_HTTP_LOC_CONF_OFFSET,
0,
NULL },
ngx_null_command
};
static ngx_http_module_t ngx_http_secret_cookie_module_ctx = {
ngx_http_secret_cookie_add_variable, /* preconfiguration */
NULL, /* postconfiguration */
NULL, /* create main configuration
*/
NULL, /* init main configuration */
NULL, /* create server configuration
*/
NULL, /* merge server configuration
*/
ngx_http_secret_cookie_create_conf, /* create location
configuration */
ngx_http_secret_cookie_merge_conf /* merge location
configuration */
};
ngx_module_t ngx_http_secret_cookie_module = {
NGX_MODULE_V1,
&ngx_http_secret_cookie_module_ctx, /* module context */
ngx_http_secret_cookie_commands, /* module directives */
NGX_HTTP_MODULE, /* module type */
NULL, /* init master */
NULL, /* init module */
NULL, /* init process */
NULL, /* init thread */
NULL, /* exit thread */
NULL, /* exit process */
NULL, /* exit master */
NGX_MODULE_V1_PADDING
};
static ngx_http_secret_cookie_variable_t ngx_http_secret_cookie_vars[]
= {
{ ngx_string("secret_cookie_value"),
ngx_http_secret_cookie_variable,
NGX_HTTP_SECRET_COOKIE_NOT_SET },
{ ngx_null_string, NULL, 0 }
};
/*
* This function set the $secret_cookie_value to found secret_cookie
names,
* if they are set and valid.
*/
static ngx_int_t
ngx_http_secret_cookie_variable(ngx_http_request_t *r,
ngx_http_variable_value_t *v,
uintptr_t data)
{
ngx_http_secret_cookie_ctx_t *rctx;
ngx_http_secret_cookie_conf_t *cf;
cf = ngx_http_get_module_loc_conf(r,
ngx_http_secret_cookie_module);
// Check if the module is enable?
if (cf->status == NGX_HTTP_SECRET_COOKIE_ON){
// Only perform cookie search if the module is enable
rctx = ngx_http_secret_cookie_handler(r, cf);
if (rctx != NULL){
#if (NGX_DEBUG)
ngx_log_debug(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"secret_cookie: Rctx is returned with
value");
#endif
*v = *rctx->secret_cookie_value;
return NGX_OK;
} else {
// There is something wrong with the search for secret
cookies,
// just return null value to fail all user-defined checks
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
"secret_cookie: Rctx is null, which is often
due to lack of memory");
*v = ngx_http_variable_null_value;
return NGX_OK;
}
}
// In case the secret_cookie is disabled,
// all defined secret cookies are assumed to be found,
// so that user-defined checks are successful
*v = *cf->secret_cookie_value_disabled;
return NGX_OK;
}
/*
* This is the main function: It looks for a secret cookie
* in the HTTP request header, and compared with constructed value
* Return: Secret Cookie SET or NOT SET!
*/
static ngx_http_secret_cookie_ctx_t *
ngx_http_secret_cookie_handler(ngx_http_request_t *r,
ngx_http_secret_cookie_conf_t *cf)
{
ngx_http_secret_cookie_ctx_t *ctx;
ngx_http_secret_cookie_t *sc;
ngx_uint_t n, i, ua_len;
ngx_int_t m;
ngx_str_t name, rule, salt, last_change,
remote_address, user_agent,
computed_sc, submitted_sc, sc_string,
secret_cookie_value;
time_t timestamp; // Current UNIX timestamp
u_char *p;
ngx_sha1_t sha_ctx;
// Try to get the context variable
ctx = ngx_http_get_module_ctx(r, ngx_http_secret_cookie_module);
// If context existed, secret_cookie was checked before, so stop!
if (ctx){
#if (NGX_DEBUG)
ngx_log_debug(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"secret_cookie: Checking was done before,
aborting!");
#endif
return ctx;
}
// Otherwise, start the checking process
if (ctx == NULL) {
#if (NGX_DEBUG)
ngx_log_debug(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"secret_cookie: Checking was not done before, start
checking");
#endif
// This r->pool temporary memory will be destroyed later,
// after this request is served!
ctx = ngx_pcalloc(r->pool,
sizeof(ngx_http_secret_cookie_ctx_t));
if (ctx == NULL) {
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
"secret_cookie: Out of memory for context variable
(ctx)");
return NULL;
}
ngx_http_set_ctx(r, ctx, ngx_http_secret_cookie_module);
}
ctx->secret_cookie_value = ngx_palloc(r->pool,
sizeof(ngx_http_variable_value_t));
if (ctx->secret_cookie_value == NULL){
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
"secret_cookie: Out of memory for
ctx->secret_cookie_value variable");
return NULL;
}
*ctx->secret_cookie_value = ngx_http_variable_null_value;
remote_address.len = r->connection->addr_text.len;
remote_address.data = r->connection->addr_text.data;
if (r->headers_in.user_agent == NULL) {
// The user-agent value is null
user_agent.len = 0;
user_agent.data = NULL;
#if (NGX_DEBUG)
ngx_log_debug(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"secret_cookie: User agent is empty");
#endif
} else {
// The user-agent value is not null
user_agent.len = r->headers_in.user_agent->value.len;
user_agent.data = r->headers_in.user_agent->value.data;
#if (NGX_DEBUG)
ngx_log_debug(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"secret_cookie: User agent is not empty");
#endif
}
secret_cookie_value.len = 0;
// Allocate maximum size for this variable
secret_cookie_value.data = ngx_pcalloc(r->pool,
cf->secret_cookie_value_disabled->len);
if (secret_cookie_value.data == NULL){
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
"secret_cookie: Out of memory for
secret_cookie_value string");
return NULL;
}
sc = cf->secret_cookies->elts;
for (i=0; i < cf->secret_cookies->nelts; i++){
// Cookie name must be initialized first, in case of jumping to
secret_cookie_found!
name.len = sc[i].name.len;
name.data = sc[i].name.data;
if (sc[i].status == NGX_HTTP_SECRET_COOKIE_OFF){
#if (NGX_DEBUG)
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"secret_cookie: checking of cookie \"%V\" is off",
&name);
#endif
goto secret_cookie_found;
}
// First, search for the secret_cookie's name in http header:
m = ngx_http_parse_multi_header_lines(&r->headers_in.cookies,
&name,
&submitted_sc);
if (m == NGX_DECLINED) {
#if (NGX_DEBUG)
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"secret_cookie: cookie \"%V\" is not found in
header", &name);
#endif
goto secret_cookie_not_found;
}
#if (NGX_DEBUG)
ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"secret_cookie: cookie \"%V\" found in header,
value=%V and length=%i",
&name, &submitted_sc, submitted_sc.len);
#endif
if (submitted_sc.len != 2*SHA_DIGEST_LENGTH) {
#if (NGX_DEBUG)
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"secret_cookie: size of cookie \"%V\" is incorrect",
&name);
#endif
goto secret_cookie_not_found;
}
// User Agent can be very large. Limit to a certain size
// to keep small memory footprint
if ((sc[i].ua_limit > 0) && (user_agent.len > sc[i].ua_limit))
{
ua_len = sc[i].ua_limit;
} else {
ua_len = user_agent.len;
}
salt.len = sc[i].salt.len;
salt.data = sc[i].salt.data;
rule.len = sc[i].rule.len;
rule.data = sc[i].rule.data;
// Obtain current time in second
timestamp = ngx_time();
// Calculate the last_change and convert it to string
last_change.data = ngx_pcalloc(r->pool, NGX_INT64_LEN);
if (last_change.data == NULL) {
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
"secret_cookie: Out of memory for
last_change string");
return NULL;
}
p = ngx_num2str(last_change.data,
last_change.data + NGX_INT64_LEN,
(uint64_t) timestamp / sc[i].duration);
last_change.len = p - last_change.data;
#if (NGX_DEBUG)
ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"secret_cookie: name has length=%i and value=%V",
name.len, &name);
ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"secret_cookie: salt has length=%i and value=%V",
salt.len, &salt);
ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"secret_cookie: rule has length=%i and value=%V",
rule.len, &rule);
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"secret_cookie: duration = %i", sc[i].duration);
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"secret_cookie: last_change = %V", &last_change);
ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"secret_cookie: remote_address has length=%i and
value=%V",
remote_address.len, &remote_address);
ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"secret_cookie: user-agent has length=%i from
value=%V",
ua_len, &user_agent);
#endif
// Second, compute the secret_cookie according to the rule:
sc_string.len = 0;
for (n=0; n < rule.len; n++){
switch (ngx_tolower(rule.data[n])){
case NGX_HTTP_SECRET_COOKIE_RULE_ADDRESS:
sc_string.len += remote_address.len;
break;
case NGX_HTTP_SECRET_COOKIE_RULE_SALT:
sc_string.len += salt.len;
break;
case NGX_HTTP_SECRET_COOKIE_RULE_USER_AGENT:
sc_string.len += ua_len;
break;
case NGX_HTTP_SECRET_COOKIE_RULE_TIME:
sc_string.len += last_change.len;
break;
default:
#if (NGX_DEBUG)
ngx_log_debug(NGX_LOG_DEBUG_HTTP,
r->connection->log, 0,
"secret_cookie: Unknown rule");
#endif
break;
} // End of switch
}
sc_string.data = ngx_pcalloc(r->pool, sc_string.len);
if (sc_string.data == NULL) {
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
"secret_cookie: Out of memory for sc_string
variable");
return NULL;
}
p = sc_string.data;
for (n=0; n < rule.len; n++){
switch (ngx_tolower(rule.data[n])){
case NGX_HTTP_SECRET_COOKIE_RULE_ADDRESS:
// This ngx_copy faster than ngx_cpymem with buffer
< 16 bytes
p = ngx_copy(p, remote_address.data,
remote_address.len);
break;
case NGX_HTTP_SECRET_COOKIE_RULE_SALT:
p = ngx_copy(p, salt.data, salt.len);
break;
case NGX_HTTP_SECRET_COOKIE_RULE_USER_AGENT:
if (ua_len > 0){
p = ngx_cpymem(p, user_agent.data, ua_len);
}
break;
case NGX_HTTP_SECRET_COOKIE_RULE_TIME:
p = ngx_copy(p, last_change.data, last_change.len);
break;
default:
#if (NGX_DEBUG)
ngx_log_debug(NGX_LOG_DEBUG_HTTP,
r->connection->log, 0,
"secret_cookie: Unknown rule");
#endif
break;
} // End of switch
}
#if (NGX_DEBUG)
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"secret_cookie: String to compute secret_cookie has
length=%i and value=%V",
sc_string.len, &sc_string);
#endif
// Third, perform sha1 on the content
computed_sc.len = SHA_DIGEST_LENGTH;
computed_sc.data = ngx_pcalloc(r->pool, SHA_DIGEST_LENGTH);
if (computed_sc.data == NULL) {
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
"secret_cookie: Out of memory for computed_sc
variable");
return NULL;
}
n = ngx_sha1_init(&sha_ctx);
if (n == 0) {
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
"secret_cookie: SHA1 init fails");
return NULL;
}
n = ngx_sha1_update(&sha_ctx, sc_string.data, sc_string.len);
if (n == 0) {
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
"secret_cookie: SHA1 update fails");
return NULL;
}
n = ngx_sha1_final(computed_sc.data, &sha_ctx);
if (n == 0) {
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
"secret_cookie: SHA1 final fails");
return NULL;
}
// Release the sc_string memory:
#if (NGX_DEBUG)
ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"secret_cookie: computed_secret_cookie has length=%i
and value=%V", SHA_DIGEST_LENGTH, &computed_sc);
#endif
if (ngx_raw_vs_hex(computed_sc.data, SHA_DIGEST_LENGTH,
submitted_sc.data, 2*SHA_DIGEST_LENGTH) == 0){
if (sc[i].log == NGX_HTTP_SECRET_COOKIE_ON){
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
"secret_cookie: cookie \"%V\" is valid", &name);
}
goto secret_cookie_found;
}
#if (NGX_DEBUG)
ngx_log_debug(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"secret_cookie: cookie \"%V\" does not match",
&name);
#endif
secret_cookie_not_found:
if (sc[i].log == NGX_HTTP_SECRET_COOKIE_ON){
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
"secret_cookie: no valid cookie \"%V\" in header",
&name);
}
continue;
secret_cookie_found:
// Append the found secret_cookie's name into
secret_cookie_value:
p = ngx_copy(secret_cookie_value.data + secret_cookie_value.len,
name.data, name.len);
*p = (u_char) NGX_HTTP_SECRET_COOKIE_DIVIDER; // Name is
separate by a space
secret_cookie_value.len += name.len + 1;
}
// Setup the secret_cookie_value variable:
ctx->secret_cookie_value->len = secret_cookie_value.len;
ctx->secret_cookie_value->data = secret_cookie_value.data;
ctx->secret_cookie_value->valid = 1;
ctx->secret_cookie_value->no_cacheable = 1;
ctx->secret_cookie_value->not_found = 0;
#if (NGX_DEBUG)
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"secret_cookie: The final secret_cookie_value has
length=%i and value=%V", secret_cookie_value.len,
&secret_cookie_value);
#endif
// Return the result
return ctx;
}
/* Add $secret_cookie_set variable to the http process.
* Called by "preconfiguration" hook!
*/
static ngx_int_t
ngx_http_secret_cookie_add_variable(ngx_conf_t *cf)
{
ngx_http_secret_cookie_variable_t *var;
ngx_http_variable_t *v;
for (var = ngx_http_secret_cookie_vars; var->name.len; var++) {
v = ngx_http_add_variable(cf, &var->name,
NGX_HTTP_VAR_CHANGEABLE);
if (v == NULL) {
return NGX_ERROR;
}
v->get_handler = var->handler;
v->data = var->data;
}
return NGX_OK;
}
/*
* This function is called when location configuration is created.
* It will create a default configuration for secret_cookie module.
*/
static void *
ngx_http_secret_cookie_create_conf(ngx_conf_t *cf)
{
ngx_http_secret_cookie_conf_t *conf;
conf = ngx_pcalloc(cf->pool,
sizeof(ngx_http_secret_cookie_conf_t));
if (conf == NULL) {
return NULL;
}
/*
* Set by ngx_pcalloc():
*
* conf->secret_cookies = NULL;
* conf->secret_cookies_value_disabled = NULL;
*/
conf->status = NGX_CONF_UNSET;
return conf;
}
/*
* This function is called when location configuration is merged to main
config.
* It will create a default configuration for secret_cookie module.
*/
static char *
ngx_http_secret_cookie_merge_conf(ngx_conf_t *cf, void *parent, void
*child)
{
ngx_http_secret_cookie_conf_t *prev = parent;
ngx_http_secret_cookie_conf_t *conf = child;
u_char *p;
ngx_str_t secret_cookie_value_disabled;
ngx_uint_t i;
ngx_http_secret_cookie_t *sc;
// Merge previous to current configration, with a default value:
ngx_conf_merge_value(conf->status, prev->status,
NGX_HTTP_SECRET_COOKIE_OFF);
if (conf->secret_cookies == NULL){
conf->secret_cookies = prev->secret_cookies;
conf->secret_cookie_value_disabled =
prev->secret_cookie_value_disabled;
} else {
// Generate the disabled_value for this configuration:
// First, count the required string length
secret_cookie_value_disabled.len = 0;
sc = conf->secret_cookies->elts;
for (i=0; isecret_cookies->nelts; i++){
secret_cookie_value_disabled.len += sc[i].name.len + 1;
}
// Secondly, create the buffer containing disabled_value
secret_cookie_value_disabled.data = ngx_pcalloc(cf->pool,
secret_cookie_value_disabled.len);
if (secret_cookie_value_disabled.data == NULL){
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"Not enough memory for
secret_cookie_value_disabled string");
return NGX_CONF_ERROR;
}
// Thirdly, copy all secret cookie's name to disabled_value
p = secret_cookie_value_disabled.data;
for (i=0; isecret_cookies->nelts; i++){
p = ngx_copy(p, sc[i].name.data, sc[i].name.len);
*p = (u_char) NGX_HTTP_SECRET_COOKIE_DIVIDER; // Name is
separate by a space
p++;
}
#if (NGX_DEBUG)
ngx_conf_log_error(NGX_LOG_NOTICE, cf, 0,
"String secret_cookie_value_disabled has length = %i and
value = %V", secret_cookie_value_disabled.len,
&secret_cookie_value_disabled);
#endif
conf->secret_cookie_value_disabled = ngx_pcalloc(cf->pool,
sizeof(ngx_http_variable_value_t));
if (conf->secret_cookie_value_disabled == NULL){
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"Not enough memory for
conf->secret_cookie_value_disabled variable");
return NGX_CONF_ERROR;
}
conf->secret_cookie_value_disabled->len =
secret_cookie_value_disabled.len;
conf->secret_cookie_value_disabled->valid = 1;
conf->secret_cookie_value_disabled->no_cacheable = 1;
conf->secret_cookie_value_disabled->not_found = 0;
conf->secret_cookie_value_disabled->data =
secret_cookie_value_disabled.data;
}
return NGX_CONF_OK;
}
/*
* This function is called after secret_cookie_def is passed
* from config to module. Here you can validate the param, or change the
* param to meaningful value.
*/
static char *
ngx_http_secret_cookie_def(ngx_conf_t *cf, ngx_command_t *cmd, void
*conf)
{
ngx_http_secret_cookie_conf_t *sccf = conf;
ngx_uint_t n, i, anumber;
u_char c;
ngx_str_t *value;
ngx_http_secret_cookie_t *sc;
// Create secret_cookies array to hold definitions
if (sccf->secret_cookies == NULL){
sccf->secret_cookies = ngx_array_create(cf->pool, 3,
sizeof(ngx_http_secret_cookie_t));
if (sccf->secret_cookies == NULL){
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"Not enough memory for sccf->secret_cookies
array");
return NGX_CONF_ERROR;
}
}
// Create new element in the array to hold one definition
sc = ngx_array_push(sccf->secret_cookies);
if (sc == NULL) {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"Not enough memory for new element in
sccf->secret_cookies array");
return NGX_CONF_ERROR;
}
// Process the parameters
sc->status = NGX_HTTP_SECRET_COOKIE_ON;
sc->log = NGX_HTTP_SECRET_COOKIE_OFF;
sc->ua_limit = 0;
value = cf->args->elts;
for (n=1; n < cf->args->nelts; n++){
// off
if (ngx_strncmp(value[n].data,"off",3)==0){
sc->status = NGX_HTTP_SECRET_COOKIE_OFF;
continue;
}
// log
if (ngx_strncmp(value[n].data,"log=on",6)==0){
sc->log = NGX_HTTP_SECRET_COOKIE_ON;
continue;
}
//ua_limit=
if (ngx_strncmp(value[n].data, "ua_limit=", 9) == 0){
// Convert ua_limit to number:
anumber = 0;
for (i=9; i < value[n].len; i++){
c = value[n].data[i];
if (c >= '0' && c <= '9'){
anumber = anumber*10 + (c - '0');
continue;
}
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"Invalid \"ua_limit\" (must be an integer)");
return NGX_CONF_ERROR;
}
// Validate the ua_limit:
if ((anumber > 0) && (anumber <
NGX_HTTP_SECRET_COOKIE_MINIMUM_UA_LIMIT)){
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"Invalid \"ua_limit\" (must be greater than
%i)", NGX_HTTP_SECRET_COOKIE_MINIMUM_UA_LIMIT);
return NGX_CONF_ERROR;
}
sc->ua_limit = anumber;
continue;
}
// name=
if (ngx_strncmp(value[n].data, "name=", 5) == 0){
sc->name.len = value[n].len - 5;
if ((sc->name.len < 1) || (sc->name.len >
NGX_HTTP_SECRET_COOKIE_MAX_SHORT_STR_SIZE)){
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"Parameter \"name\" is empty or too long");
return NGX_CONF_ERROR;
}
sc->name.data = value[n].data + 5;
continue;
}
// salt=
if (ngx_strncmp(value[n].data, "salt=", 5) == 0){
sc->salt.len = value[n].len - 5;
if ((sc->salt.len < 1) || (sc->salt.len >
NGX_HTTP_SECRET_COOKIE_MAX_SHORT_STR_SIZE)){
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"Parameter \"salt\" is empty or too long");
return NGX_CONF_ERROR;
}
sc->salt.data = value[n].data + 5;
continue;
}
// rule=
if (ngx_strncmp(value[n].data, "rule=", 5) == 0){
// Validate the rule:
for (i=5; i < value[n].len; i++){
c = ngx_tolower(value[n].data[i]);
switch (c){
case NGX_HTTP_SECRET_COOKIE_RULE_ADDRESS:
case NGX_HTTP_SECRET_COOKIE_RULE_TIME:
case NGX_HTTP_SECRET_COOKIE_RULE_SALT:
case NGX_HTTP_SECRET_COOKIE_RULE_USER_AGENT:
break;
default:
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"Rule does not accept characters other than
\"a\", \"t\", \"s\" and \"u\"");
return NGX_CONF_ERROR;
}
}
sc->rule.len = value[n].len - 5;
if ((sc->rule.len < 1) || (sc->rule.len >
NGX_HTTP_SECRET_COOKIE_MAX_SHORT_STR_SIZE)){
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"Parameter \"rule\" is empty or too long");
return NGX_CONF_ERROR;
}
sc->rule.data = value[n].data + 5;
continue;
}
// duration
if (ngx_strncmp(value[n].data, "duration=", 9) == 0){
// Convert duration to number:
anumber = 0;
for (i=9; i < value[n].len; i++){
c = value[n].data[i];
if (c >= '0' && c <= '9'){
anumber = anumber*10 + (c - '0');
continue;
}
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"Invalid \"duration\" (must be an integer)");
return NGX_CONF_ERROR;
}
// Validate the duration:
if (anumber < NGX_HTTP_SECRET_COOKIE_MINIMUM_DURATION){
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"Invalid \"duration\" (must be greater than
%i)", NGX_HTTP_SECRET_COOKIE_MINIMUM_DURATION);
return NGX_CONF_ERROR;
}
sc->duration = anumber;
continue;
}
}
if (sc->rule.data == NULL){
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"The required parameter \"rule\" is
missing!");
return NGX_CONF_ERROR;
}
if (sc->salt.data == NULL){
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"The required parameter \"salt\" is
missing!");
return NGX_CONF_ERROR;
}
if (sc->name.data == NULL){
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"The required parameter \"name\" is
missing!");
return NGX_CONF_ERROR;
}
if (sc->duration == 0){
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"The required parameter \"duration\" is
missing");
return NGX_CONF_ERROR;
}
#if (NGX_DEBUG)
ngx_conf_log_error(NGX_LOG_DEBUG, cf, 0,
"Secret_cookie_def: on/off=%i name=%V salt=%V rule=%V
duration=%i",
sc->status, &sc->name, &sc->salt, &sc->rule,
sc->duration);
#endif
return NGX_CONF_OK;
}
/*
* Convert an int64 to string presentation
*/
static u_char * ngx_num2str(u_char *buf, u_char *last, uint64_t ui64)
{
u_char *p, temp[NGX_INT64_LEN + 1];
/*
* we need temp[NGX_INT64_LEN] only,
* but icc issues the warning
*/
size_t len;
uint32_t ui32;
p = temp + NGX_INT64_LEN;
if (ui64 <= NGX_MAX_UINT32_VALUE) {
ui32 = (uint32_t) ui64;
do {
*--p = (u_char) (ui32 % 10 + '0');
} while (ui32 /= 10);
} else {
do {
*--p = (u_char) (ui64 % 10 + '0');
} while (ui64 /= 10);
}
/* number safe copy */
len = (temp + NGX_INT64_LEN) - p;
if (buf + len > last) {
len = last - buf;
}
return ngx_cpymem(buf, p, len);
}
/*
* Comparison of a raw string and a hex-style string
*/
static ngx_int_t ngx_raw_vs_hex(u_char *rawbuf, size_t rlen, u_char
*hexbuf, size_t hlen)
{
static u_char hex[] = "0123456789abcdef";
u_char hexchar[] = "aa";
ngx_int_t len, i;
// Compare by the shortest length
len = ((rlen < hlen / 2) ? rlen : hlen / 2);
i = 0;
while (i < len){
// Calculate a hexchar from rawbuff
hexchar[1] = hex[rawbuf[i] & 0xf];
hexchar[0] = hex[(rawbuf[i]>>4) & 0xf];
if ((hexchar[0] != hexbuf[2*i]) || (hexchar[1] !=
hexbuf[2*i+1])){
return 1;
}
i++;
}
return 0;
}
[/code]
Posted at Nginx Forum: http://forum.nginx.org/read.php?2,55378,173796#msg-173796
More information about the nginx
mailing list