summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSimon Rettberg2015-10-23 12:38:53 +0200
committerSimon Rettberg2015-10-23 12:38:53 +0200
commitc12db031150b104e8811828fbfb2a97b270caafd (patch)
tree089f5bb40d5d7d0246d11fc6ca7214bf026815af
parentUpdate Makefile (diff)
downloadldadp-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.c50
-rw-r--r--types.h2
2 files changed, 44 insertions, 8 deletions
diff --git a/server.c b/server.c
index 3d02eb4..c4eb37d 100644
--- a/server.c
+++ b/server.c
@@ -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;
}
diff --git a/types.h b/types.h
index 23888db..faa5292 100644
--- a/types.h
+++ b/types.h
@@ -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;