diff options
-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; |