SET(CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "")
ADD_DEFINITIONS(-Os -Wall -Werror -Wmissing-declarations --std=gnu99 -g3)
+OPTION(TLS_SUPPORT "TLS support" ON)
+
IF(APPLE)
INCLUDE_DIRECTORIES(/opt/local/include)
LINK_DIRECTORIES(/opt/local/lib)
SET(LIBS "")
ENDIF()
-ADD_EXECUTABLE(uhttpd main.c listen.c client.c utils.c file.c auth.c cgi.c relay.c proc.c)
-TARGET_LINK_LIBRARIES(uhttpd ubox ${LIBS})
+SET(SOURCES main.c listen.c client.c utils.c file.c auth.c cgi.c relay.c proc.c)
+IF(TLS_SUPPORT)
+ SET(SOURCES ${SOURCES} tls.c)
+ ADD_DEFINITIONS(-DHAVE_TLS)
+ENDIF()
+
+ADD_EXECUTABLE(uhttpd ${SOURCES})
+TARGET_LINK_LIBRARIES(uhttpd ubox dl ${LIBS})
#include <ctype.h>
#include "uhttpd.h"
+#include "tls.h"
static LIST_HEAD(clients);
[CLIENT_STATE_DATA] = client_data_cb,
};
-static void client_read_cb(struct client *cl)
+void uh_client_read_cb(struct client *cl)
{
struct ustream *us = cl->us;
char *str;
n_clients--;
uh_dispatch_done(cl);
uloop_timeout_cancel(&cl->timeout);
+ if (cl->tls)
+ uh_tls_client_detach(cl);
ustream_free(&cl->sfd.stream);
close(cl->sfd.fd.fd);
list_del(&cl->list);
uh_unblock_listeners();
}
+void uh_client_notify_state(struct client *cl)
+{
+ struct ustream *s = cl->us;
+
+ if (!s->write_error) {
+ if (cl->state == CLIENT_STATE_DATA)
+ return;
+
+ if (!s->eof || s->w.data_bytes)
+ return;
+ }
+
+ return client_close(cl);
+}
+
static void client_ustream_read_cb(struct ustream *s, int bytes)
{
struct client *cl = container_of(s, struct client, sfd);
- client_read_cb(cl);
+ uh_client_read_cb(cl);
}
static void client_ustream_write_cb(struct ustream *s, int bytes)
{
struct client *cl = container_of(s, struct client, sfd);
- if (!s->write_error) {
- if (cl->state == CLIENT_STATE_DATA)
- return;
-
- if (!s->eof || s->w.data_bytes)
- return;
- }
-
- return client_close(cl);
+ uh_client_notify_state(cl);
}
static void set_addr(struct uh_addr *addr, void *src)
}
}
-bool uh_accept_client(int fd)
+bool uh_accept_client(int fd, bool tls)
{
static struct client *next_client;
struct client *cl;
sl = sizeof(addr);
getsockname(fd, (struct sockaddr *) &addr, &sl);
set_addr(&cl->srv_addr, &addr);
+
cl->us = &cl->sfd.stream;
+ if (tls) {
+ uh_tls_client_attach(cl);
+ } else {
+ cl->us->notify_read = client_ustream_read_cb;
+ cl->us->notify_write = client_ustream_write_cb;
+ cl->us->notify_state = client_notify_state;
+ }
+
cl->us->string_data = true;
- cl->us->notify_read = client_ustream_read_cb;
- cl->us->notify_write = client_ustream_write_cb;
- cl->us->notify_state = client_notify_state;
ustream_fd_init(&cl->sfd, sfd);
cl->timeout.cb = client_timeout;
next_client = NULL;
n_clients++;
cl->id = client_id++;
+
return true;
}
struct listener *l = container_of(fd, struct listener, fd);
while (1) {
- if (!uh_accept_client(fd->fd))
+ if (!uh_accept_client(fd->fd, l->tls))
break;
}
#include <libubox/usock.h>
#include "uhttpd.h"
+#include "tls.h"
char uh_buf[4096];
int main(int argc, char **argv)
{
+ const char *tls_key, *tls_crt;
bool nofork = false;
char *port;
int opt, ch;
int cur_fd;
int bound = 0;
+ int n_tls = 0;
BUILD_BUG_ON(sizeof(uh_buf) < PATH_MAX);
switch(ch) {
case 's':
+ n_tls++;
tls = true;
/* fall through */
case 'p':
conf.file = optarg;
break;
+ case 'C':
+ tls_crt = optarg;
+ break;
+
+ case 'K':
+ tls_key = optarg;
+ break;
default:
return usage(argv[0]);
}
return 1;
}
+ if (n_tls) {
+ if (!tls_crt || !tls_key) {
+ fprintf(stderr, "Please specify a certificate and "
+ "a key file to enable SSL support\n");
+ return 1;
+ }
+
+#ifdef HAVE_TLS
+ if (uh_tls_init(tls_key, tls_crt))
+ return 1;
+#else
+ fprintf(stderr, "Error: TLS support not compiled in.\n");
+ return 1;
+#endif
+ }
+
/* fork (if not disabled) */
if (!nofork) {
switch (fork()) {
--- /dev/null
+/*
+ * uhttpd - Tiny single-threaded httpd - Main header
+ *
+ * Copyright (C) 2010-2012 Jo-Philipp Wich <xm@subsignal.org>
+ * Copyright (C) 2012 Felix Fietkau <nbd@openwrt.org>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <dlfcn.h>
+#include "uhttpd.h"
+#include "tls.h"
+
+#ifdef __APPLE__
+#define LIB_EXT "dylib"
+#else
+#define LIB_EXT "so"
+#endif
+
+static struct ustream_ssl_ops *ops;
+static void *dlh;
+static void *ctx;
+
+int uh_tls_init(const char *key, const char *crt)
+{
+ static bool _init = false;
+
+ if (_init)
+ return 0;
+
+ _init = true;
+ dlh = dlopen("libustream-ssl." LIB_EXT, RTLD_LAZY | RTLD_LOCAL);
+ if (!dlh) {
+ fprintf(stderr, "Failed to load ustream-ssl library: %s\n", dlerror());
+ return -ENOENT;
+ }
+
+ ops = dlsym(dlh, "ustream_ssl_ops");
+ if (!ops) {
+ fprintf(stderr, "Could not find required symbol 'ustream_ssl_ops' in ustream-ssl library\n");
+ return -ENOENT;
+ }
+
+ ctx = ops->context_new(true);
+ if (!ctx) {
+ fprintf(stderr, "Failed to initialize ustream-ssl\n");
+ return -EINVAL;
+ }
+
+ if (ops->context_set_crt_file(ctx, crt) ||
+ ops->context_set_key_file(ctx, key)) {
+ fprintf(stderr, "Failed to load certificate/key files\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static void tls_ustream_read_cb(struct ustream *s, int bytes)
+{
+ struct client *cl = container_of(s, struct client, ssl);
+
+ uh_client_read_cb(cl);
+}
+
+static void tls_ustream_write_cb(struct ustream *s, int bytes)
+{
+ struct client *cl = container_of(s, struct client, ssl);
+
+ if (cl->dispatch.write_cb)
+ cl->dispatch.write_cb(cl);
+}
+
+static void tls_notify_state(struct ustream *s)
+{
+ struct client *cl = container_of(s, struct client, ssl);
+
+ uh_client_notify_state(cl);
+}
+
+void uh_tls_client_attach(struct client *cl)
+{
+ cl->us = &cl->ssl.stream;
+ ops->init(&cl->ssl, &cl->sfd.stream, ctx, true);
+ cl->us->notify_read = tls_ustream_read_cb;
+ cl->us->notify_write = tls_ustream_write_cb;
+ cl->us->notify_state = tls_notify_state;
+}
+
+void uh_tls_client_detach(struct client *cl)
+{
+ ustream_free(&cl->ssl.stream);
+}
--- /dev/null
+/*
+ * uhttpd - Tiny single-threaded httpd - Main header
+ *
+ * Copyright (C) 2010-2012 Jo-Philipp Wich <xm@subsignal.org>
+ * Copyright (C) 2012 Felix Fietkau <nbd@openwrt.org>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __UHTTPD_TLS_H
+#define __UHTTPD_TLS_H
+
+#ifdef HAVE_TLS
+
+int uh_tls_init(const char *key, const char *crt);
+void uh_tls_client_attach(struct client *cl);
+void uh_tls_client_detach(struct client *cl);
+
+#else
+
+static inline int uh_tls_init(const char *key, const char *crt)
+{
+ return -1;
+}
+
+static inline void uh_tls_client_attach(struct client *cl)
+{
+}
+
+static inline void uh_tls_client_detach(struct client *cl)
+{
+}
+
+#endif
+
+#endif
#include <libubox/ustream.h>
#include <libubox/blob.h>
#include <libubox/utils.h>
+#ifdef HAVE_TLS
+#include <libubox/ustream-ssl.h>
+#endif
#include "utils.h"
struct ustream *us;
struct ustream_fd sfd;
#ifdef HAVE_TLS
- struct ustream_ssl stream_ssl;
+ struct ustream_ssl ssl;
#endif
struct uloop_timeout timeout;
enum client_state state;
+ bool tls;
struct http_request request;
struct uh_addr srv_addr, peer_addr;
void uh_index_add(const char *filename);
-bool uh_accept_client(int fd);
+bool uh_accept_client(int fd, bool tls);
void uh_unblock_listeners(void);
void uh_setup_listeners(void);
void uh_handle_request(struct client *cl);
void client_poll_post_data(struct client *cl);
+void uh_client_read_cb(struct client *cl);
+void uh_client_notify_state(struct client *cl);
void uh_auth_add(const char *path, const char *user, const char *pass);
bool uh_auth_check(struct client *cl, struct path_info *pi);