summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSimon Rettberg2014-09-09 18:07:48 +0200
committerSimon Rettberg2014-09-09 18:07:48 +0200
commitbbdf2fba7b9ae0fa97aa164bcf84c1b88df38f32 (patch)
tree0bad2dc5bb0112940272b22a31f5dc4a0e8b2840
parentBail out on startup if an AD server is not reachable (diff)
downloadldadp-bbdf2fba7b9ae0fa97aa164bcf84c1b88df38f32.tar.gz
ldadp-bbdf2fba7b9ae0fa97aa164bcf84c1b88df38f32.tar.xz
ldadp-bbdf2fba7b9ae0fa97aa164bcf84c1b88df38f32.zip
Add OpenSSL-Support (Client<->Proxy)
-rw-r--r--Makefile5
-rw-r--r--client.c196
-rw-r--r--client.h2
-rw-r--r--config/config.example3
-rw-r--r--helper.c11
-rw-r--r--ldadp.c33
-rw-r--r--openssl.c68
-rw-r--r--openssl.h21
-rw-r--r--proxy.c78
-rw-r--r--proxy.h4
-rw-r--r--server.c10
-rw-r--r--server.h2
-rw-r--r--types.h11
13 files changed, 328 insertions, 116 deletions
diff --git a/Makefile b/Makefile
index c3619e1..cdbc8b1 100644
--- a/Makefile
+++ b/Makefile
@@ -30,7 +30,7 @@ CC=gcc
CFLAGS=-g -pipe -W -Wall -Wextra -std=gnu99 -Wno-unused-parameter
#CC=clang
#CFLAGS=-g -pipe -fsanitize=address -O1 -fno-omit-frame-pointer -W -Wall -Wextra -std=gnu99 -Wno-unused-parameter
-LIBS+=-lowfat
+LIBS+=-lowfat -lssl
%.o: %.c
$(CC) $(CFLAGS) -c $<
@@ -41,7 +41,7 @@ LIBS+=-lowfat
%: %.c
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS) ${LIBS}
-ldadp: tmpbuffer.o ini.o client.o server.o helper.o proxy.o epoll.o ldap.a asn1.a
+ldadp: tmpbuffer.o ini.o client.o server.o helper.o proxy.o epoll.o openssl.o ldap.a asn1.a
.PHONY: clean tar
clean:
@@ -59,6 +59,7 @@ server.o: server.c server.h
helper.o: helper.c helper.h
proxy.o: proxy.c proxy.h
epoll.o: epoll.c epoll.h
+openssl.o: openssl.c openssl.h
fmt_asn1int.o: fmt_asn1int.c asn1.h
fmt_asn1intpayload.o: fmt_asn1intpayload.c asn1.h
diff --git a/client.c b/client.c
index b71b69e..e9e9453 100644
--- a/client.c
+++ b/client.c
@@ -3,20 +3,23 @@
#include "epoll.h"
#include "helper.h"
#include "asn1.h"
+#include "openssl.h"
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <errno.h>
-#define MAX_SEND_BUFFER 100000
+#define MAX_SEND_BUFFER 150000
-static void client_flush(epoll_client_t *client);
+static void client_haveIn(epoll_client_t *client);
+static void client_haveOut(epoll_client_t *client);
static void client_free(epoll_client_t *client)
{
proxy_removeClient(client);
if (client->sendBuffer != NULL) free(client->sendBuffer);
+ if (client->ssl != NULL) SSL_free(client->ssl);
if (client->fd != -1) {
//ePoll_remove(client->fd); // epoll would remove closed descriptors automatically, but just to be sure we don't cause use after free, we remove it explicitly
close(client->fd);
@@ -27,110 +30,187 @@ static void client_free(epoll_client_t *client)
void client_callback(void *data, int haveIn, int haveOut, int doCleanup)
{
epoll_client_t *client = (epoll_client_t*)data;
- if (doCleanup) {
+ if (doCleanup || client->kill) {
printf("Client gone.\n");
client_free(client);
return;
}
- // Anything to read?
- if (haveIn) {
- for (;;) {
- if (client->rbPos >= REQLEN) {
- printf("[C->Proxy] Read buffer overflow. Disconnecting.\n");
- client_free(client);
- return;
- }
- const size_t buflen = REQLEN - client->rbPos;
- const ssize_t ret = read(client->fd, client->readBuffer + client->rbPos, buflen);
+ if (client->ssl == NULL) {
+ // Plain connection
+ if (haveIn) client_haveIn(client);
+ if (haveOut) client_haveOut(client);
+ if (client->kill) client_free(client);
+ return;
+ }
+ // SSL connection
+ if (!client->sslAccepted) {
+ // Still SSL-Connecting
+ if (!ssl_acceptClient(client)) {
+ printf("SSL Client accept failed.\n");
+ client_free(client);
+ return;
+ }
+ if (!client->sslAccepted) return;
+ }
+ // Since we don't know if the incoming data is just wrapped application data or ssl protocol stuff, we always call both
+ client_haveIn(client);
+ client_haveOut(client);
+ if (client->kill) {
+ printf("Client killed.\n");
+ client_free(client);
+ }
+}
+
+static void client_haveIn(epoll_client_t *client)
+{
+ for (;;) {
+ if (client->rbPos >= REQLEN) {
+ printf("[C->Proxy] Read buffer overflow. Disconnecting.\n");
+ client->kill = TRUE;
+ return;
+ }
+ const size_t buflen = REQLEN - client->rbPos;
+ ssize_t ret;
+ if (client->ssl == NULL) {
+ // Plain
+ ret = read(client->fd, client->readBuffer + client->rbPos, buflen);
if (ret < 0 && errno == EINTR) continue;
if (ret < 0 && errno == EAGAIN) break;
if (ret <= 0) {
printf("Client gone while reading.\n");
- client_free(client);
+ client->kill = TRUE;
return;
}
- client->rbPos += ret;
- // Request complete?
- for (;;) {
- size_t consumed, len;
- consumed = scan_asn1SEQUENCE(client->readBuffer, client->readBuffer + client->rbPos, &len);
- if (consumed == 0) break; // Length-Header not complete
- len += consumed;
- if (len > client->rbPos) break; // Body not complete yet
- printf("Received complete requrest...\n");
- if (proxy_fromClient(client, len) == -1) {
- printf("Error parsing request from client.\n");
- client_free(client);
- return;
- }
- // Shift remaining buffer contents
- if (len == client->rbPos) {
- client->rbPos = 0;
- break;
- }
- memmove(client->readBuffer, client->readBuffer + len, client->rbPos - len);
- client->rbPos -= len;
+ } else {
+ // SSL
+ ret = SSL_read(client->ssl, client->readBuffer + client->rbPos, buflen);
+ if (ret <= 0) {
+ int err = SSL_get_error(client->ssl, ret);
+ if (SSL_BLOCKED(err)) break;
+ printf("Client gone while reading (%d, %d).\n", (int)ret, err);
+ client->kill = TRUE;
+ return;
}
- if ((ssize_t)buflen > ret) break; // Read less than buffer len, epoll will fire again
}
+ // We reach here if something was read (so ret > 0)
+ client->rbPos += ret;
+ // Request complete?
+ for (;;) {
+ size_t consumed, len;
+ consumed = scan_asn1SEQUENCE(client->readBuffer, client->readBuffer + client->rbPos, &len);
+ if (consumed == 0) break; // Length-Header not complete
+ len += consumed;
+ if (len > client->rbPos) break; // Body not complete yet
+ printf("Received complete requrest...\n");
+ if (!proxy_fromClient(client, len)) {
+ printf("Error parsing request from client.\n");
+ client->kill = TRUE;
+ return;
+ }
+ // Shift remaining buffer contents
+ if (len == client->rbPos) {
+ client->rbPos = 0;
+ break;
+ }
+ memmove(client->readBuffer, client->readBuffer + len, client->rbPos - len);
+ client->rbPos -= len;
+ }
+ if (client->ssl == NULL && (ssize_t)buflen > ret) break; // Read less than buffer len, epoll will fire again
}
- // Anything to send?
- if (haveOut) client_flush(client);
}
-static void client_flush(epoll_client_t *client)
+static void client_haveOut(epoll_client_t *client)
{
+ client->writeBlocked = FALSE;
while (client->sbPos < client->sbFill) {
const int tosend = client->sbFill - client->sbPos;
- const int ret = write(client->fd, client->sendBuffer + client->sbPos, tosend);
- if (ret < 0 && errno == EINTR) continue;
- if (ret < 0 && errno == EAGAIN) return;
- if (ret <= 0) {
- printf("Cannot send to client (ret: %d, errno: %d)\n", ret, errno);
- return;
+ ssize_t ret;
+ if (client->ssl == NULL) {
+ // Plain
+ ret = write(client->fd, client->sendBuffer + client->sbPos, tosend);
+ if (ret < 0 && errno == EINTR) continue;
+ if (ret < 0 && errno == EAGAIN) return;
+ if (ret <= 0) {
+ printf("Cannot send to client (ret: %d, errno: %d)\n", (int)ret, errno);
+ client->kill = TRUE;
+ return;
+ }
+ } else {
+ // SSL
+ ret = SSL_write(client->ssl, client->sendBuffer + client->sbPos, tosend);
+ if (ret <= 0) {
+ int err = SSL_get_error(client->ssl, ret);
+ if (SSL_BLOCKED(err)) {
+ client->writeBlocked = TRUE;
+ return; // Blocking
+ }
+ printf("SSL client gone while sending (%d)\n", err);
+ ERR_print_errors_fp(stdout);
+ client->kill = TRUE;
+ return; // Closed
+ }
}
client->sbPos += ret;
- if (ret != tosend) return; // Sent less than requested -> buffer full, epoll will trigger us again
+ if (client->ssl != NULL) {
+ memmove(client->sendBuffer, client->sendBuffer + client->sbPos, client->sbFill - client->sbPos);
+ client->sbFill -= client->sbPos;
+ client->sbPos = 0;
+ }
+ if (client->ssl == NULL && ret != tosend) return; // Sent less than requested -> buffer full, epoll will trigger us again
}
client->sbPos = client->sbFill = 0;
+ if (client->ssl == NULL && client->sbLen > MAX_SEND_BUFFER / 2) {
+ helper_realloc(&client->sendBuffer, &client->sbLen, 8000, "client_haveOut");
+ }
}
-int client_send(epoll_client_t *client, const char *buffer, size_t len, const BOOL cork)
+BOOL client_send(epoll_client_t *client, const char *buffer, size_t len, const BOOL cork)
{
- if (client->sbFill == 0 && !cork) {
+ if (client->ssl == NULL && client->sbFill == 0 && !cork) {
// Nothing in send buffer, fire away
const int ret = write(client->fd, buffer, len);
if (ret == 0 || (ret < 0 && errno != EINTR && errno != EAGAIN)) {
printf("Client gone when trying to send.\n");
- return -1;
+ client->kill = TRUE;
+ return FALSE;
}
- if (ret == (int)len) return 0;
+ if (ret == (int)len) return TRUE;
// Couldn't send everything, continue with buffering logic below
if (ret > 0) {
buffer += ret;
len -= (size_t)ret;
}
}
- // Sanity
- if ((client->sbLen - client->sbPos) + len > MAX_SEND_BUFFER) {
- printf("Dropping client as the send buffer would exceed %d bytes.\n", (int)MAX_SEND_BUFFER);
- return -1;
- }
// Buffer...
if (client->sbLen - client->sbFill < len) { // Buffer too small?
+ if (client->writeBlocked) {
+ printf("SSL Write blocked and buffer to small (%d)\n", (int)client->sbLen);
+ client->kill = TRUE;
+ return FALSE;
+ }
if (client->sbPos != 0) { // See if we can compact it
memmove(client->sendBuffer, client->sendBuffer + client->sbPos, client->sbFill - client->sbPos);
client->sbFill -= client->sbPos;
client->sbPos = 0;
}
+ // Sanity
+ if (client->sbFill + len > MAX_SEND_BUFFER) {
+ printf("Dropping client as the send buffer would exceed %d bytes.\n", (int)MAX_SEND_BUFFER);
+ client->kill = TRUE;
+ return FALSE;
+ }
if (client->sbLen - client->sbFill < len) { // Still too small after compacting? realloc
- if (helper_realloc(&client->sendBuffer, &client->sbLen, client->sbLen + len + 1500, "client_send") == -1) return -1;
+ if (helper_realloc(&client->sendBuffer, &client->sbLen, client->sbLen + len + (client->ssl && client->sbLen > 0 ? MAX_SEND_BUFFER : 4000), "client_send") == -1) {
+ client->kill = TRUE;
+ return FALSE;
+ }
+ printf("Send Buffer now %d\n", (int)client->sbLen);
}
}
// Finally append to buffer
memcpy(client->sendBuffer + client->sbFill, buffer, len);
client->sbFill += len;
- if (!cork) client_flush(client);
- return 0;
+ if (!cork) client_haveOut(client);
+ return TRUE;
}
diff --git a/client.h b/client.h
index 64f0171..9a19439 100644
--- a/client.h
+++ b/client.h
@@ -5,6 +5,6 @@
void client_callback(void *data, int haveIn, int haveOut, int doCleanup);
-int client_send(epoll_client_t *client, const char *buffer, size_t len, const BOOL cork);
+BOOL client_send(epoll_client_t *client, const char *buffer, size_t len, const BOOL cork);
#endif
diff --git a/config/config.example b/config/config.example
index b2850d4..6ad38a6 100644
--- a/config/config.example
+++ b/config/config.example
@@ -7,4 +7,7 @@ bindpw=geheim
base=DC=public,DC=ads,DC=example,DC=com
# optional: template for home directory mount point to pass to client. use %s as the users account name. only used if AD doesn't supply the homeDirectory attribute (or it doesn't contain a UNC path)
home=\\windows-server\users\%s
+# For using SSL between client and proxy, uncomment these. For plaintext, remove or comment out
+cert=/my/cert.pem
+privkey=/my/privatekey.pem
diff --git a/helper.c b/helper.c
index 6aed251..8dec6e4 100644
--- a/helper.c
+++ b/helper.c
@@ -85,13 +85,10 @@ void helper_nonblock(const int fd)
static void helper_printavaInt(struct AttributeValueAssertion* a,const char* rel)
{
- putchar('[');
- printf("%.*s", (int)a->desc.l,a->desc.s);
- putchar(' ');
- printf("%s", rel);
- putchar(' ');
- printf("%.*s", (int)a->value.l,a->value.s);
- putchar(']');
+ printf("[%.*s %s", (int)a->desc.l, a->desc.s, rel);
+ if (a->value.l != 0 && a->value.s != NULL) {
+ printf(" %.*s]", (int)a->value.l,a->value.s);
+ }
}
void helper_printava(struct AttributeValueAssertion* a,const char* rel)
diff --git a/ldadp.c b/ldadp.c
index 4d481df..b0e8e52 100644
--- a/ldadp.c
+++ b/ldadp.c
@@ -5,6 +5,7 @@
#include "proxy.h"
#include "ini.h"
#include "helper.h"
+#include "openssl.h"
#include <stdio.h>
#include <socket.h>
#include <io.h>
@@ -17,6 +18,7 @@ static void listen_callback(void *data, int haveIn, int haveOut, int doCleanup);
static void loadConfig(char *file);
static int localPort = 1234;
+static char *certFile = NULL, *keyFile = NULL;
int main(int argc, char **argv)
{
@@ -37,8 +39,16 @@ int main(int argc, char **argv)
char listen_addr[4] = {0, 0, 0, 0};
// Setup socket
epoll_listen_t lsn;
+ memset(&lsn, 0, sizeof(lsn));
lsn.callback = &listen_callback;
lsn.fd = socket_tcp4();
+ if (certFile != NULL && keyFile != NULL) {
+ printf("Using SSL\n");
+ ssl_init();
+ lsn.sslContext = ssl_newServerCtx(certFile, keyFile);
+ } else {
+ printf("Not using SSL\n");
+ }
if (lsn.fd == -1) bail("Could not create listen socket");
if (socket_bind4_reuse(lsn.fd, listen_addr, localPort) == -1) bail("Could not bind to listening port");
if (socket_listen(lsn.fd, 10) == -1) bail("Could not listen");
@@ -70,10 +80,27 @@ static void listen_callback(void *data, int haveIn, int haveOut, int doCleanup)
printf("Error accepting new connection.\n");
return;
}
+ helper_nonblock(sock);
printf("Accepted connection.\n");
+ SSL *ssl = NULL;
+ if (listen->sslContext != NULL) {
+ ssl = ssl_startAccept(sock, listen->sslContext);
+ if (ssl == NULL) {
+ close(sock);
+ return;
+ }
+ }
epoll_client_t *client = calloc(1, sizeof(epoll_client_t));
client->fd = sock;
client->callback = &client_callback;
+ client->ssl = ssl;
+ if (ssl != NULL && !ssl_acceptClient(client)) {
+ printf("SSL-Accepting client failed.\n");
+ SSL_free(ssl);
+ close(sock);
+ free(client);
+ return;
+ }
ePoll_add(EPOLLIN | EPOLLOUT | EPOLLET, (epoll_item_t*)client);
}
@@ -94,6 +121,12 @@ static int loadConfig_handler(void *stuff, const char *section, const char *key,
if (strcmp(key, "port") == 0) {
localPort = atoi(value);
}
+ if (strcmp(key, "cert") == 0) {
+ certFile = strdup(value);
+ }
+ if (strcmp(key, "privkey") == 0) {
+ keyFile = strdup(value);
+ }
return 1;
}
diff --git a/openssl.c b/openssl.c
new file mode 100644
index 0000000..32c7bca
--- /dev/null
+++ b/openssl.c
@@ -0,0 +1,68 @@
+#include "openssl.h"
+#include "helper.h"
+
+static BOOL initDone = FALSE;
+
+void ssl_printErrors(char *bailMsg)
+{
+ unsigned long err;
+ while ((err = ERR_get_error())) {
+ char *msg = ERR_error_string(err, NULL);
+ printf("OpenSSL: %s\n", msg);
+ }
+ if (bailMsg != NULL) bail(bailMsg);
+}
+
+BOOL ssl_init()
+{
+ if (initDone) return TRUE;
+ SSL_load_error_strings();
+ SSL_library_init();
+ OpenSSL_add_all_algorithms();
+ return TRUE;
+}
+
+SSL_CTX* ssl_newServerCtx(char *certfile, char *keyfile)
+{
+ const SSL_METHOD *m = SSLv23_server_method();
+ if (m == NULL) ssl_printErrors("newServerCtx: method is NULL");
+ SSL_CTX *ctx = SSL_CTX_new(m);
+ if (ctx == NULL) ssl_printErrors("newServerCtx: ctx is NULL");
+ SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv2);
+ SSL_CTX_use_certificate_file(ctx, certfile, SSL_FILETYPE_PEM);
+ SSL_CTX_use_PrivateKey_file(ctx, keyfile, SSL_FILETYPE_PEM);
+ if (!SSL_CTX_check_private_key(ctx)) ssl_printErrors("Could not load cert/private key");
+ return ctx;
+}
+
+SSL *ssl_startAccept(int clientFd, SSL_CTX *ctx)
+{
+ SSL *ssl = SSL_new(ctx);
+ if (ssl == NULL) {
+ ssl_printErrors(NULL);
+ return NULL;
+ }
+ if (!SSL_set_fd(ssl, clientFd)) {
+ ssl_printErrors(NULL);
+ SSL_free(ssl);
+ return NULL;
+ }
+ SSL_set_mode(ssl, SSL_MODE_ENABLE_PARTIAL_WRITE);
+ return ssl;
+}
+
+BOOL ssl_acceptClient(epoll_client_t *client)
+{
+ if (client->sslAccepted) return TRUE;
+ int ret = SSL_accept(client->ssl);
+ if (ret == 1) {
+ client->sslAccepted = TRUE;
+ return TRUE;
+ }
+ if (ret < 0) {
+ int err = SSL_get_error(client->ssl, ret);
+ if (SSL_BLOCKED(err)) return TRUE;
+ }
+ return FALSE;
+}
+
diff --git a/openssl.h b/openssl.h
new file mode 100644
index 0000000..a564b97
--- /dev/null
+++ b/openssl.h
@@ -0,0 +1,21 @@
+#ifndef _LDADP_OPENSSL_H_
+#define _LDADP_OPENSSL_H_
+
+#include "types.h"
+#include <openssl/ssl.h>
+#include <openssl/err.h>
+
+#define SSL_BLOCKED(err) ((err) == SSL_ERROR_WANT_READ || (err) == SSL_ERROR_WANT_WRITE || (err) == SSL_ERROR_WANT_X509_LOOKUP)
+
+void ssl_printErrors(char *bailMsg);
+
+BOOL ssl_init();
+
+SSL_CTX* ssl_newServerCtx(char *certfile, char *keyfile);
+
+SSL *ssl_startAccept(int clientFd, SSL_CTX *ctx);
+
+BOOL ssl_acceptClient(epoll_client_t *client);
+
+#endif
+
diff --git a/proxy.c b/proxy.c
index 5bd9541..c888c2f 100644
--- a/proxy.c
+++ b/proxy.c
@@ -51,12 +51,12 @@ static struct string str_ADUSER;
//
-static int proxy_clientBindRequest(epoll_client_t *client, const unsigned long messageId, const size_t offset, const size_t maxLen);
-static int proxy_serverBindResponse(epoll_server_t *server, const unsigned long messageId, const size_t offset, const size_t maxLen);
-static int proxy_clientSearchRequest(epoll_client_t *client, const unsigned long messageId, const size_t offset, const size_t maxLen);
-static int proxy_serverSearchResult(epoll_server_t *server, const unsigned long messageId, const unsigned long type, const size_t offset, const size_t maxLen);
+static BOOL proxy_clientBindRequest(epoll_client_t *client, const unsigned long messageId, const size_t offset, const size_t maxLen);
+static BOOL proxy_serverBindResponse(epoll_server_t *server, const unsigned long messageId, const size_t offset, const size_t maxLen);
+static BOOL proxy_clientSearchRequest(epoll_client_t *client, const unsigned long messageId, const size_t offset, const size_t maxLen);
+static BOOL proxy_serverSearchResult(epoll_server_t *server, const unsigned long messageId, const unsigned long type, const size_t offset, const size_t maxLen);
-static int proxy_localSearchRequest(epoll_client_t *client, const unsigned long messageId, const struct SearchRequest *req);
+static BOOL proxy_localSearchRequest(epoll_client_t *client, const unsigned long messageId, const struct SearchRequest *req);
//
@@ -97,12 +97,12 @@ void proxy_init()
}
#undef SETSTR
-int proxy_fromClient(epoll_client_t *client, const size_t maxLen)
+BOOL proxy_fromClient(epoll_client_t *client, const size_t maxLen)
{
unsigned long messageId, op;
size_t len;
const size_t res = scan_ldapmessage(client->readBuffer, client->readBuffer + maxLen, &messageId, &op, &len);
- if (res == 0) return -1;
+ if (res == 0) return FALSE;
printf("[C] scan_ldapmessage: Consumed %d, remaining length %d, id %lu, op %lu\n", (int)res, (int)len, messageId, op);
// TODO: Caching
switch (op) {
@@ -111,9 +111,9 @@ int proxy_fromClient(epoll_client_t *client, const size_t maxLen)
case SearchRequest:
return proxy_clientSearchRequest(client, messageId, res, maxLen);
case UnbindRequest:
- return 0;
+ return TRUE;
}
- return 0;
+ return TRUE;
}
void proxy_removeClient(const epoll_client_t *client)
@@ -126,12 +126,12 @@ void proxy_removeClient(const epoll_client_t *client)
_pendingCount = lastValid + 1;
}
-int proxy_fromServer(epoll_server_t *server, const size_t maxLen)
+BOOL proxy_fromServer(epoll_server_t *server, const size_t maxLen)
{
unsigned long messageId, op;
size_t len;
const size_t res = scan_ldapmessage(server->readBuffer, server->readBuffer + maxLen, &messageId, &op, &len);
- if (res == 0) return -1;
+ if (res == 0) return FALSE;
printf("[AD] scan_ldapmessage: Consumed %d, remaining length %d, id %lu, op %lu\n", (int)res, (int)len, messageId, op);
switch (op) {
case BindResponse:
@@ -141,7 +141,7 @@ int proxy_fromServer(epoll_server_t *server, const size_t maxLen)
return proxy_serverSearchResult(server, messageId, op, res, maxLen);
}
printf("Unsupported op: %lu\n", op);
- return -1;
+ return FALSE;
}
//
@@ -491,15 +491,15 @@ static struct PartialAttributeList* response_addPal(struct PartialAttributeList
// -----
-static int proxy_clientSearchRequest(epoll_client_t *client, const unsigned long messageId, const size_t offset, const size_t maxLen)
+static BOOL proxy_clientSearchRequest(epoll_client_t *client, const unsigned long messageId, const size_t offset, const size_t maxLen)
{
struct SearchRequest req;
const size_t res = scan_ldapsearchrequest(client->readBuffer + offset, client->readBuffer + maxLen, &req);
- if (res == 0) return -1;
+ if (res == 0) return FALSE;
server_t *server = server_getFromBase(&req.baseObject);
if (server == NULL) {
printf("scan_ldapsearchrequest: baseObj '%.*s' unknown.\n", (int)req.baseObject.l, req.baseObject.s);
- return -1;
+ return FALSE;
}
printf("scan_ldapsearchrequest: baseObj: %.*s, scope: %d, derefAliases: %d\n", (int)req.baseObject.l, req.baseObject.s, req.scope, req.derefAliases);
// Try to figure out if this is a lookup for a user/multiple users, or something else (eg. group)
@@ -507,16 +507,17 @@ static int proxy_clientSearchRequest(epoll_client_t *client, const unsigned long
// Handle locally
printf("Handling local:\n");
helper_printfilter(req.filter);
- const int ret = proxy_localSearchRequest(client, messageId, &req);
+ const BOOL ret = proxy_localSearchRequest(client, messageId, &req);
free_ldapsearchrequest(&req);
return ret;
}
- //
+ // Forward
+ if (req.sizeLimit == 0 || req.sizeLimit > 500) req.sizeLimit = 500; // TODO: Magic value
pending_t *pending = proxy_getFreePendingSlot(client);
if (pending == NULL) {
printf("No more slots for pending requests\n");
free_ldapsearchrequest(&req);
- return -1;
+ return FALSE;
}
if (req.attributes == NULL) {
memset(&pending->attr, -1, sizeof(pending->attr));
@@ -533,22 +534,23 @@ static int proxy_clientSearchRequest(epoll_client_t *client, const unsigned long
pending->serverMessageId = server_searchRequest(server, &req);
if (pending->serverMessageId == 0) {
// Failed to forward.. TODO: Fail client
+ printf("Failed to forward search request.\n");
pending->client = NULL;
}
free_ldapsearchrequest(&req);
//
- if (pending->client == NULL) return -1;
- return 0;
+ if (pending->client == NULL) return FALSE;
+ return TRUE;
}
-static int proxy_serverSearchResult(epoll_server_t *server, const unsigned long messageId, const unsigned long type, const size_t offset, const size_t maxLen)
+static BOOL proxy_serverSearchResult(epoll_server_t *server, const unsigned long messageId, const unsigned long type, const size_t offset, const size_t maxLen)
{
static char *bodyBuffer = NULL;
if (bodyBuffer == NULL) bodyBuffer = malloc(MAXMSGLEN);
pending_t *pending = proxy_getPendingFromServer(messageId);
if (pending == NULL) {
printf("No client matching server message id %lu\n", messageId);
- return 0;
+ return TRUE;
}
printf("ServerID %lu -> ClientID %lu\n", messageId, pending->clientMessageId);
const char *body;
@@ -561,18 +563,18 @@ static int proxy_serverSearchResult(epoll_server_t *server, const unsigned long
// Transform reply
struct SearchResultEntry sre;
const size_t res = scan_ldapsearchresultentry(server->readBuffer + offset, server->readBuffer + maxLen, &sre);
- if (res == 0) return -1;
+ if (res == 0) return FALSE;
response_replacePal(server->serverData, &sre.attributes, &pending->attr);
bodyLen = fmt_ldapsearchresultentry(NULL, &sre);
if (bodyLen == 0) {
printf("Error formatting ldapsearchresultentry after transformation\n");
free_ldapsearchresultentry(&sre);
- return -1;
+ return FALSE;
}
if (bodyLen > MAXMSGLEN) {
printf("ldapsearchresultentry too large after transformation\n");
free_ldapsearchresultentry(&sre);
- return -1;
+ return FALSE;
}
fmt_ldapsearchresultentry(bodyBuffer, &sre);
free_ldapsearchresultentry(&sre);
@@ -585,10 +587,10 @@ static int proxy_serverSearchResult(epoll_server_t *server, const unsigned long
client_send(pending->client, buffer, headerLen, TRUE);
client_send(pending->client, body, bodyLen, FALSE);
if (type == SearchResultDone) pending->client = NULL;
- return 0;
+ return TRUE;
}
-static int proxy_clientBindRequest(epoll_client_t *client, const unsigned long messageId, const size_t offset, const size_t maxLen)
+static BOOL proxy_clientBindRequest(epoll_client_t *client, const unsigned long messageId, const size_t offset, const size_t maxLen)
{
unsigned long version, method;
struct string name, password;
@@ -596,7 +598,7 @@ static int proxy_clientBindRequest(epoll_client_t *client, const unsigned long m
char *bufoff = buffer + 100;
size_t bodyLen;
const size_t res = scan_ldapbindrequest(client->readBuffer + offset, client->readBuffer + maxLen, &version, &name, &method);
- if (res == 0) return -1; // Parsing request failed
+ if (res == 0) return FALSE; // Parsing request failed
if (method != 0) {
// Other than simple bind - currently not supported
printf("Unsupported bind method: %lu\n", method);
@@ -628,41 +630,41 @@ static int proxy_clientBindRequest(epoll_client_t *client, const unsigned long m
// Request queued, client needs to wait
pending->clientMessageId = messageId;
pending->serverMessageId = smid;
- return 0;
+ return TRUE;
}
}
}
}
const size_t headerLen = fmt_ldapmessage(NULL, messageId, BindResponse, bodyLen);
- if (headerLen > 100) return -1; // Too long - don't care
+ if (headerLen > 100) return FALSE; // Too long - don't care
fmt_ldapmessage(bufoff - headerLen, messageId, BindResponse, bodyLen);
return client_send(client, bufoff - headerLen, bodyLen + headerLen, FALSE);
}
-static int proxy_serverBindResponse(epoll_server_t *server, const unsigned long messageId, const size_t offset, const size_t maxLen)
+static BOOL proxy_serverBindResponse(epoll_server_t *server, const unsigned long messageId, const size_t offset, const size_t maxLen)
{
unsigned long result;
struct string binddn, error, refer;
const size_t res = scan_ldapbindresponse(server->readBuffer + offset, server->readBuffer + maxLen, &result, &binddn, &error, &refer);
- if (res == 0) return -1; // Parsing request failed
+ if (res == 0) return FALSE; // Parsing request failed
printf("scan_ldapbindresponse: Consumed %d, result: %lu, binddn: %.*s, error: %.*s, referral: %.*s\n", (int)res, result, (int)binddn.l, binddn.s, (int)error.l, error.s, (int)refer.l, refer.s);
if (result == success) server->bound = TRUE;
- if (messageId <= 1) return 0;
+ if (messageId <= 1) return TRUE;
// Was a forwarded auth
pending_t *pending = proxy_getPendingFromServer(messageId);
- if (pending == NULL) return 0;
+ if (pending == NULL) return FALSE;
const size_t headerLen = fmt_ldapmessage(NULL, pending->clientMessageId, BindResponse, res);
char buffer[headerLen];
fmt_ldapmessage(buffer, pending->clientMessageId, BindResponse, res);
client_send(pending->client, buffer, headerLen, TRUE);
- client_send(pending->client, server->readBuffer + offset, maxLen, FALSE);
+ client_send(pending->client, server->readBuffer + offset, res, FALSE);
pending->client = NULL;
- return -1;
+ return FALSE; // Return FALSE here so server.c will kill off this server connection
}
// ---- Local handling ----
-static int proxy_localSearchRequest(epoll_client_t *client, const unsigned long messageId, const struct SearchRequest *req)
+static BOOL proxy_localSearchRequest(epoll_client_t *client, const unsigned long messageId, const struct SearchRequest *req)
{
struct string name;
uint32_t number = 2;
@@ -729,6 +731,6 @@ static int proxy_localSearchRequest(epoll_client_t *client, const unsigned long
fmt_ldapmessage(buffer, messageId, SearchResultDone, doneLen);
return client_send(client, buffer, doneHeaderLen + doneLen, FALSE);
}
- return -1;
+ return FALSE;
}
diff --git a/proxy.h b/proxy.h
index 032ebe4..c54f896 100644
--- a/proxy.h
+++ b/proxy.h
@@ -5,10 +5,10 @@
void proxy_init();
-int proxy_fromClient(epoll_client_t *client, const size_t maxLen);
+BOOL proxy_fromClient(epoll_client_t *client, const size_t maxLen);
void proxy_removeClient(const epoll_client_t *client);
-int proxy_fromServer(epoll_server_t *server, const size_t maxLen);
+BOOL proxy_fromServer(epoll_server_t *server, const size_t maxLen);
#endif
diff --git a/server.c b/server.c
index aeb9d12..39f8dce 100644
--- a/server.c
+++ b/server.c
@@ -254,7 +254,7 @@ static void server_callback(void *data, int haveIn, int haveOut, int doCleanup)
len += consumed;
if (len > server->rbPos) break; // Body not complete
printf("[AD] Received complete reply...\n");
- if (proxy_fromServer(server, len) == -1) {
+ if (!proxy_fromServer(server, len)) {
if (server->dynamic) {
server_free(server);
return;
@@ -276,17 +276,17 @@ static void server_callback(void *data, int haveIn, int haveOut, int doCleanup)
if (haveOut) server_flush(server);
}
-int server_send(epoll_server_t *server, const char *buffer, size_t len, const BOOL cork)
+BOOL server_send(epoll_server_t *server, const char *buffer, size_t len, const BOOL cork)
{
if (server->sbFill == 0 && !cork) {
// Nothing in send buffer, fire away
const int ret = write(server->fd, buffer, len);
if (ret == 0 || (ret < 0 && errno != EINTR && errno != EAGAIN)) {
printf("Server gone when trying to send.\n");
- return -1;
+ return FALSE;
}
server->lastActive = time(NULL);
- if (ret == (int)len) return 0;
+ if (ret == (int)len) return TRUE;
// Couldn't send everything, continue with buffering logic below
if (ret > 0) {
printf("[AD] Partial send (%d of %d)\n", ret, (int)len);
@@ -300,7 +300,7 @@ int server_send(epoll_server_t *server, const char *buffer, size_t len, const BO
memcpy(server->sendBuffer + server->sbFill, buffer, len);
server->sbFill += len;
if (!cork) server_flush(server);
- return 0;
+ return TRUE;
}
static void server_flush(epoll_server_t * const server)
diff --git a/server.h b/server.h
index 7c966a2..d2d84ef 100644
--- a/server.h
+++ b/server.h
@@ -16,7 +16,7 @@ void server_setHomeTemplate(const char *server, const char *hometemplate);
BOOL server_initServers();
-int server_send(epoll_server_t *server, const char *buffer, size_t len, const BOOL cork);
+BOOL server_send(epoll_server_t *server, const char *buffer, size_t len, const BOOL cork);
server_t *server_getFromBase(struct string *in);
diff --git a/types.h b/types.h
index 692042a..71cd36d 100644
--- a/types.h
+++ b/types.h
@@ -4,6 +4,7 @@
#include <stddef.h>
#include <stdint.h>
#include <time.h>
+#include <openssl/ssl.h>
#define ADDRLEN 40
#define BINDLEN 250
@@ -29,19 +30,25 @@ typedef struct {
typedef struct {
void (*callback)(void *data, int haveIn, int haveOut, int doCleanup);
int fd;
+ //
+ SSL_CTX *sslContext; // Listening for SSL connections, NULL otherwise
} epoll_listen_t;
typedef struct {
void (*callback)(void *data, int haveIn, int haveOut, int doCleanup);
int fd;
- int padding;
+ //
+ BOOL bound; // Client did successful ldap bind
+ BOOL sslAccepted; // SSL_accept done?
+ BOOL kill; // Should the connection be killed?
+ BOOL writeBlocked; // An SSL_write returned WANT_*, so we must not reallocate the current send buffer
// Send buffer (me to client)
size_t sbPos, sbFill, sbLen;
+ SSL *ssl; // NULL if not encrypted
char *sendBuffer; // Dynamically allocated, might or might not get huge
// Recv buffer (client's request)
size_t rbPos;
char readBuffer[REQLEN]; // Static, queries > 4000 bytes simply not supported
- BOOL bound;
} epoll_client_t;
typedef struct {