static int mod_status_header_append(buffer *b, const char *key) {
	BUFFER_APPEND_STRING_CONST(b, "   <tr>\n");
	BUFFER_APPEND_STRING_CONST(b, "    <th colspan=\"2\">");
	buffer_append_string(b, key);
	BUFFER_APPEND_STRING_CONST(b, "</th>\n");
	BUFFER_APPEND_STRING_CONST(b, "   </tr>\n");

	return 0;
}
static int mod_status_header_append_sort(buffer *b, void *p_d, const char* key) {
	plugin_data *p = p_d;

	if (p->conf.sort) {
		BUFFER_APPEND_STRING_CONST(b, "<th class=\"status\"><a href=\"#\" class=\"sortheader\" onclick=\"resort(this);return false;\">");
		buffer_append_string(b, key);
		BUFFER_APPEND_STRING_CONST(b, "<span class=\"sortarrow\">:</span></a></th>\n");
	} else {
		BUFFER_APPEND_STRING_CONST(b, "<th class=\"status\">");
		buffer_append_string(b, key);
		BUFFER_APPEND_STRING_CONST(b, "</th>\n");
	}

	return 0;
}
示例#3
0
static void accesslog_append_escaped(buffer *dest, buffer *str) {
	char *ptr, *start, *end;

	/* replaces non-printable chars with \xHH where HH is the hex representation of the byte */
	/* exceptions: " => \", \ => \\, whitespace chars => \n \t etc. */
	if (buffer_string_is_empty(str)) return;
	buffer_string_prepare_append(dest, buffer_string_length(str));

	for (ptr = start = str->ptr, end = str->ptr + buffer_string_length(str); ptr < end; ptr++) {
		unsigned char const c = (unsigned char) *ptr;
		if (c >= ' ' && c <= '~' && c != '"' && c != '\\') {
			/* nothing to change, add later as one block */
		} else {
			/* copy previous part */
			if (start < ptr) {
				buffer_append_string_len(dest, start, ptr - start);
			}
			start = ptr + 1;

			switch (c) {
			case '"':
				BUFFER_APPEND_STRING_CONST(dest, "\\\"");
				break;
			case '\\':
				BUFFER_APPEND_STRING_CONST(dest, "\\\\");
				break;
			case '\b':
				BUFFER_APPEND_STRING_CONST(dest, "\\b");
				break;
			case '\n':
				BUFFER_APPEND_STRING_CONST(dest, "\\n");
				break;
			case '\r':
				BUFFER_APPEND_STRING_CONST(dest, "\\r");
				break;
			case '\t':
				BUFFER_APPEND_STRING_CONST(dest, "\\t");
				break;
			case '\v':
				BUFFER_APPEND_STRING_CONST(dest, "\\v");
				break;
			default: {
					/* non printable char => \xHH */
					char hh[5] = {'\\','x',0,0,0};
					char h = c / 16;
					hh[2] = (h > 9) ? (h - 10 + 'A') : (h + '0');
					h = c % 16;
					hh[3] = (h > 9) ? (h - 10 + 'A') : (h + '0');
					buffer_append_string_len(dest, &hh[0], 4);
				}
				break;
			}
		}
	}

	if (start < end) {
		buffer_append_string_len(dest, start, end - start);
	}
}
static int mod_status_row_append(buffer *b, const char *key, const char *value) {
	BUFFER_APPEND_STRING_CONST(b, "   <tr>\n");
	BUFFER_APPEND_STRING_CONST(b, "    <td><b>");
	buffer_append_string(b, key);
	BUFFER_APPEND_STRING_CONST(b, "</b></td>\n");
	BUFFER_APPEND_STRING_CONST(b, "    <td>");
	buffer_append_string(b, value);
	BUFFER_APPEND_STRING_CONST(b, "</td>\n");
	BUFFER_APPEND_STRING_CONST(b, "   </tr>\n");

	return 0;
}
示例#5
0
static handler_t mod_status_handle_server_status_text(server *srv, connection *con, void *p_d) {
	plugin_data *p = p_d;
	buffer *b;
	double avg;
	time_t ts;
	char buf[32];

	b = chunkqueue_get_append_buffer(con->write_queue);

	/* output total number of requests */
	BUFFER_APPEND_STRING_CONST(b, "Total Accesses: ");
	avg = p->abs_requests;
	snprintf(buf, sizeof(buf) - 1, "%.0f", avg);
	buffer_append_string(b, buf);
	BUFFER_APPEND_STRING_CONST(b, "\n");

	/* output total traffic out in kbytes */
	BUFFER_APPEND_STRING_CONST(b, "Total kBytes: ");
	avg = p->abs_traffic_out / 1024;
	snprintf(buf, sizeof(buf) - 1, "%.0f", avg);
	buffer_append_string(b, buf);
	BUFFER_APPEND_STRING_CONST(b, "\n");

	/* output uptime */
	BUFFER_APPEND_STRING_CONST(b, "Uptime: ");
	ts = srv->cur_ts - srv->startup_ts;
	buffer_append_long(b, ts);
	BUFFER_APPEND_STRING_CONST(b, "\n");

	/* output busy servers */
	BUFFER_APPEND_STRING_CONST(b, "BusyServers: ");
	buffer_append_long(b, srv->conns->used);
	BUFFER_APPEND_STRING_CONST(b, "\n");

	/* set text/plain output */

	response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/plain"));

	return 0;
}
static handler_t mod_status_handle_server_config(server *srv, connection *con, void *p_d) {
	plugin_data *p = p_d;
	buffer *b, *m = p->module_list;
	size_t i;

	struct ev_map { fdevent_handler_t et; const char *name; } event_handlers[] =
	{
		/* - poll is most reliable
		 * - select works everywhere
		 * - linux-* are experimental
		 */
#ifdef USE_POLL
		{ FDEVENT_HANDLER_POLL,           "poll" },
#endif
#ifdef USE_SELECT
		{ FDEVENT_HANDLER_SELECT,         "select" },
#endif
#ifdef USE_LINUX_EPOLL
		{ FDEVENT_HANDLER_LINUX_SYSEPOLL, "linux-sysepoll" },
#endif
#ifdef USE_LINUX_SIGIO
		{ FDEVENT_HANDLER_LINUX_RTSIG,    "linux-rtsig" },
#endif
#ifdef USE_SOLARIS_DEVPOLL
		{ FDEVENT_HANDLER_SOLARIS_DEVPOLL,"solaris-devpoll" },
#endif
#ifdef USE_FREEBSD_KQUEUE
		{ FDEVENT_HANDLER_FREEBSD_KQUEUE, "freebsd-kqueue" },
#endif
		{ FDEVENT_HANDLER_UNSET,          NULL }
	};

	b = chunkqueue_get_append_buffer(con->write_queue);

	BUFFER_COPY_STRING_CONST(b,
			   "<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>\n"
			   "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n"
			   "         \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n"
			   "<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">\n"
			   " <head>\n"
			   "  <title>Status</title>\n"
			   " </head>\n"
			   " <body>\n"
			   "  <h1>" PACKAGE_NAME " " PACKAGE_VERSION "</h1>\n"
			   "  <table summary=\"status\" border=\"1\">\n");

	mod_status_header_append(b, "Server-Features");
#ifdef HAVE_PCRE_H
	mod_status_row_append(b, "RegEx Conditionals", "enabled");
#else
	mod_status_row_append(b, "RegEx Conditionals", "disabled - pcre missing");
#endif
	mod_status_header_append(b, "Network Engine");

	for (i = 0; event_handlers[i].name; i++) {
		if (event_handlers[i].et == srv->event_handler) {
			mod_status_row_append(b, "fd-Event-Handler", event_handlers[i].name);
			break;
		}
	}

	mod_status_header_append(b, "Config-File-Settings");

	for (i = 0; i < srv->plugins.used; i++) {
		plugin **ps = srv->plugins.ptr;

		plugin *pl = ps[i];

		if (i == 0) {
			buffer_copy_string_buffer(m, pl->name);
		} else {
			BUFFER_APPEND_STRING_CONST(m, "<br />");
			buffer_append_string_buffer(m, pl->name);
		}
	}

	mod_status_row_append(b, "Loaded Modules", m->ptr);

	BUFFER_APPEND_STRING_CONST(b, "  </table>\n");

	BUFFER_APPEND_STRING_CONST(b,
		      " </body>\n"
		      "</html>\n"
		      );

	response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/html"));

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

	return HANDLER_FINISHED;
}
static handler_t mod_status_handle_server_status_html(server *srv, connection *con, void *p_d) {
	plugin_data *p = p_d;
	buffer *b;
	size_t j;
	double avg;
	char multiplier = '\0';
	char buf[32];
	time_t ts;

	int days, hours, mins, seconds;

	b = chunkqueue_get_append_buffer(con->write_queue);

	BUFFER_COPY_STRING_CONST(b,
				 "<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>\n"
				 "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n"
				 "         \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n"
				 "<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">\n"
				 " <head>\n"
				 "  <title>Status</title>\n");

	BUFFER_APPEND_STRING_CONST(b,
				   "  <style type=\"text/css\">\n"
				   "    table.status { border: black solid thin; }\n"
				   "    td.int { background-color: #f0f0f0; text-align: right }\n"
				   "    td.string { background-color: #f0f0f0; text-align: left }\n"
				   "    th.status { background-color: black; color: white; font-weight: bold; }\n"
				   "    a.sortheader { background-color: black; color: white; font-weight: bold; text-decoration: none; display: block; }\n"
				   "    span.sortarrow { color: white; text-decoration: none; }\n"
				   "  </style>\n");

	if (p->conf.sort) {
		BUFFER_APPEND_STRING_CONST(b,
					   "<script type=\"text/javascript\">\n"
					   "// <!--\n"
					   "var sort_column;\n"
					   "var prev_span = null;\n");

		BUFFER_APPEND_STRING_CONST(b,
					   "function get_inner_text(el) {\n"
					   " if((typeof el == 'string')||(typeof el == 'undefined'))\n"
					   "  return el;\n"
					   " if(el.innerText)\n"
					   "  return el.innerText;\n"
					   " else {\n"
					   "  var str = \"\";\n"
					   "  var cs = el.childNodes;\n"
					   "  var l = cs.length;\n"
					   "  for (i=0;i<l;i++) {\n"
					   "   if (cs[i].nodeType==1) str += get_inner_text(cs[i]);\n"
					   "   else if (cs[i].nodeType==3) str += cs[i].nodeValue;\n"
					   "  }\n"
					   " }\n"
					   " return str;\n"
					   "}\n");

		BUFFER_APPEND_STRING_CONST(b,
					   "function sortfn(a,b) {\n"
					   " var at = get_inner_text(a.cells[sort_column]);\n"
					   " var bt = get_inner_text(b.cells[sort_column]);\n"
					   " if (a.cells[sort_column].className == 'int') {\n"
					   "  return parseInt(at)-parseInt(bt);\n"
					   " } else {\n"
					   "  aa = at.toLowerCase();\n"
					   "  bb = bt.toLowerCase();\n"
					   "  if (aa==bb) return 0;\n"
					   "  else if (aa<bb) return -1;\n"
					   "  else return 1;\n"
					   " }\n"
					   "}\n");

		BUFFER_APPEND_STRING_CONST(b,
					   "function resort(lnk) {\n"
					   " var span = lnk.childNodes[1];\n"
					   " var table = lnk.parentNode.parentNode.parentNode.parentNode;\n"
					   " var rows = new Array();\n"
					   " for (j=1;j<table.rows.length;j++)\n"
					   "  rows[j-1] = table.rows[j];\n"
					   " sort_column = lnk.parentNode.cellIndex;\n"
					   " rows.sort(sortfn);\n");

		BUFFER_APPEND_STRING_CONST(b,
					   " if (prev_span != null) prev_span.innerHTML = '';\n"
					   " if (span.getAttribute('sortdir')=='down') {\n"
					   "  span.innerHTML = '&uarr;';\n"
					   "  span.setAttribute('sortdir','up');\n"
					   "  rows.reverse();\n"
					   " } else {\n"
					   "  span.innerHTML = '&darr;';\n"
					   "  span.setAttribute('sortdir','down');\n"
					   " }\n"
					   " for (i=0;i<rows.length;i++)\n"
					   "  table.tBodies[0].appendChild(rows[i]);\n"
					   " prev_span = span;\n"
					   "}\n"
					   "// -->\n"
					   "</script>\n");
	}

	BUFFER_APPEND_STRING_CONST(b,
				 " </head>\n"
				 " <body>\n");



	/* connection listing */
	BUFFER_APPEND_STRING_CONST(b, "<h1>Server-Status</h1>");

	BUFFER_APPEND_STRING_CONST(b, "<table summary=\"status\" class=\"status\">");
	BUFFER_APPEND_STRING_CONST(b, "<tr><td>Hostname</td><td class=\"string\">");
	buffer_append_string_buffer(b, con->uri.authority);
	BUFFER_APPEND_STRING_CONST(b, " (");
	buffer_append_string_buffer(b, con->server_name);
	BUFFER_APPEND_STRING_CONST(b, ")</td></tr>\n");
	BUFFER_APPEND_STRING_CONST(b, "<tr><td>Uptime</td><td class=\"string\">");

	ts = srv->cur_ts - srv->startup_ts;

	days = ts / (60 * 60 * 24);
	ts %= (60 * 60 * 24);

	hours = ts / (60 * 60);
	ts %= (60 * 60);

	mins = ts / (60);
	ts %= (60);

	seconds = ts;

	if (days) {
		buffer_append_long(b, days);
		BUFFER_APPEND_STRING_CONST(b, " days ");
	}

	if (hours) {
		buffer_append_long(b, hours);
		BUFFER_APPEND_STRING_CONST(b, " hours ");
	}

	if (mins) {
		buffer_append_long(b, mins);
		BUFFER_APPEND_STRING_CONST(b, " min ");
	}

	buffer_append_long(b, seconds);
	BUFFER_APPEND_STRING_CONST(b, " s");

	BUFFER_APPEND_STRING_CONST(b, "</td></tr>\n");
	BUFFER_APPEND_STRING_CONST(b, "<tr><td>Started at</td><td class=\"string\">");

	ts = srv->startup_ts;

	strftime(buf, sizeof(buf) - 1, "%Y-%m-%d %H:%M:%S", localtime(&ts));
	buffer_append_string(b, buf);
	BUFFER_APPEND_STRING_CONST(b, "</td></tr>\n");


	BUFFER_APPEND_STRING_CONST(b, "<tr><th colspan=\"2\">absolute (since start)</th></tr>\n");

	BUFFER_APPEND_STRING_CONST(b, "<tr><td>Requests</td><td class=\"string\">");
	avg = p->abs_requests;

	mod_status_get_multiplier(&avg, &multiplier, 1000);

	buffer_append_long(b, avg);
	BUFFER_APPEND_STRING_CONST(b, " ");
	if (multiplier)	buffer_append_string_len(b, &multiplier, 1);
	BUFFER_APPEND_STRING_CONST(b, "req</td></tr>\n");

	BUFFER_APPEND_STRING_CONST(b, "<tr><td>Traffic</td><td class=\"string\">");
	avg = p->abs_traffic_out;

	mod_status_get_multiplier(&avg, &multiplier, 1024);

	sprintf(buf, "%.2f", avg);
	buffer_append_string(b, buf);
	BUFFER_APPEND_STRING_CONST(b, " ");
	if (multiplier)	buffer_append_string_len(b, &multiplier, 1);
	BUFFER_APPEND_STRING_CONST(b, "byte</td></tr>\n");



	BUFFER_APPEND_STRING_CONST(b, "<tr><th colspan=\"2\">average (since start)</th></tr>\n");

	BUFFER_APPEND_STRING_CONST(b, "<tr><td>Requests</td><td class=\"string\">");
	avg = p->abs_requests / (srv->cur_ts - srv->startup_ts);

	mod_status_get_multiplier(&avg, &multiplier, 1000);

	buffer_append_long(b, avg);
	BUFFER_APPEND_STRING_CONST(b, " ");
	if (multiplier)	buffer_append_string_len(b, &multiplier, 1);
	BUFFER_APPEND_STRING_CONST(b, "req/s</td></tr>\n");

	BUFFER_APPEND_STRING_CONST(b, "<tr><td>Traffic</td><td class=\"string\">");
	avg = p->abs_traffic_out / (srv->cur_ts - srv->startup_ts);

	mod_status_get_multiplier(&avg, &multiplier, 1024);

	sprintf(buf, "%.2f", avg);
	buffer_append_string(b, buf);
	BUFFER_APPEND_STRING_CONST(b, " ");
	if (multiplier)	buffer_append_string_len(b, &multiplier, 1);
	BUFFER_APPEND_STRING_CONST(b, "byte/s</td></tr>\n");



	BUFFER_APPEND_STRING_CONST(b, "<tr><th colspan=\"2\">average (5s sliding average)</th></tr>\n");
	for (j = 0, avg = 0; j < 5; j++) {
		avg += p->mod_5s_requests[j];
	}

	avg /= 5;

	BUFFER_APPEND_STRING_CONST(b, "<tr><td>Requests</td><td class=\"string\">");

	mod_status_get_multiplier(&avg, &multiplier, 1000);

	buffer_append_long(b, avg);
	BUFFER_APPEND_STRING_CONST(b, " ");
	if (multiplier)	buffer_append_string_len(b, &multiplier, 1);

	BUFFER_APPEND_STRING_CONST(b, "req/s</td></tr>\n");

	for (j = 0, avg = 0; j < 5; j++) {
		avg += p->mod_5s_traffic_out[j];
	}

	avg /= 5;

	BUFFER_APPEND_STRING_CONST(b, "<tr><td>Traffic</td><td class=\"string\">");

	mod_status_get_multiplier(&avg, &multiplier, 1024);

	sprintf(buf, "%.2f", avg);
	buffer_append_string(b, buf);
	BUFFER_APPEND_STRING_CONST(b, " ");
	if (multiplier)	buffer_append_string_len(b, &multiplier, 1);
	BUFFER_APPEND_STRING_CONST(b, "byte/s</td></tr>\n");

	BUFFER_APPEND_STRING_CONST(b, "</table>\n");


	BUFFER_APPEND_STRING_CONST(b, "<hr />\n<pre><b>legend</b>\n");
	BUFFER_APPEND_STRING_CONST(b, ". = connect, C = close, E = hard error\n");
	BUFFER_APPEND_STRING_CONST(b, "r = read, R = read-POST, W = write, h = handle-request\n");
	BUFFER_APPEND_STRING_CONST(b, "q = request-start,  Q = request-end\n");
	BUFFER_APPEND_STRING_CONST(b, "s = response-start, S = response-end\n");

	BUFFER_APPEND_STRING_CONST(b, "<b>");
	buffer_append_long(b, srv->conns->used);
	BUFFER_APPEND_STRING_CONST(b, " connections</b>\n");

	for (j = 0; j < srv->conns->used; j++) {
		connection *c = srv->conns->ptr[j];
		const char *state = connection_get_short_state(c->state);

		buffer_append_string_len(b, state, 1);

		if (((j + 1) % 50) == 0) {
			BUFFER_APPEND_STRING_CONST(b, "\n");
		}
	}

	BUFFER_APPEND_STRING_CONST(b, "\n</pre><hr />\n<h2>Connections</h2>\n");

	BUFFER_APPEND_STRING_CONST(b, "<table summary=\"status\" class=\"status\">\n");
	BUFFER_APPEND_STRING_CONST(b, "<tr>");
	mod_status_header_append_sort(b, p_d, "Client IP");
	mod_status_header_append_sort(b, p_d, "Read");
	mod_status_header_append_sort(b, p_d, "Written");
	mod_status_header_append_sort(b, p_d, "State");
	mod_status_header_append_sort(b, p_d, "Time");
	mod_status_header_append_sort(b, p_d, "Host");
	mod_status_header_append_sort(b, p_d, "URI");
	mod_status_header_append_sort(b, p_d, "File");
	BUFFER_APPEND_STRING_CONST(b, "</tr>\n");

	for (j = 0; j < srv->conns->used; j++) {
		connection *c = srv->conns->ptr[j];

		BUFFER_APPEND_STRING_CONST(b, "<tr><td class=\"string\">");

		buffer_append_string(b, inet_ntop_cache_get_ip(srv, &(c->dst_addr)));

		BUFFER_APPEND_STRING_CONST(b, "</td><td class=\"int\">");

		if (con->request.content_length) {
			buffer_append_long(b, c->request_content_queue->bytes_in);
			BUFFER_APPEND_STRING_CONST(b, "/");
			buffer_append_long(b, c->request.content_length);
		} else {
			BUFFER_APPEND_STRING_CONST(b, "0/0");
		}

		BUFFER_APPEND_STRING_CONST(b, "</td><td class=\"int\">");

		buffer_append_off_t(b, chunkqueue_written(c->write_queue));
		BUFFER_APPEND_STRING_CONST(b, "/");
		buffer_append_off_t(b, chunkqueue_length(c->write_queue));

		BUFFER_APPEND_STRING_CONST(b, "</td><td class=\"string\">");

		buffer_append_string(b, connection_get_state(c->state));

		BUFFER_APPEND_STRING_CONST(b, "</td><td class=\"int\">");

		buffer_append_long(b, srv->cur_ts - c->request_start);

		BUFFER_APPEND_STRING_CONST(b, "</td><td class=\"string\">");

		if (buffer_is_empty(c->server_name)) {
			buffer_append_string_buffer(b, c->uri.authority);
		}
		else {
			buffer_append_string_buffer(b, c->server_name);
		}

		BUFFER_APPEND_STRING_CONST(b, "</td><td class=\"string\">");

		if (!buffer_is_empty(c->uri.path)) {
			buffer_append_string_encoded(b, CONST_BUF_LEN(c->uri.path), ENCODING_HTML);
		}

		BUFFER_APPEND_STRING_CONST(b, "</td><td class=\"string\">");

		buffer_append_string_buffer(b, c->physical.path);

		BUFFER_APPEND_STRING_CONST(b, "</td></tr>\n");
	}


	BUFFER_APPEND_STRING_CONST(b,
		      "</table>\n");


	BUFFER_APPEND_STRING_CONST(b,
		      " </body>\n"
		      "</html>\n"
		      );

	response_header_overwrite(srv, con, CONST_STR_LEN("Content-Type"), CONST_STR_LEN("text/html"));

	return 0;
}
示例#8
0
static int proxy_create_env(server *srv, handler_ctx *hctx) {
	size_t i;
	connection *con   = hctx->remote_conn;
	buffer *b;

	/* build header */

	b = chunkqueue_get_append_buffer(hctx->wb);

	/* request line */
	buffer_copy_string(b, get_http_method_name(con->request.http_method));
	BUFFER_APPEND_STRING_CONST(b, " ");

	buffer_append_string_buffer(b, con->request.uri);
	BUFFER_APPEND_STRING_CONST(b, " HTTP/1.0\r\n");

	proxy_append_header(con, "X-Forwarded-For", (char *)inet_ntop_cache_get_ip(srv, &(con->dst_addr)));
	/* http_host is NOT is just a pointer to a buffer
	 * which is NULL if it is not set */
	if (con->request.http_host &&
	    !buffer_is_empty(con->request.http_host)) {
		proxy_set_header(con, "X-Host", con->request.http_host->ptr);
	}
	proxy_set_header(con, "X-Forwarded-Proto", con->conf.is_ssl ? "https" : "http");

	/* request header */
	for (i = 0; i < con->request.headers->used; i++) {
		data_string *ds;

		ds = (data_string *)con->request.headers->data[i];

		if (ds->value->used && ds->key->used) {
			if (buffer_is_equal_string(ds->key, CONST_STR_LEN("Connection"))) continue;

			buffer_append_string_buffer(b, ds->key);
			BUFFER_APPEND_STRING_CONST(b, ": ");
			buffer_append_string_buffer(b, ds->value);
			BUFFER_APPEND_STRING_CONST(b, "\r\n");
		}
	}

	BUFFER_APPEND_STRING_CONST(b, "\r\n");

	hctx->wb->bytes_in += b->used - 1;
	/* body */

	if (con->request.content_length) {
		chunkqueue *req_cq = con->request_content_queue;
		chunk *req_c;
		off_t offset;

		/* something to send ? */
		for (offset = 0, req_c = req_cq->first; offset != req_cq->bytes_in; req_c = req_c->next) {
			off_t weWant = req_cq->bytes_in - offset;
			off_t weHave = 0;

			/* we announce toWrite octects
			 * now take all the request_content chunk that we need to fill this request
			 * */

			switch (req_c->type) {
			case FILE_CHUNK:
				weHave = req_c->file.length - req_c->offset;

				if (weHave > weWant) weHave = weWant;

				chunkqueue_append_file(hctx->wb, req_c->file.name, req_c->offset, weHave);

				req_c->offset += weHave;
				req_cq->bytes_out += weHave;

				hctx->wb->bytes_in += weHave;

				break;
			case MEM_CHUNK:
				/* append to the buffer */
				weHave = req_c->mem->used - 1 - req_c->offset;

				if (weHave > weWant) weHave = weWant;

				b = chunkqueue_get_append_buffer(hctx->wb);
				buffer_append_memory(b, req_c->mem->ptr + req_c->offset, weHave);
				b->used++; /* add virtual \0 */

				req_c->offset += weHave;
				req_cq->bytes_out += weHave;

				hctx->wb->bytes_in += weHave;

				break;
			default:
				break;
			}

			offset += weHave;
		}

	}

	return 0;
}
示例#9
0
static cond_result_t config_check_cond_nocache(server *srv, connection *con, data_config *dc) {
    conf_buffer *l;
    server_socket *srv_sock = con->srv_socket;

    /* check parent first */
    if (dc->parent && dc->parent->context_ndx) {
        /**
         * a nested conditional
         *
         * if the parent is not decided yet or false, we can't be true either
         */
        if (con->conf.log_condition_handling) {
            log_error_write(srv, __FILE__, __LINE__,  "sb", "go parent", dc->parent->key);
        }

        switch (config_check_cond_cached(srv, con, dc->parent)) {
        case COND_RESULT_FALSE:
            return COND_RESULT_FALSE;
        case COND_RESULT_UNSET:
            return COND_RESULT_UNSET;
        default:
            break;
        }
    }

    if (dc->prev) {
        /**
         * a else branch
         *
         * we can only be executed, if all of our previous brothers
         * are false
         */
        if (con->conf.log_condition_handling) {
            log_error_write(srv, __FILE__, __LINE__,  "sb", "go prev", dc->prev->key);
        }

        /* make sure prev is checked first */
        config_check_cond_cached(srv, con, dc->prev);

        /* one of prev set me to FALSE */
        switch (con->cond_cache[dc->context_ndx].result) {
        case COND_RESULT_FALSE:
            return con->cond_cache[dc->context_ndx].result;
        default:
            break;
        }
    }

    if (!con->conditional_is_valid[dc->comp]) {
        if (con->conf.log_condition_handling) {
            log_error_write(srv, __FILE__, __LINE__,  "dss",
                dc->comp,
                dc->key->ptr,
                con->conditional_is_valid[dc->comp] ? "yeah" : "nej");
        }

        return COND_RESULT_UNSET;
    }

    /* pass the rules */

    switch (dc->comp) {
    case COMP_HTTP_HOST: {
        char *ck_colon = NULL, *val_colon = NULL;

        if (!buffer_is_empty(con->uri.authority)) {

            /*
             * append server-port to the HTTP_POST if necessary
             */

            l = con->uri.authority;

            switch(dc->cond) {
            case CONFIG_COND_NE:
            case CONFIG_COND_EQ:
                ck_colon = strchr(dc->string->ptr, ':');
                val_colon = strchr(l->ptr, ':');

                if (ck_colon == val_colon) {
                    /* nothing to do with it */
                    break;
                }
                if (ck_colon) {
                    /* condition "host:port" but client send "host" */
                    buffer_copy_string_buffer(srv->cond_check_buf, l);
                    BUFFER_APPEND_STRING_CONST(srv->cond_check_buf, ":");
                    buffer_append_long(srv->cond_check_buf, sock_addr_get_port(&(srv_sock->addr)));
                    l = srv->cond_check_buf;
                } else if (!ck_colon) {
                    /* condition "host" but client send "host:port" */
                    buffer_copy_string_len(srv->cond_check_buf, l->ptr, val_colon - l->ptr);
                    l = srv->cond_check_buf;
                }
                break;
            default:
                break;
            }
        } else {
            l = srv->empty_string;
        }
        break;
    }
    case COMP_HTTP_REMOTEIP: {
        char *nm_slash;
        /* handle remoteip limitations
         *
         * "10.0.0.1" is provided for all comparisions
         *
         * only for == and != we support
         *
         * "10.0.0.1/24"
         */

        if ((dc->cond == CONFIG_COND_EQ ||
             dc->cond == CONFIG_COND_NE) &&
            (con->dst_addr.plain.sa_family == AF_INET) &&
            (NULL != (nm_slash = strchr(dc->string->ptr, '/')))) {
            int nm_bits;
            long nm;
            char *err;
            struct in_addr val_inp;

            if (*(nm_slash+1) == '\0') {
                log_error_write(srv, __FILE__, __LINE__, "sb", "ERROR: no number after / ", dc->string);

                return COND_RESULT_FALSE;
            }

            nm_bits = strtol(nm_slash + 1, &err, 10);

            if (*err) {
                log_error_write(srv, __FILE__, __LINE__, "sbs", "ERROR: non-digit found in netmask:", dc->string, err);

                return COND_RESULT_FALSE;
            }

            /* take IP convert to the native */
            buffer_copy_string_len(srv->cond_check_buf, dc->string->ptr, nm_slash - dc->string->ptr);
#ifdef __WIN32
            if (INADDR_NONE == (val_inp.s_addr = inet_addr(srv->cond_check_buf->ptr))) {
                log_error_write(srv, __FILE__, __LINE__, "sb", "ERROR: ip addr is invalid:", srv->cond_check_buf);

                return COND_RESULT_FALSE;
            }

#else
            if (0 == inet_aton(srv->cond_check_buf->ptr, &val_inp)) {
                log_error_write(srv, __FILE__, __LINE__, "sb", "ERROR: ip addr is invalid:", srv->cond_check_buf);

                return COND_RESULT_FALSE;
            }
#endif

            /* build netmask */
            nm = htonl(~((1 << (32 - nm_bits)) - 1));

            if ((val_inp.s_addr & nm) == (con->dst_addr.ipv4.sin_addr.s_addr & nm)) {
                return (dc->cond == CONFIG_COND_EQ) ? COND_RESULT_TRUE : COND_RESULT_FALSE;
            } else {
                return (dc->cond == CONFIG_COND_EQ) ? COND_RESULT_FALSE : COND_RESULT_TRUE;
            }
        } else {
            l = con->dst_addr_buf;
        }
        break;
    }
    case COMP_HTTP_URL:
        l = con->uri.path;
        break;

    case COMP_HTTP_QUERYSTRING:
        l = con->uri.query;
        break;

    case COMP_SERVER_SOCKET:
        l = srv_sock->srv_token;
        break;

    case COMP_HTTP_REFERER: {
        data_string *ds;

        if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "Referer"))) {
            l = ds->value;
        } else {
            l = srv->empty_string;
        }
        break;
    }
    case COMP_HTTP_COOKIE: {
        data_string *ds;
        if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "Cookie"))) {
            l = ds->value;
        } else {
            l = srv->empty_string;
        }
        break;
    }
    case COMP_HTTP_USERAGENT: {
        data_string *ds;
        if (NULL != (ds = (data_string *)array_get_element(con->request.headers, "User-Agent"))) {
            l = ds->value;
        } else {
            l = srv->empty_string;
        }
        break;
    }

    default:
        return COND_RESULT_FALSE;
    }

    if (NULL == l) {
        if (con->conf.log_condition_handling) {
            log_error_write(srv, __FILE__, __LINE__,  "bsbs", dc->comp_key,
                    "(", l, ") compare to NULL");
        }
        return COND_RESULT_FALSE;
    }

    if (con->conf.log_condition_handling) {
        log_error_write(srv, __FILE__, __LINE__,  "bsbsb", dc->comp_key,
                "(", l, ") compare to ", dc->string);
    }
    switch(dc->cond) {
    case CONFIG_COND_NE:
    case CONFIG_COND_EQ:
        if (buffer_is_equal(l, dc->string)) {
            return (dc->cond == CONFIG_COND_EQ) ? COND_RESULT_TRUE : COND_RESULT_FALSE;
        } else {
            return (dc->cond == CONFIG_COND_EQ) ? COND_RESULT_FALSE : COND_RESULT_TRUE;
        }
        break;
#ifdef HAVE_PCRE_H
    case CONFIG_COND_NOMATCH:
    case CONFIG_COND_MATCH: {
        cond_cache_t *cache = &con->cond_cache[dc->context_ndx];
        int n;

#ifndef elementsof
#define elementsof(x) (sizeof(x) / sizeof(x[0]))
#endif
        n = pcre_exec(dc->regex, dc->regex_study, l->ptr, l->used - 1, 0, 0,
                cache->matches, elementsof(cache->matches));

        cache->patterncount = n;
        if (n > 0) {
            cache->comp_value = l;
            cache->comp_type  = dc->comp;
            return (dc->cond == CONFIG_COND_MATCH) ? COND_RESULT_TRUE : COND_RESULT_FALSE;
        } else {
            /* cache is already cleared */
            return (dc->cond == CONFIG_COND_MATCH) ? COND_RESULT_FALSE : COND_RESULT_TRUE;
        }
        break;
    }
#endif
    default:
        /* no way */
        break;
    }

    return COND_RESULT_FALSE;
}
示例#10
0
static handler_t mod_authn_gssapi_basic(server *srv, connection *con, void *p_d, const http_auth_require_t *require, const buffer *username, const char *pw)
{
    krb5_context kcontext  = NULL;
    krb5_keytab keytab     = NULL;
    krb5_principal s_princ = NULL;
    krb5_principal c_princ = NULL;
    krb5_creds c_creds;
    krb5_ccache c_ccache   = NULL;
    krb5_ccache ret_ccache = NULL;
    krb5_error_code code;
    int ret;
    buffer *sprinc;
    buffer *user_at_realm  = NULL;
    plugin_data * const p = (plugin_data *)p_d;

    if (*pw == '\0') {
        log_error_write(srv, __FILE__, __LINE__, "s", "Empty passwords are not accepted");
        return mod_authn_gssapi_send_401_unauthorized_basic(srv, con);
    }

    mod_authn_gssapi_patch_connection(srv, con, p);

    code = krb5_init_context(&kcontext);
    if (code) {
        log_error_write(srv, __FILE__, __LINE__, "sd", "krb5_init_context():", code);
        return mod_authn_gssapi_send_401_unauthorized_basic(srv, con); /*(well, should be 500)*/
    }

    code = krb5_kt_resolve(kcontext, p->conf.auth_gssapi_keytab->ptr, &keytab);
    if (code) {
        log_error_write(srv, __FILE__, __LINE__, "sdb", "krb5_kt_resolve():", code, p->conf.auth_gssapi_keytab);
        return mod_authn_gssapi_send_401_unauthorized_basic(srv, con); /*(well, should be 500)*/
    }

    sprinc = buffer_init_buffer(p->conf.auth_gssapi_principal);
    if (strchr(sprinc->ptr, '/') == NULL) {
        /*(copy HTTP Host, omitting port if port is present)*/
        /* ??? Should con->server_name be used if http_host not present?
         * ??? What if con->server_name is not set?
         * ??? Will this work below if IPv6 provided in Host?  probably not */
        if (!buffer_is_empty(con->request.http_host)) {
            buffer_append_string(sprinc, "/");
            buffer_append_string_len(sprinc, con->request.http_host->ptr, strcspn(con->request.http_host->ptr, ":"));
        }
    }

    /*(init c_creds before anything which might krb5_free_cred_contents())*/
    memset(&c_creds, 0, sizeof(c_creds));

    ret = krb5_parse_name(kcontext, sprinc->ptr, &s_princ);
    if (ret) {
        mod_authn_gssapi_log_krb5_error(srv, __FILE__, __LINE__, "krb5_parse_name", sprinc->ptr, kcontext, ret);
        ret = -1;
        goto end;
    }

    if (strchr(username->ptr, '@') == NULL) {
        user_at_realm = buffer_init_buffer(username);
        BUFFER_APPEND_STRING_CONST(user_at_realm, "@");
        buffer_append_string_buffer(user_at_realm, require->realm);
    }

    ret = krb5_parse_name(kcontext, (user_at_realm ? user_at_realm->ptr : username->ptr), &c_princ);
    if (ret) {
        mod_authn_gssapi_log_krb5_error(srv, __FILE__, __LINE__, "krb5_parse_name", (user_at_realm ? user_at_realm->ptr : username->ptr), kcontext, ret);
        if (user_at_realm) buffer_free(user_at_realm);
        ret = -1;
        goto end;
    }
    if (user_at_realm) buffer_free(user_at_realm);
    /* XXX: if the qualified username with @realm should be in REMOTE_USER,
     * then http_auth_backend_t basic interface needs to change to pass
     * modifiable buffer *username, but note that const char *pw follows
     * in the truncated buffer *username, so pw would need to be copied
     * before modifying buffer *username */

    /*
     * char *name = NULL;
     * ret = krb5_unparse_name(kcontext, c_princ, &name);
     * if (ret == 0) {
     *    log_error_write(srv, __FILE__, __LINE__, "sbss", "Trying to get TGT for user:"******"password:"******"krb5_get_init_creds_password", NULL, kcontext, ret);
        goto end;
    }

    ret = mod_authn_gssapi_verify_krb5_init_creds(srv, kcontext, &c_creds, s_princ, keytab);
    if (ret) {
        mod_authn_gssapi_log_krb5_error(srv, __FILE__, __LINE__, "mod_authn_gssapi_verify_krb5_init_creds", NULL, kcontext, ret);
        goto end;
    }

    ret = krb5_cc_resolve(kcontext, "MEMORY:", &ret_ccache);
    if (ret) {
        mod_authn_gssapi_log_krb5_error(srv, __FILE__, __LINE__, "krb5_cc_resolve", NULL, kcontext, ret);
        goto end;
    }

    ret = krb5_cc_initialize(kcontext, ret_ccache, c_princ);
    if (ret) {
        mod_authn_gssapi_log_krb5_error(srv, __FILE__, __LINE__, "krb5_cc_initialize", NULL, kcontext, ret);
        goto end;
    }

    ret = krb5_cc_store_cred(kcontext, ret_ccache, &c_creds);
    if (ret) {
        mod_authn_gssapi_log_krb5_error(srv, __FILE__, __LINE__, "krb5_cc_store_cred", NULL, kcontext, ret);
        goto end;
    }

    c_ccache = ret_ccache;
    ret_ccache = NULL;

    end:

        krb5_free_cred_contents(kcontext, &c_creds);
        if (ret_ccache)
            krb5_cc_destroy(kcontext, ret_ccache);

        if (!ret && c_ccache && (ret = mod_authn_gssapi_store_krb5_creds(srv, con, p, kcontext, c_ccache))) {
            log_error_write(srv, __FILE__, __LINE__, "sb", "mod_authn_gssapi_store_krb5_creds failed for", username);
        }

        buffer_free(sprinc);
        if (c_princ)
            krb5_free_principal(kcontext, c_princ);
        if (s_princ)
            krb5_free_principal(kcontext, s_princ);
        if (c_ccache)
            krb5_cc_destroy(kcontext, c_ccache);
        if (keytab)
            krb5_kt_close(kcontext, keytab);

        krb5_free_context(kcontext);

        if (0 == ret && http_auth_match_rules(require,username->ptr,NULL,NULL)){
            return HANDLER_GO_ON;
        }
        else {
            /* ret == KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN or no authz rules match */
            log_error_write(srv, __FILE__, __LINE__, "sbsBsB", "password doesn't match for", con->uri.path, "username:"******", IP:", con->dst_addr_buf);
            return mod_authn_gssapi_send_401_unauthorized_basic(srv, con);
        }
}