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 --- proxy.c | 98 ++++++++++++++++++++++++++++++++++++++++------------------------- 1 file changed, 60 insertions(+), 38 deletions(-) (limited to 'proxy.c') 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); -- cgit v1.2.3-55-g7522