From 8cf0202d2bccc7c74d7cbc23351c47416fb431d9 Mon Sep 17 00:00:00 2001 From: Simon Rettberg Date: Wed, 25 Feb 2015 17:51:59 +0100 Subject: "Support" feature query (done by sssd) --- proxy.c | 151 ++++++++++++++++++++++++++++++++++++++++++++++------------------ 1 file changed, 108 insertions(+), 43 deletions(-) (limited to 'proxy.c') diff --git a/proxy.c b/proxy.c index 38f94e9..22fbdbf 100644 --- a/proxy.c +++ b/proxy.c @@ -11,6 +11,7 @@ #include #define MAXPENDING 200 +#define MAX(a,b) ((a) > (b) ? (a) : (b)) typedef struct { @@ -47,7 +48,8 @@ static int _pendingCount = 0; static struct string s_shadowAccount, s_posixAccount, s_user, s_uid, s_sAMAccountName, s_objectSid; static struct string s_objectClass, s_objectclass, s_homeDirectory, s_gidNumber, s_gecos, s_cn, s_dn, s_posixGroup; static struct string s_loginShell, s_uidNumber, s_mail, s_objectCategory, s_memberOf, s_distinguishedName; -static struct string s_1001, s_homeMount, s_member, s_memberUid, s_realAccount; +static struct string s_3, s_1001, s_homeMount, s_member, s_memberUid, s_realAccount; +static struct string s_namingContexts, s_supportedControl, s_supportedExtension, s_supportedFeatures, s_supportedLDAPVersion, s_lastUSN, s_highestCommittedUSN; static struct string str_ADUSER; // HACK @@ -89,6 +91,7 @@ static BOOL proxy_serverBindResponse(epoll_server_t *server, const unsigned long static BOOL proxy_clientSearchRequest(epoll_client_t *client, const unsigned long messageId, const size_t offset, const size_t maxLen); static BOOL proxy_serverSearchResult(epoll_server_t *server, const unsigned long messageId, const unsigned long type, const size_t offset, const size_t maxLen); +static BOOL proxy_localFeatureReply(epoll_client_t *client, const unsigned long messageId); static BOOL proxy_localSearchRequest(epoll_client_t *client, const unsigned long messageId, const struct SearchRequest *req); // @@ -124,7 +127,15 @@ void proxy_init() SETSTR(member); SETSTR(memberUid); SETSTR(realAccount); + SETSTR(namingContexts); + SETSTR(supportedControl); + SETSTR(supportedExtension); + SETSTR(supportedFeatures); + SETSTR(supportedLDAPVersion); + SETSTR(lastUSN); + SETSTR(highestCommittedUSN); SETSTR(1001); + SETSTR(3); // TODO: configurable str_ADUSER.s = "ad_user"; str_ADUSER.l = strlen("ad_user"); @@ -234,10 +245,11 @@ static inline int iequals(struct string *a, struct string *b) //#define PREF(...) do { pref(spaces, prefix); printf(__VA_ARGS__); } while (0) static BOOL request_isUserFilter(struct Filter *filter); +static BOOL request_isServerCheck(struct AttributeDescriptionList* adl); static BOOL request_getGroupFilter(struct Filter *filter, struct string *wantedGroupName, uint32_t *wantedGroupId, BOOL *wantsMember); -static void request_replaceFilter(server_t *server, struct Filter *filter); +static void request_replaceFilter(server_t *server, struct Filter **filter); static void request_replaceAdl(server_t *server, struct AttributeDescriptionList **adl, attr_t *attr); -static void request_replaceAttribute(server_t *server, struct string *attribute, struct string *value, attr_t *attr); +static BOOL request_replaceAttribute(server_t *server, struct string *attribute, struct string *value, attr_t *attr); static BOOL request_isUserFilter(struct Filter *filter) { @@ -266,6 +278,22 @@ static BOOL request_isUserFilter(struct Filter *filter) return FALSE; } +static BOOL request_isServerCheck(struct AttributeDescriptionList* adl) +{ + int counter = 0; + for (; adl != NULL; adl = adl->next) { + if (equals(&adl->a, &s_namingContexts)) counter++; + if (equals(&adl->a, &s_supportedControl)) counter++; + if (equals(&adl->a, &s_supportedExtension)) counter++; + if (equals(&adl->a, &s_supportedLDAPVersion)) counter++; + if (equals(&adl->a, &s_supportedFeatures)) counter++; + if (equals(&adl->a, &s_lastUSN)) counter++; + if (equals(&adl->a, &s_highestCommittedUSN)) counter++; + if (counter > 3) return TRUE; + } + return FALSE; +} + /** * This is REALLY cheap. It doesn't really look at the logic operators in the filter as we assume that pam_ldap * or nss_ldap etc. won't do anything fancy like "!(objectClass=groupAccount)", just simple AND and OR combined @@ -304,27 +332,43 @@ static BOOL request_getGroupFilter(struct Filter *filter, struct string *wantedG return retval; } -static void request_replaceFilter(server_t *server, struct Filter *filter) +static void request_replaceFilter(server_t *server, struct Filter **filter) { - for (; filter != NULL; filter = filter->next) { - switch (filter->type) { + while (*filter != NULL) { + BOOL del = FALSE; + switch ((*filter)->type) { case NOT: case AND: case OR: - request_replaceFilter(server, filter->x); + request_replaceFilter(server, &(*filter)->x); + if ((*filter)->x == NULL) { + del = TRUE; + } break; case PRESENT: case SUBSTRING: - request_replaceAttribute(server, &filter->ava.desc, NULL, NULL); + if (!request_replaceAttribute(server, &(*filter)->ava.desc, NULL, NULL)) { + del = TRUE; + } break; case EQUAL: case GREATEQUAL: case LESSEQUAL: case APPROX: - request_replaceAttribute(server, &filter->ava.desc, &filter->ava.value, NULL); + if (!request_replaceAttribute(server, &(*filter)->ava.desc, &(*filter)->ava.value, NULL)) { + del = TRUE; + } break; default: break; } + if (del) { + struct Filter *old = *filter; + *filter = (*filter)->next; + old->next = NULL; + free_ldapsearchfilter(old); + } else { + filter = &(*filter)->next; + } } } @@ -354,31 +398,33 @@ static void request_replaceAdl(server_t *server, struct AttributeDescriptionList } #undef elifSETATTR -static void request_replaceAttribute(server_t *server, struct string *attribute, struct string *value, attr_t *attr) +static BOOL request_replaceAttribute(server_t *server, struct string *attribute, struct string *value, attr_t *attr) { if (equals(attribute, &s_uid)) { *attribute = s_sAMAccountName; if (attr) attr->hasUser = TRUE; // If uid is of format s[0-9]+, we assume that it's a numeric account name in AD, as a workaround - if (value == NULL) return; + if (value == NULL) return FALSE; fixUnNumeric(value); ////// ################### } else if (equals(attribute, &s_homeMount)) { *attribute = s_homeDirectory; if (attr != NULL) attr->homeMount = TRUE; } else if (iequals(attribute, &s_objectclass)) { - if (value == NULL) return; + if (value == NULL) return TRUE; if (equals(value, &s_shadowAccount)) *value = s_user; else if (equals(value, &s_posixAccount)) *value = s_user; } else if (equals(attribute, &s_uidNumber)) { *attribute = s_objectSid; - if (value == NULL) return; + if (value == NULL) return TRUE; + if (value != NULL && value->l == 1 && value->s[0] == '0') return FALSE; uint32_t tmp = 0; for (size_t i = 0; i < value->l; ++i) tmp = (tmp * 10) + (value->s[i] - '0'); memcpy(server->sid + (SIDLEN - 4), &tmp, 4); value->s = server->sid; value->l = SIDLEN; } + return TRUE; } // --------- AD to client replacements @@ -541,9 +587,14 @@ static BOOL proxy_clientSearchRequest(epoll_client_t *client, const unsigned lon struct SearchRequest req; const size_t res = scan_ldapsearchrequest(client->readBuffer + offset, client->readBuffer + maxLen, &req); if (res == 0) return FALSE; + if (req.scope == baseObject && request_isServerCheck(req.attributes)) { + const BOOL ret = proxy_localFeatureReply(client, messageId); + free_ldapsearchrequest(&req); + return ret; + } server_t *server = server_getFromBase(&req.baseObject); if (server == NULL) { - printf("scan_ldapsearchrequest: baseObj '%.*s' unknown.\n", (int)req.baseObject.l, req.baseObject.s); + printf("scan_ldapsearchrequest: 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); @@ -569,7 +620,8 @@ static BOOL proxy_clientSearchRequest(epoll_client_t *client, const unsigned lon } else { request_replaceAdl(server, &req.attributes, &pending->attr); } - request_replaceFilter(server, req.filter); + helper_printfilter(req.filter); + request_replaceFilter(server, &req.filter); helper_printfilter(req.filter); helper_printal(req.attributes); //printf("Attrs: "); @@ -710,6 +762,42 @@ static BOOL proxy_serverBindResponse(epoll_server_t *server, const unsigned long // ---- Local handling ---- + +static void prependPal(struct SearchResultEntry *dest, struct PartialAttributeList *pal, struct AttributeDescriptionList *adl, struct string *key, struct string *value) +{ + memset(pal, 0, sizeof *pal); + memset(adl, 0, sizeof *adl); + pal->next = dest->attributes; + dest->attributes = pal; + pal->type = *key; + pal->values = adl; + adl->a = *value; +} + +static BOOL proxy_localFeatureReply(epoll_client_t *client, const unsigned long messageId) +{ + printf("Sending fake feature request reply\n"); + struct SearchResultEntry sre; + struct PartialAttributeList vers; + struct AttributeDescriptionList versVal; + memset(&sre, 0, sizeof(sre)); + sre.objectName.l = 0; + prependPal(&sre, &vers, &versVal, &s_supportedLDAPVersion, &s_3); + // Build reply + const size_t bodyLen = fmt_ldapsearchresultentry(NULL, &sre); + const size_t headerLen = fmt_ldapmessage(NULL, messageId, SearchResultEntry, bodyLen); + const size_t doneLen = fmt_ldapsearchresultdone(NULL, success, "", "", ""); + const size_t doneHeaderLen = fmt_ldapmessage(NULL, messageId, SearchResultDone, doneLen); + size_t len = MAX(bodyLen + headerLen, doneLen + doneHeaderLen); + char buffer[len]; + fmt_ldapmessage(buffer, messageId, SearchResultEntry, bodyLen); + fmt_ldapsearchresultentry(buffer + headerLen, &sre); + client_send(client, buffer, headerLen + bodyLen, TRUE); + fmt_ldapmessage(buffer, messageId, SearchResultDone, doneLen); + fmt_ldapsearchresultdone(buffer + doneHeaderLen, success, "", "", ""); + return client_send(client, buffer, doneHeaderLen + doneLen, FALSE); +} + static BOOL proxy_localSearchRequest(epoll_client_t *client, const unsigned long messageId, const struct SearchRequest *req) { struct string name; @@ -722,44 +810,21 @@ static BOOL proxy_localSearchRequest(epoll_client_t *client, const unsigned long // posixGroup requested, but neither gidNumber nor cn requested, so it must be "list all" number = 1001; name.l = 1; - } else if (name.l != 0 && strncmp(name.s, "ad_user", name.l) != 0) { + } else if (!equals(&name, &str_ADUSER)) { // We know only one group... name.l = 0; } if (number == 1001 || name.l != 0) { // At least one of them was set printf("Sending fake group membership\n"); - // TODO: Helper for setting this stuff up struct SearchResultEntry sre; struct PartialAttributeList gidNumber, cn, objectClass; struct AttributeDescriptionList gidNumberVal, cnVal, objectClassVal; - //sre.objectName.l = snprintf(dnbuffer, BASELEN, "cn=ad_user,%.*s", (int)req->baseObject.l, req->baseObject.s); - //sre.objectName.s = dnbuffer; - //if (sre.objectName.l > BASELEN) sre.objectName.l = BASELEN; - sre.objectName.l = 0; memset(&sre, 0, sizeof(sre)); - memset(&gidNumber, 0, sizeof(gidNumber)); - memset(&cn, 0, sizeof(cn)); - memset(&cnVal, 0, sizeof(cnVal)); - cn.next = sre.attributes; - sre.attributes = &cn; - cn.type = s_cn; - cn.values = &cnVal; - cnVal.a = str_ADUSER; - memset(&gidNumber, 0, sizeof(gidNumber)); - memset(&gidNumberVal, 0, sizeof(gidNumberVal)); - gidNumber.next = sre.attributes; - sre.attributes = &gidNumber; - gidNumber.type = s_gidNumber; - gidNumber.values = &gidNumberVal; - gidNumberVal.a = s_1001; - memset(&objectClass, 0, sizeof(objectClass)); - memset(&objectClassVal, 0, sizeof(objectClassVal)); - objectClass.next = sre.attributes; - sre.attributes = &objectClass; - objectClass.type = s_objectClass; - objectClass.values = &objectClassVal; - objectClassVal.a = s_posixGroup; + sre.objectName.l = 0; + prependPal(&sre, &cn, &cnVal, &s_cn, &str_ADUSER); + prependPal(&sre, &gidNumber, &gidNumberVal, &s_gidNumber, &s_1001); + prependPal(&sre, &objectClass, &objectClassVal, &s_objectClass, &s_posixGroup); // Build reply const size_t bodyLen = fmt_ldapsearchresultentry(NULL, &sre); const size_t headerLen = fmt_ldapmessage(NULL, messageId, SearchResultEntry, bodyLen); -- cgit v1.2.3-55-g7522