From 2e37d6b71692508fa5d2764c1c80f3c7ca7c2894 Mon Sep 17 00:00:00 2001 From: Simon Rettberg Date: Fri, 26 Jun 2015 14:58:03 +0200 Subject: Send search requests on the same connection the explicit bind was done on, so the user's permissions regarding visibility of search results will be applied --- client.c | 30 +++++++++----------- client.h | 2 ++ helper.c | 12 ++++++++ helper.h | 1 + ldadp.c | 14 ++++----- proxy.c | 98 ++++++++++++++++++++++++++++++++++++++------------------------- proxy.h | 4 ++- server.c | 99 ++++++++++++++++++++++++++++++++-------------------------------- server.h | 6 +++- types.h | 12 +++++--- 10 files changed, 162 insertions(+), 116 deletions(-) diff --git a/client.c b/client.c index f2c9683..906b718 100644 --- a/client.c +++ b/client.c @@ -15,7 +15,7 @@ static void client_haveIn(epoll_client_t *client); static void client_haveOut(epoll_client_t *client); -static void client_free(epoll_client_t *client) +void client_free(epoll_client_t *client) { proxy_removeClient(client); if (client->sendBuffer != NULL) free(client->sendBuffer); @@ -31,7 +31,7 @@ void client_callback(void *data, int haveIn, int haveOut, int doCleanup) { epoll_client_t *client = (epoll_client_t*)data; if (doCleanup || client->kill) { - printf("Client gone (1).\n"); + //printf("Client gone (1).\n"); client_free(client); return; } @@ -40,7 +40,7 @@ void client_callback(void *data, int haveIn, int haveOut, int doCleanup) if (haveIn) client_haveIn(client); if (haveOut) client_haveOut(client); if (client->kill) { - printf("Client gone (2).\n"); + //printf("Client gone (2).\n"); client_free(client); } return; @@ -49,7 +49,7 @@ void client_callback(void *data, int haveIn, int haveOut, int doCleanup) if (!client->sslAccepted) { // Still SSL-Connecting if (!ssl_acceptClient(client)) { - printf("SSL Client accept failed.\n"); + printf("[Proxy] SSL Client accept failed.\n"); client_free(client); return; } @@ -59,7 +59,7 @@ void client_callback(void *data, int haveIn, int haveOut, int doCleanup) client_haveIn(client); client_haveOut(client); if (client->kill) { - printf("Client gone (3).\n"); + //printf("Client gone (3).\n"); client_free(client); } } @@ -68,7 +68,7 @@ static void client_haveIn(epoll_client_t *client) { for (;;) { if (client->rbPos >= REQLEN) { - printf("[C->Proxy] Read buffer overflow. Disconnecting.\n"); + printf("[Proxy] Buffer overflow reading from client. Disconnecting.\n"); client->kill = TRUE; return; } @@ -80,7 +80,7 @@ static void client_haveIn(epoll_client_t *client) if (ret < 0 && errno == EINTR) continue; if (ret < 0 && errno == EAGAIN) break; if (ret <= 0) { - printf("Client gone while reading.\n"); + printf("[Proxy] Client gone while reading (ret=%d, errno=%d).\n", (int)ret, errno); client->kill = TRUE; return; } @@ -90,7 +90,7 @@ static void client_haveIn(epoll_client_t *client) 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); + printf("[Proxy] SSL client gone while reading (ret=%d, err=%d).\n", (int)ret, err); client->kill = TRUE; return; } @@ -104,9 +104,8 @@ static void client_haveIn(epoll_client_t *client) 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"); + printf("[Proxy] Error parsing request from client.\n"); client->kill = TRUE; return; } @@ -134,7 +133,7 @@ static void client_haveOut(epoll_client_t *client) 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); + printf("[Proxy] Cannot send to client (ret=%d, errno=%d)\n", (int)ret, errno); client->kill = TRUE; return; } @@ -147,7 +146,7 @@ static void client_haveOut(epoll_client_t *client) client->writeBlocked = TRUE; return; // Blocking } - printf("SSL client gone while sending (%d)\n", err); + printf("[Proxy] SSL cannot send to client (ret=%d, err=%d)\n", (int)ret, err); ERR_print_errors_fp(stdout); client->kill = TRUE; return; // Closed @@ -173,7 +172,7 @@ BOOL client_send(epoll_client_t *client, const char *buffer, size_t len, const B // 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"); + printf("[Proxy] Client gone when trying to send.\n"); client->kill = TRUE; return FALSE; } @@ -187,7 +186,7 @@ BOOL client_send(epoll_client_t *client, const char *buffer, size_t len, const B // 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); + printf("[Proxy] SSL write to client blocked and buffer to small (%d bytes)\n", (int)client->sbLen); client->kill = TRUE; return FALSE; } @@ -198,7 +197,7 @@ BOOL client_send(epoll_client_t *client, const char *buffer, size_t len, const B } // Sanity if (client->sbFill + len > MAX_SEND_BUFFER) { - printf("Dropping client as the send buffer would exceed %d bytes.\n", (int)MAX_SEND_BUFFER); + printf("[Proxy] Dropping client as the send buffer would exceed %d bytes.\n", (int)MAX_SEND_BUFFER); client->kill = TRUE; return FALSE; } @@ -207,7 +206,6 @@ BOOL client_send(epoll_client_t *client, const char *buffer, size_t len, const B client->kill = TRUE; return FALSE; } - printf("Send Buffer now %d\n", (int)client->sbLen); } } // Finally append to buffer diff --git a/client.h b/client.h index 9a19439..2cc8090 100644 --- a/client.h +++ b/client.h @@ -3,6 +3,8 @@ #include "types.h" +void client_free(epoll_client_t *client); + void client_callback(void *data, int haveIn, int haveOut, int doCleanup); BOOL client_send(epoll_client_t *client, const char *buffer, size_t len, const BOOL cork); diff --git a/helper.c b/helper.c index c938783..b125f42 100644 --- a/helper.c +++ b/helper.c @@ -111,6 +111,18 @@ void helper_printal(struct AttributeDescriptionList* a) putchar('\n'); } +void helper_printpal(struct PartialAttributeList *pal) +{ + printf("-- PAL --\n"); + while (pal) { + printf("entry ("); + if (pal->type.l && pal->type.s) printf("%.*s", (int)pal->type.l, pal->type.s); + printf("): "); + helper_printal(pal->values); + pal = pal->next; + } +} + static void helper_printfilterInt(struct Filter* f) { if (f == NULL) { diff --git a/helper.h b/helper.h index 840813d..838078f 100644 --- a/helper.h +++ b/helper.h @@ -11,6 +11,7 @@ void helper_nonblock(const int fd); void helper_printava(struct AttributeValueAssertion* a,const char* rel); void helper_printal(struct AttributeDescriptionList* a); +void helper_printpal(struct PartialAttributeList *pal); void helper_printfilter(struct Filter* f); static inline int min(const int a, const int b) diff --git a/ldadp.c b/ldadp.c index 8d320a8..3b8d5f6 100644 --- a/ldadp.c +++ b/ldadp.c @@ -27,6 +27,7 @@ int main(int argc, char **argv) printf("Nö\n"); exit(1); } + setbuf(stdout, NULL); signal(SIGPIPE, SIG_IGN); if (strcmp(argv[1], "-n") == 0 && argc > 2) { isdaemon = FALSE; @@ -77,11 +78,10 @@ static void listen_callback(void *data, int haveIn, int haveOut, int doCleanup) uint16 port; int sock = socket_accept4(listen->fd, remote, &port); if (sock < 0) { - printf("Error accepting new connection.\n"); + printf("[Proxy] Error accepting new connection.\n"); return; } helper_nonblock(sock); - printf("Accepted connection.\n"); SSL *ssl = NULL; if (listen->sslContext != NULL) { ssl = ssl_new(sock, listen->sslContext); @@ -95,7 +95,7 @@ static void listen_callback(void *data, int haveIn, int haveOut, int doCleanup) client->callback = &client_callback; client->ssl = ssl; if (ssl != NULL && !ssl_acceptClient(client)) { - printf("SSL-Accepting client failed.\n"); + printf("[Proxy] SSL-Accepting client failed.\n"); SSL_free(ssl); close(sock); free(client); @@ -123,10 +123,10 @@ static int loadConfig_handler(void *stuff, const char *section, const char *key, server_setPassword(section, value); } else if (strcmp(key, "base") == 0) { server_setBase(section, value); - } else if (strcmp(key, "home") == 0 && *value != '\0') { - server_setHomeTemplate(section, value); - } else if (strcmp(key, "fingerprint") == 0 && *value != '\0') { - server_setFingerprint(section, value); + } else if (strcmp(key, "home") == 0) { + if (value[0] != '\0') server_setHomeTemplate(section, value); + } else if (strcmp(key, "fingerprint") == 0) { + if (value[0] != '\0') server_setFingerprint(section, value); } else if (strcmp(key, "port") == 0) { server_setPort(section, value); } else { diff --git a/proxy.c b/proxy.c index 5bfbac7..a709616 100644 --- a/proxy.c +++ b/proxy.c @@ -9,6 +9,7 @@ #include #include #include +#include #define MAXPENDING 200 #define MAX(a,b) ((a) > (b) ? (a) : (b)) @@ -36,12 +37,6 @@ typedef struct attr_t attr; } pending_t; -typedef struct -{ - const char *search; - struct string replace; -} replace_t; - static pending_t _pendingRequest[MAXPENDING]; static int _pendingCount = 0; @@ -148,7 +143,7 @@ BOOL proxy_fromClient(epoll_client_t *client, const size_t maxLen) size_t len; const size_t res = scan_ldapmessage(client->readBuffer, client->readBuffer + maxLen, &messageId, &op, &len); 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); + //printf("[C] scan_ldapmessage: Consumed %d, remaining length %d, id %lu, op %lu\n", (int)res, (int)len, messageId, op); // TODO: Caching switch (op) { case BindRequest: @@ -161,7 +156,7 @@ BOOL proxy_fromClient(epoll_client_t *client, const size_t maxLen) return TRUE; } -void proxy_removeClient(const epoll_client_t *client) +void proxy_removeClient(epoll_client_t * const client) { int i, lastValid = -1; for (i = 0; i < _pendingCount; ++i) { @@ -169,6 +164,20 @@ void proxy_removeClient(const epoll_client_t *client) else if (_pendingRequest[i].client != NULL) lastValid = i; } _pendingCount = lastValid + 1; + if (client->fixedServer != NULL) { + client->fixedServer->kill = TRUE; + shutdown(client->fixedServer->fd, SHUT_RDWR); + client->fixedServer->fixedClient = NULL; + } +} + +void proxy_removeServer(epoll_server_t * const server) +{ + if (server->fixedClient != NULL) { + server->fixedClient->kill = TRUE; + if (server->fixedClient->sbFill == 0) shutdown(server->fixedClient->fd, SHUT_RDWR); + server->fixedClient->fixedServer = NULL; + } } BOOL proxy_fromServer(epoll_server_t *server, const size_t maxLen) @@ -179,7 +188,7 @@ BOOL proxy_fromServer(epoll_server_t *server, const size_t maxLen) 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); + //printf("[AD] scan_ldapmessage: Consumed %d, remaining length %d, id %lu, op %lu\n", (int)res, (int)len, messageId, op); switch (op) { case BindResponse: return proxy_serverBindResponse(server, messageId, res, maxLen); @@ -496,8 +505,8 @@ static void response_replacePal(server_t *server, struct PartialAttributeList ** ADDATTR(homeDirectory, "/home/%s", user); ADDATTR(gecos, "%s,,,", user); ADDATTR(cn, "%s", user); + if (wasNumeric) user++; // From here on, user is the real AD username, no leading 's' if (attr->homeMount && server->homeTemplate[0] != '\0') { - if (wasNumeric) user++; ADDATTR(homeMount, server->homeTemplate, user, user, user, user, user, user); } // Do this here so user++ will have been executed @@ -596,20 +605,22 @@ static BOOL proxy_clientSearchRequest(epoll_client_t *client, const unsigned lon } server_t *server = server_getFromBase(&req.baseObject); if (server == NULL) { - printf("scan_ldapsearchrequest: baseObj '%.*s' unknown (scope %d).\n", (int)req.baseObject.l, req.baseObject.s, (int)req.scope); + printf("[Client] Invalid search request: baseObj '%.*s' unknown (scope %d).\n", (int)req.baseObject.l, req.baseObject.s, (int)req.scope); return FALSE; } - printf("scan_ldapsearchrequest: baseObj: %.*s, scope: %d, derefAliases: %d\n", (int)req.baseObject.l, req.baseObject.s, req.scope, req.derefAliases); + //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) if (!request_isUserFilter(req.filter)) { // Handle locally - printf("Handling local:\n"); + printf("[Client] Search request (handling local): "); helper_printfilter(req.filter); const BOOL ret = proxy_localSearchRequest(client, messageId, &req); free_ldapsearchrequest(&req); return ret; } // Forward + printf("[Client] Search request (forwarding): "); + helper_printfilter(req.filter); if (req.sizeLimit == 0 || req.sizeLimit > 20) req.sizeLimit = 20; // TODO: Magic value pending_t *pending = proxy_getFreePendingSlot(client); if (pending == NULL) { @@ -622,15 +633,15 @@ static BOOL proxy_clientSearchRequest(epoll_client_t *client, const unsigned lon } else { request_replaceAdl(server, &req.attributes, &pending->attr); } - helper_printfilter(req.filter); request_replaceFilter(server, &req.filter); - helper_printfilter(req.filter); - helper_printal(req.attributes); - //printf("Attrs: "); - //for (size_t i = 0; i < sizeof(attr_t); ++i) putchar(((char*)&pending->attr)[i] == 0 ? '0' : '1'); - //putchar('\n'); + //helper_printfilter(req.filter); + //helper_printal(req.attributes); pending->clientMessageId = messageId; - pending->serverMessageId = server_searchRequest(server, &req); + if (client->fixedServer == NULL) { + pending->serverMessageId = server_searchRequest(server, &req); + } else { + pending->serverMessageId = server_searchRequestOnConnection(client->fixedServer, &req); + } if (pending->serverMessageId == 0) { // Failed to forward.. TODO: Fail client printf("Failed to forward search request.\n"); @@ -648,10 +659,9 @@ static BOOL proxy_serverSearchResult(epoll_server_t *server, const unsigned long 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); + printf("[AD] Received message with unknown messageId %lu, ignoring\n", messageId); return TRUE; } - printf("ServerID %lu -> ClientID %lu\n", messageId, pending->clientMessageId); const char *body; size_t bodyLen; if (type == SearchResultDone) { @@ -700,36 +710,43 @@ static BOOL proxy_clientBindRequest(epoll_client_t *client, const unsigned long 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); + printf("[Client] Unsupported bind method: %lu\n", method); bodyLen = fmt_ldapbindresponse(bufoff, authMethodNotSupported, "", "SIMPLE only", ""); } else { // Simple bind :-) - const size_t res2 = scan_ldapstring(client->readBuffer + offset + res, client->readBuffer + maxLen, &password); - printf("scan_ldapbindrequest: Consumed %d, version %lu, method %lu, name '%.*s'\n", (int)(res + res2), version, method, (int)name.l, name.s); + password.l = 0; + scan_ldapstring(client->readBuffer + offset + res, client->readBuffer + maxLen, &password); + //printf("scan_ldapbindrequest: Consumed %d, version %lu, method %lu, name '%.*s'\n", (int)(res + res2), version, method, (int)name.l, name.s); if (name.l == 0 && password.l == 0) { // Anonymous bind used for "normal" lookups - printf("Anonymous bind ok\n"); + printf("[Client] Anonymous bind accepted\n"); bodyLen = fmt_ldapbindresponse(bufoff, success, "", "main screen turn on", ""); } else { + BOOL incorrect; server_t *server = server_getFromBase(&name); - if (server == NULL || strncmp(password.s, "\x08\x0a\x0d\x7fINCORRECT", 13) == 0 || isInt(&name, 0)) { - // The INCORRECT part is some weird thing I saw pam_ldap do - save the round trip to AD and deny - printf("Password INCORRECT or binddn unknown or numeric username\n"); + if (server == NULL || (incorrect = (strncmp(password.s, "\x08\x0a\x0d\x7fINCORRECT", 13) == 0)) || isInt(&name, 0)) { + // The INCORRECT part is some weird thing I saw pam_ldap do - probably to identify misconfigured + // LDAP servers/accounts that will accept any password - save the round trip to AD and deny + if (!incorrect) printf("[Client] Numeric account or invalid binddn for %.*s\n", (int)name.l, name.s); bodyLen = fmt_ldapbindresponse(bufoff, invalidCredentials, "", "invalid credentials", ""); } else { - // Seems to be an actual bind - forward to AD - TODO: SASL (DIGEST-MD5?) + // Seems to be an actual bind - forward to AD - TODO: SASL (DIGEST-MD5? Something?) fixUnNumeric(&name); pending_t *pending = proxy_getFreePendingSlot(client); - const unsigned long smid = server_tryUserBind(server, &name, &password); + epoll_server_t *con; + const unsigned long smid = server_tryUserBind(server, &name, &password, &con); if (pending == NULL || smid == 0) { // Busy if (pending != NULL) pending->client = NULL; - printf("Too many pending requests, or cannot connect to AD\n"); + printf("[Client] Too many pending requests, or cannot connect to AD for bind\n"); bodyLen = fmt_ldapbindresponse(bufoff, busy, "", "can't handle it", ""); } else { // Request queued, client needs to wait + printf("[Client] Forwarding bind to AD for user %.*s\n", (int)name.l, name.s); pending->clientMessageId = messageId; pending->serverMessageId = smid; + con->fixedClient = client; + client->fixedServer = con; return TRUE; } } @@ -747,8 +764,13 @@ static BOOL proxy_serverBindResponse(epoll_server_t *server, const unsigned long 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 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; + //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); + server->bound = (result == success); + if (server->bound) { + printf("[AD] Accepted credentials (#%lu)\n", messageId); + } else { + printf("[AD] Wrong credentials (#%lu)\n", messageId); + } if (messageId <= 1) return TRUE; // Was a forwarded auth pending_t *pending = proxy_getPendingFromServer(messageId); @@ -759,7 +781,7 @@ static BOOL proxy_serverBindResponse(epoll_server_t *server, const unsigned long client_send(pending->client, buffer, headerLen, TRUE); client_send(pending->client, server->readBuffer + offset, res, FALSE); pending->client = NULL; - return FALSE; // Return FALSE here so server.c will kill off this server connection + return server->bound; // Return FALSE here so server.c will kill off this server connection } // ---- Local handling ---- @@ -778,7 +800,7 @@ static void prependPal(struct SearchResultEntry *dest, struct PartialAttributeLi static BOOL proxy_localFeatureReply(epoll_client_t *client, const unsigned long messageId) { - printf("Sending fake feature request reply\n"); + printf("[Proxy] Sending static feature request reply to client\n"); struct SearchResultEntry sre; struct PartialAttributeList vers; struct AttributeDescriptionList versVal; @@ -818,7 +840,7 @@ static BOOL proxy_localSearchRequest(epoll_client_t *client, const unsigned long } if (number == 1001 || name.l != 0) { // At least one of them was set - printf("Sending fake group membership\n"); + printf("[Proxy] Sending static group membership to client\n"); struct SearchResultEntry sre; struct PartialAttributeList gidNumber, cn, objectClass; struct AttributeDescriptionList gidNumberVal, cnVal, objectClassVal; @@ -835,7 +857,7 @@ static BOOL proxy_localSearchRequest(epoll_client_t *client, const unsigned long fmt_ldapsearchresultentry(buffer + headerLen, &sre); client_send(client, buffer, headerLen + bodyLen, TRUE); } else { - printf("Sending empty posixGroup search result.\n"); + printf("[Proxy] Sending empty posixGroup search result to client.\n"); } const size_t doneLen = fmt_ldapsearchresultdone(NULL, success, "", "", ""); const size_t doneHeaderLen = fmt_ldapmessage(NULL, messageId, SearchResultDone, doneLen); diff --git a/proxy.h b/proxy.h index c54f896..f9a781e 100644 --- a/proxy.h +++ b/proxy.h @@ -7,7 +7,9 @@ void proxy_init(); BOOL proxy_fromClient(epoll_client_t *client, const size_t maxLen); -void proxy_removeClient(const epoll_client_t *client); +void proxy_removeClient(epoll_client_t * const client); + +void proxy_removeServer(epoll_server_t * const server); BOOL proxy_fromServer(epoll_server_t *server, const size_t maxLen); diff --git a/server.c b/server.c index 91164bb..2fdb601 100644 --- a/server.c +++ b/server.c @@ -22,7 +22,6 @@ static int serverCount = 0; static void server_init(); static server_t *server_create(const char *server); -static void server_free(epoll_server_t *server); static void server_callback(void *data, int haveIn, int haveOut, int doCleanup); static void server_haveIn(epoll_server_t *server); static void server_haveOut(epoll_server_t * const server); @@ -171,6 +170,12 @@ server_t *server_getFromBase(struct string *in) uint32_t server_searchRequest(server_t *server, struct SearchRequest *req) { if (!server_ensureConnected(server)) return 0; + epoll_server_t * const s = &server->con; + return server_searchRequestOnConnection(s, req); +} + +uint32_t server_searchRequestOnConnection(epoll_server_t *server, struct SearchRequest *req) +{ const uint32_t msgid = msgId(); const size_t bodyLen = fmt_ldapsearchrequest(NULL, req); const size_t headerLen = fmt_ldapmessage(NULL, msgid, SearchRequest, bodyLen); @@ -178,36 +183,35 @@ uint32_t server_searchRequest(server_t *server, struct SearchRequest *req) char *bufoff = buffer + 50; fmt_ldapsearchrequest(bufoff, req); fmt_ldapmessage(bufoff - headerLen, msgid, SearchRequest, bodyLen); - epoll_server_t * const s = &server->con; - server_send(s, bufoff - headerLen, headerLen + bodyLen, FALSE); + server_send(server, bufoff - headerLen, headerLen + bodyLen, FALSE); return msgid; } -uint32_t server_tryUserBind(server_t *server, struct string *binddn, struct string *password) +uint32_t server_tryUserBind(server_t *server, struct string *binddn, struct string *password, epoll_server_t **newcon) { epoll_server_t *con = calloc(1, sizeof(epoll_server_t)); con->serverData = server; con->fd = -1; con->bound = FALSE; con->dynamic = TRUE; - printf("Connecting to AD '%s' for %.*ss bind...\n", server->addr, (int)binddn->l, binddn->s); con->sbPos = con->sbFill = 0; int sock = server_connectInternal(server); if (sock == -1) { + printf("[Proxy] Could not connect to AD for user bind.\n"); server_free(con); return 0; } - printf("[ADB] Connected, binding....\n"); helper_nonblock(sock); con->fd = sock; con->callback = &server_callback; if (ePoll_add(EPOLLIN | EPOLLOUT | EPOLLET, (epoll_item_t*)con) == -1) { - printf("[ADB] epoll_add failed for ad server %s\n", server->addr); + printf("[Proxy] epoll_add failed for AD server %s on user bind\n", server->addr); server_free(con); return 0; } // SSL if (!server_connectSsl(con)) { + printf("[Proxy] SSL handshake failed for AD server %s on user bind\n", server->addr); server_free(con); return 0; } @@ -218,13 +222,14 @@ uint32_t server_tryUserBind(server_t *server, struct string *binddn, struct stri char buffer[bodyLen + 50]; char *bufoff = buffer + 50; if (headerLen >= 50) { - printf("[ADB] bind too long for %s\n", server->addr); + printf("[Proxy] User bind too long for %s\n", server->addr); server_free(con); return 0; } fmt_ldapbindrequeststring(bufoff, 3, binddn, password); fmt_ldapmessage(bufoff - headerLen, id, BindRequest, bodyLen); server_send(con, bufoff - headerLen, bodyLen + headerLen, FALSE); + *newcon = con; return id; } @@ -254,8 +259,9 @@ static server_t *server_create(const char *server) return &servers[serverCount++]; } -static void server_free(epoll_server_t *server) +void server_free(epoll_server_t *server) { + proxy_removeServer(server); server->bound = FALSE; if (server->ssl != NULL) { SSL_free(server->ssl); @@ -267,7 +273,7 @@ static void server_free(epoll_server_t *server) } server->sbPos = server->sbFill = 0; if (server->dynamic) { - printf("Freeing Bind-AD-Connection\n"); + //printf("Freeing Bind-AD-Connection\n"); free(server->sendBuffer); free(server); } @@ -276,38 +282,37 @@ static void server_free(epoll_server_t *server) static void server_callback(void *data, int haveIn, int haveOut, int doCleanup) { epoll_server_t *server = (epoll_server_t *)data; - if (doCleanup || server->kill) { - server_free(server); - return; - } if (server->ssl == NULL) { // Plain connection if (haveIn) server_haveIn(server); if (haveOut) server_haveOut(server); - if (server->kill) server_free(server); - return; - } - // SSL - if (!server->sslConnected) { - // Still SSL-Connecting - if (!ssl_connectServer(server)) { - printf("SSL Server connect failed!\n"); - server_free(server); - return; + } else { + // SSL + if (!server->sslConnected) { + // Still SSL-Connecting + if (!ssl_connectServer(server)) { + printf("[Proxy] SSL handshake for AD server %s failed.\n", server->serverData->addr); + server_free(server); + return; + } + } + // The connect above might have succeeded, so check again and start sending/receiving if so + if (server->sslConnected) { + // Since we don't know if the incoming data is just wrapped application data or ssl protocol stuff, we always call both + server_haveIn(server); + server_haveOut(server); } - if (!server->sslConnected) return; } - // Since we don't know if the incoming data is just wrapped application data or ssl protocol stuff, we always call both - server_haveIn(server); - server_haveOut(server); - if (server->kill) server_free(server); + if (doCleanup || server->kill) { + server_free(server); + } } static void server_haveIn(epoll_server_t *server) { for (;;) { if (server->rbPos >= MAXMSGLEN) { - printf("[AD->Proxy] Read buffer overflow. Disconnecting.\n"); + printf("[Proxy] Buffer overflow while reading from AD server. Disconnecting.\n"); server->kill = TRUE; return; } @@ -316,11 +321,10 @@ static void server_haveIn(epoll_server_t *server) if (server->ssl == NULL) { // Plain ret = read(server->fd, server->readBuffer + server->rbPos, buflen); - printf("AD read %d (err %d)\n", (int)ret, errno); if (ret < 0 && errno == EINTR) continue; if (ret < 0 && errno == EAGAIN) break; + if (ret < 0) printf("[Proxy] AD Server %s gone while reading (ret=%d, errno=%d).\n", server->serverData->addr, (int)ret, errno); if (ret <= 0) { - printf("AD Server gone while reading.\n"); server->kill = TRUE; return; } @@ -330,7 +334,7 @@ static void server_haveIn(epoll_server_t *server) if (ret <= 0) { int err = SSL_get_error(server->ssl, ret); if (SSL_BLOCKED(err)) break; - printf("AD Server gone while reading (%d, %d).\n", (int)ret, err); + if (err != 0) printf("[Proxy] AD Server %s gone while reading (ret=%d, err=%d).\n", server->serverData->addr, (int)ret, err); server->kill = TRUE; return; } @@ -343,13 +347,13 @@ static void server_haveIn(epoll_server_t *server) if (consumed == 0) break; // Length-Header not complete len += consumed; if (len > server->rbPos) break; // Body not complete - printf("[AD] Received complete reply (need %d, have %d)...\n", (int)len, (int)server->rbPos); + //printf("[AD] Received complete reply (need %d, have %d)...\n", (int)len, (int)server->rbPos); if (!proxy_fromServer(server, len)) { if (server->dynamic) { server->kill = TRUE; return; } - printf("Error parsing reply from AD.\n"); + printf("[Proxy] Error parsing message from AD.\n"); // Let's try to go on with the next message.... } // Shift remaining buffer contents @@ -370,14 +374,13 @@ BOOL server_send(epoll_server_t *server, const char *buffer, size_t len, const B // 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"); + printf("[Proxy] AD Server %s gone when trying to send.\n", server->serverData->addr); return FALSE; } server->lastActive = time(NULL); 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); buffer += ret; len -= (size_t)ret; } @@ -405,7 +408,7 @@ static void server_haveOut(epoll_server_t * const server) if (ret < 0 && errno == EINTR) continue; if (ret < 0 && errno == EAGAIN) return; if (ret <= 0) { - printf("Connection to AD Server failed while flushing (ret: %d, errno: %d)\n", (int)ret, errno); + printf("[Proxy] AD Server %s gone while flushing send buffer (ret=%d, errno=%d)\n", server->serverData->addr, (int)ret, errno); return; } } else { @@ -419,7 +422,7 @@ static void server_haveOut(epoll_server_t * const server) } else if (err == SSL_ERROR_SSL) { ssl_printErrors(NULL); } - printf("SSL server gone while sending (%d)\n", err); + printf("[Proxy] AD Server %s gone while flushing send buffer (ret=%d, err=%d)\n", server->serverData->addr, (int)ret, err); ERR_print_errors_fp(stdout); server->kill = TRUE; return; // Closed @@ -443,16 +446,14 @@ static BOOL server_ensureConnected(server_t *server) if (con->fd != -1 && con->lastActive + 120 > time(NULL)) return TRUE; if (con->fd != -1) close(con->fd); con->bound = FALSE; - printf("Connecting to AD '%s'...\n", server->addr); con->sbPos = con->sbFill = 0; int sock = server_connectInternal(server); if (sock == -1) return FALSE; - printf("Connected, binding....\n"); helper_nonblock(sock); con->fd = sock; con->callback = &server_callback; if (ePoll_add(EPOLLIN | EPOLLOUT | EPOLLET, (epoll_item_t*)con) == -1) { - printf("epoll_add failed for ad server %s\n", server->addr); + printf("[Proxy] epoll_add failed for ad server %s\n", server->addr); close(con->fd); con->fd = -1; return FALSE; @@ -469,7 +470,7 @@ static BOOL server_ensureConnected(server_t *server) char buffer[bodyLen + 50]; char *bufoff = buffer + 50; if (headerLen >= 50) { - printf("[AD] bind too long for %s\n", server->addr); + printf("[Proxy] bind too long for %s\n", server->addr); close(con->fd); con->fd = -1; return FALSE; @@ -488,7 +489,7 @@ static BOOL server_ensureSendBuffer(epoll_server_t * const s, const size_t len) } if (s->sbLen - s->sbFill < len) { if (s->writeBlocked) { - printf("SSL Write blocked and buffer to small (%d)\n", (int)s->sbLen); + printf("[Proxy] SSL write to AD server blocked and buffer to small (%d bytes)\n", (int)s->sbLen); return FALSE; } if (s->sbPos != 0) { @@ -512,17 +513,17 @@ static int server_connectInternal(server_t *server) if (server->lastLookup + 300 < time(NULL)) { sock = helper_connect4(server->addr, port, server->ip); if (sock == -1) { - printf("Could not resolve/connect to AD server %s\n", server->addr); + printf("[Proxy] Could not resolve hostname or connect to AD server %s\n", server->addr); return -1; } } else { sock = socket_tcp4b(); if (sock == -1) { - printf("Could not allocate socket for connection to AD\n"); + printf("[Proxy] Could not allocate socket for connection to AD server %s\n", server->addr); return -1; } if (socket_connect4(sock, server->ip, port) == -1) { - printf("Could not connect to cached IP of %s\n", server->addr); + printf("[Proxy] Could not connect to cached IP (%s) of %s\n", server->ip, server->addr); server->lastLookup = 0; close(sock); return -1; @@ -537,11 +538,11 @@ static BOOL server_connectSsl(epoll_server_t *server) server->sslConnected = FALSE; server->ssl = ssl_new(server->fd, server->serverData->sslContext); if (server->ssl == NULL) { - printf("Could not get SSL client from context\n"); + printf("[Proxy] Could not get SSL client from context\n"); return FALSE; } if (!ssl_connectServer(server)) { - printf("SSL connect failed.\n"); + printf("[Proxy] SSL connect to AD server %s failed.\n", server->serverData->addr); SSL_free(server->ssl); server->ssl = NULL; return FALSE; diff --git a/server.h b/server.h index 6c4d889..813634b 100644 --- a/server.h +++ b/server.h @@ -20,13 +20,17 @@ void server_setFingerprint(const char *server, const char *fingerprint); BOOL server_initServers(); +void server_free(epoll_server_t *server); + BOOL server_send(epoll_server_t *server, const char *buffer, size_t len, const BOOL cork); server_t *server_getFromBase(struct string *in); uint32_t server_searchRequest(server_t *server, struct SearchRequest *req); -uint32_t server_tryUserBind(server_t *server, struct string *binddn, struct string *password); +uint32_t server_searchRequestOnConnection(epoll_server_t *con, struct SearchRequest *req); + +uint32_t server_tryUserBind(server_t *server, struct string *binddn, struct string *password, epoll_server_t **newcon); #endif diff --git a/types.h b/types.h index 373b52a..183c41f 100644 --- a/types.h +++ b/types.h @@ -22,6 +22,8 @@ #define FALSE (0) typedef struct _server_t_ server_t; +typedef struct _epoll_client_t_ epoll_client_t; +typedef struct _epoll_server_t_ epoll_server_t; /** * General epoll struct, to be implemented by every epoll struct. @@ -44,7 +46,7 @@ typedef struct { /** * epoll struct for a client we're serving. */ -typedef struct { +struct _epoll_client_t_ { void (*callback)(void *data, int haveIn, int haveOut, int doCleanup); int fd; // @@ -56,15 +58,16 @@ typedef struct { size_t sbPos, sbFill, sbLen; SSL *ssl; // NULL if not encrypted char *sendBuffer; // Dynamically allocated, might or might not get huge + epoll_server_t *fixedServer; // If client performed explicit bind, tie to server connection // Recv buffer (client's request) size_t rbPos; char readBuffer[REQLEN]; // Static, queries > 4000 bytes simply not supported -} epoll_client_t; +}; /** * epoll struct for a connection to AD. */ -typedef struct { +struct _epoll_server_t_ { void (*callback)(void *data, int haveIn, int haveOut, int doCleanup); int fd; // @@ -72,6 +75,7 @@ typedef struct { size_t sbPos, sbFill, sbLen; SSL *ssl; // NULL if not encrypted char *sendBuffer; // Dynamically allocated, might or might not get huge + epoll_client_t *fixedClient; // If client performed explicit bind, this is the client belonging to this connection // Recv buffer (server's response) size_t rbPos; char readBuffer[MAXMSGLEN]; @@ -82,7 +86,7 @@ typedef struct { BOOL writeBlocked; // An SSL_write returned WANT_*, so we must not reallocate the current send buffer time_t lastActive; server_t *serverData; -} epoll_server_t; +}; /** * Configuration data for an ADS we're proxying. -- cgit v1.2.3-55-g7522