diff options
author | Simon Rettberg | 2015-10-23 12:38:53 +0200 |
---|---|---|
committer | Simon Rettberg | 2015-10-23 12:38:53 +0200 |
commit | c12db031150b104e8811828fbfb2a97b270caafd (patch) | |
tree | 089f5bb40d5d7d0246d11fc6ca7214bf026815af | |
parent | Update Makefile (diff) | |
download | ldadp-c12db031150b104e8811828fbfb2a97b270caafd.tar.gz ldadp-c12db031150b104e8811828fbfb2a97b270caafd.tar.xz ldadp-c12db031150b104e8811828fbfb2a97b270caafd.zip |
Send search requests to server only after bind succeeded.
There are server implementations that ignore a search request if
it is sent in the same packet as the bind request, apparently
leaving it in some server side buffer. If another search request
is received by the server afterwards, it suddenly discovers the first
search request, handles it, and then proceeds to handle the second one.
So we now buffer all search requests we want to forward to the server
until we received a positive bind response from the server.
-rw-r--r-- | server.c | 50 | ||||
-rw-r--r-- | types.h | 2 |
2 files changed, 44 insertions, 8 deletions
@@ -262,7 +262,13 @@ uint32_t server_tryUserBind(server_t *server, struct string *binddn, struct stri } fmt_ldapbindrequeststring(bufoff, 3, binddn, password); fmt_ldapmessage(bufoff - headerLen, id, BindRequest, bodyLen); - if (!server_send(con, bufoff - headerLen, bodyLen + headerLen, FALSE)) { + con->bindLen = (int)(bodyLen + headerLen); + if (con->bindLen < 0 || con->bindLen > BINDLEN) { + printf("[Server] Error: bind too long"); + con->bindLen = BINDLEN; + } + memcpy(con->bindBuffer, bufoff - headerLen, con->bindLen); + if (!server_haveOut(con)) { printf("[Server] Could not send user bindrequest to server %s\n", server->addr); server_free(con); return 0; @@ -336,13 +342,11 @@ static void server_callback(void *data, int haveIn, int haveOut, int doCleanup) server_free(server); return; } + if (!server->sslConnected) 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); - } + // 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 (doCleanup || server->kill) { server_free(server); @@ -351,6 +355,7 @@ static void server_callback(void *data, int haveIn, int haveOut, int doCleanup) static void server_haveIn(epoll_server_t *server) { + if (server->ssl != NULL && !server->sslConnected) return; for (;;) { if (server->rbPos >= MAXMSGLEN) { printf("[Proxy] Buffer overflow while reading from AD server. Disconnecting.\n"); @@ -445,6 +450,28 @@ BOOL server_send(epoll_server_t *server, const char *buffer, size_t len, const B static BOOL server_haveOut(epoll_server_t * const server) { if (server->kill) return FALSE; + if (server->ssl != NULL && !server->sslConnected) return TRUE; + // Bind not sent/acknowledged yet - send bind if pending, otherwise do nothing + if (!server->bound) { + if (server->bindLen == 0) return TRUE; + int ret; + if (server->ssl == NULL) { + ret = write(server->fd, server->bindBuffer, server->bindLen); + } else { + ret = SSL_write(server->ssl, server->bindBuffer, server->bindLen); + } + if (ret <= 0) { + printf("[Server] Flushing bind to LDAP/AD failed...\n"); + server->kill = TRUE; + return FALSE; + } + if (ret < server->bindLen) { + memmove(server->bindBuffer, server->bindBuffer + ret, server->bindLen - ret); + } + server->bindLen -= ret; + return TRUE; + } + // Only flush the regular send buffer (containing searches) if we know the bind succeeded while (server->sbPos < server->sbFill) { const ssize_t tosend = server->sbFill - server->sbPos; ssize_t ret; @@ -474,6 +501,7 @@ static BOOL server_haveOut(epoll_server_t * const server) server->kill = TRUE; return FALSE; // Closed } + server->writeBlocked = FALSE; } server->sbPos += ret; if (server->ssl != NULL) { @@ -534,7 +562,13 @@ static BOOL server_ensureConnected(server_t *server) con->kill = FALSE; fmt_ldapbindrequest(bufoff, 3, server->bind, server->password); fmt_ldapmessage(bufoff - headerLen, MSGID_BIND, BindRequest, bodyLen); - if (!server_send(con, bufoff - headerLen, bodyLen + headerLen, FALSE)) { + con->bindLen = (int)(bodyLen + headerLen); + if (con->bindLen < 0 || con->bindLen > BINDLEN) { + printf("[Server] Error: bind too long"); + con->bindLen = BINDLEN; + } + memcpy(con->bindBuffer, bufoff - headerLen, con->bindLen); + if (!server_haveOut(con)) { printf("[Server] Sending bindrequest for shared connection failed for server %s\n", server->addr); return FALSE; } @@ -76,6 +76,8 @@ struct _epoll_server_t_ { size_t sbPos, sbFill, sbLen; SSL *ssl; // NULL if not encrypted char *sendBuffer; // Dynamically allocated, might or might not get huge + char bindBuffer[BINDLEN]; // Used for the bind request. We need this to prevent sending any requests before the server acknowledged the bind request + int bindLen; // Length of buffered bind request 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; |