summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSimon Rettberg2015-02-25 17:51:59 +0100
committerSimon Rettberg2015-02-25 17:51:59 +0100
commit8cf0202d2bccc7c74d7cbc23351c47416fb431d9 (patch)
tree02d3aa58fe5bb4254a88edd217e2603f580f52a7
parentFix formatting bug in print filter function; skip NULL filters (which would b... (diff)
downloadldadp-8cf0202d2bccc7c74d7cbc23351c47416fb431d9.tar.gz
ldadp-8cf0202d2bccc7c74d7cbc23351c47416fb431d9.tar.xz
ldadp-8cf0202d2bccc7c74d7cbc23351c47416fb431d9.zip
"Support" feature query (done by sssd)
-rw-r--r--proxy.c151
1 files changed, 108 insertions, 43 deletions
diff --git a/proxy.c b/proxy.c
index 38f94e9..22fbdbf 100644
--- a/proxy.c
+++ b/proxy.c
@@ -11,6 +11,7 @@
#include <stdarg.h>
#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);