include $(TOPDIR)/rules.mk
PKG_NAME:=uhttpd
-PKG_RELEASE:=23.3
+PKG_RELEASE:=28
PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME)
-PKG_BUILD_DEPENDS := libcyassl liblua
+PKG_CONFIG_DEPENDS := \
+ CONFIG_PACKAGE_uhttpd-mod-lua \
+ CONFIG_PACKAGE_uhttpd-mod-tls \
+ CONFIG_PACKAGE_uhttpd-mod-tls_cyassl \
+ CONFIG_PACKAGE_uhttpd-mod-tls_openssl
include $(INCLUDE_DIR)/package.mk
define Package/uhttpd/default
SECTION:=net
CATEGORY:=Network
+ SUBMENU:=Web Servers/Proxies
TITLE:=uHTTPd - tiny, single threaded HTTP server
+ MAINTAINER:=Jo-Philipp Wich <xm@subsignal.org>
endef
define Package/uhttpd
define Package/uhttpd-mod-tls
$(Package/uhttpd/default)
TITLE+= (TLS plugin)
- DEPENDS:=uhttpd +libcyassl
+ DEPENDS:=uhttpd +PACKAGE_uhttpd-mod-tls_cyassl:libcyassl +PACKAGE_uhttpd-mod-tls_openssl:libopenssl
endef
define Package/uhttpd-mod-tls/description
The TLS plugin adds HTTPS support to uHTTPd.
endef
+define Package/uhttpd-mod-tls/config
+ choice
+ depends on PACKAGE_uhttpd-mod-tls
+ prompt "TLS Provider"
+ default PACKAGE_uhttpd-mod-tls_cyassl
+
+ config PACKAGE_uhttpd-mod-tls_cyassl
+ bool "CyaSSL"
+
+ config PACKAGE_uhttpd-mod-tls_openssl
+ bool "OpenSSL"
+ endchoice
+endef
+
+UHTTPD_TLS:=
+TLS_CFLAGS:=
+TLS_LDFLAGS:=
+
+ifneq ($(CONFIG_PACKAGE_uhttpd-mod-tls_cyassl),)
+ UHTTPD_TLS:=cyassl
+ TLS_CFLAGS:=-I$(STAGING_DIR)/usr/include/cyassl -DTLS_IS_CYASSL
+ TLS_LDFLAGS:=-lcyassl -lm
+endif
+
+ifneq ($(CONFIG_PACKAGE_uhttpd-mod-tls_openssl),)
+ UHTTPD_TLS:=openssl
+ TLS_CFLAGS:=-DTLS_IS_OPENSSL
+ TLS_LDFLAGS:=-lssl
+endif
+
define Package/uhttpd-mod-lua
$(Package/uhttpd/default)
endef
-# hack to use CyASSL headers
-TARGET_CFLAGS += -I$(firstword $(wildcard $(BUILD_DIR)/cyassl-*/include))
-TARGET_LDFLAGS += -lm
-MAKE_VARS += FPIC="$(FPIC)"
+TARGET_CFLAGS += $(TLS_CFLAGS)
+TARGET_LDFLAGS += $(TLS_LDFLAGS)
+MAKE_VARS += \
+ FPIC="$(FPIC)" \
+ LUA_SUPPORT="$(if $(CONFIG_PACKAGE_uhttpd-mod-lua),1)" \
+ TLS_SUPPORT="$(if $(CONFIG_PACKAGE_uhttpd-mod-tls),1)" \
+ UHTTPD_TLS="$(UHTTPD_TLS)" \
+ TLS_CFLAGS="$(TLS_CFLAGS)" \
+ TLS_LDFLAGS="$(TLS_LDFLAGS)"
define Build/Prepare
mkdir -p $(PKG_BUILD_DIR)
[ -x "$PX5G_BIN" ] && {
$PX5G_BIN selfsigned -der \
-days ${days:-730} -newkey rsa:${bits:-1024} -keyout "$UHTTPD_KEY" -out "$UHTTPD_CERT" \
- -subj /C=${country:-DE}/ST=${state:-Saxony}/L=${location:-Leipzig}/CN=${commonname:-OpenWrt}
+ -subj /C="${country:-DE}"/ST="${state:-Saxony}"/L="${location:-Leipzig}"/CN="${commonname:-OpenWrt}"
}
}
CGI_SUPPORT ?= 1
LUA_SUPPORT ?= 1
TLS_SUPPORT ?= 1
+UHTTPD_TLS ?= cyassl
-CFLAGS ?= -I./lua-5.1.4/src -I./cyassl-1.4.0/include -O0 -ggdb3
-LDFLAGS ?= -L./lua-5.1.4/src -L./cyassl-1.4.0/src/.libs
+CFLAGS ?= -I./lua-5.1.4/src $(TLS_CFLAGS) -O0 -ggdb3
+LDFLAGS ?= -L./lua-5.1.4/src
CFLAGS += -Wall --std=gnu99
-OBJ = uhttpd.o uhttpd-file.o uhttpd-utils.o
-LIB = -Wl,--export-dynamic -lcrypt -ldl
+ifeq ($(UHTTPD_TLS),openssl)
+ TLS_LDFLAGS ?= -L./openssl-0.9.8m -lssl
+ TLS_CFLAGS ?= -I./openssl-0.9.8m/include -DTLS_IS_OPENSSL
+else
+ TLS_LDFLAGS ?= -L./cyassl-1.4.0/src/.libs -lcyassl
+ TLS_CFLAGS ?= -I./cyassl-1.4.0/include -DTLS_IS_CYASSL
+endif
-TLSLIB =
-LUALIB =
+OBJ := uhttpd.o uhttpd-file.o uhttpd-utils.o
+LIB := -Wl,--export-dynamic -lcrypt -ldl
+TLSLIB :=
+LUALIB :=
-world: compile
+HAVE_SHADOW=$(shell echo 'int main(void){ return !getspnam("root"); }' | \
+ $(CC) -include shadow.h -xc -o/dev/null - 2>/dev/null && echo yes)
+
+ifeq ($(HAVE_SHADOW),yes)
+ CFLAGS += -DHAVE_SHADOW
+endif
+
+ifeq ($(TLS_SUPPORT),1)
+ CFLAGS += -DHAVE_TLS
+endif
ifeq ($(CGI_SUPPORT),1)
- OBJ += uhttpd-cgi.o
CFLAGS += -DHAVE_CGI
endif
ifeq ($(LUA_SUPPORT),1)
CFLAGS += -DHAVE_LUA
- LUALIB = uhttpd_lua.so
+endif
+
+
+world: compile
+
+ifeq ($(CGI_SUPPORT),1)
+ OBJ += uhttpd-cgi.o
+endif
+
+ifeq ($(LUA_SUPPORT),1)
+ LUALIB := uhttpd_lua.so
$(LUALIB): uhttpd-lua.c
$(CC) $(CFLAGS) $(LDFLAGS) $(FPIC) \
endif
ifeq ($(TLS_SUPPORT),1)
- CFLAGS += -DHAVE_TLS
- TLSLIB = uhttpd_tls.so
+ TLSLIB := uhttpd_tls.so
$(TLSLIB): uhttpd-tls.c
$(CC) $(CFLAGS) $(LDFLAGS) $(FPIC) \
- -shared -lcyassl \
+ -shared $(TLS_LDFLAGS) \
-o $(TLSLIB) uhttpd-tls.c
endif
clean:
rm -f *.o *.so uhttpd
-
#include "uhttpd-tls.h"
#include "uhttpd-utils.h"
+#include <syslog.h>
+#define dbg(...) syslog(LOG_INFO, __VA_ARGS__)
+
+#ifdef TLS_IS_CYASSL
+static int uh_cyassl_recv_cb(char *buf, int sz, void *ctx)
+{
+ int rv;
+ int socket = *(int *)ctx;
+ struct client *cl;
+
+ if (!(cl = uh_client_lookup(socket)))
+ return -1; /* unexpected error */
+
+ rv = uh_tcp_recv_lowlevel(cl, buf, sz);
+
+ if (rv < 0)
+ return -4; /* interrupted */
+
+ if (rv == 0)
+ return -5; /* connection closed */
+
+ return rv;
+}
+
+static int uh_cyassl_send_cb(char *buf, int sz, void *ctx)
+{
+ int rv;
+ int socket = *(int *)ctx;
+ struct client *cl;
+
+ if (!(cl = uh_client_lookup(socket)))
+ return -1; /* unexpected error */
+
+ rv = uh_tcp_send_lowlevel(cl, buf, sz);
+
+ if (rv <= 0)
+ return -5; /* connection dead */
+
+ return rv;
+}
+
+void SetCallbackIORecv_Ctx(SSL_CTX*, int (*)(char *, int, void *));
+void SetCallbackIOSend_Ctx(SSL_CTX*, int (*)(char *, int, void *));
+
+static void uh_tls_ctx_setup(SSL_CTX *ctx)
+{
+ SSL_CTX_set_verify(ctx, SSL_VERIFY_NONE, NULL);
+ SetCallbackIORecv_Ctx(ctx, uh_cyassl_recv_cb);
+ SetCallbackIOSend_Ctx(ctx, uh_cyassl_send_cb);
+ return;
+}
+
+static int uh_tls_client_ctx_setup(SSL *ssl, int socket)
+{
+ return SSL_set_fd(ssl, socket);
+}
+#endif /* TLS_IS_CYASSL */
+
+#ifdef TLS_IS_OPENSSL
+static long uh_openssl_bio_ctrl_cb(BIO *b, int cmd, long num, void *ptr)
+{
+ long rv = 1;
+
+ switch (cmd)
+ {
+ case BIO_C_SET_FD:
+ b->num = *((int *)ptr);
+ b->shutdown = (int)num;
+ b->init = 1;
+ break;
+
+ case BIO_C_GET_FD:
+ if (!b->init)
+ return -1;
+
+ if (ptr)
+ *((int *)ptr) = b->num;
+
+ rv = b->num;
+ break;
+ }
+
+ return rv;
+}
+
+static int uh_openssl_bio_read_cb(BIO *b, char *out, int outl)
+{
+ int rv = 0;
+ struct client *cl;
+
+ if (!(cl = uh_client_lookup(b->num)))
+ return -1;
+
+ if (out != NULL)
+ rv = uh_tcp_recv_lowlevel(cl, out, outl);
+
+ return rv;
+}
+
+static int uh_openssl_bio_write_cb(BIO *b, const char *in, int inl)
+{
+ struct client *cl;
+
+ if (!(cl = uh_client_lookup(b->num)))
+ return -1;
+
+ return uh_tcp_send_lowlevel(cl, in, inl);
+}
+
+static BIO_METHOD uh_openssl_bio_methods = {
+ .type = BIO_TYPE_SOCKET,
+ .name = "uhsocket",
+ .ctrl = uh_openssl_bio_ctrl_cb,
+ .bwrite = uh_openssl_bio_write_cb,
+ .bread = uh_openssl_bio_read_cb
+};
+
+static void uh_tls_ctx_setup(SSL_CTX *ctx)
+{
+ SSL_CTX_set_verify(ctx, SSL_VERIFY_NONE, NULL);
+ return;
+}
+
+static int uh_tls_client_ctx_setup(SSL *ssl, int socket)
+{
+ BIO *b;
+
+ if (!(b = BIO_new(&uh_openssl_bio_methods)))
+ return 0;
+
+ BIO_set_fd(b, socket, BIO_NOCLOSE);
+ SSL_set_bio(ssl, b, b);
+
+ return 1;
+}
+#endif /* TLS_IS_OPENSSL */
+
SSL_CTX * uh_tls_ctx_init()
{
- SSL_CTX *c = NULL;
+ SSL_CTX *c;
+
SSL_load_error_strings();
SSL_library_init();
- if( (c = SSL_CTX_new(TLSv1_server_method())) != NULL )
- SSL_CTX_set_verify(c, SSL_VERIFY_NONE, NULL);
+ if ((c = SSL_CTX_new(TLSv1_server_method())) != NULL)
+ uh_tls_ctx_setup(c);
return c;
}
}
-void uh_tls_client_accept(struct client *c)
+int uh_tls_client_accept(struct client *c)
{
+ int rv;
+
if( c->server && c->server->tls )
{
c->tls = SSL_new(c->server->tls);
- SSL_set_fd(c->tls, c->socket);
+ if( c->tls )
+ {
+ if( (rv = uh_tls_client_ctx_setup(c->tls, c->socket)) < 1 )
+ goto cleanup;
+
+ if( (rv = SSL_accept(c->tls)) < 1 )
+ goto cleanup;
+ }
+ else
+ rv = 0;
}
+ else
+ {
+ c->tls = NULL;
+ rv = 1;
+ }
+
+done:
+ return rv;
+
+cleanup:
+ SSL_free(c->tls);
+ c->tls = NULL;
+ goto done;
}
int uh_tls_client_recv(struct client *c, void *buf, int len)
c->tls = NULL;
}
}
-
-
int uh_tls_ctx_key(SSL_CTX *c, const char *file);
void uh_tls_ctx_free(struct listener *l);
-void uh_tls_client_accept(struct client *c);
+int uh_tls_client_accept(struct client *c);
int uh_tls_client_recv(struct client *c, void *buf, int len);
int uh_tls_client_send(struct client *c, void *buf, int len);
void uh_tls_client_close(struct client *c);
#endif
-
}
-int uh_tcp_send(struct client *cl, const char *buf, int len)
+int uh_tcp_send_lowlevel(struct client *cl, const char *buf, int len)
{
fd_set writer;
struct timeval timeout;
timeout.tv_sec = cl->server->conf->network_timeout;
timeout.tv_usec = 0;
- if( select(cl->socket + 1, NULL, &writer, NULL, &timeout) > 0 )
- {
-#ifdef HAVE_TLS
- if( cl->tls )
- return cl->server->conf->tls_send(cl, (void *)buf, len);
- else
-#endif
- return send(cl->socket, buf, len, 0);
- }
+ if (select(cl->socket + 1, NULL, &writer, NULL, &timeout) > 0)
+ return send(cl->socket, buf, len, 0);
return -1;
}
+int uh_tcp_send(struct client *cl, const char *buf, int len)
+{
+#ifdef HAVE_TLS
+ if (cl->tls)
+ return cl->server->conf->tls_send(cl, (void *)buf, len);
+ else
+#endif
+ return uh_tcp_send_lowlevel(cl, buf, len);
+}
+
int uh_tcp_peek(struct client *cl, char *buf, int len)
{
+ /* sanity check, prevent overflowing peek buffer */
+ if (len > sizeof(cl->peekbuf))
+ return -1;
+
int sz = uh_tcp_recv(cl, buf, len);
/* store received data in peek buffer */
return sz;
}
+int uh_tcp_recv_lowlevel(struct client *cl, char *buf, int len)
+{
+ fd_set reader;
+ struct timeval timeout;
+
+ FD_ZERO(&reader);
+ FD_SET(cl->socket, &reader);
+
+ timeout.tv_sec = cl->server->conf->network_timeout;
+ timeout.tv_usec = 0;
+
+ if (select(cl->socket + 1, &reader, NULL, NULL, &timeout) > 0)
+ return recv(cl->socket, buf, len, 0);
+
+ return -1;
+}
+
int uh_tcp_recv(struct client *cl, char *buf, int len)
{
int sz = 0;
int rsz = 0;
- fd_set reader;
- struct timeval timeout;
-
/* first serve data from peek buffer */
- if( cl->peeklen > 0 )
+ if (cl->peeklen > 0)
{
sz = min(cl->peeklen, len);
len -= sz; cl->peeklen -= sz;
-
memcpy(buf, cl->peekbuf, sz);
memmove(cl->peekbuf, &cl->peekbuf[sz], cl->peeklen);
}
/* caller wants more */
- if( len > 0 )
+ if (len > 0)
{
- FD_ZERO(&reader);
- FD_SET(cl->socket, &reader);
-
- timeout.tv_sec = cl->server->conf->network_timeout;
- timeout.tv_usec = 0;
-
- if( select(cl->socket + 1, &reader, NULL, NULL, &timeout) > 0 )
- {
#ifdef HAVE_TLS
- if( cl->tls )
- rsz = cl->server->conf->tls_recv(cl, (void *)&buf[sz], len);
- else
+ if (cl->tls)
+ rsz = cl->server->conf->tls_recv(cl, (void *)&buf[sz], len);
+ else
#endif
- rsz = recv(cl->socket, (void *)&buf[sz], len, 0);
+ rsz = uh_tcp_recv_lowlevel(cl, (void *)&buf[sz], len);
- if( (sz == 0) || (rsz > 0) )
- sz += rsz;
- }
- else if( sz == 0 )
- {
- sz = -1;
- }
+ if (rsz < 0)
+ return rsz;
+
+ sz += rsz;
}
return sz;
int select_intr(int n, fd_set *r, fd_set *w, fd_set *e, struct timeval *t);
int uh_tcp_send(struct client *cl, const char *buf, int len);
+int uh_tcp_send_lowlevel(struct client *cl, const char *buf, int len);
int uh_tcp_peek(struct client *cl, char *buf, int len);
int uh_tcp_recv(struct client *cl, char *buf, int len);
+int uh_tcp_recv_lowlevel(struct client *cl, char *buf, int len);
int uh_http_sendhf(
struct client *cl, int code, const char *summary,
#ifdef HAVE_TLS
/* setup client tls context */
if( conf->tls )
- conf->tls_accept(cl);
+ {
+ if( conf->tls_accept(cl) < 1 )
+ {
+ fprintf(stderr,
+ "tls_accept failed, "
+ "connection dropped\n");
+
+ /* close client socket */
+ close(new_fd);
+
+ /* remove from global client list */
+ uh_client_remove(new_fd);
+
+ continue;
+ }
+ }
#endif
/* add client socket to global fdset */
int (*tls_cert) (SSL_CTX *c, const char *file);
int (*tls_key) (SSL_CTX *c, const char *file);
void (*tls_free) (struct listener *l);
- void (*tls_accept) (struct client *c);
+ int (*tls_accept) (struct client *c);
void (*tls_close) (struct client *c);
int (*tls_recv) (struct client *c, void *buf, int len);
int (*tls_send) (struct client *c, void *buf, int len);
#endif
#endif
-