Esempio n. 1
0
ret_t
cherokee_buffer_add_buffer (cherokee_buffer_t *buf, cherokee_buffer_t *buf2)
{
	return cherokee_buffer_add (buf, buf2->buf, buf2->len);
}
ret_t
cherokee_handler_proxy_conn_recv_headers (cherokee_handler_proxy_conn_t *pconn,
					  cherokee_buffer_t             *body,
					  cherokee_boolean_t             flexible)
{
	ret_t    ret;
	char    *end;
	cuint_t  sep_len;
	size_t   size     = 0;

	/* Read
	 */
	ret = cherokee_socket_bufread (&pconn->socket,
				       &pconn->header_in_raw,
				       DEFAULT_RECV_SIZE, &size);
	switch (ret) {
	case ret_ok:
		break;
	case ret_eof:
	case ret_error:
		return ret;
	case ret_eagain:
		if (cherokee_buffer_is_empty (&pconn->header_in_raw)) {
			return ret_eagain;
		}
		break;
	default:
		RET_UNKNOWN(ret);
	}

	/* Look for the end of header
	 */
	ret = cherokee_find_header_end (&pconn->header_in_raw, &end, &sep_len);
	switch (ret) {
	case ret_ok:
		break;
	case ret_not_found:
		return ret_eagain;
	default:
		/* Did not success
		 */
		if (! flexible) {
			goto error;
		}

		/* Plan B!
		 */
		TRACE (ENTRIES, "Header end not found. Being more flexible about malformed headers\n");

		ret = find_header_end_flexible (&pconn->header_in_raw, &end, &sep_len);
		switch (ret) {
		case ret_ok:
			break;
		case ret_not_found:
			return ret_eagain;
		default:
			goto error;
		}
	}

	/* Copy the body if there is any
	 */
	size = (pconn->header_in_raw.buf + pconn->header_in_raw.len) - (end + sep_len);

	cherokee_buffer_add (body, end+sep_len, size);
	cherokee_buffer_drop_ending (&pconn->header_in_raw, size);

	return ret_ok;

error:
	LOG_ERROR (CHEROKEE_ERROR_PROXY_HEADER_PARSE,
		   pconn->header_in_raw.len,
		   pconn->header_in_raw.buf);

	return ret_error;
}
Esempio n. 3
0
static ret_t
cherokee_url_parse_guts (cherokee_url_t    *url,
			 cherokee_buffer_t *url_buf,
			 cherokee_buffer_t *user_ret,
			 cherokee_buffer_t *password_ret)
{
	ret_t    ret;
	cuint_t  len = 0 ;
	char    *port;
	char    *slash;
	char    *server;
	char    *arroba;
	char    *tmp;

	/* Drop protocol, if exists..
	 */
	ret = parse_protocol (url, url_buf->buf, &len);
	if (unlikely(ret < ret_ok)) return ret_error;

	tmp = url_buf->buf + len;

	/* User (and password)
	 */
	arroba = strchr (tmp, '@');
	if (arroba != NULL) {
		char *sep;

		sep = strchr (tmp, ':');
		if (sep == NULL) {
			cherokee_buffer_clean (user_ret);
			cherokee_buffer_add (user_ret, tmp, arroba - tmp);
		} else {
			cherokee_buffer_clean (user_ret);
			cherokee_buffer_add (user_ret, tmp, sep - tmp);
			sep++;
			cherokee_buffer_clean (password_ret);
			cherokee_buffer_add (password_ret, sep, arroba - sep);
		}

		tmp = arroba + 1;
	}

	/* Split the host/request
	 */
	server = tmp;
	len    = strlen (server);
	slash  = strpbrk (server, "/\\");

	if (slash == NULL) {
		cherokee_buffer_add (&url->request, "/", 1);
		cherokee_buffer_add (&url->host, server, len);
	} else {
		cherokee_buffer_add (&url->request, slash, len-(slash-server));
		cherokee_buffer_add (&url->host, server, slash-server);
	}

	/* Drop up the port, if exists..
	 */
	port = strchr (url->host.buf, ':');
	if (port != NULL) {

		/* Read port number
		 */
		if (slash != NULL) *slash = '\0';
		URL_PORT(url) = atoi (port+1);
		if (slash != NULL) *slash =  '/';

		/* .. and remove it
		 */
		ret = cherokee_buffer_drop_ending (&url->host, strlen(port));
		if (unlikely(ret < ret_ok)) return ret;
	}

#if 0
	cherokee_url_print (url);
#endif

	return ret_ok;
}
Esempio n. 4
0
static ret_t
fork_and_execute_cgi_win32 (cherokee_handler_cgi_t *cgi)
{
	int                    re;
	PROCESS_INFORMATION    pi;
	STARTUPINFO            si;
	char                  *cmd;
	cherokee_buffer_t      cmd_line = CHEROKEE_BUF_INIT;
	cherokee_buffer_t      exec_dir = CHEROKEE_BUF_INIT;
	cherokee_connection_t *conn     = HANDLER_CONN(cgi);

	SECURITY_ATTRIBUTES saSecAtr;
	HANDLE hProc;
	HANDLE hChildStdinRd  = INVALID_HANDLE_VALUE;
	HANDLE hChildStdinWr  = INVALID_HANDLE_VALUE;
	HANDLE hChildStdoutRd = INVALID_HANDLE_VALUE;
	HANDLE hChildStdoutWr = INVALID_HANDLE_VALUE;

	/* Create the environment for the process
	 */
	add_environment (cgi, conn);
	cherokee_buffer_add (&cgi->envp, "\0", 1);

	/* Command line
	 */
	cmd = HDL_CGI_BASE(cgi)->executable.buf;
	cherokee_buffer_add (&cmd_line, cmd, strlen(cmd));
//	cherokee_buffer_add_va (&cmd_line, " \"%s\"", HDL_CGI_BASE(cgi)->param.buf);

	/* Execution directory
	 */
	if (! cherokee_buffer_is_empty (&conn->effective_directory)) {
		cherokee_buffer_add_buffer (&exec_dir, &conn->effective_directory);
	} else {
		char *file = strrchr (cmd, '/');
		char *end  = HDL_CGI_BASE(cgi)->executable.buf + HDL_CGI_BASE(cgi)->executable.len;

		cherokee_buffer_add (&exec_dir, cmd,
				     HDL_CGI_BASE(cgi)->executable.len - (end - file));
	}

	/* Set the bInheritHandle flag so pipe handles are inherited.
	 */
	memset(&saSecAtr, 0, sizeof(SECURITY_ATTRIBUTES));
	saSecAtr.nLength = sizeof(SECURITY_ATTRIBUTES);
	saSecAtr.lpSecurityDescriptor = NULL;
	saSecAtr.bInheritHandle       = TRUE;

	/* Create the pipes
	 */
	hProc = GetCurrentProcess();

	re = CreatePipe (&hChildStdoutRd, &hChildStdoutWr, &saSecAtr, 0);
	if (!re) return ret_error;

	re = CreatePipe (&hChildStdinRd, &hChildStdinWr, &saSecAtr, 0);
	if (!re) return ret_error;

	/* Make them inheritable
	 */
	re = DuplicateHandle (hProc,  hChildStdoutRd,
			      hProc, &hChildStdoutRd,
			      0, TRUE,
			      DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS);
	if (!re) return ret_error;

	re = DuplicateHandle (hProc,  hChildStdinWr,
			      hProc, &hChildStdinWr,
			      0, TRUE,
			      DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS);
	if (!re) return ret_error;


	/* Starting information
	 */
	ZeroMemory (&si, sizeof(STARTUPINFO));
	si.cb         = sizeof(STARTUPINFO);
	si.hStdOutput = hChildStdoutWr;
	si.hStdError  = hChildStdoutWr;
	si.hStdInput  = hChildStdinRd;
	si.dwFlags   |= STARTF_USESTDHANDLES;

	TRACE (ENTRIES, "exec %s dir %s\n", cmd_line.buf, exec_dir.buf);

	/* Launch the child process
	 */
	re = CreateProcess (cmd,              /* ApplicationName */
			    cmd_line.buf,     /* Command line */
			    NULL,             /* Process handle not inheritable */
			    NULL,             /* Thread handle not inheritable */
			    TRUE,             /* Handle inheritance */
			    0,                /* Creation flags */
			    cgi->envp.buf,    /* Use parent's environment block */
			    exec_dir.buf,     /* Use parent's starting directory */
			    &si,              /* Pointer to STARTUPINFO structure */
			    &pi);             /* Pointer to PROCESS_INFORMATION structure */

	CloseHandle (hChildStdinRd);
	CloseHandle (hChildStdoutWr);

	if (!re) {
		LOG_ERROR (CHEROKEE_ERROR_HANDLER_CGI_CREATEPROCESS, GetLastError());

		CloseHandle (pi.hProcess);
		CloseHandle (pi.hThread);

		conn->error_code = http_internal_error;
		return ret_error;
	}

	cherokee_buffer_mrproper (&cmd_line);
	cherokee_buffer_mrproper (&exec_dir);

	cgi->thread  = pi.hThread;
	cgi->process = pi.hProcess;

	/* Wait for the CGI process to be ready
	 */
	WaitForInputIdle (pi.hProcess, INFINITE);

	/* Extract the file descriptors
	 */
	cgi->pipeInput  = _open_osfhandle((LONG)hChildStdoutRd, O_BINARY|_O_RDONLY);

	if (! conn->post.len <= 0) {
		CloseHandle (hChildStdinWr);
	} else {
		cgi->pipeOutput = _open_osfhandle((LONG)hChildStdinWr,  O_BINARY|_O_WRONLY);
	}

	TRACE (ENTRIES, "In fd %d, Out fd %d\n", cgi->pipeInput, cgi->pipeOutput);

	return ret_ok;
}
Esempio n. 5
0
ret_t
cherokee_handler_tmi_read_post (cherokee_handler_tmi_t *hdl)
{
    zmq_msg_t message;
    int					  re;
    ret_t					ret;
    ret_t					ret_final;
    cherokee_buffer_t	   *post = &HANDLER_THREAD(hdl)->tmp_buf1;
    cherokee_buffer_t	   *encoded = &HANDLER_THREAD(hdl)->tmp_buf2;
    cherokee_connection_t   *conn = HANDLER_CONN(hdl);

    /* Check for the post info
     */
    if (! conn->post.has_info) {
        conn->error_code = http_bad_request;
        return ret_error;
    }

    cherokee_buffer_clean (post);
    ret = cherokee_post_read (&conn->post, &conn->socket, post);
    switch (ret) {
    case ret_ok:
        cherokee_connection_update_timeout (conn);
        break;
    case ret_eagain:
        ret = cherokee_thread_deactive_to_polling (HANDLER_THREAD(hdl),
                HANDLER_CONN(hdl),
                conn->socket.socket,
                FDPOLL_MODE_READ, false);
        if (ret != ret_ok) {
            return ret_error;
        } else {
            return ret_eagain;
        }
    default:
        conn->error_code = http_bad_request;
        return ret_error;
    }

    TRACE (ENTRIES, "Post contains: '%s'\n", post->buf);

    re = cherokee_post_read_finished (&conn->post);
    ret_final = re ? ret_ok : ret_eagain;

    cherokee_buffer_clean(encoded);
    if (hdl->encoder != NULL) {
        if (ret == ret_ok) {
            cherokee_encoder_flush(hdl->encoder, post, encoded);
        } else {
            cherokee_encoder_encode(hdl->encoder, post, encoded);
        }
    } else {
        encoded = post;
    }

    cherokee_buffer_add_buffer(&hdl->output, post);

    if (ret_final == ret_ok) {
        cherokee_buffer_t	 *tmp  = &HANDLER_THREAD(hdl)->tmp_buf1;
        cherokee_handler_tmi_props_t *props = HANDLER_TMI_PROPS(hdl);
        zmq_msg_t envelope;
        zmq_msg_t message;
        cuint_t len;

        if ((cherokee_buffer_is_empty (&conn->web_directory)) ||
                (cherokee_buffer_is_ending (&conn->web_directory, '/')))
        {
            len = conn->web_directory.len;
        } else {
            len = conn->web_directory.len + 1;
        }

        cherokee_buffer_clean (tmp);
        cherokee_buffer_add   (tmp, conn->request.buf + len,
                               conn->request.len - len);

        TRACE(ENTRIES, "ZeroMQ: incomming path '%s'\n", tmp->buf);

        zmq_msg_init_size (&envelope, tmp->len);
        memcpy (zmq_msg_data (&envelope), tmp->buf, tmp->len);
        zmq_msg_init_size (&message, hdl->output.len);
        memcpy (zmq_msg_data (&message), hdl->output.buf, hdl->output.len);

        /* Atomic Section */
        CHEROKEE_MUTEX_LOCK (&props->mutex);
        zmq_msg_send (&envelope, props->socket, ZMQ_DONTWAIT | ZMQ_SNDMORE);
        zmq_msg_send (&message, props->socket, ZMQ_DONTWAIT);
        CHEROKEE_MUTEX_UNLOCK (&props->mutex);

        zmq_msg_close (&envelope);
        zmq_msg_close (&message);

#ifdef LIBXML_PUSH_ENABLED
        if (hdl->validate_xml) {
            if (hdl->inflated) {
                hdl->strm.avail_in = hdl->output.len;
                hdl->strm.next_in = hdl->output.buf;

                /* run inflate() on input until output buffer not full */
                do  {
#define CHUNK 131072
                    int have;
                    char out[CHUNK];
                    hdl->strm.avail_out = CHUNK;
                    hdl->strm.next_out = out;
                    hdl->z_ret = inflate(&(hdl->strm), Z_NO_FLUSH);
                    switch (hdl->z_ret) {
                    case Z_NEED_DICT:
                        hdl->z_ret = Z_DATA_ERROR;	 /* and fall through */
                    case Z_DATA_ERROR:
                    case Z_MEM_ERROR:
                    case Z_STREAM_ERROR:
                        hdl->z_ret = Z_STREAM_ERROR;
                        return ret_ok;
                    }
                    have = CHUNK - hdl->strm.avail_out;
                    xmlParseChunk(hdl->ctxt, out, have, 0);
                } while (hdl->strm.avail_out == 0);
            } else {
                xmlParseChunk(hdl->ctxt, hdl->output.buf, hdl->output.len, 0);
            }
        }
#endif
    }

    return ret_final;
}
Esempio n. 6
0
ret_t
cherokee_handler_admin_read_post (cherokee_handler_admin_t *hdl)
{
    int                      re;
    ret_t                    ret;
    char                    *tmp;
    cherokee_buffer_t        post = CHEROKEE_BUF_INIT;
    cherokee_buffer_t        line = CHEROKEE_BUF_INIT;
    cherokee_connection_t   *conn = HANDLER_CONN(hdl);

    /* Check for the post info
     */
    if (! conn->post.has_info) {
        conn->error_code = http_bad_request;
        return ret_error;
    }

    /* Process line per line
     */
    ret = cherokee_post_read (&conn->post, &conn->socket, &post);
    switch (ret) {
    case ret_ok:
    case ret_eagain:
        break;
    default:
        conn->error_code = http_bad_request;
        return ret_error;
    }

    /* Parse
     */
    TRACE (ENTRIES, "Post contains: '%s'\n", post.buf);

    cherokee_dwriter_list_open (&hdl->dwriter);

    for (tmp = post.buf;;) {
        char *end1 = strchr (tmp, CHR_LF);
        char *end2 = strchr (tmp, CHR_CR);
        char *end  = cherokee_min_str (end1, end2);

        if (end == NULL) break;
        if (end - tmp < 2) break;

        /* Copy current line and go to the next one
         */
        cherokee_buffer_add (&line, tmp, end - tmp);
        while ((*end == CHR_CR) || (*end == CHR_LF)) end++;
        tmp = end;

        /* Process current line
         */
        ret = process_request_line (hdl, &line);
        if (ret == ret_error) {
            conn->error_code = http_bad_request;
            ret = ret_error;
            goto exit2;
        }

        /* Clean up for the next iteration
         */
        cherokee_buffer_clean (&line);
    }

    cherokee_dwriter_list_close (&hdl->dwriter);

    /* There might be more POST to read
     */
    re = cherokee_post_read_finished (&conn->post);
    ret = re ? ret_ok : ret_eagain;

exit2:
    cherokee_buffer_mrproper (&post);
    cherokee_buffer_mrproper (&line);
    return ret;
}
Esempio n. 7
0
void
cherokee_trace_do_trace (const char *entry, const char *file, int line, const char *func, const char *fmt, ...)
{
	ret_t                  ret;
	char                  *p;
	char                  *lentry;
	char                  *lentry_end;
	va_list                args;
	cherokee_connection_t *conn;
	cherokee_buffer_t     *trace_modules = &trace.modules;
	cherokee_boolean_t     do_log        = false;
	cherokee_buffer_t      entries       = CHEROKEE_BUF_INIT;

	/* Prevents loops
	 */
	if (disabled) {
		return;
	}

	disabled = true;

	/* Return ASAP if nothing is being traced
	 */
	if (cherokee_buffer_is_empty (&trace.modules)) {
		goto out;
	}

	/* Check the connection source, if possible
	 */
	if (trace.from_filter != NULL) {
		conn = CONN (CHEROKEE_THREAD_PROP_GET (thread_connection_ptr));

		/* No conn, no trace entry
		 */
		if (conn == NULL) {
			goto out;
		}

		if (conn->socket.socket < 0) {
			goto out;
		}

		/* Skip the trace if the conn doesn't match
		 */
		ret = cherokee_access_ip_match (trace.from_filter, &conn->socket);
		if (ret != ret_ok) {
			goto out;
		}
	}

	/* Also, check for 'all'
	 */
	p = strstr (trace_modules->buf, "all");
	if (p == NULL) {
		/* Parse the In-code module string
		 */
		cherokee_buffer_add (&entries, entry, strlen(entry));

		for (lentry = entries.buf;;) {
			lentry_end = strchr (lentry, ',');
			if (lentry_end) *lentry_end = '\0';

			/* Check the type
			 */
			p = strstr (trace_modules->buf, lentry);
			if (p) {
				char *tmp = p + strlen(lentry);
				if ((*tmp == '\0') || (*tmp == ',') || (*tmp == ' '))
					do_log = true;
			}

			if ((lentry_end == NULL) || (do_log))
				break;

			lentry = lentry_end + 1;
		}

		/* Return if trace entry didn't match with the configured list
		 */
		if (! do_log) {
			goto out;
		}
	}

	/* Format the message and log it:
	 * 'entries' is not needed at this stage, reuse it
	 */
	cherokee_buffer_clean (&entries);
	if (trace.print_thread) {
		int        len;
		char       tmp[32+1];
		static int longest_len = 0;

		len = snprintf (tmp, 32+1, "%llX", (unsigned long long) CHEROKEE_THREAD_SELF);
		longest_len = MAX (longest_len, len);

		cherokee_buffer_add_str    (&entries, "{0x");
		cherokee_buffer_add_char_n (&entries, '0', longest_len - len);
		cherokee_buffer_add        (&entries, tmp, len);
		cherokee_buffer_add_str    (&entries, "} ");
	}

	if (trace.print_time) {
		cherokee_buffer_add_char (&entries, '[');
		cherokee_buf_add_bogonow (&entries, true);
		cherokee_buffer_add_str  (&entries, "] ");
	}

	cherokee_buffer_add_va (&entries, "%18s:%04d (%30s): ", file, line, func);

	va_start (args, fmt);
	cherokee_buffer_add_va_list (&entries, (char *)fmt, args);
	va_end (args);

	if (trace.use_syslog) {
		cherokee_syslog (LOG_DEBUG, &entries);
	} else {
#ifdef HAVE_FLOCKFILE
		flockfile (stdout);
#endif
		fprintf (stdout, "%s", entries.buf);
#ifdef HAVE_FUNLOCKFILE
		funlockfile (stdout);
#endif
	}

out:
	cherokee_buffer_mrproper (&entries);
	disabled = false;
}
Esempio n. 8
0
static ret_t
process_chunk (cherokee_post_t   *post,
	       cherokee_buffer_t *in,
	       cherokee_buffer_t *out)
{
	char    *p;
	char    *begin;
	char    *end;
        ssize_t  content_size;

        TRACE (ENTRIES, "Post in-buffer len=%d\n", in->len);

	p     = in->buf;
	begin = in->buf;

        while (true) {
                end = in->buf + in->len;

                /* Iterate through the number
		 */
                while ((p < end) &&
                       (((*p >= '0') && (*p <= '9')) ||
                        ((*p >= 'a') && (*p <= 'f')) ||
                        ((*p >= 'A') && (*p <= 'F'))))
                        p++;

                if (unlikely (p+2 > end)) {
                        return ret_ok;
		}

                /* Check the CRLF after the length
		 */
                if (p[0] != CHR_CR) {
                        return ret_error;
		}
                if (p[1] != CHR_LF) {
                        return ret_error;
		}

		p += 2;

                /* Read the length
		 */
                content_size = (size_t) strtoul (begin, NULL, 16);
                if (unlikely (content_size < 0)) {
                        return ret_error;
		}

                /* Check if there's enough info
		 */
                if (content_size == 0) {
                        post->chunked.last = true;

		} else if (p + content_size + 2 > end) {
                        TRACE (ENTRIES, "Unfinished chunk(len="FMT_OFFSET"), has=%d, out->len="FMT_OFFSET"\n",
                               content_size, (int)(end-p), out->len);
			break;
                }

		/* Last block check
		 */
                if (post->chunked.last) {
                        TRACE(ENTRIES, "Last chunk: %s\n", "exiting");

			if (post->chunked.retransmit) {
				cherokee_buffer_add_str (out, "0" CRLF);
			}
			begin = p;
			break;
		}

		/* Move the information
		 */
		if (post->chunked.retransmit) {
			cherokee_buffer_add (out, begin, (p + content_size + 2) - begin);
		} else {
			cherokee_buffer_add (out, p, content_size);
		}

                TRACE (ENTRIES, "Processing chunk len=%d\n", content_size);

                /* Next iteration
		 */
                begin = p + content_size + 2;
		p = begin;
	}

	/* Clean up in-buffer
	 */
	if (begin != in->buf) {
		cherokee_buffer_move_to_begin (in, begin - in->buf);
	}

	/* Very unlikely, but still possible
	 */
	if (! cherokee_buffer_is_empty(in)) {
		TRACE (ENTRIES, "There are %d left-over bytes in the post buffer -> incoming header", in->len);
/* 		cherokee_buffer_add_buffer (&conn->incoming_header, in); */
/* 		cherokee_buffer_clean (in); */
	}

	TRACE (ENTRIES, "Un-chunked buffer len=%d\n", out->len);
	return ret_ok;
}
Esempio n. 9
0
ret_t
cherokee_request_header_build_string (cherokee_request_header_t *request, cherokee_buffer_t *buf, cherokee_buffer_t *tmp1, cherokee_buffer_t *tmp2)
{
	ret_t           ret;
	const char     *ptr;
	cuint_t         len;
	cherokee_url_t *url = REQUEST_URL(request);

	/* 200 bytes should be enough for a small header
	 */
	cherokee_buffer_ensure_size (buf, 200);

	/* Add main request line:
	 * GET /dir/object HTTP/1.1
	 */
	ret = cherokee_http_method_to_string (request->method, &ptr, &len);
	if (ret != ret_ok) return ret;

	ret = cherokee_buffer_add (buf, ptr, len);
	if (ret != ret_ok) return ret;

	cherokee_buffer_add_str (buf, " ");

	/* Check if the requests goes through a proxy
	 */
	if (request->proxy) {
		cherokee_buffer_add_str (buf, "http://");
		cherokee_buffer_add_buffer (buf, URL_HOST(url));
	}

	cherokee_buffer_add_buffer (buf, URL_REQUEST(url));

	switch (REQUEST_VERSION(request)) {
	case http_version_11:
		cherokee_buffer_add_str (buf, " HTTP/1.1" CRLF);
		break;
	case http_version_10:
		cherokee_buffer_add_str (buf, " HTTP/1.0" CRLF);
		break;
	default:
		SHOULDNT_HAPPEN;
		return ret_error;
	}

	/* Add "Host:" header - in HTTP/1.1
	 */
	if (REQUEST_VERSION(request) == http_version_11) {
		cherokee_buffer_add_str    (buf, "Host: ");
		cherokee_buffer_add_buffer (buf, URL_HOST(url));
		cherokee_buffer_add_str    (buf, CRLF);
	}

	/* Post information
	 */
	if (request->post_len != 0) {
		/* "Content-Length: " FMT_OFFSET CRLF, request->post_len;
		 */
		cherokee_buffer_add_str      (buf, "Content-Length: ");
		cherokee_buffer_add_ullong10 (buf, (cullong_t) request->post_len);
		cherokee_buffer_add_str      (buf, CRLF);
	}

	/* Add "Connection:" header
	 */
	if (REQUEST_KEEPALIVE(request)) {
		cherokee_buffer_add_str (buf, "Connection: Keep-Alive"CRLF);
	} else {
		cherokee_buffer_add_str (buf, "Connection: close"CRLF);
	}

	/* Authentication
	 */
	if (! cherokee_buffer_is_empty (&request->user) ||
	    ! cherokee_buffer_is_empty (&request->password)) {
		cherokee_buffer_clean (tmp1);
		cherokee_buffer_clean (tmp2);

		cherokee_buffer_add_buffer (tmp1, &request->user);
		cherokee_buffer_add_char   (tmp1, ':');
		cherokee_buffer_add_buffer (tmp1, &request->password);

		cherokee_buffer_encode_base64 (tmp1, tmp2);

		cherokee_buffer_add_str    (buf, "Authorization: Basic ");
		cherokee_buffer_add_buffer (buf, tmp2);
		cherokee_buffer_add_str    (buf, CRLF);
	}

	/* Extra headers
	 */
	if (! cherokee_buffer_is_empty (&request->extra_headers)) {
		cherokee_buffer_add_buffer (buf, &request->extra_headers);
	}

	/* Finish the header
	 */
	cherokee_buffer_add_str (buf, CRLF);
	return ret_ok;
}
Esempio n. 10
0
ret_t
cherokee_validator_plain_check (cherokee_validator_plain_t *plain,
				cherokee_connection_t      *conn)
{
	int                re;
	ret_t              ret;
	const char        *p;
	const char        *end;
	cherokee_buffer_t *fpass;
	cherokee_buffer_t  file  = CHEROKEE_BUF_INIT;
	cherokee_buffer_t  buser = CHEROKEE_BUF_INIT;
	cherokee_buffer_t  bpass = CHEROKEE_BUF_INIT;

	/* Sanity check */
	if (unlikely ((conn->validator == NULL) ||
	    cherokee_buffer_is_empty(&conn->validator->user))) {
		return ret_error;
	}

	/* Get the full path to the file */
	ret = cherokee_validator_file_get_full_path (VFILE(plain), conn, &fpass,
						     &CONN_THREAD(conn)->tmp_buf1);
	if (ret != ret_ok) {
		ret = ret_error;
		goto out;
	}

	/* Read its contents */
	ret = cherokee_buffer_read_file (&file, fpass->buf);
	if (ret != ret_ok) {
		ret = ret_error;
		goto out;
	}

	if (! cherokee_buffer_is_ending(&file, '\n'))
		cherokee_buffer_add_str (&file, "\n");

	p   = file.buf;
	end = file.buf + file.len;

	while (p < end) {
		char *eol;
		char *colon;

		/* Look for the EOL
		 */
		eol = strchr (p, '\n');
		if (eol == NULL) {
			ret = ret_ok;
			goto out;
		}
		*eol = '\0';

		/* Skip comments
		 */
		if (p[0] == '#')
			goto next;

		colon = strchr (p, ':');
		if (colon == NULL) {
			goto next;
		}

		/* Is it the right user?
		 */
		cherokee_buffer_clean (&buser);
		cherokee_buffer_add (&buser, p, colon - p);

		re = cherokee_buffer_cmp_buf (&buser, &conn->validator->user);
		if (re != 0)
			goto next;

		/* Check the password
		 */
		cherokee_buffer_clean (&bpass);
		cherokee_buffer_add (&bpass, colon+1, eol - (colon+1));

		switch (conn->req_auth_type) {
		case http_auth_basic:
			/* Empty password
			 */
			if (cherokee_buffer_is_empty (&bpass) &&
			    cherokee_buffer_is_empty (&conn->validator->passwd)) {
				ret = ret_ok;
				goto out;
			}

			/* Check the passwd
			 */
			re = cherokee_buffer_cmp_buf (&bpass, &conn->validator->passwd);
			if (re != 0)
				ret = ret_deny;
			goto out;

		case http_auth_digest:
			ret = cherokee_validator_digest_check (VALIDATOR(plain), &bpass, conn);
			goto out;

		default:
			SHOULDNT_HAPPEN;
		}

		/* A user entry has been tested and failed
		 */
		ret = ret_deny;
		goto out;

	next:
		p = eol + 1;

		/* Reached the end without success
		 */
		if (p >= end) {
			ret = ret_deny;
			goto out;
		}
	}

out:
 	cherokee_buffer_mrproper (&file);
 	cherokee_buffer_mrproper (&buser);
 	cherokee_buffer_mrproper (&bpass);
	return ret;
}
Esempio n. 11
0
static ret_t
fork_and_execute_cgi_via_spawner(cherokee_handler_cgi_t *cgi)
{
	int                          re;
	int                          pid           = -1;
	cherokee_connection_t       *conn          = HANDLER_CONN(cgi);
	cherokee_handler_cgi_base_t *cgi_base      = HDL_CGI_BASE(cgi);
	ret_t                        ret;
	uid_t                        uid;
	gid_t                        gid;
	cherokee_buffer_t            empty         = CHEROKEE_BUF_INIT;
	cherokee_buffer_t            username      = CHEROKEE_BUF_INIT;
	cherokee_services_fdmap_t    fd_map;
	cherokee_buffer_t           *chdir         = NULL;
	cherokee_buffer_t            chdir_backing = CHEROKEE_BUF_INIT;
	struct passwd                ent;
	char                         ent_tmp[1024];

	struct {
		int cgi[2];
		int server[2];
	} pipes;

	TRACE (ENTRIES, "Trying to create CGI via spawner\n");

	if (! cherokee_buffer_is_empty (&conn->effective_directory)) {
		chdir = &conn->effective_directory;
	} else {
		int ofs = cgi_base->executable.len - 1;
		while (ofs >= 0 && cgi_base->executable.buf[ofs] != '/') {
			ofs--;
		}
		TRACE (ENTRIES, "While building chdir, ofs=%d\n", ofs);
		if (ofs < 0 || cherokee_buffer_add (&chdir_backing,
						    cgi_base->executable.buf,
						    ofs + 1) != ret_ok) {
			conn->error_code = http_internal_error;
			TRACE (ENTRIES, "Failed, cannot build chdir entry\n");
			cherokee_buffer_mrproper(&chdir_backing);
			return ret_error;
		}
		chdir = &chdir_backing;
	}

	/* Creates the pipes ...
	 */
	re  = cherokee_pipe (pipes.cgi);
	re |= cherokee_pipe (pipes.server);

	if (re != 0) {
		conn->error_code = http_internal_error;
		cherokee_buffer_mrproper(&chdir_backing);
		TRACE (ENTRIES, "Failed, cannot build pipes\n");
		return ret_error;
	}

	if (HANDLER_CGI_PROPS(cgi_base)->change_user) {
		struct stat                        nocache_info;
		struct stat                       *info;
		cherokee_iocache_entry_t          *io_entry = NULL;
		cherokee_server_t                 *srv      = CONN_SRV(conn);
		cherokee_handler_cgi_base_props_t *props    = HANDLER_CGI_BASE_PROPS(cgi);

		ret = cherokee_io_stat (srv->iocache, &cgi_base->executable, props->use_cache, &nocache_info, &io_entry, &info);
		if (ret != ret_ok) {
			info = &nocache_info;
			nocache_info.st_uid = getuid();
			nocache_info.st_gid = getgid();
		}

		uid = info->st_uid;
		gid = info->st_gid;

		cherokee_iocache_entry_unref(&io_entry);
	} else {
		/* Not changing, so launch as the same uid/gid as the worker */
		uid = getuid();
		gid = getgid();
	}

	/* Determine the username of the owner of the file */
	ret = cherokee_getpwuid(uid, &ent, ent_tmp, sizeof (ent_tmp));
	if (ret != ret_ok ||
	    cherokee_buffer_add(&username,
				ent.pw_name,
				strlen(ent.pw_name) != ret_ok)) {
		cherokee_fd_close(pipes.cgi[0]);
		cherokee_fd_close(pipes.cgi[1]);
		cherokee_fd_close(pipes.server[0]);
		cherokee_fd_close(pipes.server[1]);
		conn->error_code = http_internal_error;
		cherokee_buffer_mrproper(&chdir_backing);
		cherokee_buffer_mrproper(&username);
		TRACE (ENTRIES, "Failed, Unable to retrieve username for uid %d\n", uid);
		return ret_error;
	}


	/* Update the environment ready to run */
	add_environment (cgi, conn);

	/* Set up the FD map */
	fd_map.fd_in = pipes.server[0];
	fd_map.fd_out = pipes.cgi[1];

	if ((CONN_VSRV(conn)->error_writer != NULL) &&
	    (CONN_VSRV(conn)->error_writer->fd != -1)) {
		fd_map.fd_err = CONN_VSRV(conn)->error_writer->fd;
	} else {
		fd_map.fd_err = fd_map.fd_out;
	}


	TRACE (ENTRIES, "Doing Spawn\n");
	ret = cherokee_services_client_spawn (&cgi_base->executable,
					      &username,
					      uid,
					      gid,
					      &empty,
					      chdir,
					      false,
					      cgi->envp,
					      CONN_VSRV(conn)->error_writer,
					      &pid,
					      &fd_map);

	cherokee_buffer_mrproper(&chdir_backing);
	cherokee_buffer_mrproper(&username);

	/* Close the client FDs */
	cherokee_fd_close (pipes.server[0]);
	cherokee_fd_close (pipes.cgi[1]);

	/* Did we fail to try to spawn? */
	if (ret != ret_ok) {
		/* Close the server FDs too */
		cherokee_fd_close (pipes.server[1]);
		cherokee_fd_close (pipes.cgi[0]);
		TRACE (ENTRIES, "Failed to spawn\n");
		return ret;
	}

	/* Did we try, but fail, to spawn? */
	if (pid == -1) {
		/* Close the server FDs too */
		cherokee_fd_close (pipes.server[1]);
		cherokee_fd_close (pipes.cgi[0]);
		TRACE (ENTRIES, "Spawned, but failed server side\n");
		return ret_error;
	}

	/* Successfully launched */
	cgi->pid        = pid;
	cgi->pipeInput  = pipes.cgi[0];
	cgi->pipeOutput = pipes.server[1];

	/* Set to Input to NON-BLOCKING
	 */
	_fd_set_properties (cgi->pipeInput, O_NDELAY|O_NONBLOCK, 0);

	TRACE (ENTRIES, "CGI running, PID=%d\n", pid);
	return ret_ok;
}
Esempio n. 12
0
static ret_t
build_log_string (cherokee_logger_ncsa_t *logger,
		  cherokee_connection_t  *cnt,
		  cherokee_buffer_t      *buf)
{
	ret_t              ret;
	const char        *method;
	const char        *username;
	const char        *version;
	cuint_t            method_len                   = 0;
	size_t             username_len                 = 0;
	cuint_t            version_len                  = 0;
	cherokee_buffer_t *referer                      = &logger->referer;
	cherokee_buffer_t *useragent                    = &logger->useragent;
	char               ipaddr[CHE_INET_ADDRSTRLEN];

	/* Look for the user
	 */
	if (cnt->validator && !cherokee_buffer_is_empty (&cnt->validator->user)) {
		username_len = cnt->validator->user.len;
		username = cnt->validator->user.buf;
	} else {
		username_len = 1;
		username = "******";
	}

	/* Get the method and version strings
	 */
	ret = cherokee_http_method_to_string (cnt->header.method, &method, &method_len);
	if (unlikely (ret < ret_ok)) {
		method     = "";
		method_len = 0;
	}

	ret = cherokee_http_version_to_string (cnt->header.version, &version, &version_len);
	if (unlikely (ret < ret_ok)) {
		version     = "";
		version_len = 0;
	}

	/* Build the log string
	 *
	 * "%s - %s [%02d/%s/%d:%02d:%02d:%02d %c%02d%02d] \"%s %s %s\" %d "
	 * FMT_OFFSET
	 */
	if (cherokee_buffer_is_empty (&cnt->logger_real_ip)) {
		memset (ipaddr, 0, sizeof(ipaddr));
		cherokee_socket_ntop (&cnt->socket, ipaddr, sizeof(ipaddr)-1);
		cherokee_buffer_add (buf, ipaddr, strlen(ipaddr));
	} else {
		cherokee_buffer_add_buffer (buf, &cnt->logger_real_ip);
	}

	cherokee_buffer_add_str (buf, " - ");
	cherokee_buffer_add     (buf, username, username_len);

	/* " [date time] "
	 */
	cherokee_buffer_add_buffer (buf, &now);
	cherokee_buffer_add        (buf, method, method_len);
	cherokee_buffer_add_char   (buf, ' ');

	if (! cherokee_buffer_is_empty (&cnt->request_original)) {
		cherokee_buffer_add_buffer (buf, &cnt->request_original);
		if (! cherokee_buffer_is_empty (&cnt->query_string_original)) {
			cherokee_buffer_add_char   (buf, '?');
			cherokee_buffer_add_buffer (buf, &cnt->query_string_original);
		}
	} else {
		cherokee_buffer_add_buffer (buf, &cnt->request);
		if (! cherokee_buffer_is_empty (&cnt->query_string)) {
			cherokee_buffer_add_char   (buf, '?');
			cherokee_buffer_add_buffer (buf, &cnt->query_string);
		}
	}

	cherokee_buffer_add_char   (buf, ' ');
	cherokee_buffer_add        (buf, version, version_len);
	cherokee_buffer_add_str    (buf, "\" ");

	if (unlikely (cnt->error_internal_code != http_unset)) {
		cherokee_buffer_add_long10 (buf, cnt->error_internal_code);
	} else {
		cherokee_buffer_add_long10 (buf, cnt->error_code);
	}

	cherokee_buffer_add_char (buf, ' ');
	cherokee_buffer_add_ullong10 (buf, cnt->tx);

	/* Look for the "combined" information
	 */
	if (!logger->combined) {
		cherokee_buffer_add_char (buf, '\n');
		return ret_ok;
	}

	/* "combined" information
	 */
	cherokee_buffer_clean (referer);
	cherokee_buffer_clean (useragent);

	cherokee_header_copy_known (&cnt->header, header_referer, referer);
	cherokee_header_copy_known (&cnt->header, header_user_agent, useragent);
	cherokee_buffer_ensure_addlen (buf, 8 + referer->len + referer->len);

	if (referer->len > 0) {
		cherokee_buffer_add_str    (buf, " \"");
		cherokee_buffer_add_buffer (buf, referer);
		cherokee_buffer_add_str    (buf, "\" \"");
	} else {
		cherokee_buffer_add_str (buf, " \"-\" \"");
	}

	if (useragent->len > 0) {
		cherokee_buffer_add_buffer (buf, useragent);
	}

	cherokee_buffer_add_str (buf, "\"\n");
	return ret_ok;
}
Esempio n. 13
0
ret_t
cherokee_handler_secdownload_new (cherokee_handler_t     **hdl,
				  void                    *cnt,
				  cherokee_module_props_t *props)
{
	int                    re;
	ret_t                  ret;
	char                  *p;
	cuint_t                path_len;
	time_t                 time_url;
	char                  *time_s;
	cherokee_buffer_t      md5      = CHEROKEE_BUF_INIT;
	cherokee_connection_t *conn     = CONN(cnt);

	TRACE(ENTRIES, "Analyzing request '%s'\n", conn->request.buf);

	/* Sanity check
	 */
	if (conn->request.len <= 1 + 32 + 2) {
		TRACE(ENTRIES, "Malformed URL. Too short: len=%d.\n", conn->request.len);
		conn->error_code = http_not_found;
		return ret_error;
	}

	if (conn->request.buf[0] != '/') {
		TRACE(ENTRIES, "Malformed URL: %s\n", "Not slash (1)");
		conn->error_code = http_not_found;
		return ret_error;
	}

	p = conn->request.buf + 1;
	if (check_hex (p, 32)) {
		TRACE(ENTRIES, "Malformed URL: %s\n", "No MD5");
		conn->error_code = http_not_found;
		return ret_error;
	}
	p += 32;

	if (*p != '/') {
		TRACE(ENTRIES, "Malformed URL: %s\n", "Not slash (2)");
		conn->error_code = http_not_found;
		return ret_error;
	}
	p += 1;
	time_s = p;

	if (check_hex (p, 8)) {
		TRACE(ENTRIES, "Malformed URL: %s\n", "No MD5 (2)");
		conn->error_code = http_not_found;
		return ret_error;
	}
	p += 8;

	/* Check the time
	 */
	time_url = get_time (time_s);
	if ((cherokee_bogonow_now - time_url) > (int)PROP_SECDOWN(props)->timeout) {
		TRACE(ENTRIES, "Time out: %d (now=%d)\n", time_url, cherokee_bogonow_now);
		conn->error_code = http_gone;
		return ret_error;
	}

	/* Check the MD5
	 * [secret][path][hex(time)]
	 */
	path_len = (conn->request.buf + conn->request.len) - p;

	cherokee_buffer_add_buffer (&md5, &PROP_SECDOWN(props)->secret);
	cherokee_buffer_add        (&md5, p, path_len);
	cherokee_buffer_add        (&md5, time_s, 8);

	cherokee_buffer_encode_md5_digest (&md5);

	re = strncasecmp (md5.buf, &conn->request.buf[1], 32);
	if (re != 0) {
		TRACE(ENTRIES, "MD5 (%s) didn't match\n", md5.buf);
		cherokee_buffer_mrproper(&md5);

		conn->error_code = http_access_denied;
		return ret_error;
	}

	cherokee_buffer_mrproper (&md5);

	/* At this point the request has been validated
	 */
	if (cherokee_buffer_is_empty (&conn->request_original)) {
		cherokee_buffer_add_buffer (&conn->request_original, &conn->request);
		cherokee_buffer_add_buffer (&conn->query_string_original, &conn->query_string);
	}

	cherokee_buffer_clean (&conn->request);
	cherokee_buffer_add   (&conn->request, p, path_len);

	/* Instance the File handler
	 */
	ret = cherokee_handler_file_new (hdl, cnt, MODULE_PROPS(PROP_SECDOWN(props)->props_file));
	if (ret != ret_ok)
		return ret_ok;

	return ret_ok;
}
Esempio n. 14
0
static ret_t
downloader_header_read (cherokee_downloader_t *downloader,
                        cherokee_buffer_t     *tmp1,
                        cherokee_buffer_t     *tmp2)
{
	ret_t               ret;
	cuint_t             len;
	size_t              read_      = 0;
	cherokee_socket_t  *sock       = &downloader->socket;
	cherokee_http_t     error_code = http_bad_request;

	UNUSED(tmp2);

	ret = cherokee_socket_bufread (sock, &downloader->reply_header, DEFAULT_RECV_SIZE, &read_);
	switch (ret) {
	case ret_eof:
		return ret_eof;

	case ret_eagain:
		return ret_eagain;

	case ret_ok:
		/* Count
		 */
		downloader->info.headers_recv += read_;

		/* Check the header. Is it complete?
		 */
		ret = cherokee_header_has_header (downloader->header, &downloader->reply_header, 0);
		switch (ret) {
		case ret_ok:
			break;
		case ret_not_found:
			/* It needs to read more headers ...
			 */
			return ret_eagain;
		default:
			/* Too many initial CRLF
			 */
			return ret_error;
		}

		/* Parse the header
		 */
		ret = cherokee_header_parse (downloader->header,
		                             &downloader->reply_header,
		                             &error_code);
		if (unlikely (ret != ret_ok)) return ret_error;

		/* Look for the length, it will need to drop out the header from the buffer
		 */
		cherokee_header_get_length (downloader->header, &len);

		/* Maybe it has some body
		 */
		if (downloader->reply_header.len > len) {
			uint32_t body_chunk;

			/* Skip the CRLF separator and copy the body
			 */
			len += 2;
			body_chunk = downloader->reply_header.len - len;

			downloader->info.body_recv += body_chunk;
			cherokee_buffer_add (&downloader->body, downloader->reply_header.buf + len, body_chunk);

			cherokee_buffer_drop_ending (&downloader->reply_header, body_chunk);
		}

		/* Try to read the "Content-Length" response header
		 */
		ret = cherokee_header_has_known (downloader->header, header_content_length);
		if (ret == ret_ok) {
			cherokee_buffer_clean (tmp1);
			ret = cherokee_header_copy_known (downloader->header, header_content_length, tmp1);
			if (ret == ret_ok) {
				ret = cherokee_atou (tmp1->buf, &downloader->content_length);
#ifdef TRACE_ENABLED
				if (ret == ret_ok) {
					TRACE (ENTRIES, "Known length: %d bytes\n", downloader->content_length);
				} else {
					TRACE (ENTRIES, "Could not parse Content-Length\n");
				}
#endif
			}
		}

		return ret_ok;

	case ret_error:
		/* Opsss.. something has failed
		 */
		return ret_error;

	default:
		RET_UNKNOWN (ret);
		return ret;
	}

	return ret_error;
}
Esempio n. 15
0
ret_t
cherokee_buffer_add_buffer_slice (cherokee_buffer_t *buf,
                                  cherokee_buffer_t *buf2,
                                  ssize_t            begin,
                                  ssize_t            end)
{
	ssize_t pos_end;
	ssize_t pos_begin;

	/* Ensure there's something to copy
	 */
	if (unlikely (cherokee_buffer_is_empty (buf2)))
		return ret_ok;

	if ((end   != CHEROKEE_BUF_SLIDE_NONE) &&
	    (begin != CHEROKEE_BUF_SLIDE_NONE))
	{
		pos_begin = (begin > 0) ? begin : buf2->len - abs(begin);
		pos_end   = (end   > 0) ? end   : buf2->len - abs(end);

		if (pos_end <= pos_begin) {
			return ret_ok;
		}
	}

	/* Check the end
	 */
	if (end == CHEROKEE_BUF_SLIDE_NONE) {
		/* [__:] */
		pos_end = buf2->len;
	} else {
		if (end > 0) {
			/* [__:x] */
			pos_end = end;
		} else {
			if ((-end) <= buf2->len) {
				/* [__:-x] */
				pos_end = buf2->len - (-end);
			} else {
				/* [__:-xxxxx] */
				return ret_ok;
			}
		}
	}

	/* Check the beginning
	 */
	if (begin == CHEROKEE_BUF_SLIDE_NONE) {
		/* [:__] */
		pos_begin = 0;
	} else {
		if (begin >= 0) {
			if (begin > buf2->len) {
				/* [xxxx:__]  */
				pos_begin = buf2->len;
			} else {
				/* [x:__] */
				pos_begin = begin;
			}
		} else {
			if ((-begin) < buf2->len) {
				/* [-x:__] */
				pos_begin = buf2->len - (-begin);
			} else {
				/* [-xxxx:__] */
				pos_begin = 0;
			}
		}
	}

	/* Sanity check
	 */
	if (unlikely ((pos_begin < 0)       ||
	              (pos_end < 0)         ||
	              (pos_end > buf2->len) ||
	              (pos_end < pos_begin)))
	{
		return ret_ok;
	}

	/* Copy the substring
	 */
	return cherokee_buffer_add (buf, buf2->buf + pos_begin, pos_end - pos_begin);
}
/* Methods implementation
 */
static ret_t
process_package (cherokee_handler_fcgi_t *hdl, cherokee_buffer_t *inbuf, cherokee_buffer_t *outbuf)
{
	FCGI_Header *header;
	cuint_t      len;
	char        *data;
	cuint_t      type;
	cuint_t      id;
	cuint_t      padding;

	/* Is there enough information?
	 */
	if (inbuf->len < sizeof(FCGI_Header))
		return ret_ok;

	/* At least there is a header
	 */
	header = (FCGI_Header *)inbuf->buf;

	if (header->version != 1) {
		cherokee_buffer_print_debug (inbuf, -1);
		LOG_ERROR_S (CHEROKEE_ERROR_HANDLER_FCGI_VERSION);
		return ret_error;
	}

	if (header->type != FCGI_STDERR &&
	    header->type != FCGI_STDOUT &&
	    header->type != FCGI_END_REQUEST) {
		cherokee_buffer_print_debug (inbuf, -1);
		LOG_ERROR_S (CHEROKEE_ERROR_HANDLER_FCGI_PARSING);
		return ret_error;
	}

	/* Read the header
	 */
	type    =  header->type;
	padding =  header->paddingLength;
	id      = (header->requestIdB0     | (header->requestIdB1 << 8));
	len     = (header->contentLengthB0 | (header->contentLengthB1 << 8));
	data    = inbuf->buf +  FCGI_HEADER_LEN;

/*	printf ("have %d, hdr=%d exp_len=%d pad=%d\n", inbuf->len, FCGI_HEADER_LEN, len, padding); */

	/* Is the package complete?
	 */
	if (len + padding > inbuf->len - FCGI_HEADER_LEN) {
/*		printf ("Incomplete: %d < %d\n", len + padding, inbuf->len - FCGI_HEADER_LEN); */
		return ret_ok;
	}

	/* It has received the full package content
	 */
	switch (type) {
	case FCGI_STDERR:
/*		printf ("READ:STDERR (%d): %s", len, data?data:""); */

		LOG_ERROR (CHEROKEE_ERROR_HANDLER_FCGI_STDERR, data);

		/* Debug mode */
		if (SOURCE_INT(hdl->src_ref)->debug) {
			PRINT_MSG ("%.*s\n", len, data);
		}

		break;

	case FCGI_STDOUT:
/*		printf ("READ:STDOUT eof=%d: %d", HDL_CGI_BASE(hdl)->got_eof, len); */
		cherokee_buffer_add (outbuf, data, len);
		break;

	case FCGI_END_REQUEST:
/*		printf ("READ:END"); */
		HDL_CGI_BASE(hdl)->got_eof = true;
		break;

	default:
		SHOULDNT_HAPPEN;
	}

	cherokee_buffer_move_to_begin (inbuf, len + FCGI_HEADER_LEN + padding);
/*	printf ("- FCGI left %d\n", inbuf->len); */
	return ret_eagain;
}
Esempio n. 17
0
ret_t
cherokee_validator_parse_digest (cherokee_validator_t *validator,
				 char *str, cuint_t str_len)
{
	cuint_t             len;
	char               *end;
	char               *entry;
	char               *comma;
	char               *equal;
	cherokee_buffer_t   auth = CHEROKEE_BUF_INIT;
	cherokee_buffer_t  *entry_buf;

	/* Copy authentication string
	 */
	cherokee_buffer_add (&auth, str, str_len);

	entry = auth.buf;
	end   = auth.buf + auth.len;

	do {
		/* Skip some chars
		 */
		while ((*entry == CHR_SP) ||
		       (*entry == CHR_CR) ||
		       (*entry == CHR_LF)) entry++;

		/* Check for the end
		 */
		if (entry >= end)
			break;

		comma = strchr(entry, ',');

		if (equal_str (entry, "nc")) {
			entry_buf = &validator->nc;
		} else if (equal_str (entry, "uri")) {
			entry_buf = &validator->uri;
		} else if (equal_str (entry, "qop")) {
			entry_buf = &validator->qop;
		} else if (equal_str (entry, "realm")) {
			entry_buf = &validator->realm;
		} else if (equal_str (entry, "nonce")) {
			entry_buf = &validator->nonce;
		} else if (equal_str (entry, "cnonce")) {
			entry_buf = &validator->cnonce;
		} else if (equal_str (entry, "username")) {
			entry_buf = &validator->user;
		} else if (equal_str (entry, "response")) {
			entry_buf = &validator->response;
		} else if (equal_str (entry, "algorithm")) {
			entry_buf = &validator->algorithm;
		} else {
			entry = comma + 1;
			continue;
		}

		/* Split the string [1]
		 */
		if (comma) *comma = '\0';

		equal = strchr (entry, '=');
		if (equal == NULL) {
			if (comma) *comma = ',';  /* [1] */
			continue;
		}

		/* Check for "s and skip it
		 */
		equal += (equal[1] == '"') ? 2 : 1;
		len = strlen(equal);
		while ((len > 0) &&
		       ((equal[len-1] == '"')  ||
			(equal[len-1] == CHR_CR) ||
			(equal[len-1] == CHR_LF))) len--;

		/* Copy the entry value
		 */
		cherokee_buffer_add (entry_buf, equal, len);

		/* Resore [1], and prepare next loop
		 */
		if (comma)
			*comma = ',';
		entry = comma + 1;

	} while (comma != NULL);

#if 0
	printf ("nc           %s\n", validator->nc.buf);
	printf ("uri          %s\n", validator->uri.buf);
	printf ("qop          %s\n", validator->qop.buf);
	printf ("realm        %s\n", validator->realm.buf);
	printf ("nonce        %s\n", validator->nonce.buf);
	printf ("cnonce       %s\n", validator->cnonce.buf);
	printf ("username     %s\n", validator->user.buf);
	printf ("reponse      %s\n", validator->response.buf);
	printf ("algorithm    %s\n", validator->algorithm.buf);
#endif

	/* Clean up and exit
	 */
	cherokee_buffer_mrproper (&auth);
	return ret_ok;
}
Esempio n. 18
0
static ret_t
local_file_exists (cherokee_rule_extensions_t *rule,
                   cherokee_connection_t      *conn,
                   cherokee_config_entry_t    *ret_conf)
{
	ret_t                     ret;
	struct stat              *info;
	struct stat               nocache_info;
	cherokee_boolean_t        is_file;
	cherokee_iocache_entry_t *io_entry      = NULL;
	cherokee_server_t        *srv           = CONN_SRV(conn);
	cherokee_buffer_t        *tmp           = THREAD_TMP_BUF1(CONN_THREAD(conn));

	UNUSED(rule);

	/* Build the full path
	 */
	cherokee_buffer_clean (tmp);

	if (ret_conf->document_root != NULL) {
		/* A previous non-final rule set a custom document root */
		cherokee_buffer_add_buffer (tmp, ret_conf->document_root);
	} else {
		cherokee_buffer_add_buffer (tmp, &conn->local_directory);
	}

	if (! cherokee_buffer_is_empty (&conn->web_directory)) {
		cherokee_buffer_add (tmp,
		                     conn->request.buf + conn->web_directory.len,
		                     conn->request.len - conn->web_directory.len);
	} else {
		cherokee_buffer_add_buffer (tmp, &conn->request);
	}

	/* Check the local file
	 */
	ret = cherokee_io_stat (srv->iocache, tmp, rule->use_iocache,
	                        &nocache_info, &io_entry, &info);

	if (ret == ret_ok) {
		is_file = S_ISREG(info->st_mode);
	}

	if (io_entry) {
		cherokee_iocache_entry_unref (&io_entry);
	}

	/* Report and return
	 */
	if (ret != ret_ok) {
		TRACE(ENTRIES, "Rule extensions: almost matched '%s', but file does not exist\n", tmp->buf);
		return ret_not_found;
	}

	if (! is_file) {
		TRACE(ENTRIES, "Rule extensions: almost matched '%s', but it is not a file\n", tmp->buf);
		return ret_not_found;
	}

	return ret_ok;
}
Esempio n. 19
0
static ret_t
common_server_initialization (cherokee_server_t *srv)
{
	ret_t            ret;
	struct sigaction act;

	/* Signals it handles
	 */
	memset(&act, 0, sizeof(act));

	/* SIGPIPE */
	act.sa_handler = SIG_IGN;
	sigaction (SIGPIPE, &act, NULL);

	/* Signal Handler */
	act.sa_sigaction = signals_handler;
	act.sa_flags     = SA_SIGINFO;

	sigaction (SIGHUP,  &act, NULL);
	sigaction (SIGUSR2, &act, NULL);
	sigaction (SIGSEGV, &act, NULL);
	sigaction (SIGTERM, &act, NULL);
	sigaction (SIGINT,  &act, NULL);
	sigaction (SIGCHLD, &act, NULL);
#ifdef SIGBUS
	sigaction (SIGBUS,  &act, NULL);
#endif

	if (document_root != NULL) {
		cherokee_buffer_t tmp   = CHEROKEE_BUF_INIT;
		cherokee_buffer_t droot = CHEROKEE_BUF_INIT;

		/* Sanity check
		 */
		if (port > 0xFFFF) {
			PRINT_ERROR ("Port %d is out of limits\n", port);
			return ret_error;
		}

		/* Build the configuration string
		 */
		cherokee_buffer_add (&droot, document_root, strlen(document_root));
		cherokee_path_arg_eval (&droot);

		cherokee_buffer_add_va (&tmp,
					"server!bind!1!port = %d\n"
					"vserver!1!document_root = %s\n"
					BASIC_CONFIG, port, droot.buf);

		/* Apply it
		 */
		ret = cherokee_server_read_config_string (srv, &tmp);

		cherokee_buffer_mrproper (&tmp);
		cherokee_buffer_mrproper (&droot);

		if (ret != ret_ok) {
			PRINT_MSG ("Couldn't start serving directory %s\n", document_root);
			return ret_error;
		}

	} else {
		const char *config;

		/* Check parameter inconsistencies */
		if (port_set) {
			PRINT_MSG ("The -p parameter can only be used in conjunction with -r.");
			return ret_error;
		}

		/* Read the configuration file
		 */
		config = (config_file) ? config_file : DEFAULT_CONFIG_FILE;
		ret = cherokee_server_read_config_file (srv, config);

		if (ret != ret_ok) {
			PRINT_MSG ("Couldn't read the config file: %s\n", config);
			return ret_error;
		}
	}

	if (daemon_mode)
		cherokee_server_daemonize (srv);

	ret = cherokee_server_initialize (srv);
	if (ret != ret_ok) return ret_error;

	cherokee_server_unlock_threads (srv);
	return ret_ok;
}
Esempio n. 20
0
static ret_t
parse (cherokee_handler_ssi_t *hdl,
       cherokee_buffer_t      *in,
       cherokee_buffer_t      *out)
{
	char              *p, *q;
	char              *begin;
	int                re;
	cuint_t            len;
	operations_t       op;
	path_type_t        path;
	struct stat        info;
	cherokee_boolean_t ignore;
	cherokee_buffer_t  key     = CHEROKEE_BUF_INIT;
	cherokee_buffer_t  val     = CHEROKEE_BUF_INIT;
	cherokee_buffer_t  pair    = CHEROKEE_BUF_INIT;
	cherokee_buffer_t  fpath   = CHEROKEE_BUF_INIT;

	q = in->buf;

	while (true) {
		begin = q;

		/* Check the end
		 */
		if (q >= in->buf + in->len)
			break;

		/* Find next SSI tag
		 */
		p = strstr (q, "<!--#");
		if (p == NULL) {
			cherokee_buffer_add (out, begin, (in->buf + in->len) - begin);
			return ret_ok;
		}

		q = strstr (p + 5, "-->");
		if (q == NULL)
			return ret_error;

		len = q - p;
		len -= 5;

		cherokee_buffer_clean (&key);
		cherokee_buffer_add (&key, p+5, len);
		cherokee_buffer_trim (&key);

		q += 3;
		TRACE(ENTRIES, "Found key '%s'\n", key.buf);

		/* Add the previous chunk
		 */
		cherokee_buffer_add (out, begin, p - begin);

		/* Check element
		 */
		op     = op_none;
		ignore = false;

		if (strncmp (key.buf, "include", 7) == 0) {
			op  = op_include;
			len = 7;
		} else if (strncmp (key.buf, "fsize", 5) == 0) {
			op  = op_size;
			len = 5;
		} else if (strncmp (key.buf, "flastmod", 8) == 0) {
			op  = op_lastmod;
			len = 8;
		} else {
			LOG_ERROR (CHEROKEE_ERROR_HANDLER_SSI_PROPERTY, key.buf);
		}

		/* Deeper parsing
		 */
		path = path_none;

		switch (op) {
		case op_size:
		case op_include:
		case op_lastmod:
			/* Read a property key
			 */
			cherokee_buffer_move_to_begin (&key, len);
			cherokee_buffer_trim (&key);

			cherokee_buffer_clean (&pair);
			get_pair (&key, &pair);

			cherokee_buffer_drop_ending (&key, pair.len);
			cherokee_buffer_trim (&key);

			/* Parse the property
			 */
			if (strncmp (pair.buf, "file=", 5) == 0) {
				path = path_file;
				len  = 5;
			} else if (strncmp (pair.buf, "virtual=", 8) == 0) {
				path = path_virtual;
				len  = 8;
			}

			cherokee_buffer_clean (&val);
			get_val (pair.buf + len, &val);

			cherokee_buffer_clean (&fpath);

			switch (path) {
			case path_file:
				cherokee_buffer_add_buffer (&fpath, &hdl->dir);
				cherokee_buffer_add_char   (&fpath, '/');
				cherokee_buffer_add_buffer (&fpath, &val);

				TRACE(ENTRIES, "Path: file '%s'\n", fpath.buf);
				break;
			case path_virtual:
				cherokee_buffer_add_buffer (&fpath, &HANDLER_VSRV(hdl)->root);
				cherokee_buffer_add_char   (&fpath, '/');
				cherokee_buffer_add_buffer (&fpath, &val);

				TRACE(ENTRIES, "Path: virtual '%s'\n", fpath.buf);
				break;
			default:
				SHOULDNT_HAPPEN;
			}

			/* Path security check: ensure that the file
			 * to include is inside the document root.
			 */
			if (! cherokee_buffer_is_empty (&fpath)) {
				cherokee_path_short (&fpath);

				if (fpath.len < HANDLER_VSRV(hdl)->root.len) {
					ignore = true;

				}  else {
					re = strncmp (fpath.buf,
						      HANDLER_VSRV(hdl)->root.buf,
						      HANDLER_VSRV(hdl)->root.len);
					if (re != 0) {
						ignore = true;
					}
				}
			}

			/* Perform the operation
			 */
			if (! ignore) {
				switch (op) {
				case op_include:
					TRACE(ENTRIES, "Including file '%s'\n", fpath.buf);
					cherokee_buffer_read_file (out, fpath.buf);
					break;

				case op_size:
					TRACE(ENTRIES, "Including file size '%s'\n", fpath.buf);
					re = cherokee_stat (fpath.buf, &info);
					if (re >=0) {
						cherokee_buffer_add_ullong10 (out, info.st_size);
					}
					break;

				case op_lastmod:
					TRACE(ENTRIES, "Including file modification date '%s'\n", fpath.buf);
					re = cherokee_stat (fpath.buf, &info);
					if (re >= 0) {
						char tmp[50];

						strftime (tmp, sizeof(tmp),
							  "%d-%b-%Y %H:%M",
							  localtime(&info.st_mtime));
						cherokee_buffer_add (out, tmp, strlen(tmp));
					}
					break;
				default:
					SHOULDNT_HAPPEN;
				}
			} /* !ignore */

			break;
		default:
			SHOULDNT_HAPPEN;
		} /* switch(op) */
	} /* while */

	return ret_ok;
}