diff options
author | Simon Rettberg | 2014-09-09 18:07:48 +0200 |
---|---|---|
committer | Simon Rettberg | 2014-09-09 18:07:48 +0200 |
commit | bbdf2fba7b9ae0fa97aa164bcf84c1b88df38f32 (patch) | |
tree | 0bad2dc5bb0112940272b22a31f5dc4a0e8b2840 | |
parent | Bail out on startup if an AD server is not reachable (diff) | |
download | ldadp-bbdf2fba7b9ae0fa97aa164bcf84c1b88df38f32.tar.gz ldadp-bbdf2fba7b9ae0fa97aa164bcf84c1b88df38f32.tar.xz ldadp-bbdf2fba7b9ae0fa97aa164bcf84c1b88df38f32.zip |
Add OpenSSL-Support (Client<->Proxy)
-rw-r--r-- | Makefile | 5 | ||||
-rw-r--r-- | client.c | 196 | ||||
-rw-r--r-- | client.h | 2 | ||||
-rw-r--r-- | config/config.example | 3 | ||||
-rw-r--r-- | helper.c | 11 | ||||
-rw-r--r-- | ldadp.c | 33 | ||||
-rw-r--r-- | openssl.c | 68 | ||||
-rw-r--r-- | openssl.h | 21 | ||||
-rw-r--r-- | proxy.c | 78 | ||||
-rw-r--r-- | proxy.h | 4 | ||||
-rw-r--r-- | server.c | 10 | ||||
-rw-r--r-- | server.h | 2 | ||||
-rw-r--r-- | types.h | 11 |
13 files changed, 328 insertions, 116 deletions
@@ -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 @@ -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; } @@ -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 @@ -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) @@ -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 + @@ -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; } @@ -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 @@ -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) @@ -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); @@ -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 { |