Exemple #1
0
static int cache_call_lua(server *srv, connection *con, plugin_data *p, buffer *cml_file) {
	buffer *b;
	char *c;

	/* cleanup basedir */
	b = p->baseurl;
	buffer_copy_string_buffer(b, con->uri.path);
	for (c = b->ptr + b->used - 1; c > b->ptr && *c != '/'; c--);

	if (*c == '/') {
		b->used = c - b->ptr + 2;
		*(c+1) = '\0';
	}

	b = p->basedir;
	buffer_copy_string_buffer(b, con->physical.path);
	for (c = b->ptr + b->used - 1; c > b->ptr && *c != '/'; c--);

	if (*c == '/') {
		b->used = c - b->ptr + 2;
		*(c+1) = '\0';
	}


	/* prepare variables
	 *   - cookie-based
	 *   - get-param-based
	 */
	return cache_parse_lua(srv, con, p, cml_file);
}
static data_unset *data_string_copy(const data_unset *s) {
	data_string *src = (data_string *)s;
	data_string *ds = data_string_init();

	buffer_copy_string_buffer(ds->key, src->key);
	buffer_copy_string_buffer(ds->value, src->value);
	ds->is_index_key = src->is_index_key;
	return (data_unset *)ds;
}
static data_unset *data_config_copy(const data_unset *s) {
	data_config *src = (data_config *)s;
	data_config *ds = data_config_init();

	buffer_copy_string_buffer(ds->key, src->key);
	buffer_copy_string_buffer(ds->comp_key, src->comp_key);
	array_free(ds->value);
	ds->value = array_init_array(src->value);
	return (data_unset *)ds;
}
Exemple #4
0
static int log_buffer_prepare(buffer *b, server *srv, const char *filename, unsigned int line) {
    switch(srv->errorlog_mode) {
    case ERRORLOG_PIPE:
    case ERRORLOG_FILE:
    case ERRORLOG_FD:
        if (-1 == srv->errorlog_fd) return -1;
        /* cache the generated timestamp */
        if (srv->cur_ts != srv->last_generated_debug_ts) {
            buffer_prepare_copy(srv->ts_debug_str, 255);
            strftime(srv->ts_debug_str->ptr, srv->ts_debug_str->size - 1, "%Y-%m-%d %H:%M:%S", localtime(&(srv->cur_ts)));
            srv->ts_debug_str->used = strlen(srv->ts_debug_str->ptr) + 1;

            srv->last_generated_debug_ts = srv->cur_ts;
        }

        buffer_copy_string_buffer(b, srv->ts_debug_str);
        buffer_append_string_len(b, CONST_STR_LEN(": ("));
        break;
    case ERRORLOG_SYSLOG:
        /* syslog is generating its own timestamps */
        buffer_copy_string_len(b, CONST_STR_LEN("("));
        break;
    }

    buffer_append_string(b, filename);
    buffer_append_string_len(b, CONST_STR_LEN("."));
    buffer_append_long(b, line);
    buffer_append_string_len(b, CONST_STR_LEN(") "));

    return 0;
}
fd_data * mod_lisp_allocate_socket (plugin_data *p)
{
  int i;
  fd_data *ff, *ff_open, *ff_free, *ff_stale, *ff_borrowed;

  ff_open = ff_free = ff_stale = ff_borrowed = NULL;
  for (ff = p->LispSocketPool, i = 0;
       i <= p->LispSocketPoolUsed && i < p->LispSocketPoolSize
         && ! (ff_open && ff_free && ff_stale && ff_borrowed);
       ++i, ++ff) {
    if (ff->fd >= 0) {
      if (! (ff->state & (FD_STATE_WRITE | FD_STATE_READ))) {
        if (buffer_is_equal(ff->ip, p->conf.LispServerIP)
            && ff->port == p->conf.LispServerPort) {
          /* Option 1: an open, non-stale socket to reuse */
          if (!ff_open) ff_open = ff;
        } else {
          /* Option 2: the same, but the socket is open to a different Lisp */
          if (!ff_borrowed) ff_borrowed = ff;
        }
      } else if ((FD_STATE_UNSAFE_EV_COUNT(ff->state)
                    >= LISP_STALE_SOCKET_TOLERANCE)) {
        /* Option 3: a stale socket */
        if (!ff_stale) ff_stale = ff;
      }
    } else {
      /* Option 4: an unallocated slot */
      if (!ff_free) ff_free = ff;
    }
  }

  /* Allocation priority */
  if (ff_open) ff = ff_open;
  else if (ff_free) ff = ff_free;
  else if (ff_stale) ff = ff_stale;
  else ff = ff_borrowed;

  if (ff != ff_open) {
    if (ff == ff_borrowed) FD_STATE_UNSAFE_EV_COUNT_INC(ff->state);
    buffer_copy_string_buffer(ff->ip, p->conf.LispServerIP);
    buffer_copy_string_buffer(ff->id, p->conf.LispServerId);
    ff->port = p->conf.LispServerPort;
  }
  if ((int) (ff - p->LispSocketPool) >= p->LispSocketPoolUsed)
    ++(p->LispSocketPoolUsed);
  return ff;
}
Exemple #6
0
static int build_doc_root(server *srv, connection *con, plugin_data *p, buffer *out, buffer *host) {
	stat_cache_entry *sce = NULL;

	buffer_prepare_copy(out, 128);

	if (p->conf.server_root->used) {
		buffer_copy_string_buffer(out, p->conf.server_root);

		if (host->used) {
			/* a hostname has to start with a alpha-numerical character
			 * and must not contain a slash "/"
			 */
			char *dp;

			BUFFER_APPEND_SLASH(out);

			if (NULL == (dp = strchr(host->ptr, ':'))) {
				buffer_append_string_buffer(out, host);
			} else {
				buffer_append_string_len(out, host->ptr, dp - host->ptr);
			}
		}
		BUFFER_APPEND_SLASH(out);

		if (p->conf.document_root->used > 2 && p->conf.document_root->ptr[0] == '/') {
			buffer_append_string_len(out, p->conf.document_root->ptr + 1, p->conf.document_root->used - 2);
		} else {
			buffer_append_string_buffer(out, p->conf.document_root);
			BUFFER_APPEND_SLASH(out);
		}
	} else {
		buffer_copy_string_buffer(out, con->conf.document_root);
		BUFFER_APPEND_SLASH(out);
	}

	if (HANDLER_ERROR == stat_cache_get_entry(srv, con, out, &sce)) {
		if (p->conf.debug) {
			log_error_write(srv, __FILE__, __LINE__, "sb",
					strerror(errno), out);
		}
		return -1;
	} else if (!S_ISDIR(sce->st.st_mode)) {
		return -1;
	}

	return 0;
}
Exemple #7
0
int config_setup_connection(server *srv, connection *con) {
	specific_config *s = srv->config_storage[0];

	PATCH(allow_http11);
	PATCH(mimetypes);
	PATCH(document_root);
	PATCH(max_keep_alive_requests);
	PATCH(max_keep_alive_idle);
	PATCH(max_read_idle);
	PATCH(max_write_idle);
	PATCH(use_xattr);
	PATCH(error_handler);
	PATCH(errorfile_prefix);
#ifdef HAVE_LSTAT
	PATCH(follow_symlink);
#endif
	PATCH(server_tag);
	PATCH(kbytes_per_second);
	PATCH(global_kbytes_per_second);
	PATCH(global_bytes_per_second_cnt);

	con->conf.global_bytes_per_second_cnt_ptr = &s->global_bytes_per_second_cnt;
	buffer_copy_string_buffer(con->server_name, s->server_name);

	PATCH(log_request_header);
	PATCH(log_response_header);
	PATCH(log_request_handling);
	PATCH(log_condition_handling);
	PATCH(log_file_not_found);
	PATCH(log_ssl_noise);
	PATCH(log_timeouts);

	PATCH(range_requests);
	PATCH(force_lowercase_filenames);
	PATCH(is_ssl);

	PATCH(ssl_pemfile);
#ifdef USE_OPENSSL
	PATCH(ssl_ctx);
#endif
	PATCH(ssl_ca_file);
	PATCH(ssl_cipher_list);
	PATCH(ssl_dh_file);
	PATCH(ssl_ec_curve);
	PATCH(ssl_use_sslv2);
	PATCH(ssl_use_sslv3);
	PATCH(etag_use_inode);
	PATCH(etag_use_mtime);
	PATCH(etag_use_size);

	PATCH(ssl_verifyclient);
	PATCH(ssl_verifyclient_enforce);
	PATCH(ssl_verifyclient_depth);
	PATCH(ssl_verifyclient_username);
	PATCH(ssl_verifyclient_export_cert);

	return 0;
}
Exemple #8
0
static data_unset *data_array_copy(const data_unset * s)
{
	data_array *src = (data_array *) s;
	data_array *ds = data_array_init();

	buffer_copy_string_buffer(ds->key, src->key);
	array_free(ds->value);
	ds->value = array_init_array(src->value);
	ds->is_index_key = src->is_index_key;
	return (data_unset *) ds;
}
Exemple #9
0
int chunkqueue_prepend_buffer(chunkqueue *cq, buffer *mem) {
	chunk *c;

	if (mem->used == 0) return 0;

	c = chunkqueue_get_unused_chunk(cq);
	c->type = MEM_CHUNK;
	c->offset = 0;
	buffer_copy_string_buffer(c->mem, mem);

	chunkqueue_prepend_chunk(cq, c);

	return 0;
}
static void http_list_directory_footer(server *srv, connection *con, plugin_data *p, buffer *out) {
	UNUSED(srv);

	buffer_append_string_len(out, CONST_STR_LEN(
		"</tbody>\n"
		"</table>\n"
		"</div>\n"
	));

	if (p->conf.show_readme) {
		stream s;
		/* if we have a README file, display it in <pre class="readme"></pre> */

		buffer_copy_string_buffer(p->tmp_buf,  con->physical.path);
		BUFFER_APPEND_SLASH(p->tmp_buf);
		buffer_append_string_len(p->tmp_buf, CONST_STR_LEN("README.txt"));

		if (-1 != stream_open(&s, p->tmp_buf)) {
			if (p->conf.encode_readme) {
				buffer_append_string_len(out, CONST_STR_LEN("<pre class=\"readme\">"));
				buffer_append_string_encoded(out, s.start, s.size, ENCODING_MINIMAL_XML);
				buffer_append_string_len(out, CONST_STR_LEN("</pre>"));
			} else {
				buffer_append_string_len(out, s.start, s.size);
			}
		}
		stream_close(&s);
	}

	if(p->conf.auto_layout) {
		buffer_append_string_len(out, CONST_STR_LEN(
			"<div class=\"foot\">"
		));

		if (p->conf.set_footer->used > 1) {
			buffer_append_string_buffer(out, p->conf.set_footer);
		} else if (buffer_is_empty(con->conf.server_tag)) {
			buffer_append_string_len(out, CONST_STR_LEN(PACKAGE_DESC));
		} else {
			buffer_append_string_buffer(out, con->conf.server_tag);
		}

		buffer_append_string_len(out, CONST_STR_LEN(
			"</div>\n"
			"</body>\n"
			"</html>\n"
		));
	}
}
int rewrite_rule_buffer_append(rewrite_rule_buffer *kvb, buffer *key, buffer *value, int once) {
#ifdef HAVE_PCRE_H
	size_t i;
	const char *errptr;
	int erroff;

	if (!key) return -1;

	if (kvb->size == 0) {
		kvb->size = 4;
		kvb->used = 0;

		kvb->ptr = malloc(kvb->size * sizeof(*kvb->ptr));

		for(i = 0; i < kvb->size; i++) {
			kvb->ptr[i] = calloc(1, sizeof(**kvb->ptr));
		}
	} else if (kvb->used == kvb->size) {
		kvb->size += 4;

		kvb->ptr = realloc(kvb->ptr, kvb->size * sizeof(*kvb->ptr));

		for(i = kvb->used; i < kvb->size; i++) {
			kvb->ptr[i] = calloc(1, sizeof(**kvb->ptr));
		}
	}

	if (NULL == (kvb->ptr[kvb->used]->key = pcre_compile(key->ptr,
							    0, &errptr, &erroff, NULL))) {

		return -1;
	}

	kvb->ptr[kvb->used]->value = buffer_init();
	buffer_copy_string_buffer(kvb->ptr[kvb->used]->value, value);
	kvb->ptr[kvb->used]->once = once;

	kvb->used++;

	return 0;
#else
	UNUSED(kvb);
	UNUSED(value);
	UNUSED(once);
	UNUSED(key);

	return -1;
#endif
}
static int data_string_insert_dup(data_unset *dst, data_unset *src) {
	data_string *ds_dst = (data_string *)dst;
	data_string *ds_src = (data_string *)src;

	if (ds_dst->value->used) {
		buffer_append_string_len(ds_dst->value, CONST_STR_LEN(", "));
		buffer_append_string_buffer(ds_dst->value, ds_src->value);
	} else {
		buffer_copy_string_buffer(ds_dst->value, ds_src->value);
	}

	src->free(src);

	return 0;
}
Exemple #13
0
int config_patch_connection(server *srv, connection *con, comp_key_t comp) {
    size_t i, j;

    con->conditional_is_valid[comp] = 1;

    /* skip the first, the global context */
    for (i = 1; i < srv->config_context->used; i++) {
        data_config *dc = (data_config *)srv->config_context->data[i];
        specific_config *s = &srv->config_storage[i];

        /* not our stage */
        if (comp != dc->comp) continue;

        /* condition didn't match */
        if (!config_check_cond(srv, con, dc)) continue;

        /* merge config */
        for (j = 0; j < dc->value->used; j++) {
            data_unset *du = dc->value->data[j];

            if (buffer_is_equal_string(du->key, CONST_STR_LEN("server.document-root"))) {
                PATCH(document_root);
            } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("ssl.pemfile"))) {
                PATCH(ssl_pemfile);
            } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("ssl.ca-file"))) {
                PATCH(ssl_ca_file);
            } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("ssl.cipher-list"))) {
                PATCH(ssl_cipher_list);
            } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("ssl.engine"))) {
                PATCH(is_ssl);
#ifdef HAVE_LSTAT
            } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("server.follow-symlink"))) {
                PATCH(follow_symlink);
#endif
            } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("server.name"))) {
                buffer_copy_string_buffer(con->server_name, s->server_name);
            } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("connection.kbytes-per-second"))) {
                PATCH(kbytes_per_second);
            } else if (buffer_is_equal_string(du->key, CONST_STR_LEN("server.kbytes-per-second"))) {
                PATCH(global_kbytes_per_second);
                PATCH(global_bytes_per_second_cnt);
                con->conf.global_bytes_per_second_cnt_ptr = &s->global_bytes_per_second_cnt;
            }
        }
    }

    return 0;
}
static int excludes_buffer_append(excludes_buffer *exb, buffer *string) {
#ifdef HAVE_PCRE_H
	size_t i;
	const char *errptr;
	int erroff;

	if (!string) return -1;

	if (exb->size == 0) {
		exb->size = 4;
		exb->used = 0;

		exb->ptr = malloc(exb->size * sizeof(*exb->ptr));

		for(i = 0; i < exb->size ; i++) {
			exb->ptr[i] = calloc(1, sizeof(**exb->ptr));
		}
	} else if (exb->used == exb->size) {
		exb->size += 4;

		exb->ptr = realloc(exb->ptr, exb->size * sizeof(*exb->ptr));

		for(i = exb->used; i < exb->size; i++) {
			exb->ptr[i] = calloc(1, sizeof(**exb->ptr));
		}
	}


	if (NULL == (exb->ptr[exb->used]->regex = pcre_compile(string->ptr, 0,
						    &errptr, &erroff, NULL))) {
		return -1;
	}

	exb->ptr[exb->used]->string = buffer_init();
	buffer_copy_string_buffer(exb->ptr[exb->used]->string, string);

	exb->used++;

	return 0;
#else
	UNUSED(exb);
	UNUSED(string);

	return -1;
#endif
}
Exemple #15
0
static handler_t mod_simple_vhost_docroot(server *srv, connection *con, void *p_data) {
	plugin_data *p = p_data;

	/*
	 * cache the last successfull translation from hostname (authority) to docroot
	 * - this saves us a stat() call
	 *
	 */

	mod_simple_vhost_patch_connection(srv, con, p);

	if (p->conf.docroot_cache_key->used &&
	    con->uri.authority->used &&
	    buffer_is_equal(p->conf.docroot_cache_key, con->uri.authority)) {
		/* cache hit */
		buffer_copy_string_buffer(con->physical.doc_root, p->conf.docroot_cache_value);
		buffer_copy_string_buffer(con->server_name,       p->conf.docroot_cache_servername);
	} else {
		/* build document-root */
		if ((con->uri.authority->used == 0) ||
		    build_doc_root(srv, con, p, p->doc_root, con->uri.authority)) {
			/* not found, fallback the default-host */
			if (build_doc_root(srv, con, p,
					   p->doc_root,
					   p->conf.default_host)) {
				return HANDLER_GO_ON;
			} else {
				buffer_copy_string_buffer(con->server_name, p->conf.default_host);
			}
		} else {
			buffer_copy_string_buffer(con->server_name, con->uri.authority);
		}

		/* copy to cache */
		buffer_copy_string_buffer(p->conf.docroot_cache_key,        con->uri.authority);
		buffer_copy_string_buffer(p->conf.docroot_cache_value,      p->doc_root);
		buffer_copy_string_buffer(p->conf.docroot_cache_servername, con->server_name);

		buffer_copy_string_buffer(con->physical.doc_root, p->doc_root);
	}

	return HANDLER_GO_ON;
}
Exemple #16
0
int chunkqueue_append_file(chunkqueue *cq, buffer *fn, off_t offset, off_t len) {
	chunk *c;

	if (len == 0) return 0;

	c = chunkqueue_get_unused_chunk(cq);

	c->type = FILE_CHUNK;

	buffer_copy_string_buffer(c->file.name, fn);
	c->file.start = offset;
	c->file.length = len;
	c->offset = 0;

	chunkqueue_append_chunk(cq, c);

	return 0;
}
Exemple #17
0
int chunkqueue_steal_tempfile(chunkqueue *cq, chunk *in) {
    chunk *c;

    assert(in->type == FILE_CHUNK);
    assert(in->file.is_temp == 1);

    c = chunkpool_get_unused_chunk();

    c->type = FILE_CHUNK;
    buffer_copy_string_buffer(c->file.name, in->file.name);
    c->file.start = in->file.start + in->offset;
    c->file.length = in->file.length - in->offset;
    c->offset = 0;
    c->file.is_temp = 1;
    in->file.is_temp = 0;

    chunkqueue_append_chunk(cq, c);

    return 0;
}
static int config_parse(server *srv, config_t *context, tokenizer_t *t) {
	void *pParser;
	int token_id;
	buffer *token, *lasttoken;
	int ret;

	pParser = configparserAlloc( malloc );
	lasttoken = buffer_init();
	token = buffer_init();

	while((1 == (ret = config_tokenizer(srv, t, &token_id, token))) && context->ok) {
		buffer_copy_string_buffer(lasttoken, token);
		configparser(pParser, token_id, token, context);

		token = buffer_init();
	}
	buffer_free(token);

	if (ret != -1 && context->ok) {
		/* add an EOL at EOF, better than say sorry */
		configparser(pParser, TK_EOL, buffer_init_string("(EOL)"), context);
		if (context->ok) {
			configparser(pParser, 0, NULL, context);
		}
	}
	configparserFree(pParser, free);

	if (ret == -1) {
		log_error_write(srv, __FILE__, __LINE__, "sb",
				"configfile parser failed:", lasttoken);
	} else if (context->ok == 0) {
		log_error_write(srv, __FILE__, __LINE__, "sbsdsdsb",
				"source:", t->source,
				"line:", t->line, "pos:", t->line_pos,
				"parser failed somehow near here:", lasttoken);
		ret = -1;
	}
	buffer_free(lasttoken);

	return ret == -1 ? -1 : 0;
}
Exemple #19
0
int config_setup_connection(server *srv, connection *con) {
    specific_config *s = &srv->config_storage[0];

    PATCH(document_root);
#ifdef HAVE_LSTAT
    PATCH(follow_symlink);
#endif
    PATCH(kbytes_per_second);
    PATCH(global_kbytes_per_second);
    PATCH(global_bytes_per_second_cnt);

    con->conf.global_bytes_per_second_cnt_ptr = &s->global_bytes_per_second_cnt;
    buffer_copy_string_buffer(con->server_name, s->server_name);

    PATCH(is_ssl);

    PATCH(ssl_pemfile);
    PATCH(ssl_ca_file);
    PATCH(ssl_cipher_list);

    return 0;
}
Exemple #20
0
int chunkqueue_append_smb_file(chunkqueue *cq, buffer *fn, off_t offset, off_t len) {
	chunk *c;

	if (len == 0) return 0;

	c = chunkqueue_get_unused_chunk(cq);

	c->type = SMB_CHUNK;

	buffer_copy_string_buffer(c->file.name, fn);
	c->file.start = offset;
	c->file.length = len;
	c->offset = 0;

	//- JerryLin add
	c->roffset = 0;
	c->open_thread = -1;
	c->listcount = 0;
	Cdbg(1,"chunkqueue_append_smb_file.....fn=[%s]", fn->ptr);

	chunkqueue_append_chunk(cq, c);

	return 0;
}
//该函数用于逐个记录那些被转换了的配置信息(记录在srv->config_touched中)
int config_insert_values_global(server *srv, array *ca, const config_values_t cv[]) {
	size_t i;
	data_unset *du;
	//对将要被转换的配置值逐个判断以记录被使用了的配置项
	for (i = 0; cv[i].key; i++) {
		data_string *touched;

		if (NULL == (du = array_get_element(ca, cv[i].key))) {
			/* no found */
			//配置文件里没有对其的配置项
			continue;
		}

		/* touched */ //有配置
		touched = data_string_init();

		buffer_copy_string_len(touched->value, CONST_STR_LEN("")); //并不关心其配置值
		buffer_copy_string_buffer(touched->key, du->key); //获取其配置项的Key

		array_insert_unique(srv->config_touched, (data_unset *)touched); //记录被使用的配置项
	}

	return config_insert_values_internal(srv, ca, cv); //调用函数config_insert_values_internal()获取配置值
}
int config_insert_values_global(server *srv, array *ca, const config_values_t cv[]) {
	size_t i;
	data_unset *du;

	for (i = 0; cv[i].key; i++) {
		data_string *touched;
		
		if (NULL == (du = array_get_element(ca, cv[i].key))) {
			/* no found */

			continue;
		}
		
		/* touched */
		touched = data_string_init();

		buffer_copy_string_len(touched->value, CONST_STR_LEN(""));
		buffer_copy_string_buffer(touched->key, du->key);
		
		array_insert_unique(srv->config_touched, (data_unset *)touched);		
	}
	
	return config_insert_values_internal(srv, ca, cv);
}
Exemple #23
0
static handler_t mod_auth_uri_handler(server *srv, connection *con, void *p_d) {
	size_t k;
	int auth_required = 0, auth_satisfied = 0;
	char *http_authorization = NULL;
	data_string *ds;
	mod_auth_plugin_data *p = p_d;
	array *req;
	
	/* select the right config */
	mod_auth_patch_connection(srv, con, p);

	if (p->conf.auth_require == NULL) return HANDLER_GO_ON;
	
	/*
	 * AUTH
	 *
	 */

	/* do we have to ask for auth ? */

	auth_required = 0;
	auth_satisfied = 0;

	/* search auth-directives for path */
	for (k = 0; k < p->conf.auth_require->used; k++) {
		buffer *require = p->conf.auth_require->data[k]->key;
		
		if (require->used == 0) continue;
		if (con->uri.path->used < require->used) continue;

		/* if we have a case-insensitive FS we have to lower-case the URI here too */

		if (con->conf.force_lowercase_filenames) {
			if (0 == strncasecmp(con->uri.path->ptr, require->ptr, require->used - 1)) {
				auth_required = 1;
				break;
			}
		} else {
			if (0 == strncmp(con->uri.path->ptr, require->ptr, require->used - 1)) {
				auth_required = 1;
				break;
			}
		}
	}
	
	/* nothing to do for us */
	if (auth_required == 0) return HANDLER_GO_ON;

	req = ((data_array *)(p->conf.auth_require->data[k]))->value;

	/* try to get Authorization-header */

	if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "Authorization"))) {
		http_authorization = ds->value->ptr;
	}

	if (ds && ds->value && ds->value->used) {
		char *auth_realm;
		data_string *method;

		method = (data_string *)array_get_element(req, "method");

		/* parse auth-header */
		if (NULL != (auth_realm = strchr(http_authorization, ' '))) {
			int auth_type_len = auth_realm - http_authorization;

			if ((auth_type_len == 5) &&
			    (0 == strncasecmp(http_authorization, "Basic", auth_type_len))) {

				if (0 == strcmp(method->value->ptr, "basic")) {
					auth_satisfied = http_auth_basic_check(srv, con, p, req, con->uri.path, auth_realm+1);
				}
			} else if ((auth_type_len == 6) &&
				   (0 == strncasecmp(http_authorization, "Digest", auth_type_len))) {
				if (0 == strcmp(method->value->ptr, "digest")) {
					if (-1 == (auth_satisfied = http_auth_digest_check(srv, con, p, req, con->uri.path, auth_realm+1))) {
						con->http_status = 400;
						con->mode = DIRECT;

						/* a field was missing */

						return HANDLER_FINISHED;
					}
				}
			} else {
				log_error_write(srv, __FILE__, __LINE__, "ss",
						"unknown authentification type:",
						http_authorization);
			}
		}
	}

	if (!auth_satisfied) {
		data_string *method, *realm;
		method = (data_string *)array_get_element(req, "method");
		realm = (data_string *)array_get_element(req, "realm");

		con->http_status = 401;
		con->mode = DIRECT;

		if (0 == strcmp(method->value->ptr, "basic")) {
			buffer_copy_string_len(p->tmp_buf, CONST_STR_LEN("Basic realm=\""));
			buffer_append_string_buffer(p->tmp_buf, realm->value);
			buffer_append_string_len(p->tmp_buf, CONST_STR_LEN("\""));

			response_header_insert(srv, con, CONST_STR_LEN("WWW-Authenticate"), CONST_BUF_LEN(p->tmp_buf));
		} else if (0 == strcmp(method->value->ptr, "digest")) {
			char hh[33];
			http_auth_digest_generate_nonce(srv, p, srv->tmp_buf, hh);

			buffer_copy_string_len(p->tmp_buf, CONST_STR_LEN("Digest realm=\""));
			buffer_append_string_buffer(p->tmp_buf, realm->value);
			buffer_append_string_len(p->tmp_buf, CONST_STR_LEN("\", nonce=\""));
			buffer_append_string(p->tmp_buf, hh);
			buffer_append_string_len(p->tmp_buf, CONST_STR_LEN("\", qop=\"auth\""));

			response_header_insert(srv, con, CONST_STR_LEN("WWW-Authenticate"), CONST_BUF_LEN(p->tmp_buf));
		} else {
			/* evil */
		}
		return HANDLER_FINISHED;
	} else {
		/* the REMOTE_USER header */

		buffer_copy_string_buffer(con->authed_user, p->auth_user);
	}

	return HANDLER_GO_ON;
}
Exemple #24
0
handler_t http_response_prepare(server *srv, connection *con) {
	handler_t r;
Cdbg(DBE, "enter http_response_prepare..mode=[%d], status=[%d][%s]", con->mode, con->http_status, connection_get_state(con->http_status));
	/* looks like someone has already done a decision */
	if ( (con->mode == DIRECT || con->mode == SMB_BASIC || con->mode == SMB_NTLM) &&
	    (con->http_status != 0 && con->http_status != 200)) {
		/* remove a packets in the queue */
		if (con->file_finished == 0) {
			chunkqueue_reset(con->write_queue);
		}

		return HANDLER_FINISHED;
	}

	/* no decision yet, build conf->filename */
	if ( (con->mode == DIRECT || con->mode == SMB_BASIC || con->mode == SMB_NTLM) && con->physical.path->used == 0) {
		char *qstr;

		/* we only come here when we have the parse the full request again
		 *
		 * a HANDLER_COMEBACK from mod_rewrite and mod_fastcgi might be a
		 * problem here as mod_setenv might get called multiple times
		 *
		 * fastcgi-auth might lead to a COMEBACK too
		 * fastcgi again dead server too
		 *
		 * mod_compress might add headers twice too
		 *
		 *  */

		config_cond_cache_reset(srv, con);
		config_setup_connection(srv, con); /* Perhaps this could be removed at other places. */
		
		if (con->conf.log_condition_handling) {
			log_error_write(srv, __FILE__, __LINE__,  "s",  "run condition");
		}

		config_patch_connection(srv, con, COMP_SERVER_SOCKET); /* SERVERsocket */
		
		/**
		 * prepare strings
		 *
		 * - uri.path_raw
		 * - uri.path (secure)
		 * - uri.query
		 *
		 */

		/**
		 * Name according to RFC 2396
		 *
		 * - scheme
		 * - authority
		 * - path
		 * - query
		 *
		 * (scheme)://(authority)(path)?(query)#fragment
		 *
		 *
		 */

		if (con->conf.is_ssl) {
			buffer_copy_string_len(con->uri.scheme, CONST_STR_LEN("https"));
		} else {
			buffer_copy_string_len(con->uri.scheme, CONST_STR_LEN("http"));
		}
		buffer_copy_string_buffer(con->uri.authority, con->request.http_host);
		buffer_to_lower(con->uri.authority);
		
		config_patch_connection(srv, con, COMP_HTTP_SCHEME);    /* Scheme:      */
		config_patch_connection(srv, con, COMP_HTTP_HOST);      /* Host:        */
		config_patch_connection(srv, con, COMP_HTTP_REMOTE_IP); /* Client-IP */
		config_patch_connection(srv, con, COMP_HTTP_REFERER);   /* Referer:     */
		config_patch_connection(srv, con, COMP_HTTP_USER_AGENT);/* User-Agent:  */
		config_patch_connection(srv, con, COMP_HTTP_LANGUAGE);  /* Accept-Language:  */
		config_patch_connection(srv, con, COMP_HTTP_COOKIE);    /* Cookie:  */
		config_patch_connection(srv, con, COMP_HTTP_REQUEST_METHOD); /* REQUEST_METHOD */

		/** their might be a fragment which has to be cut away */
		if (NULL != (qstr = strchr(con->request.uri->ptr, '#'))) {
			con->request.uri->used = qstr - con->request.uri->ptr;
			con->request.uri->ptr[con->request.uri->used++] = '\0';
		}

		/** extract query string from request.uri */
		if (NULL != (qstr = strchr(con->request.uri->ptr, '?'))) {
			buffer_copy_string(con->uri.query, qstr + 1);
			buffer_copy_string_len(con->uri.path_raw, con->request.uri->ptr, qstr - con->request.uri->ptr);
		} else {
			buffer_reset(con->uri.query);
			buffer_copy_string_buffer(con->uri.path_raw, con->request.uri);
		}

		if (con->conf.log_request_handling) {
			log_error_write(srv, __FILE__, __LINE__,  "s",  "-- splitting Request-URI");
			log_error_write(srv, __FILE__, __LINE__,  "sb", "Request-URI  : ", con->request.uri);
			log_error_write(srv, __FILE__, __LINE__,  "sb", "URI-scheme   : ", con->uri.scheme);
			log_error_write(srv, __FILE__, __LINE__,  "sb", "URI-authority: ", con->uri.authority);
			log_error_write(srv, __FILE__, __LINE__,  "sb", "URI-path     : ", con->uri.path_raw);
			log_error_write(srv, __FILE__, __LINE__,  "sb", "URI-query    : ", con->uri.query);
		}


		/**
		 *
		 * call plugins
		 *
		 * - based on the raw URL
		 *
		 */		
		switch(r = plugins_call_handle_uri_raw(srv, con)) {
		case HANDLER_GO_ON:
			break;
		case HANDLER_FINISHED:
		case HANDLER_COMEBACK:
		case HANDLER_WAIT_FOR_EVENT:
		case HANDLER_ERROR:
			return r;
		default:
			log_error_write(srv, __FILE__, __LINE__, "sd", "handle_uri_raw: unknown return value", r);
			break;
		}

		/* build filename
		 *
		 * - decode url-encodings  (e.g. %20 -> ' ')
		 * - remove path-modifiers (e.g. /../)
		 */
		if (con->request.http_method == HTTP_METHOD_OPTIONS &&
		    con->uri.path_raw->ptr[0] == '*' && con->uri.path_raw->ptr[1] == '\0') {
			/* OPTIONS * ... */
			buffer_copy_string_buffer(con->uri.path, con->uri.path_raw);
		} else {
			buffer_copy_string_buffer(srv->tmp_buf, con->uri.path_raw);
			buffer_urldecode_path(srv->tmp_buf);			
			buffer_path_simplify(con->uri.path, srv->tmp_buf);			
		}

		if (con->conf.log_request_handling) {
			log_error_write(srv, __FILE__, __LINE__,  "s",  "-- sanatising URI");
			log_error_write(srv, __FILE__, __LINE__,  "sb", "URI-path     : ", con->uri.path);
		}

#ifdef USE_OPENSSL
		if (con->conf.is_ssl && con->conf.ssl_verifyclient) {
			https_add_ssl_entries(con);
		}
#endif

		/**
		 *
		 * call plugins
		 *
		 * - based on the clean URL
		 *
		 */
		config_patch_connection(srv, con, COMP_HTTP_URL); /* HTTPurl */
		config_patch_connection(srv, con, COMP_HTTP_QUERY_STRING); /* HTTPqs */

		/* do we have to downgrade to 1.0 ? */
		if (!con->conf.allow_http11) {
			con->request.http_version = HTTP_VERSION_1_0;
		}
		
		switch(r = plugins_call_handle_uri_clean(srv, con)) {
		case HANDLER_GO_ON:
			break;
		case HANDLER_FINISHED:
		case HANDLER_COMEBACK:
		case HANDLER_WAIT_FOR_EVENT:
		case HANDLER_ERROR:
			return r;
		default:
			log_error_write(srv, __FILE__, __LINE__, "");
			break;
		}
		
		if (con->request.http_method == HTTP_METHOD_OPTIONS &&
		    con->uri.path->ptr[0] == '*' && con->uri.path_raw->ptr[1] == '\0') {
			/* option requests are handled directly without checking of the path */

			response_header_insert(srv, con, CONST_STR_LEN("Allow"), CONST_STR_LEN("OPTIONS, GET, HEAD, POST"));

			con->http_status = 200;
			con->file_finished = 1;

			return HANDLER_FINISHED;
		}

		/***
		 *
		 * border
		 *
		 * logical filename (URI) becomes a physical filename here
		 *
		 *
		 *
		 */




		/* 1. stat()
		 * ... ISREG() -> ok, go on
		 * ... ISDIR() -> index-file -> redirect
		 *
		 * 2. pathinfo()
		 * ... ISREG()
		 *
		 * 3. -> 404
		 *
		 */

		/*
		 * SEARCH DOCUMENT ROOT
		 */

		/* set a default */
		buffer_copy_string_buffer(con->physical.doc_root, con->conf.document_root);
		buffer_copy_string_buffer(con->physical.rel_path, con->uri.path);
		
#if defined(__WIN32) || defined(__CYGWIN__)
		/* strip dots from the end and spaces
		 *
		 * windows/dos handle those filenames as the same file
		 *
		 * foo == foo. == foo..... == "foo...   " == "foo..  ./"
		 *
		 * This will affect in some cases PATHINFO
		 *
		 * on native windows we could prepend the filename with \\?\ to circumvent
		 * this behaviour. I have no idea how to push this through cygwin
		 *
		 * */

		if (con->physical.rel_path->used > 1) {
			buffer *b = con->physical.rel_path;
			size_t i;

			if (b->used > 2 &&
			    b->ptr[b->used-2] == '/' &&
			    (b->ptr[b->used-3] == ' ' ||
			     b->ptr[b->used-3] == '.')) {
				b->ptr[b->used--] = '\0';
			}

			for (i = b->used - 2; b->used > 1; i--) {
				if (b->ptr[i] == ' ' ||
				    b->ptr[i] == '.') {
					b->ptr[b->used--] = '\0';
				} else {
					break;
				}
			}
		}
#endif

		if (con->conf.log_request_handling) {
			log_error_write(srv, __FILE__, __LINE__,  "s",  "-- before doc_root");
			log_error_write(srv, __FILE__, __LINE__,  "sb", "Doc-Root     :", con->physical.doc_root);
			log_error_write(srv, __FILE__, __LINE__,  "sb", "Rel-Path     :", con->physical.rel_path);
			log_error_write(srv, __FILE__, __LINE__,  "sb", "Path         :", con->physical.path);
		}
		/* the docroot plugin should set the doc_root and might also set the physical.path
		 * for us (all vhost-plugins are supposed to set the doc_root)
		 * */
		switch(r = plugins_call_handle_docroot(srv, con)) {
		case HANDLER_GO_ON:
			break;
		case HANDLER_FINISHED:
		case HANDLER_COMEBACK:
		case HANDLER_WAIT_FOR_EVENT:
		case HANDLER_ERROR:
			return r;
		default:
			log_error_write(srv, __FILE__, __LINE__, "");
			break;
		}
		
		/* MacOS X and Windows can't distiguish between upper and lower-case
		 *
		 * convert to lower-case
		 */
		if (con->conf.force_lowercase_filenames) {
			buffer_to_lower(con->physical.rel_path);
		}
		
		/* the docroot plugins might set the servername, if they don't we take http-host */
		if (buffer_is_empty(con->server_name)) {
			buffer_copy_string_buffer(con->server_name, con->uri.authority);
		}
		
		/**
		 * create physical filename
		 * -> physical.path = docroot + rel_path
		 *
		 */		
		buffer_copy_string_buffer(con->physical.path, con->physical.doc_root);
		BUFFER_APPEND_SLASH(con->physical.path);
		buffer_copy_string_buffer(con->physical.basedir, con->physical.path);
		if (con->physical.rel_path->used &&
		    con->physical.rel_path->ptr[0] == '/') {
		    
			buffer_append_string_len(con->physical.path, con->physical.rel_path->ptr + 1, con->physical.rel_path->used - 2);
			
			//buffer_append_string_encoded(con->physical.path, con->physical.rel_path->ptr + 1, con->physical.rel_path->used - 2, ENCODING_REL_URI);
			//Cdbg(1,"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa %s", con->physical.path->ptr);
		} else {		
			buffer_append_string_buffer(con->physical.path, con->physical.rel_path);
		}
		
		if (con->conf.log_request_handling) {
			log_error_write(srv, __FILE__, __LINE__,  "s",  "-- after doc_root");
			log_error_write(srv, __FILE__, __LINE__,  "sb", "Doc-Root     :", con->physical.doc_root);
			log_error_write(srv, __FILE__, __LINE__,  "sb", "Rel-Path     :", con->physical.rel_path);
			log_error_write(srv, __FILE__, __LINE__,  "sb", "Path         :", con->physical.path);
		}
		
		switch(r = plugins_call_handle_physical(srv, con)) {
			case HANDLER_GO_ON:
				break;
			case HANDLER_FINISHED:
			case HANDLER_COMEBACK:
			case HANDLER_WAIT_FOR_EVENT:
			case HANDLER_ERROR:
				return r;
			default:
				log_error_write(srv, __FILE__, __LINE__, "");
				break;
		}
		
		if (con->conf.log_request_handling) {
			log_error_write(srv, __FILE__, __LINE__,  "s",  "-- logical -> physical");
			log_error_write(srv, __FILE__, __LINE__,  "sb", "Doc-Root     :", con->physical.doc_root);
			log_error_write(srv, __FILE__, __LINE__,  "sb", "Rel-Path     :", con->physical.rel_path);
			log_error_write(srv, __FILE__, __LINE__,  "sb", "Path         :", con->physical.path);
		}
	}
	
	/*
	 * Noone catched away the file from normal path of execution yet (like mod_access)
	 *
	 * Go on and check of the file exists at all
	 */
	if (con->mode == DIRECT || con->mode == SMB_BASIC || con->mode == SMB_NTLM) {
		char *slash = NULL;
		char *pathinfo = NULL;
		int found = 0;
		stat_cache_entry *sce = NULL;
		
		if (con->conf.log_request_handling) {
			log_error_write(srv, __FILE__, __LINE__,  "s",  "-- handling physical path");
			log_error_write(srv, __FILE__, __LINE__,  "sb", "Path         :", con->physical.path);
		}
		
		if ( HANDLER_ERROR != stat_cache_get_entry(srv, con, smbc_wrapper_physical_url_path(srv, con), &sce)) {
			/* file exists */

			if (con->conf.log_request_handling) {
				log_error_write(srv, __FILE__, __LINE__,  "s",  "-- file found");
				log_error_write(srv, __FILE__, __LINE__,  "sb", "Path         :", con->physical.path);
			}
#ifdef HAVE_LSTAT
			if ((sce->is_symlink != 0) && !con->conf.follow_symlink) {
				con->http_status = 403;

				if (con->conf.log_request_handling) {
					log_error_write(srv, __FILE__, __LINE__,  "s",  "-- access denied due symlink restriction");
					log_error_write(srv, __FILE__, __LINE__,  "sb", "Path         :", con->physical.path);
				}
				
				buffer_reset(con->physical.path);
				return HANDLER_FINISHED;
			};
#endif
			if (S_ISDIR(sce->st.st_mode)) {
				if (con->uri.path->ptr[con->uri.path->used - 2] != '/') {
					/* redirect to .../ */

					http_response_redirect_to_directory(srv, con);

					return HANDLER_FINISHED;
				}
#ifdef HAVE_LSTAT
			} else if (!S_ISREG(sce->st.st_mode) && !sce->is_symlink) {
#else
			} else if (!S_ISREG(sce->st.st_mode)) {
#endif
				/* any special handling of non-reg files ?*/


			}
		} 
		else {		
			switch (errno) {
			case EACCES:
				con->http_status = 403;

				if (con->conf.log_request_handling) {
					log_error_write(srv, __FILE__, __LINE__,  "s",  "-- access denied");
					log_error_write(srv, __FILE__, __LINE__,  "sb", "Path         :", con->physical.path);
				}
				
				buffer_reset(con->physical.path);
				return HANDLER_FINISHED;
			case ENOENT:
				con->http_status = 404;
				
				if (con->conf.log_request_handling) {
					log_error_write(srv, __FILE__, __LINE__,  "s",  "-- file not found");
					log_error_write(srv, __FILE__, __LINE__,  "sb", "Path         :", con->physical.path);
				}

				buffer_reset(con->physical.path);
				return HANDLER_FINISHED;
			case ENOTDIR:
				/* PATH_INFO ! :) */
				break;
			default:
				/* we have no idea what happend. let's tell the user so. */
				con->http_status = 500;
				buffer_reset(con->physical.path);
				
				log_error_write(srv, __FILE__, __LINE__, "ssbsb",
						"file not found ... or so: ", strerror(errno),
						con->uri.path,
						"->", con->physical.path);

				return HANDLER_FINISHED;
			}

			/* not found, perhaps PATHINFO */

			buffer_copy_string_buffer(srv->tmp_buf, con->physical.path);
			
			do {
				if (slash) {
					buffer_copy_string_len(con->physical.path, srv->tmp_buf->ptr, slash - srv->tmp_buf->ptr);
				} else {
					buffer_copy_string_buffer(con->physical.path, srv->tmp_buf);
				}

				if (HANDLER_ERROR != stat_cache_get_entry(srv, con, con->physical.path, &sce)) {				
					found = S_ISREG(sce->st.st_mode);
					break;
				}

				if (pathinfo != NULL) {
					*pathinfo = '\0';
				}
				slash = strrchr(srv->tmp_buf->ptr, '/');

				if (pathinfo != NULL) {
					/* restore '/' */
					*pathinfo = '/';
				}

				if (slash) pathinfo = slash;
			} while ((found == 0) && (slash != NULL) && ((size_t)(slash - srv->tmp_buf->ptr) > (con->physical.basedir->used - 2)));

			if (found == 0) {
				/* no it really doesn't exists */
				con->http_status = 404;

				if (con->conf.log_file_not_found) {
					log_error_write(srv, __FILE__, __LINE__, "sbsb",
							"file not found:", con->uri.path,
							"->", con->physical.path);
				}

				buffer_reset(con->physical.path);

				return HANDLER_FINISHED;
			}

#ifdef HAVE_LSTAT
			if ((sce->is_symlink != 0) && !con->conf.follow_symlink) {
				con->http_status = 403;

				if (con->conf.log_request_handling) {
					log_error_write(srv, __FILE__, __LINE__,  "s",  "-- access denied due symlink restriction");
					log_error_write(srv, __FILE__, __LINE__,  "sb", "Path         :", con->physical.path);
				}

				buffer_reset(con->physical.path);
				return HANDLER_FINISHED;
			};
#endif

			/* we have a PATHINFO */
			if (pathinfo) {
				buffer_copy_string(con->request.pathinfo, pathinfo);

				/*
				 * shorten uri.path
				 */

				con->uri.path->used -= strlen(pathinfo);
				con->uri.path->ptr[con->uri.path->used - 1] = '\0';
			}

			if (con->conf.log_request_handling) {
				log_error_write(srv, __FILE__, __LINE__,  "s",  "-- after pathinfo check");
				log_error_write(srv, __FILE__, __LINE__,  "sb", "Path         :", con->physical.path);
				log_error_write(srv, __FILE__, __LINE__,  "sb", "URI          :", con->uri.path);
				log_error_write(srv, __FILE__, __LINE__,  "sb", "Pathinfo     :", con->request.pathinfo);
			}
		}

		if (con->conf.log_request_handling) {
			log_error_write(srv, __FILE__, __LINE__,  "s",  "-- handling subrequest");
			log_error_write(srv, __FILE__, __LINE__,  "sb", "Path         :", con->physical.path);
		}
		
		/* call the handlers */
		switch(r = plugins_call_handle_subrequest_start(srv, con)) {
		case HANDLER_GO_ON:
			/* request was not handled */
			break;
		case HANDLER_FINISHED:
		default:
			if (con->conf.log_request_handling) {
				log_error_write(srv, __FILE__, __LINE__,  "s",  "-- subrequest finished");
			}

			/* something strange happend */
			return r;
		}

		/* if we are still here, no one wanted the file, status 403 is ok I think */

		if ((con->mode == DIRECT || con->mode == SMB_BASIC || con->mode == SMB_NTLM) && con->http_status == 0) {
			switch (con->request.http_method) {
			case HTTP_METHOD_OPTIONS:
				con->http_status = 200;
				break;
			default:
				con->http_status = 403;
			}

			return HANDLER_FINISHED;
		}

	}

	switch(r = plugins_call_handle_subrequest(srv, con)) {
	case HANDLER_GO_ON:
		/* request was not handled, looks like we are done */
		return HANDLER_FINISHED;
	case HANDLER_FINISHED:
		/* request is finished */
	default:
		/* something strange happend */
		return r;
	}

	/* can't happen */
	return HANDLER_COMEBACK;
}
Exemple #25
0
static void https_add_ssl_entries(connection *con) {
	X509 *xs;
	X509_NAME *xn;
	X509_NAME_ENTRY *xe;
	int i, nentries;

	if (
		SSL_get_verify_result(con->ssl) != X509_V_OK
		|| !(xs = SSL_get_peer_certificate(con->ssl))
	) {
		return;
	}

	xn = X509_get_subject_name(xs);
	for (i = 0, nentries = X509_NAME_entry_count(xn); i < nentries; ++i) {
		int xobjnid;
		const char * xobjsn;
		data_string *envds;

		if (!(xe = X509_NAME_get_entry(xn, i))) {
			continue;
		}
		xobjnid = OBJ_obj2nid((ASN1_OBJECT*)X509_NAME_ENTRY_get_object(xe));
		xobjsn = OBJ_nid2sn(xobjnid);
		if (!xobjsn) {
			continue;
		}

		if (NULL == (envds = (data_string *)array_get_unused_element(con->environment, TYPE_STRING))) {
			envds = data_string_init();
		}
		buffer_copy_string_len(envds->key, CONST_STR_LEN("SSL_CLIENT_S_DN_"));
		buffer_append_string(envds->key, xobjsn);
		buffer_copy_string_len(
			envds->value,
			(const char *)xe->value->data, xe->value->length
		);
		/* pick one of the exported values as "authed user", for example
		 * ssl.verifyclient.username   = "******" or "SSL_CLIENT_S_DN_emailAddress"
		 */
		if (buffer_is_equal(con->conf.ssl_verifyclient_username, envds->key)) {
			buffer_copy_string_buffer(con->authed_user, envds->value);
		}
		array_insert_unique(con->environment, (data_unset *)envds);
	}
	if (con->conf.ssl_verifyclient_export_cert) {
		BIO *bio;
		if (NULL != (bio = BIO_new(BIO_s_mem()))) {
			data_string *envds;
			int n;

			PEM_write_bio_X509(bio, xs);
			n = BIO_pending(bio);

			if (NULL == (envds = (data_string *)array_get_unused_element(con->environment, TYPE_STRING))) {
				envds = data_string_init();
			}

			buffer_copy_string_len(envds->key, CONST_STR_LEN("SSL_CLIENT_CERT"));
			buffer_prepare_copy(envds->value, n+1);
			BIO_read(bio, envds->value->ptr, n);
			BIO_free(bio);
			envds->value->ptr[n] = '\0';
			envds->value->used = n+1;
			array_insert_unique(con->environment, (data_unset *)envds);
		}
	}
	X509_free(xs);
}
handler_t basic_authentication_handler(server *srv, connection *con, plugin_data *p)
{
	data_string *ds_auth = (data_string *)array_get_element(con->request.headers, "Authorization");
	
	buffer *user = buffer_init();
	buffer *pass = buffer_init();
	buffer_copy_string(user, " ");
	buffer_copy_string(pass, " ");
	
	//Cdbg(DBE, "*********** con->request.uri..%s", con->request.uri->ptr);
	
	char *auth_username = NULL;
	char *auth_password = NULL;
	if( smbc_parser_basic_authentication(srv, con, &auth_username, &auth_password) != 1 ){
			
		if(con->smb_info==NULL)
			goto error_401;

		//Cdbg(DBE, "1111111, %s, %s", con->smb_info->username->ptr, con->smb_info->password->ptr);

		if( con->smb_info->username->used && con->smb_info->password->used ){
			buffer_copy_string_buffer(user, con->smb_info->username);			
			buffer_copy_string_buffer(pass, con->smb_info->password);
		}
		
		Cdbg(DBE, "fail smbc_parser_basic_authentication-> %s, %s", user->ptr, pass->ptr);
	}
	else{
		buffer_copy_string(user, auth_username);
		buffer_copy_string(pass, auth_password);
		free(auth_username);
		free(auth_password);
	}

	time_t cur_time = time(NULL);
	
	double result = difftime(cur_time, con->smb_info->auth_time);
	Cdbg(DBE, "difftime=[%1f]", result);
	
	if(con->smb_info->qflag == SMB_HOST_QUERY) {
		data_string *ds2 = (data_string *)array_get_element(con->request.headers, "user-Agent");	
		
		//- MUST login again more than 30 minutes
		if(result>1800){
			goto error_401;
		}
		
		if( con->smb_info && buffer_is_equal_string(con->smb_info->username, "RELOGIN", 7) ){
			buffer_reset(con->smb_info->username);
			buffer_reset(con->smb_info->password);
			goto error_401;
		}
		
		if(con->smb_info->username->used && con->smb_info->password->used){
			buffer_copy_string_buffer(user, con->smb_info->username);			
			buffer_copy_string_buffer(pass, con->smb_info->password);
			Cdbg(DBE, "SMB_HOST_QUERY-->copy from smb_info user=[%s], pass=[%s]", user->ptr, pass->ptr);
		}

		#if EMBEDDED_EANBLE
		if( strcmp(user->ptr, nvram_get_http_username())!=0 || 
		     strcmp(pass->ptr, nvram_get_http_passwd())!=0 ){
			Cdbg(DBE, "smbc_host_account_authentication fail user=[%s], pass=[%s]", user->ptr, pass->ptr);
			goto error_401;
		}
		#else
		if(  strcmp(user->ptr, "admin")!=0 || 
		     strcmp(pass->ptr, "admin")!=0 ){
			Cdbg(DBE, "smbc_host_account_authentication fail user=[%s], pass=[%s]", user->ptr, pass->ptr);
			goto error_401;
		}
		#endif
	}
	else {
		//- check user / password
		struct stat st;
		
		if( con->smb_info && buffer_is_equal_string(con->smb_info->username, "RELOGIN", 7) ){
			buffer_reset(con->smb_info->username);
			buffer_reset(con->smb_info->password);

			goto error_401;
		}
		
		int res = smbc_server_check_creds( con->smb_info->server->ptr, 
									     con->smb_info->share->ptr, 
									     con->smb_info->workgroup->ptr, 
									     user->ptr, 
									     pass->ptr );

		//if( res == NT_STATUS_V(NT_STATUS_NOT_SUPPORTED)) {
		if( res == 0xc00000bb ){
			buffer_free(user);
			buffer_free(pass);
			con->http_status = 406;
			
			return HANDLER_FINISHED;
		}
		else if(res != 0) { //the username/password for smb_server is not correct				
			if(con->smb_info->username->used && con->smb_info->password->used){
				buffer_copy_string_buffer(user, con->smb_info->username);			
				buffer_copy_string_buffer(pass, con->smb_info->password);
				Cdbg(DBE, "Try to login again, server=%s, share=%s, user=%s, pass=%s", 
						con->smb_info->server->ptr,
						con->smb_info->share->ptr,
						user->ptr, pass->ptr);

				//- MUST login again more than 30 minutes
				if(result>1800){
					buffer_copy_string(pass, "");
				}
				
				//sprintf(strr, "smb://%s:%s@%s", user->ptr, pass->ptr, con->request.uri->ptr+1);
				int res = smbc_server_check_creds(con->smb_info->server->ptr, 
											    con->smb_info->share->ptr, 
											    con->smb_info->workgroup->ptr, 
											    user->ptr, 
											    pass->ptr);
				if(res != 0) 
					goto error_401;
			}
			else		
				goto error_401;
		}			
	}
	
	con->smb_info->auth_time = time(NULL);

	if( !buffer_is_equal_string(user, "no", 2) && !buffer_is_equal_string(pass, "no", 2)){
		buffer_copy_string_buffer(con->smb_info->username, user);
		buffer_copy_string_buffer(con->smb_info->password, pass);
		Cdbg(DBE, "save username=[%s], password=[%s], time=[%d] to con->smb_info", con->smb_info->username->ptr, con->smb_info->password->ptr, con->smb_info->auth_time);
	}
	
	buffer_free(user);
	buffer_free(pass);
	
	return HANDLER_UNSET;

error_401:
	buffer_free(user);
	buffer_free(pass);
	
	if(con->smb_info)
		con->smb_info->auth_time = time(NULL);
	
	smbc_wrapper_response_401(srv, con);
	
	return HANDLER_FINISHED;
}
Exemple #27
0
void save_sharelink_list(){

#if EMBEDDED_EANBLE

	share_link_info_t* c;
	
	buffer* sharelink_list = buffer_init();
	buffer_copy_string(sharelink_list, "");

	for (c = share_link_info_list; c; c = c->next) {

		if(c->toshare == 0)
			continue;
		
		buffer* temp = buffer_init();

		buffer_copy_string_buffer(temp, c->shortpath);
		buffer_append_string(temp, "<");
		buffer_append_string_buffer(temp, c->realpath);
		buffer_append_string(temp, "<");
		buffer_append_string_buffer(temp, c->filename);
		buffer_append_string(temp, "<");
		buffer_append_string_buffer(temp, c->auth);
		buffer_append_string(temp, "<");

		char strTime[25] = {0};
		sprintf(strTime, "%lu", c->expiretime);		
		buffer_append_string(temp, strTime);

		buffer_append_string(temp, "<");
		
		char strTime2[25] = {0};
		sprintf(strTime2, "%lu", c->createtime);		
		buffer_append_string(temp, strTime2);
		
		buffer_append_string(temp, ">");
			
		buffer_append_string_buffer(sharelink_list, temp);
		
		buffer_free(temp);
	}
	
	nvram_set_sharelink_str(sharelink_list->ptr);		
	buffer_free(sharelink_list);
#else
	unlink(g_temp_sharelink_file);

	smb_srv_info_t* c;
	
	char mybuffer[100];
	FILE* fp = fopen(g_temp_sharelink_file, "w");

	if(fp!=NULL){
		share_link_info_t* c;
	
		for (c = share_link_info_list; c; c = c->next) {
			if(c->toshare == 0)
				continue;
			
			fprintf(fp, "%s<%s<%s<%s<%lu<%lu\n", c->shortpath->ptr, c->realpath->ptr, c->filename->ptr, c->auth->ptr, c->expiretime, c->createtime);
		}
		
		fclose(fp);
	}
#endif
}
Exemple #28
0
int smbc_parser_basic_authentication(server *srv, connection* con, char** username,  char** password){
	
	if (con->mode != SMB_BASIC&&con->mode != DIRECT) return 0;

	data_string* ds = (data_string *)array_get_element(con->request.headers, "Authorization");
	
	if(con->share_link_basic_auth->used){
		Cdbg(1, "Use for Sharelink, con->share_link_basic_auth=[%s]", con->share_link_basic_auth->ptr);
		ds = data_string_init();
		buffer_copy_string_buffer( ds->value, con->share_link_basic_auth );
		buffer_reset(con->share_link_basic_auth);

		con->is_share_link = 1;
	}
	else
		con->is_share_link = 0;
	
	if (ds != NULL) {
		char *http_authorization = NULL;
		http_authorization = ds->value->ptr;
		
		if(strncmp(http_authorization, "Basic ", 6) == 0) {
			buffer *basic_msg = buffer_init();
			buffer *user = buffer_init();
			buffer *pass = buffer_init();
					
			if (!base64_decode(basic_msg, &http_authorization[6])) {
				log_error_write(srv, __FILE__, __LINE__, "sb", "decodeing base64-string failed", basic_msg);
				buffer_free(basic_msg);
				free(user);
				free(pass);							
				return 0;
			}
			char *s, bmsg[1024] = {0};

			//fetech the username and password from credential
			memcpy(bmsg, basic_msg->ptr, basic_msg->used);
			s = strchr(bmsg, ':');
			bmsg[s-bmsg] = '\0';

			buffer_copy_string(user, bmsg);
			buffer_copy_string(pass, s+1);
			
			*username = (char*)malloc(user->used);
			strcpy(*username, user->ptr);

			*password = (char*)malloc(pass->used);
			strcpy(*password, pass->ptr);
			
			buffer_free(basic_msg);
			free(user);
			free(pass);

			Cdbg(DBE, "base64_decode=[%s][%s]", *username, *password);
			
			return 1;
		}
	}
	else
		Cdbg(DBE, "smbc_parser_basic_authentication: ds == NULL");
	
	return 0;
}
Exemple #29
0
/*
** Perform a reduce action and the shift that must immediately
** follow the reduce.
*/
static void yy_reduce(
  yyParser *yypParser,         /* The parser */
  int yyruleno                 /* Number of the rule by which to reduce */
){
  int yygoto;                     /* The next state */
  int yyact;                      /* The next action */
  YYMINORTYPE yygotominor;        /* The LHS of the rule reduced */
  yyStackEntry *yymsp;            /* The top of the parser's stack */
  int yysize;                     /* Amount to pop the stack */
  configparserARG_FETCH;
  yymsp = &yypParser->yystack[yypParser->yyidx];
#ifndef NDEBUG
  if( yyTraceFILE && yyruleno>=0
        && yyruleno<sizeof(yyRuleName)/sizeof(yyRuleName[0]) ){
    fprintf(yyTraceFILE, "%sReduce [%s].\n", yyTracePrompt,
      yyRuleName[yyruleno]);
  }
#endif /* NDEBUG */

  switch( yyruleno ){
  /* Beginning here are the reduction cases.  A typical example
  ** follows:
  **   case 0:
  **  #line <lineno> <grammarfile>
  **     { ... }           // User supplied code
  **  #line <lineno> <thisfile>
  **     break;
  */
      case 0:
        /* No destructor defined for metalines */
        break;
      case 1:
        /* No destructor defined for metalines */
        /* No destructor defined for metaline */
        break;
      case 2:
        break;
      case 3:
        /* No destructor defined for varline */
        break;
      case 4:
        /* No destructor defined for global */
        break;
      case 5:
#line 115 "./configparser.y"
{ yymsp[-1].minor.yy78 = NULL; }
#line 822 "configparser.c"
  yy_destructor(1,&yymsp[0].minor);
        break;
      case 6:
        /* No destructor defined for include */
        break;
      case 7:
        /* No destructor defined for include_shell */
        break;
      case 8:
  yy_destructor(1,&yymsp[0].minor);
        break;
      case 9:
#line 144 "./configparser.y"
{
  if (ctx->ok) {
    buffer_copy_string_buffer(yymsp[0].minor.yy41->key, yymsp[-2].minor.yy43);
    if (strncmp(yymsp[-2].minor.yy43->ptr, "env.", sizeof("env.") - 1) == 0) {
      fprintf(stderr, "Setting env variable is not supported in conditional %d %s: %s\n",
          ctx->current->context_ndx,
          ctx->current->key->ptr, yymsp[-2].minor.yy43->ptr);
      ctx->ok = 0;
    } else if (NULL == array_get_element(ctx->current->value, yymsp[0].minor.yy41->key->ptr)) {
      array_insert_unique(ctx->current->value, yymsp[0].minor.yy41);
      yymsp[0].minor.yy41 = NULL;
    } else {
      fprintf(stderr, "Duplicate config variable in conditional %d %s: %s\n",
              ctx->current->context_ndx,
              ctx->current->key->ptr, yymsp[0].minor.yy41->key->ptr);
      ctx->ok = 0;
      yymsp[0].minor.yy41->free(yymsp[0].minor.yy41);
      yymsp[0].minor.yy41 = NULL;
    }
  }
  buffer_free(yymsp[-2].minor.yy43);
  yymsp[-2].minor.yy43 = NULL;
}
#line 859 "configparser.c"
  yy_destructor(2,&yymsp[-1].minor);
        break;
      case 10:
#line 168 "./configparser.y"
{
  array *vars = ctx->current->value;
  data_unset *du;

  if (strncmp(yymsp[-2].minor.yy43->ptr, "env.", sizeof("env.") - 1) == 0) {
    fprintf(stderr, "Appending env variable is not supported in conditional %d %s: %s\n",
        ctx->current->context_ndx,
        ctx->current->key->ptr, yymsp[-2].minor.yy43->ptr);
    ctx->ok = 0;
  } else if (NULL != (du = array_get_element(vars, yymsp[-2].minor.yy43->ptr))) {
    /* exists in current block */
    du = configparser_merge_data(du, yymsp[0].minor.yy41);
    if (NULL == du) {
      ctx->ok = 0;
    }
    else {
      buffer_copy_string_buffer(du->key, yymsp[-2].minor.yy43);
      array_replace(vars, du);
    }
    yymsp[0].minor.yy41->free(yymsp[0].minor.yy41);
  } else if (NULL != (du = configparser_get_variable(ctx, yymsp[-2].minor.yy43))) {
    du = configparser_merge_data(du, yymsp[0].minor.yy41);
    if (NULL == du) {
      ctx->ok = 0;
      du->free(du);
    }
    else {
      buffer_copy_string_buffer(du->key, yymsp[-2].minor.yy43);
      array_insert_unique(ctx->current->value, du);
    }
    yymsp[0].minor.yy41->free(yymsp[0].minor.yy41);
  } else {
    buffer_copy_string_buffer(yymsp[0].minor.yy41->key, yymsp[-2].minor.yy43);
    array_insert_unique(ctx->current->value, yymsp[0].minor.yy41);
  }
  buffer_free(yymsp[-2].minor.yy43);
  yymsp[-2].minor.yy43 = NULL;
  yymsp[0].minor.yy41 = NULL;
}
#line 903 "configparser.c"
  yy_destructor(3,&yymsp[-1].minor);
        break;
      case 11:
#line 208 "./configparser.y"
{
  if (strchr(yymsp[0].minor.yy0->ptr, '.') == NULL) {
    yygotominor.yy43 = buffer_init_string("var.");
    buffer_append_string_buffer(yygotominor.yy43, yymsp[0].minor.yy0);
    buffer_free(yymsp[0].minor.yy0);
    yymsp[0].minor.yy0 = NULL;
  } else {
    yygotominor.yy43 = yymsp[0].minor.yy0;
    yymsp[0].minor.yy0 = NULL;
  }
}
#line 919 "configparser.c"
        break;
      case 12:
#line 220 "./configparser.y"
{
  yygotominor.yy41 = configparser_merge_data(yymsp[-2].minor.yy41, yymsp[0].minor.yy41);
  if (NULL == yygotominor.yy41) {
    ctx->ok = 0;
  }
  yymsp[-2].minor.yy41 = NULL;
  yymsp[0].minor.yy41->free(yymsp[0].minor.yy41);
  yymsp[0].minor.yy41 = NULL;
}
#line 932 "configparser.c"
  yy_destructor(5,&yymsp[-1].minor);
        break;
      case 13:
#line 230 "./configparser.y"
{
  yygotominor.yy41 = yymsp[0].minor.yy41;
  yymsp[0].minor.yy41 = NULL;
}
#line 941 "configparser.c"
        break;
      case 14:
#line 235 "./configparser.y"
{
  yygotominor.yy41 = NULL;
  if (strncmp(yymsp[0].minor.yy43->ptr, "env.", sizeof("env.") - 1) == 0) {
    char *env;

    if (NULL != (env = getenv(yymsp[0].minor.yy43->ptr + 4))) {
      data_string *ds;
      ds = data_string_init();
      buffer_append_string(ds->value, env);
      yygotominor.yy41 = (data_unset *)ds;
    }
    else {
      fprintf(stderr, "Undefined env variable: %s\n", yymsp[0].minor.yy43->ptr + 4);
      ctx->ok = 0;
    }
  } else if (NULL == (yygotominor.yy41 = configparser_get_variable(ctx, yymsp[0].minor.yy43))) {
    fprintf(stderr, "Undefined config variable: %s\n", yymsp[0].minor.yy43->ptr);
    ctx->ok = 0;
  }
  if (!yygotominor.yy41) {
    /* make a dummy so it won't crash */
    yygotominor.yy41 = (data_unset *)data_string_init();
  }
  buffer_free(yymsp[0].minor.yy43);
  yymsp[0].minor.yy43 = NULL;
}
#line 971 "configparser.c"
        break;
      case 15:
#line 262 "./configparser.y"
{
  yygotominor.yy41 = (data_unset *)data_string_init();
  buffer_copy_string_buffer(((data_string *)(yygotominor.yy41))->value, yymsp[0].minor.yy0);
  buffer_free(yymsp[0].minor.yy0);
  yymsp[0].minor.yy0 = NULL;
}
#line 981 "configparser.c"
        break;
      case 16:
#line 269 "./configparser.y"
{
  yygotominor.yy41 = (data_unset *)data_integer_init();
  ((data_integer *)(yygotominor.yy41))->value = strtol(yymsp[0].minor.yy0->ptr, NULL, 10);
  buffer_free(yymsp[0].minor.yy0);
  yymsp[0].minor.yy0 = NULL;
}
#line 991 "configparser.c"
        break;
      case 17:
#line 275 "./configparser.y"
{
  yygotominor.yy41 = (data_unset *)data_array_init();
  array_free(((data_array *)(yygotominor.yy41))->value);
  ((data_array *)(yygotominor.yy41))->value = yymsp[0].minor.yy40;
  yymsp[0].minor.yy40 = NULL;
}
#line 1001 "configparser.c"
        break;
      case 18:
#line 281 "./configparser.y"
{
  yygotominor.yy40 = array_init();
}
#line 1008 "configparser.c"
  yy_destructor(8,&yymsp[-1].minor);
  yy_destructor(9,&yymsp[0].minor);
        break;
      case 19:
#line 284 "./configparser.y"
{
  yygotominor.yy40 = yymsp[-1].minor.yy40;
  yymsp[-1].minor.yy40 = NULL;
}
#line 1018 "configparser.c"
  yy_destructor(8,&yymsp[-2].minor);
  yy_destructor(9,&yymsp[0].minor);
        break;
      case 20:
#line 289 "./configparser.y"
{
  if (buffer_is_empty(yymsp[0].minor.yy41->key) ||
      NULL == array_get_element(yymsp[-2].minor.yy40, yymsp[0].minor.yy41->key->ptr)) {
    array_insert_unique(yymsp[-2].minor.yy40, yymsp[0].minor.yy41);
    yymsp[0].minor.yy41 = NULL;
  } else {
    fprintf(stderr, "Duplicate array-key: %s\n",
            yymsp[0].minor.yy41->key->ptr);
    ctx->ok = 0;
    yymsp[0].minor.yy41->free(yymsp[0].minor.yy41);
    yymsp[0].minor.yy41 = NULL;
  }

  yygotominor.yy40 = yymsp[-2].minor.yy40;
  yymsp[-2].minor.yy40 = NULL;
}
#line 1040 "configparser.c"
  yy_destructor(10,&yymsp[-1].minor);
        break;
      case 21:
#line 306 "./configparser.y"
{
  yygotominor.yy40 = yymsp[-1].minor.yy40;
  yymsp[-1].minor.yy40 = NULL;
}
#line 1049 "configparser.c"
  yy_destructor(10,&yymsp[0].minor);
        break;
      case 22:
#line 311 "./configparser.y"
{
  yygotominor.yy40 = array_init();
  array_insert_unique(yygotominor.yy40, yymsp[0].minor.yy41);
  yymsp[0].minor.yy41 = NULL;
}
#line 1059 "configparser.c"
        break;
      case 23:
#line 317 "./configparser.y"
{
  yygotominor.yy41 = yymsp[0].minor.yy41;
  yymsp[0].minor.yy41 = NULL;
}
#line 1067 "configparser.c"
        break;
      case 24:
#line 321 "./configparser.y"
{
  buffer_copy_string_buffer(yymsp[0].minor.yy41->key, yymsp[-2].minor.yy43);
  buffer_free(yymsp[-2].minor.yy43);
  yymsp[-2].minor.yy43 = NULL;

  yygotominor.yy41 = yymsp[0].minor.yy41;
  yymsp[0].minor.yy41 = NULL;
}
#line 1079 "configparser.c"
  yy_destructor(11,&yymsp[-1].minor);
        break;
      case 25:
  yy_destructor(1,&yymsp[0].minor);
        break;
      case 26:
        break;
      case 27:
#line 333 "./configparser.y"
{
  data_config *dc;
  dc = (data_config *)array_get_element(ctx->srv->config_context, "global");
  assert(dc);
  configparser_push(ctx, dc, 0);
}
#line 1095 "configparser.c"
  yy_destructor(12,&yymsp[0].minor);
        break;
      case 28:
#line 340 "./configparser.y"
{
  data_config *cur;

  cur = ctx->current;
  configparser_pop(ctx);

  assert(cur && ctx->current);

  yygotominor.yy78 = cur;
}
#line 1110 "configparser.c"
        /* No destructor defined for globalstart */
  yy_destructor(13,&yymsp[-2].minor);
        /* No destructor defined for metalines */
  yy_destructor(14,&yymsp[0].minor);
        break;
      case 29:
#line 351 "./configparser.y"
{
  assert(yymsp[-3].minor.yy78->context_ndx < yymsp[0].minor.yy78->context_ndx);
  yymsp[0].minor.yy78->prev = yymsp[-3].minor.yy78;
  yymsp[-3].minor.yy78->next = yymsp[0].minor.yy78;
  yygotominor.yy78 = yymsp[0].minor.yy78;
  yymsp[-3].minor.yy78 = NULL;
  yymsp[0].minor.yy78 = NULL;
}
#line 1126 "configparser.c"
        /* No destructor defined for eols */
  yy_destructor(15,&yymsp[-1].minor);
        break;
      case 30:
#line 360 "./configparser.y"
{
  yygotominor.yy78 = yymsp[0].minor.yy78;
  yymsp[0].minor.yy78 = NULL;
}
#line 1136 "configparser.c"
        break;
      case 31:
#line 365 "./configparser.y"
{
  data_config *cur;

  cur = ctx->current;
  configparser_pop(ctx);

  assert(cur && ctx->current);

  yygotominor.yy78 = cur;
}
#line 1150 "configparser.c"
        /* No destructor defined for context */
  yy_destructor(13,&yymsp[-2].minor);
        /* No destructor defined for metalines */
  yy_destructor(14,&yymsp[0].minor);
        break;
      case 32:
#line 376 "./configparser.y"
{
  data_config *dc;
  buffer *b, *rvalue, *op;

  if (ctx->ok && yymsp[0].minor.yy41->type != TYPE_STRING) {
    fprintf(stderr, "rvalue must be string");
    ctx->ok = 0;
  }

  switch(yymsp[-1].minor.yy27) {
  case CONFIG_COND_NE:
    op = buffer_init_string("!=");
    break;
  case CONFIG_COND_EQ:
    op = buffer_init_string("==");
    break;
  case CONFIG_COND_NOMATCH:
    op = buffer_init_string("!~");
    break;
  case CONFIG_COND_MATCH:
    op = buffer_init_string("=~");
    break;
  default:
    assert(0);
    return;
  }

  b = buffer_init();
  buffer_copy_string_buffer(b, ctx->current->key);
  buffer_append_string(b, "/");
  buffer_append_string_buffer(b, yymsp[-5].minor.yy0);
  buffer_append_string_buffer(b, yymsp[-3].minor.yy43);
  buffer_append_string_buffer(b, op);
  rvalue = ((data_string*)yymsp[0].minor.yy41)->value;
  buffer_append_string_buffer(b, rvalue);

  if (NULL != (dc = (data_config *)array_get_element(ctx->all_configs, b->ptr))) {
    configparser_push(ctx, dc, 0);
  } else {
    struct {
      comp_key_t comp;
      char *comp_key;
      size_t len;
    } comps[] = {
      { COMP_SERVER_SOCKET,      CONST_STR_LEN("SERVER[\"socket\"]"   ) },
      { COMP_HTTP_URL,           CONST_STR_LEN("HTTP[\"url\"]"        ) },
      { COMP_HTTP_HOST,          CONST_STR_LEN("HTTP[\"host\"]"       ) },
      { COMP_HTTP_REFERER,       CONST_STR_LEN("HTTP[\"referer\"]"    ) },
      { COMP_HTTP_USER_AGENT,    CONST_STR_LEN("HTTP[\"useragent\"]"  ) },
      { COMP_HTTP_USER_AGENT,    CONST_STR_LEN("HTTP[\"user-agent\"]"  ) },
      { COMP_HTTP_COOKIE,        CONST_STR_LEN("HTTP[\"cookie\"]"     ) },
      { COMP_HTTP_REMOTE_IP,     CONST_STR_LEN("HTTP[\"remoteip\"]"   ) },
      { COMP_HTTP_REMOTE_IP,     CONST_STR_LEN("HTTP[\"remote-ip\"]"   ) },
      { COMP_HTTP_QUERY_STRING,  CONST_STR_LEN("HTTP[\"querystring\"]") },
      { COMP_HTTP_QUERY_STRING,  CONST_STR_LEN("HTTP[\"query-string\"]") },
      { COMP_HTTP_REQUEST_METHOD, CONST_STR_LEN("HTTP[\"request-method\"]") },
      { COMP_HTTP_SCHEME,        CONST_STR_LEN("HTTP[\"scheme\"]"     ) },
      { COMP_UNSET, NULL, 0 },
    };
    size_t i;

    dc = data_config_init();

    buffer_copy_string_buffer(dc->key, b);
    buffer_copy_string_buffer(dc->op, op);
    buffer_copy_string_buffer(dc->comp_key, yymsp[-5].minor.yy0);
    buffer_append_string_len(dc->comp_key, CONST_STR_LEN("[\""));
    buffer_append_string_buffer(dc->comp_key, yymsp[-3].minor.yy43);
    buffer_append_string_len(dc->comp_key, CONST_STR_LEN("\"]"));
    dc->cond = yymsp[-1].minor.yy27;

    for (i = 0; comps[i].comp_key; i ++) {
      if (buffer_is_equal_string(
            dc->comp_key, comps[i].comp_key, comps[i].len)) {
        dc->comp = comps[i].comp;
        break;
      }
    }
    if (COMP_UNSET == dc->comp) {
      fprintf(stderr, "error comp_key %s", dc->comp_key->ptr);
      ctx->ok = 0;
    }

    switch(yymsp[-1].minor.yy27) {
    case CONFIG_COND_NE:
    case CONFIG_COND_EQ:
      dc->string = buffer_init_buffer(rvalue);
      break;
    case CONFIG_COND_NOMATCH:
    case CONFIG_COND_MATCH: {
#ifdef HAVE_PCRE_H
      const char *errptr;
      int erroff;

      if (NULL == (dc->regex =
          pcre_compile(rvalue->ptr, 0, &errptr, &erroff, NULL))) {
        dc->string = buffer_init_string(errptr);
        dc->cond = CONFIG_COND_UNSET;

        fprintf(stderr, "parsing regex failed: %s -> %s at offset %d\n",
            rvalue->ptr, errptr, erroff);

        ctx->ok = 0;
      } else if (NULL == (dc->regex_study =
          pcre_study(dc->regex, 0, &errptr)) &&
                 errptr != NULL) {
        fprintf(stderr, "studying regex failed: %s -> %s\n",
            rvalue->ptr, errptr);
        ctx->ok = 0;
      } else {
        dc->string = buffer_init_buffer(rvalue);
      }
#else
      fprintf(stderr, "can't handle '$%s[%s] =~ ...' as you compiled without pcre support. \n"
		      "(perhaps just a missing pcre-devel package ?) \n",
                      yymsp[-5].minor.yy0->ptr, yymsp[-3].minor.yy43->ptr);
      ctx->ok = 0;
#endif
      break;
    }

    default:
      fprintf(stderr, "unknown condition for $%s[%s]\n",
                      yymsp[-5].minor.yy0->ptr, yymsp[-3].minor.yy43->ptr);
      ctx->ok = 0;
      break;
    }

    configparser_push(ctx, dc, 1);
  }

  buffer_free(b);
  buffer_free(op);
  buffer_free(yymsp[-5].minor.yy0);
  yymsp[-5].minor.yy0 = NULL;
  buffer_free(yymsp[-3].minor.yy43);
  yymsp[-3].minor.yy43 = NULL;
  yymsp[0].minor.yy41->free(yymsp[0].minor.yy41);
  yymsp[0].minor.yy41 = NULL;
}
#line 1298 "configparser.c"
  yy_destructor(16,&yymsp[-6].minor);
  yy_destructor(18,&yymsp[-4].minor);
  yy_destructor(19,&yymsp[-2].minor);
        break;
      case 33:
#line 516 "./configparser.y"
{
  yygotominor.yy27 = CONFIG_COND_EQ;
}
#line 1308 "configparser.c"
  yy_destructor(20,&yymsp[0].minor);
        break;
      case 34:
#line 519 "./configparser.y"
{
  yygotominor.yy27 = CONFIG_COND_MATCH;
}
#line 1316 "configparser.c"
  yy_destructor(21,&yymsp[0].minor);
        break;
      case 35:
#line 522 "./configparser.y"
{
  yygotominor.yy27 = CONFIG_COND_NE;
}
#line 1324 "configparser.c"
  yy_destructor(22,&yymsp[0].minor);
        break;
      case 36:
#line 525 "./configparser.y"
{
  yygotominor.yy27 = CONFIG_COND_NOMATCH;
}
#line 1332 "configparser.c"
  yy_destructor(23,&yymsp[0].minor);
        break;
      case 37:
#line 529 "./configparser.y"
{
  yygotominor.yy43 = NULL;
  if (ctx->ok) {
    if (yymsp[0].minor.yy41->type == TYPE_STRING) {
      yygotominor.yy43 = buffer_init_buffer(((data_string*)yymsp[0].minor.yy41)->value);
    } else if (yymsp[0].minor.yy41->type == TYPE_INTEGER) {
      yygotominor.yy43 = buffer_init();
      buffer_copy_long(yygotominor.yy43, ((data_integer *)yymsp[0].minor.yy41)->value);
    } else {
      fprintf(stderr, "operand must be string");
      ctx->ok = 0;
    }
  }
  yymsp[0].minor.yy41->free(yymsp[0].minor.yy41);
  yymsp[0].minor.yy41 = NULL;
}
#line 1353 "configparser.c"
        break;
      case 38:
#line 546 "./configparser.y"
{
  if (ctx->ok) {
    if (0 != config_parse_file(ctx->srv, ctx, yymsp[0].minor.yy43->ptr)) {
      ctx->ok = 0;
    }
    buffer_free(yymsp[0].minor.yy43);
    yymsp[0].minor.yy43 = NULL;
  }
}
#line 1366 "configparser.c"
  yy_destructor(24,&yymsp[-1].minor);
        break;
      case 39:
#line 556 "./configparser.y"
{
  if (ctx->ok) {
    if (0 != config_parse_cmd(ctx->srv, ctx, yymsp[0].minor.yy43->ptr)) {
      ctx->ok = 0;
    }
    buffer_free(yymsp[0].minor.yy43);
    yymsp[0].minor.yy43 = NULL;
  }
}
#line 1380 "configparser.c"
  yy_destructor(25,&yymsp[-1].minor);
        break;
  };
  yygoto = yyRuleInfo[yyruleno].lhs;
  yysize = yyRuleInfo[yyruleno].nrhs;
  yypParser->yyidx -= yysize;
  yyact = yy_find_reduce_action(yypParser,yygoto);
  if( yyact < YYNSTATE ){
    yy_shift(yypParser,yyact,yygoto,&yygotominor);
  }else if( yyact == YYNSTATE + YYNRULE + 1 ){
    yy_accept(yypParser);
  }
}
static handler_t mod_redirect_uri_handler(server *srv, connection *con, void *p_data) {
#ifdef HAVE_PCRE_H
	plugin_data *p = p_data;
	size_t i;

	/*
	 * REWRITE URL
	 *
	 * e.g. redirect /base/ to /index.php?section=base
	 *
	 */

	mod_redirect_patch_connection(srv, con, p);

	buffer_copy_string_buffer(p->match_buf, con->request.uri);

	for (i = 0; i < p->conf.redirect->used; i++) {
		pcre *match;
		pcre_extra *extra;
		const char *pattern;
		size_t pattern_len;
		int n;
		pcre_keyvalue *kv = p->conf.redirect->kv[i];
# define N 10
		int ovec[N * 3];

		match       = kv->key;
		extra       = kv->key_extra;
		pattern     = kv->value->ptr;
		pattern_len = kv->value->used - 1;

		if ((n = pcre_exec(match, extra, p->match_buf->ptr, p->match_buf->used - 1, 0, 0, ovec, 3 * N)) < 0) {
			if (n != PCRE_ERROR_NOMATCH) {
				log_error_write(srv, __FILE__, __LINE__, "sd",
						"execution error while matching: ", n);
				return HANDLER_ERROR;
			}
		} else {
			const char **list;
			size_t start, end;
			size_t k;

			/* it matched */
			pcre_get_substring_list(p->match_buf->ptr, ovec, n, &list);

			/* search for $[0-9] */

			buffer_reset(p->location);

			start = 0; end = pattern_len;
			for (k = 0; k < pattern_len; k++) {
				if ((pattern[k] == '$' || pattern[k] == '%') &&
				    isdigit((unsigned char)pattern[k + 1])) {
					/* got one */

					size_t num = pattern[k + 1] - '0';

					end = k;

					buffer_append_string_len(p->location, pattern + start, end - start);

					if (pattern[k] == '$') {
						/* n is always > 0 */
						if (num < (size_t)n) {
							buffer_append_string(p->location, list[num]);
						}
					} else {
						config_append_cond_match_buffer(con, p->conf.context, p->location, num);
					}

					k++;
					start = k + 1;
				}
			}

			buffer_append_string_len(p->location, pattern + start, pattern_len - start);

			pcre_free(list);

			response_header_insert(srv, con, CONST_STR_LEN("Location"), CONST_BUF_LEN(p->location));

			con->http_status = 301;
			con->file_finished = 1;

			return HANDLER_FINISHED;
		}
	}
#undef N

#else
	UNUSED(srv);
	UNUSED(con);
	UNUSED(p_data);
#endif

	return HANDLER_GO_ON;
}