예제 #1
0
static void test_buffer_to_lower_upper(void) {
	buffer *psrc = buffer_init();

	buffer_copy_string_len(psrc, CONST_STR_LEN("0123456789abcdefghijklmnopqrstuvwxyz"));
	buffer_to_lower(psrc);
	assert(buffer_is_equal_string(psrc, CONST_STR_LEN("0123456789abcdefghijklmnopqrstuvwxyz")));
	buffer_to_upper(psrc);
	assert(buffer_is_equal_string(psrc, CONST_STR_LEN("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ")));
	buffer_to_upper(psrc);
	assert(buffer_is_equal_string(psrc, CONST_STR_LEN("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ")));
	buffer_to_lower(psrc);
	assert(buffer_is_equal_string(psrc, CONST_STR_LEN("0123456789abcdefghijklmnopqrstuvwxyz")));

	buffer_free(psrc);
}
예제 #2
0
void http_response_xsendfile (server *srv, connection *con, buffer *path, const array *xdocroot) {
    const int status = con->http_status;
    int valid = 1;

    /* reset Content-Length, if set by backend
     * Content-Length might later be set to size of X-Sendfile static file,
     * determined by open(), fstat() to reduces race conditions if the file
     * is modified between stat() (stat_cache_get_entry()) and open(). */
    if (con->parsed_response & HTTP_CONTENT_LENGTH) {
        data_string *ds = (data_string *) array_get_element(con->response.headers, "Content-Length");
        if (ds) buffer_reset(ds->value);
        con->parsed_response &= ~HTTP_CONTENT_LENGTH;
        con->response.content_length = -1;
    }

    buffer_urldecode_path(path);
    buffer_path_simplify(path, path);
    if (con->conf.force_lowercase_filenames) {
        buffer_to_lower(path);
    }

    /* check that path is under xdocroot(s)
     * - xdocroot should have trailing slash appended at config time
     * - con->conf.force_lowercase_filenames is not a server-wide setting,
     *   and so can not be definitively applied to xdocroot at config time*/
    if (xdocroot->used) {
        size_t i, xlen = buffer_string_length(path);
        for (i = 0; i < xdocroot->used; ++i) {
            data_string *ds = (data_string *)xdocroot->data[i];
            size_t dlen = buffer_string_length(ds->value);
            if (dlen <= xlen
                    && (!con->conf.force_lowercase_filenames
                        ? 0 == memcmp(path->ptr, ds->value->ptr, dlen)
                        : 0 == strncasecmp(path->ptr, ds->value->ptr, dlen))) {
                break;
            }
        }
        if (i == xdocroot->used) {
            log_error_write(srv, __FILE__, __LINE__, "SBs",
                            "X-Sendfile (", path,
                            ") not under configured x-sendfile-docroot(s)");
            con->http_status = 403;
            valid = 0;
        }
    }

    if (valid) http_response_send_file(srv, con, path);

    if (con->http_status >= 400 && status < 300) {
        con->mode = DIRECT;
    } else if (0 != status && 200 != status) {
        con->http_status = status;
    }
}
예제 #3
0
static int network_ssl_servername_callback(SSL *ssl, int *al, server *srv) {
	const char *servername;
	connection *con = (connection *) SSL_get_app_data(ssl);
	UNUSED(al);

	buffer_copy_string(con->uri.scheme, "https");

	if (NULL == (servername = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name))) {
#if 0
		/* this "error" just means the client didn't support it */
		log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:",
				"failed to get TLS server name");
#endif
		return SSL_TLSEXT_ERR_NOACK;
	}
	buffer_copy_string(con->tlsext_server_name, servername);
	buffer_to_lower(con->tlsext_server_name);

	/* Sometimes this is still set, confusing COMP_HTTP_HOST */
	buffer_reset(con->uri.authority);

	config_cond_cache_reset(srv, con);
	config_setup_connection(srv, con);

	config_patch_connection(srv, con, COMP_SERVER_SOCKET);
	config_patch_connection(srv, con, COMP_HTTP_SCHEME);
	config_patch_connection(srv, con, COMP_HTTP_HOST);

	if (NULL == con->conf.ssl_ctx) {
		/* ssl_ctx <=> pemfile was set <=> ssl_ctx got patched: so this should never happen */
		log_error_write(srv, __FILE__, __LINE__, "ssb", "SSL:",
			"null SSL_CTX for TLS server name", con->tlsext_server_name);
		return SSL_TLSEXT_ERR_ALERT_FATAL;
	}

	/* switch to new SSL_CTX in reaction to a client's server_name extension */
	if (con->conf.ssl_ctx != SSL_set_SSL_CTX(ssl, con->conf.ssl_ctx)) {
		log_error_write(srv, __FILE__, __LINE__, "ssb", "SSL:",
			"failed to set SSL_CTX for TLS server name", con->tlsext_server_name);
		return SSL_TLSEXT_ERR_ALERT_FATAL;
	}

	return SSL_TLSEXT_ERR_OK;
}
예제 #4
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;
}
예제 #5
0
int config_set_defaults(server *srv) {
    size_t i;
    specific_config *s = srv->config_storage[0];
    struct stat st1, st2;

    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" },
        { FDEVENT_HANDLER_FREEBSD_KQUEUE, "kqueue" },
#endif
        { FDEVENT_HANDLER_UNSET,          NULL }
    };


    if (buffer_is_empty(s->document_root)) {
        log_error_write(srv, __FILE__, __LINE__, "s",
                        "a default document-root has to be set");

        return -1;
    }

    if (buffer_is_empty(srv->srvconf.changeroot)) {
        if (-1 == stat(s->document_root->ptr, &st1)) {
            log_error_write(srv, __FILE__, __LINE__, "sb",
                            "base-docroot doesn't exist:",
                            s->document_root);
            return -1;
        }

    } else {
        buffer_copy_string_buffer(srv->tmp_buf, srv->srvconf.changeroot);
        buffer_append_string_buffer(srv->tmp_buf, s->document_root);

        if (-1 == stat(srv->tmp_buf->ptr, &st1)) {
            log_error_write(srv, __FILE__, __LINE__, "sb",
                            "base-docroot doesn't exist:",
                            srv->tmp_buf);
            return -1;
        }

    }

    buffer_copy_string_buffer(srv->tmp_buf, s->document_root);

    buffer_to_lower(srv->tmp_buf);

    if (0 == stat(srv->tmp_buf->ptr, &st1)) {
        int is_lower = 0;

        is_lower = buffer_is_equal(srv->tmp_buf, s->document_root);

        /* lower-case existed, check upper-case */
        buffer_copy_string_buffer(srv->tmp_buf, s->document_root);

        buffer_to_upper(srv->tmp_buf);

        /* we have to handle the special case that upper and lower-casing results in the same filename
         * as in server.document-root = "/" or "/12345/" */

        if (is_lower && buffer_is_equal(srv->tmp_buf, s->document_root)) {
            /* lower-casing and upper-casing didn't result in
             * an other filename, no need to stat(),
             * just assume it is case-sensitive. */

            s->force_lowercase_filenames = 0;
        } else if (0 == stat(srv->tmp_buf->ptr, &st2)) {

            /* upper case exists too, doesn't the FS handle this ? */

            /* upper and lower have the same inode -> case-insensitve FS */

            if (st1.st_ino == st2.st_ino) {
                /* upper and lower have the same inode -> case-insensitve FS */

                s->force_lowercase_filenames = 1;
            }
        }
    }

    if (srv->srvconf.port == 0) {
        srv->srvconf.port = s->is_ssl ? 443 : 80;
    }

    if (srv->srvconf.event_handler->used == 0) {
        /* choose a good default
         *
         * the event_handler list is sorted by 'goodness'
         * taking the first available should be the best solution
         */
        srv->event_handler = event_handlers[0].et;

        if (FDEVENT_HANDLER_UNSET == srv->event_handler) {
            log_error_write(srv, __FILE__, __LINE__, "s",
                            "sorry, there is no event handler for this system");

            return -1;
        }
    } else {
        /*
         * User override
         */

        for (i = 0; event_handlers[i].name; i++) {
            if (0 == strcmp(event_handlers[i].name, srv->srvconf.event_handler->ptr)) {
                srv->event_handler = event_handlers[i].et;
                break;
            }
        }

        if (FDEVENT_HANDLER_UNSET == srv->event_handler) {
            log_error_write(srv, __FILE__, __LINE__, "sb",
                            "the selected event-handler in unknown or not supported:",
                            srv->srvconf.event_handler );

            return -1;
        }
    }

    if (s->is_ssl) {
        if (buffer_is_empty(s->ssl_pemfile)) {
            /* PEM file is require */

            log_error_write(srv, __FILE__, __LINE__, "s",
                            "ssl.pemfile has to be set");
            return -1;
        }

#ifndef USE_OPENSSL
        log_error_write(srv, __FILE__, __LINE__, "s",
                        "ssl support is missing, recompile with --with-openssl");

        return -1;
#endif
    }

    return 0;
}
예제 #6
0
static int network_ssl_servername_callback(SSL *ssl, int *al, server *srv) {
	const char *servername;
	connection *con = (connection *) SSL_get_app_data(ssl);
	UNUSED(al);

	buffer_copy_string(con->uri.scheme, "https");

	if (NULL == (servername = SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name))) {
#if 0
		/* this "error" just means the client didn't support it */
		log_error_write(srv, __FILE__, __LINE__, "ss", "SSL:",
				"failed to get TLS server name");
#endif
		return SSL_TLSEXT_ERR_NOACK;
	}
	buffer_copy_string(con->tlsext_server_name, servername);
	buffer_to_lower(con->tlsext_server_name);

	/* Sometimes this is still set, confusing COMP_HTTP_HOST */
	buffer_reset(con->uri.authority);

	config_cond_cache_reset(srv, con);
	config_setup_connection(srv, con);

	con->conditional_is_valid[COMP_SERVER_SOCKET] = 1;
	con->conditional_is_valid[COMP_HTTP_SCHEME] = 1;
	con->conditional_is_valid[COMP_HTTP_HOST] = 1;
	config_patch_connection(srv, con);

	if (NULL == con->conf.ssl_pemfile_x509 || NULL == con->conf.ssl_pemfile_pkey) {
		/* x509/pkey available <=> pemfile was set <=> pemfile got patched: so this should never happen, unless you nest $SERVER["socket"] */
		log_error_write(srv, __FILE__, __LINE__, "ssb", "SSL:",
			"no certificate/private key for TLS server name", con->tlsext_server_name);
		return SSL_TLSEXT_ERR_ALERT_FATAL;
	}

	/* first set certificate! setting private key checks whether certificate matches it */
	if (!SSL_use_certificate(ssl, con->conf.ssl_pemfile_x509)) {
		log_error_write(srv, __FILE__, __LINE__, "ssb:s", "SSL:",
			"failed to set certificate for TLS server name", con->tlsext_server_name,
			ERR_error_string(ERR_get_error(), NULL));
		return SSL_TLSEXT_ERR_ALERT_FATAL;
	}

	if (!SSL_use_PrivateKey(ssl, con->conf.ssl_pemfile_pkey)) {
		log_error_write(srv, __FILE__, __LINE__, "ssb:s", "SSL:",
			"failed to set private key for TLS server name", con->tlsext_server_name,
			ERR_error_string(ERR_get_error(), NULL));
		return SSL_TLSEXT_ERR_ALERT_FATAL;
	}

	if (con->conf.ssl_verifyclient) {
		if (NULL == con->conf.ssl_ca_file_cert_names) {
			log_error_write(srv, __FILE__, __LINE__, "ssb:s", "SSL:",
				"can't verify client without ssl.ca-file for TLS server name", con->tlsext_server_name,
				ERR_error_string(ERR_get_error(), NULL));
			return SSL_TLSEXT_ERR_ALERT_FATAL;
		}

		SSL_set_client_CA_list(ssl, SSL_dup_CA_list(con->conf.ssl_ca_file_cert_names));
		/* forcing verification here is really not that useful - a client could just connect without SNI */
		SSL_set_verify(
			ssl,
			SSL_VERIFY_PEER | (con->conf.ssl_verifyclient_enforce ? SSL_VERIFY_FAIL_IF_NO_PEER_CERT : 0),
			NULL
		);
		SSL_set_verify_depth(ssl, con->conf.ssl_verifyclient_depth);
	} else {
		SSL_set_verify(ssl, SSL_VERIFY_NONE, NULL);
	}

	return SSL_TLSEXT_ERR_OK;
}
예제 #7
0
int config_set_defaults(server *srv) {
    specific_config *s = &srv->config_storage[0];
#if 0
    size_t i;
    struct stat st1, st2;
#endif

    if (buffer_is_empty(s->document_root)) {
        log_error_write(srv, __FILE__, __LINE__, "s",
                "a default document-root has to be set");

        return -1;
    }

#if 0
    buffer_copy_string_buffer(srv->tmp_buf, s->document_root);

    buffer_to_lower(srv->tmp_buf);

    if (0 == stat(srv->tmp_buf->ptr, &st1)) {
        int is_lower = 0;

        is_lower = buffer_is_equal(srv->tmp_buf, s->document_root);

        /* lower-case existed, check upper-case */
        buffer_copy_string_buffer(srv->tmp_buf, s->document_root);

        buffer_to_upper(srv->tmp_buf);

        /* we have to handle the special case that upper and lower-casing results in the same filename
         * as in server.document-root = "/" or "/12345/" */

        if (is_lower && buffer_is_equal(srv->tmp_buf, s->document_root)) {
            /* lower-casing and upper-casing didn't result in
             * an other filename, no need to stat(),
             * just assume it is case-sensitive. */

            s->force_lowercase_filenames = 0;
        } else if (0 == stat(srv->tmp_buf->ptr, &st2)) {

            /* upper case exists too, doesn't the FS handle this ? */

            /* upper and lower have the same inode -> case-insensitve FS */

            if (st1.st_ino == st2.st_ino) {
                /* upper and lower have the same inode -> case-insensitve FS */

                s->force_lowercase_filenames = 1;
            }
        }
    }
#endif

    if (srv->srvconf.port == 0) {
        srv->srvconf.port = s->is_ssl ? 322 : 554;
    }

    if (srv->srvconf.max_conns == 0)
        srv->srvconf.max_conns = 100;

    if (srv->srvconf.first_udp_port == 0)
        srv->srvconf.first_udp_port = RTP_DEFAULT_PORT;
    if (srv->srvconf.buffered_frames == 0)
        srv->srvconf.buffered_frames = BUFFERED_FRAMES_DEFAULT;

    if (s->is_ssl) {
        if (buffer_is_empty(s->ssl_pemfile)) {
            /* PEM file is require */

            log_error_write(srv, __FILE__, __LINE__, "s",
                    "ssl.pemfile has to be set");
            return -1;
        }

#ifndef USE_OPENSSL
        log_error_write(srv, __FILE__, __LINE__, "s",
                "ssl support is missing, recompile with --with-openssl");

        return -1;
#endif
    }

    return 0;
}
예제 #8
0
int config_set_defaults(server *srv) {
	specific_config *s = srv->config_storage[0];
	const fdevent_handler_info_t *handler;
	const network_backend_info_t *backend;
	struct stat st1, st2;

	if (buffer_is_empty(s->document_root)) {
		log_error_write(srv, __FILE__, __LINE__, "s",
				"a default document-root has to be set");

		return -1;
	}

	if (buffer_is_empty(srv->srvconf.changeroot)) {
		pathname_unix2local(s->document_root);
		if (-1 == stat(s->document_root->ptr, &st1)) {
			log_error_write(srv, __FILE__, __LINE__, "sbs",
					"base-docroot doesn't exist:",
					s->document_root, strerror(errno));
			return -1;
		}

	} else {
		buffer_copy_string_buffer(srv->tmp_buf, srv->srvconf.changeroot);
		buffer_append_string_buffer(srv->tmp_buf, s->document_root);

		if (-1 == stat(srv->tmp_buf->ptr, &st1)) {
			log_error_write(srv, __FILE__, __LINE__, "sb",
					"base-docroot doesn't exist:",
					srv->tmp_buf);
			return -1;
		}

	}

	buffer_copy_string_buffer(srv->tmp_buf, s->document_root);

	buffer_to_lower(srv->tmp_buf);

	if (0 == stat(srv->tmp_buf->ptr, &st1)) {
		int is_lower = 0;

		is_lower = buffer_is_equal(srv->tmp_buf, s->document_root);

		/* lower-case existed, check upper-case */
		buffer_copy_string_buffer(srv->tmp_buf, s->document_root);

		buffer_to_upper(srv->tmp_buf);

		/* we have to handle the special case that upper and lower-casing results in the same filename
		 * as in server.document-root = "/" or "/12345/" */

		if (is_lower && buffer_is_equal(srv->tmp_buf, s->document_root)) {
			/* lower-casing and upper-casing didn't result in
			 * an other filename, no need to stat(),
			 * just assume it is case-sensitive. */

			s->force_lowercase_filenames = 0;
		} else if (0 == stat(srv->tmp_buf->ptr, &st2)) {

			/* upper case exists too, doesn't the FS handle this ? */

			/* upper and lower have the same inode -> case-insensitve FS */

			if (st1.st_ino == st2.st_ino) {
				/* upper and lower have the same inode -> case-insensitve FS */

				s->force_lowercase_filenames = 1;
			}
		}
	}

	if (srv->srvconf.port == 0) {
		srv->srvconf.port = s->is_ssl ? 443 : 80;
	}

	if (srv->srvconf.event_handler->used == 0) {
		/* get a useful default */
		handler = fdevent_get_defaulthandler();
		if (!handler) {
			log_error_write(srv, __FILE__, __LINE__, "s",
					"sorry, there is no event handler for this system");

			return -1;
		}
	} else {
		/*
		 * User override
		 */

		handler = fdevent_get_handler_info_by_name(srv->srvconf.event_handler->ptr);
		if (!handler) {
			log_error_write(srv, __FILE__, __LINE__, "sb",
					"the selected event-handler is unknown:",
					srv->srvconf.event_handler );

			return -1;
		}

		if (!handler->init) {
			log_error_write(srv, __FILE__, __LINE__, "sb",
					"the selected event-handler is known but not supported:",
					srv->srvconf.event_handler );

			return -1;
		}
	}
	srv->event_handler = handler->type;

	if (buffer_is_empty(srv->srvconf.network_backend)) {
		/* get a useful default */
		backend = network_get_defaultbackend();
		if (!backend) {
			log_error_write(srv, __FILE__, __LINE__, "s",
					"sorry, there is no network backend for this system");

			return -1;
		}
	} else {
		/*
		 * User override
		 */

		backend = network_get_backend_info_by_name(srv->srvconf.network_backend->ptr);
		if (!backend) {
			/* we don't know it */

			log_error_write(srv, __FILE__, __LINE__, "sb",
					"server.network-backend has a unknown value:",
					srv->srvconf.network_backend);

			return -1;
		}

		if (backend->write_handler == NULL) {
			/* we know it but not supported */

			log_error_write(srv, __FILE__, __LINE__, "sb",
					"server.network-backend not supported:",
					srv->srvconf.network_backend);

			return -1;
		}
	}
	srv->network_backend = backend->type;

	if (s->is_ssl) {
		if (buffer_is_empty(s->ssl_pemfile)) {
			/* PEM file is require */

			log_error_write(srv, __FILE__, __LINE__, "s",
					"ssl.pemfile has to be set");
			return -1;
		}

#ifndef USE_OPENSSL
		log_error_write(srv, __FILE__, __LINE__, "s",
				"ssl support is missing, recompile with --with-openssl");

		return -1;
#endif
	}

	return 0;
}