summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSimon Rettberg2017-05-29 15:47:03 +0200
committerSimon Rettberg2017-05-29 15:47:03 +0200
commitbf9f3a690ead4aa59f5dbae744503e90793f770f (patch)
tree6e4d4870886ca271d7c2b345cdd672cdee3214ce
parentAdd comment about tinyldap sources (diff)
downloadldadp-bf9f3a690ead4aa59f5dbae744503e90793f770f.tar.gz
ldadp-bf9f3a690ead4aa59f5dbae744503e90793f770f.tar.xz
ldadp-bf9f3a690ead4aa59f5dbae744503e90793f770f.zip
Support specifying custom attribute names for schema
-rw-r--r--ldadp.c2
-rw-r--r--proxy.c341
-rw-r--r--proxy.h2
-rw-r--r--server.c81
-rw-r--r--server.h2
-rw-r--r--types.h15
6 files changed, 217 insertions, 226 deletions
diff --git a/ldadp.c b/ldadp.c
index cad87ea..741df5d 100644
--- a/ldadp.c
+++ b/ldadp.c
@@ -140,6 +140,8 @@ static int loadConfig_handler(void *stuff, const char *section, const char *key,
server_setPort(section, value);
} else if (strcmp(key, "plainldap") == 0) {
server_setPlainLdap(section, value);
+ } else if (strncmp(key, "map.", 4) == 0) {
+ server_setMap(section, key+4, value);
} else {
printf("Unknown ADS config option '%s' for server '%s'\n", key, section);
}
diff --git a/proxy.c b/proxy.c
index 07c1b61..f3a5421 100644
--- a/proxy.c
+++ b/proxy.c
@@ -45,8 +45,8 @@ static struct string s_uid, s_sAMAccountName, s_objectSid, s_homeMount, s_member
static struct string s_objectClass, s_homeDirectory, s_gidNumber, s_gecos, s_cn, s_dn;
static struct string s_loginShell, s_uidNumber, s_mail, s_objectCategory, s_memberOf, s_distinguishedName;
// Some again in lowercase
-static struct string s_homemount, s_memberuid, s_realaccount, s_objectclass, s_homedirectory, s_gidnumber;
-static struct string s_uidnumber, s_memberof, s_distinguishedname, s_loginshell;
+static struct string s_samaccountname, s_objectsid, s_homemount, s_memberuid, s_realaccount, s_objectclass;
+static struct string s_homedirectory, s_gidnumber, s_uidnumber, s_memberof, s_distinguishedname, s_loginshell;
// Values
static struct string s_shadowAccount, s_posixAccount, s_posixGroup, s_3, s_1001, s_user, s_member;
// Feature query
@@ -138,6 +138,8 @@ void proxy_init()
SETSTR(highestCommittedUSN);
SETSTR(1001);
SETSTR(3);
+ SETSTR(samaccountname);
+ SETSTR(objectsid);
SETSTR(homemount);
SETSTR(memberuid);
SETSTR(realaccount);
@@ -154,6 +156,26 @@ void proxy_init()
}
#undef SETSTR
+void proxy_initDefaultMap(server_t *server)
+{
+ attr_map_t *m = &server->map;
+ if (server->plainLdap) {
+ if (m->homemount.l == 0) m->homemount = s_homemount;
+ if (m->localhome.l == 0) m->localhome = s_homedirectory;
+ if (m->posixAccount.l == 0) m->posixAccount = s_posixAccount;
+ if (m->shadowAccount.l == 0) m->shadowAccount = s_shadowAccount;
+ if (m->uid.l == 0) m->uid = s_uid;
+ if (m->uidnumber.l == 0) m->uidnumber = s_uidnumber;
+ } else {
+ if (m->homemount.l == 0) m->homemount = s_homedirectory;
+ if (m->localhome.l == 0) m->localhome = s_supportedLDAPVersion; // Unused, use something long and unlikely
+ if (m->posixAccount.l == 0) m->posixAccount = s_user;
+ if (m->shadowAccount.l == 0) m->shadowAccount = s_user;
+ if (m->uid.l == 0) m->uid = s_samaccountname;
+ if (m->uidnumber.l == 0) m->uidnumber = s_objectsid;
+ }
+}
+
BOOL proxy_fromClient(epoll_client_t *client, const size_t maxLen)
{
unsigned long messageId, op;
@@ -283,6 +305,7 @@ static void pref(int spaces, char prefix)
static inline int equals(struct string *a, struct string *b)
{
if (a->l != b->l) return 0;
+ if (a->s == b->s) return 1;
return strncmp(a->s, b->s, a->l) == 0;
}
@@ -292,6 +315,7 @@ static inline int equals(struct string *a, struct string *b)
static inline int iequals(const struct string * const a, const struct string * const b)
{
if (a->l != b->l) return 0;
+ if (a->s == b->s) return 1;
for (size_t i = 0; i < a->l; ++i) {
if (tolower(a->s[i]) != b->s[i]) return 0;
}
@@ -307,9 +331,11 @@ static BOOL request_getGroupFilter(struct Filter *filter, struct string *wantedG
static void request_replaceFilter(server_t *server, struct Filter **filter);
static void request_replaceAdl(server_t *server, struct AttributeDescriptionList **adl, attr_t *attr);
static BOOL request_replaceAttribute(server_t *server, struct string *attribute, struct string *value, attr_t *attr);
-static void request_replaceAdlLdap(server_t *server, struct AttributeDescriptionList **adl, attr_t *attr);
-static BOOL request_replaceAttributeLdap(server_t *server, struct string *attribute, struct string *value, attr_t *attr);
+/**
+ * Checks whether the filter contains attributes that indicate this is a search for a user.
+ * Expects pre-replacement attribute names.
+ */
static BOOL request_isUserFilter(struct Filter *filter)
{
for (; filter != NULL; filter = filter->next) {
@@ -436,14 +462,19 @@ static void request_replaceFilter(server_t *server, struct Filter **filter)
#define elifSETATTR(MATCH,TOSET) else if (iequals(&(*adl)->a, &s_ ## MATCH)) attr->TOSET = TRUE, next = (*adl)->next, free(*adl), *adl = next
static void request_replaceAdl(server_t *server, struct AttributeDescriptionList **adl, attr_t *attr)
{
- if (server->plainLdap) {
- request_replaceAdlLdap(server, adl, attr);
- return;
- }
while (*adl != NULL) {
struct AttributeDescriptionList *next = NULL;
if (attr == NULL) { }
- elifSETATTR(homedirectory, homeDirectory);
+ else if (iequals(&(*adl)->a, &s_homedirectory)) {
+ attr->homeDirectory = TRUE;
+ if (server->plainLdap) {
+ (*adl)->a = server->map.localhome;
+ } else {
+ next = (*adl)->next;
+ free(*adl);
+ *adl = next;
+ }
+ }
elifSETATTR(gidnumber, gidNumber);
elifSETATTR(gecos, gecos);
elifSETATTR(realaccount, realAccount);
@@ -455,87 +486,51 @@ static void request_replaceAdl(server_t *server, struct AttributeDescriptionList
if (!attr->hasUser) {
if (attr->homeDirectory || attr->gecos || attr->homeMount) {
struct AttributeDescriptionList *user = calloc(1, sizeof(struct AttributeDescriptionList));
- user->a = s_sAMAccountName;
+ user->a = server->map.uid;
user->next = *adl;
*adl = user;
}
}
}
+/**
+ * @return FALSE = delete attribute, TRUE = keep
+ */
static BOOL request_replaceAttribute(server_t *server, struct string *attribute, struct string *value, attr_t *attr)
{
- if (server->plainLdap) {
- return request_replaceAttributeLdap(server, attribute, value, attr);
- }
if (iequals(attribute, &s_uid)) {
- *attribute = s_sAMAccountName;
+ *attribute = server->map.uid;
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 FALSE;
fixUnNumeric(value);
////// ###################
} else if (iequals(attribute, &s_homemount)) {
- if (server->homeAttrLower.s == NULL) {
- *attribute = s_homeDirectory;
- } else {
- *attribute = server->homeAttr;
- }
+ *attribute = server->map.homemount;
if (attr != NULL) attr->homeMount = TRUE;
} else if (iequals(attribute, &s_objectclass)) {
if (value == NULL) return TRUE;
- if (equals(value, &s_shadowAccount)) *value = s_user;
- else if (equals(value, &s_posixAccount)) *value = s_user;
+ if (equals(value, &s_shadowAccount)) *value = server->map.shadowAccount;
+ else if (equals(value, &s_posixAccount)) *value = server->map.posixAccount;
} else if (iequals(attribute, &s_uidnumber)) {
- *attribute = s_objectSid;
+ *attribute = server->map.uidnumber;
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;
-}
-
-// ----------------- LDAP to LDAP handling
-
-static void request_replaceAdlLdap(server_t *server, struct AttributeDescriptionList **adl, attr_t *attr)
-{
- while (*adl != NULL) {
- struct AttributeDescriptionList *next = NULL;
- if (attr == NULL) { }
- else if (iequals(&(*adl)->a, &s_homedirectory)) attr->homeDirectory = TRUE;
- elifSETATTR(gidnumber, gidNumber);
- elifSETATTR(gecos, gecos);
- elifSETATTR(realaccount, realAccount);
- elifSETATTR(loginshell, loginShell);
- else request_replaceAttributeLdap(server, &(*adl)->a, NULL, attr);
- if (*adl == NULL) break;
- if (next == NULL) adl = &(*adl)->next; // If next is not NULL, we removed an entry, so we don't need to shift
- }
- if (!attr->hasUser) {
- if (attr->homeDirectory || attr->gecos || attr->homeMount) {
- struct AttributeDescriptionList *user = calloc(1, sizeof(struct AttributeDescriptionList));
- user->a = s_uid;
- user->next = *adl;
- *adl = user;
+ if (value != NULL && value->l == 1 && value->s[0] == '0') {
+ // Query for user with uidNumber == 0 - root; replace with something that
+ // should never return anything
+ *value = s_uid;
+ }
+ if (!server->plainLdap) {
+ 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;
}
- }
-}
-
-static BOOL request_replaceAttributeLdap(server_t *server, struct string *attribute, struct string *value, attr_t *attr)
-{
- if (iequals(attribute, &s_uid)) {
- if (attr) attr->hasUser = TRUE;
- // If uid is of format s[0-9]+, we assume that it's a numeric account name, as a workaround
- if (value == NULL) return FALSE;
- fixUnNumeric(value);
- } else if (iequals(attribute, &s_homemount)) {
- if (attr != NULL) attr->homeMount = TRUE;
}
return TRUE;
}
+
#undef elifSETATTR
// ----- Sanitize requested attributes by whitelist
@@ -548,6 +543,11 @@ static void prependAdl(struct AttributeDescriptionList **adl, struct string *str
*adl = item;
}
+/**
+ * Add all the default attributes we're interested in in our context to the
+ * given ADL from a client. Pre-relace/map, with names corresponding to
+ * our expected names.
+ */
static void request_addDefaultAttributes(struct AttributeDescriptionList **adl)
{
prependAdl(adl, &s_uid);
@@ -563,6 +563,11 @@ static void request_addDefaultAttributes(struct AttributeDescriptionList **adl)
}
#define S_EQ(wat) iequals(str, &s_ ## wat)
+/**
+ * Filter all requested attributes which are not on our whitelist.
+ * Attribute names are pre-replacement, directly what the client sends us, before
+ * mapping to scheme expected by server.
+ */
static void request_filterRequestedAttributes(struct AttributeDescriptionList **adl)
{
while (*adl != NULL) {
@@ -585,50 +590,52 @@ static void request_filterRequestedAttributes(struct AttributeDescriptionList **
static void response_replacePal(server_t *server, struct PartialAttributeList **pal, attr_t *attr);
static void response_replaceAdl(server_t *server, struct string *type, struct AttributeDescriptionList **adl, attr_t *attr);
-static void response_replaceAttribute(server_t *server, struct string *attribute, struct string *value);
-static void response_replacePalLdap(server_t *server, struct PartialAttributeList **pal, attr_t *attr);
-static void response_replaceAdlLdap(server_t *server, struct string *type, struct AttributeDescriptionList **adl, attr_t *attr);
-static void response_replaceAttributeLdap(server_t *server, struct string *attribute, struct string *value);
+static void response_replaceAttribute(server_t *server, struct string * const attribute, struct string * const value);
static BOOL response_filterHomeDir(struct PartialAttributeList *pal);
static BOOL response_filterLocalHomeDir(struct PartialAttributeList *pal);
static struct PartialAttributeList* response_addPal(struct PartialAttributeList *pal, struct string *attribute, const char *format, ...);
#define ADDATTR(x,...) do { if (attr->x) *pal = response_addPal(*pal, &s_ ## x, __VA_ARGS__); } while (0)
-#define elifDELATTR(MATCH,FIELD) else if (iequals(&(*pal)->type, &s_ ## MATCH)) next = (*pal)->next, del = TRUE, attr->FIELD = TRUE
-#define elifDEL(MATCH) else if (iequals(&(*pal)->type, &s_ ## MATCH)) next = (*pal)->next, del = TRUE
+#define elifDELATTR(MATCH,FIELD,...) else if (__VA_ARGS__ (iequals(&(*pal)->type, &s_ ## MATCH)) ) del = TRUE, attr->FIELD = TRUE
+#define elifDEL(MATCH) else if (iequals(&(*pal)->type, &s_ ## MATCH)) del = TRUE
static void response_replacePal(server_t *server, struct PartialAttributeList **pal, attr_t *attr)
{
- if (server->plainLdap) {
- return response_replacePalLdap(server, pal, attr);
- }
struct string *username = NULL;
- struct AttributeDescriptionList *lastObjectClass = NULL;
- struct PartialAttributeList *next = NULL;
BOOL wasNumeric = FALSE;
while (*pal != NULL) {
BOOL del = FALSE;
- if (0) { } // Remove fields we don't want from AD
+ if (0) { } // Remove fields we don't want from AD/LDAP
elifDELATTR(gidnumber, gidNumber);
elifDELATTR(gecos, gecos);
elifDELATTR(loginshell, loginShell);
- elifDELATTR(uidnumber, uidNumber);
+ elifDELATTR(uidnumber, uidNumber, !server->plainLdap &&);
elifDEL(mail);
elifDELATTR(cn, cn);
elifDEL(memberof);
- else if ( (server->homeAttrLower.s == NULL && iequals(&(*pal)->type, &s_homedirectory))
- || (server->homeAttrLower.s != NULL && iequals(&(*pal)->type, &server->homeAttrLower)) ) {
+ else if (iequals(&(*pal)->type, &server->map.homemount)) {
// homeDirectory is set in AD - it can either be a local path (in which case it's useless)
// or a UNC path, which we can easily mount via mount.cifs
if (!response_filterHomeDir(*pal)) {
+ // Not UNC, ignore and generate later if possible
del = TRUE;
attr->homeMount = TRUE;
- next = (*pal)->next;
} else {
attr->homeMount = FALSE;
+ (*pal)->type = s_homeMount;
+ }
+ }
+ else if (iequals(&(*pal)->type, &server->map.localhome)) {
+ // homeDirectory is set in LDAP - use if it's a local path
+ if(response_filterLocalHomeDir(*pal)) {
+ attr->homeDirectory = FALSE;
+ (*pal)->type = s_homeDirectory;
+ } else {
+ del = TRUE;
}
}
// Entry should be removed, free structs
if (del) {
+ struct PartialAttributeList *next = (*pal)->next;
free_ldapadl((*pal)->values);
free(*pal);
*pal = next;
@@ -640,45 +647,33 @@ static void response_replacePal(server_t *server, struct PartialAttributeList **
username = &(*pal)->values->a;
if (username->l > 1 && username->s[0] == 's' && isInt(username, 1)) wasNumeric = TRUE;
}
- // Map objectClass user back to posixAccount and shadowAccount
- if (lastObjectClass == NULL && iequals(&(*pal)->type, &s_objectclass)) {
- BOOL hasUser = FALSE;
- for (struct AttributeDescriptionList *adl = (*pal)->values; adl != NULL; adl = adl->next) {
- if (!hasUser && iequals(&adl->a, &s_user)) hasUser = TRUE;
- if (hasUser && adl->next == NULL) lastObjectClass = adl;
- }
- }
pal = &(*pal)->next;
}
if (username != NULL) {
char *user = tmpbuffer_get();
snprintf(user, TMPLEN, "%.*s", (int)username->l, username->s);
- ADDATTR(homeDirectory, "/home/%s", user);
+ if (attr->homeDirectory) {
+ 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 (wasNumeric) user++; // From here on, user is the real AD/ldap username, no leading 's'
if (attr->homeMount && server->homeTemplate[0] != '\0') {
ADDATTR(homeMount, server->homeTemplate, user, user, user, user, user, user);
}
// Do this here so user++ will have been executed
ADDATTR(realAccount, "%s", user);
}
- if (lastObjectClass != NULL) {
- ADDATTR(loginShell, "/bin/bash");
- ADDATTR(gidNumber, "1001");
- // TODO: Nicer
- lastObjectClass->next = calloc(1, sizeof(struct AttributeDescriptionList));
- lastObjectClass->next->a = s_posixAccount;
- lastObjectClass = lastObjectClass->next;
- lastObjectClass->next = calloc(1, sizeof(struct AttributeDescriptionList));
- lastObjectClass->next->a = s_shadowAccount;
- }
+ ADDATTR(loginShell, "/bin/bash");
+ ADDATTR(gidNumber, "1001");
}
-static void response_replaceAdl(server_t *server, struct string *type, struct AttributeDescriptionList **adl, attr_t *attr)
+static void response_replaceAdl(server_t *server, struct string *attribute, struct AttributeDescriptionList **adl, attr_t *attr)
{
- if (server->plainLdap) {
- return response_replaceAdlLdap(server, type, adl, attr);
+ if (iequals(attribute, &server->map.uid)) {
+ *attribute = s_uid;
+ } else if (iequals(attribute, &server->map.uidnumber)) {
+ *attribute = s_uidNumber;
}
while (*adl != NULL) {
struct AttributeDescriptionList *next = NULL;
@@ -688,34 +683,43 @@ static void response_replaceAdl(server_t *server, struct string *type, struct At
*adl = next;
continue;
}
- response_replaceAttribute(server, type, &(*adl)->a);
+ response_replaceAttribute(server, attribute, &(*adl)->a);
adl = &(*adl)->next; // If next is not NULL, we removed an entry, so we don't need to shift
}
}
-static void response_replaceAttribute(server_t *server, struct string *attribute, struct string *value)
+static void response_replaceAttribute(server_t *server, struct string * const attribute, struct string * const value)
{
- if (server->plainLdap) {
- return response_replaceAttributeLdap(server, attribute, value);
- }
- if (equals(attribute, &s_sAMAccountName)) {
+ if (iequals(attribute, &server->map.uid)) {
*attribute = s_uid;
if (value != NULL) fixNumeric(value);
- } else if (equals(attribute, &s_objectSid)) {
+ } else if (iequals(attribute, &server->map.uidnumber)) {
*attribute = s_uidNumber;
- if (value == NULL) return;
- if (value->l != SIDLEN) return;
- // It we don't have the servers SID base yet and we see a valid one, store it
- if (server->sid[0] == 0 && value->s[0] == 1 && value->s[1] == 5 && value->s[7] == 5) {
- memcpy(server->sid, value->s, SIDLEN - 4);
+ if (!server->plainLdap) {
+ // If this is AD, this must have been objectSid before - convert SID to number
+ if (value == NULL) return;
+ if (value->l != SIDLEN) return;
+ // It we don't have the servers SID base yet and we see a valid one, store it
+ if (server->sid[0] == 0 && value->s[0] == 1 && value->s[1] == 5 && value->s[7] == 5) {
+ memcpy(server->sid, value->s, SIDLEN - 4);
+ }
+ int tmp;
+ memcpy(&tmp, value->s + (value->l - 4), 4);
+ // We know value->s is in our receive buffer and there are 28 bytes available, so we reuse the buffer
+ value->l = snprintf((char*)value->s, value->l, "%u", tmp);
+ }
+ } else if (iequals(attribute, &s_objectclass)) {
+ if (equals(value, &server->map.posixAccount)) {
+ *value = s_posixAccount;
+ } else if (equals(value, &server->map.shadowAccount)) {
+ *value = s_shadowAccount;
}
- int tmp;
- memcpy(&tmp, value->s + (value->l - 4), 4);
- // We know value->s is in our receive buffer and there are 28 bytes available, so we reuse the buffer
- value->l = snprintf((char*)value->s, value->l, "%u", tmp);
}
}
+/**
+ * Remove every attribute except one that looks like a local home directory path.
+ */
static BOOL response_filterHomeDir(struct PartialAttributeList *pal)
{
for (struct AttributeDescriptionList *adl = pal->values; adl != NULL; adl = pal->values /* sic */) {
@@ -736,6 +740,9 @@ static BOOL response_filterHomeDir(struct PartialAttributeList *pal)
return FALSE;
}
+/**
+ * Remove every attribute except one that looks like a UNC path.
+ */
static BOOL response_filterLocalHomeDir(struct PartialAttributeList *pal)
{
for (struct AttributeDescriptionList *adl = pal->values; adl != NULL; adl = pal->values /* sic */) {
@@ -743,6 +750,7 @@ static BOOL response_filterLocalHomeDir(struct PartialAttributeList *pal)
if (adl->a.l > 0 && adl->a.s[0] == '/') {
free_ldapadl(adl->next);
adl->next = NULL;
+ pal->type = s_homeDirectory;
return TRUE;
}
}
@@ -756,99 +764,16 @@ static struct PartialAttributeList* response_addPal(struct PartialAttributeList
{
struct PartialAttributeList *next = malloc(sizeof(struct PartialAttributeList));
va_list args;
- va_start(args, format);
next->next = pal;
next->type = *attribute;
next->values = malloc(sizeof(struct AttributeDescriptionList));
+ va_start(args, format);
tmpbuffer_formatva(&next->values->a, format, args);
- next->values->next = NULL;
va_end(args);
+ next->values->next = NULL;
return next;
}
-// ---- replace response for LDAP to LDAP
-
-static void response_replacePalLdap(server_t *server, struct PartialAttributeList **pal, attr_t *attr)
-{
- struct string *username = NULL;
- struct PartialAttributeList *next = NULL;
- BOOL wasNumeric = FALSE;
- while (*pal != NULL) {
- BOOL del = FALSE;
- if (0) { } // Remove fields we don't want from AD
- elifDELATTR(gidnumber, gidNumber);
- elifDELATTR(gecos, gecos);
- elifDELATTR(loginshell, loginShell);
- elifDEL(mail);
- elifDELATTR(cn, cn);
- elifDEL(memberOf);
- else if (iequals(&(*pal)->type, &s_homedirectory)) {
- // homeDirectory is set in LDAP - use if it's a local path
- if(response_filterLocalHomeDir(*pal)) {
- attr->homeDirectory = FALSE;
- } else {
- next = (*pal)->next;
- del = TRUE;
- }
- }
- // Entry should be removed, free structs
- if (del) {
- free_ldapadl((*pal)->values);
- free(*pal);
- *pal = next;
- continue;
- }
- response_replaceAdlLdap(server, &(*pal)->type, &(*pal)->values, attr);
- // Fetch user name so we can add our fake fields later
- if (username == NULL && iequals(&(*pal)->type, &s_uid)) {
- username = &(*pal)->values->a;
- if (username->l > 1 && username->s[0] == 's' && isInt(username, 1)) wasNumeric = TRUE;
- }
- pal = &(*pal)->next;
- }
- if (username != NULL) {
- char *user = tmpbuffer_get();
- snprintf(user, TMPLEN, "%.*s", (int)username->l, username->s);
- if (attr->homeDirectory) {
- ADDATTR(homeDirectory, "/home/%s", user);
- }
- ADDATTR(gecos, "%s,,,", user);
- ADDATTR(cn, "%s", user);
- if (wasNumeric) user++; // From here on, user is the real ldap username, no leading 's'
- if (attr->homeMount && server->homeTemplate[0] != '\0') {
- ADDATTR(homeMount, server->homeTemplate, user, user, user, user, user, user);
- }
- // Do this here so user++ will have been executed
- ADDATTR(realAccount, "%s", user);
- }
- ADDATTR(loginShell, "/bin/bash");
- ADDATTR(gidNumber, "1001");
-}
-#undef ADDATTR
-#undef elifDELATTR
-
-static void response_replaceAdlLdap(server_t *server, struct string *type, struct AttributeDescriptionList **adl, attr_t *attr)
-{
- while (*adl != NULL) {
- struct AttributeDescriptionList *next = NULL;
- // Maybe delete entries here later
- if (next != NULL) {
- free(*adl);
- *adl = next;
- continue;
- }
- response_replaceAttributeLdap(server, type, &(*adl)->a);
- adl = &(*adl)->next; // If next is not NULL, we removed an entry, so we don't need to shift
- }
-}
-
-static void response_replaceAttributeLdap(server_t *server, struct string *attribute, struct string *value)
-{
- if (iequals(attribute, &s_uid)) {
- if (value != NULL) fixNumeric(value);
- }
-}
-
// -----
static BOOL proxy_clientSearchRequest(epoll_client_t *client, const unsigned long messageId, const size_t offset, const size_t maxLen)
@@ -897,9 +822,7 @@ static BOOL proxy_clientSearchRequest(epoll_client_t *client, const unsigned lon
if (req.attributes == NULL) {
if (client->fixedServer == NULL) {
request_addDefaultAttributes(&req.attributes);
- if (!server->plainLdap) {
- request_replaceAdl(server, &req.attributes, &pending->attr);
- }
+ request_replaceAdl(server, &req.attributes, &pending->attr);
}
memset(&pending->attr, -1, sizeof(pending->attr));
}
diff --git a/proxy.h b/proxy.h
index f9a781e..44d971d 100644
--- a/proxy.h
+++ b/proxy.h
@@ -13,4 +13,6 @@ void proxy_removeServer(epoll_server_t * const server);
BOOL proxy_fromServer(epoll_server_t *server, const size_t maxLen);
+void proxy_initDefaultMap(server_t *server);
+
#endif
diff --git a/server.c b/server.c
index 22f6085..ae6a4ae 100644
--- a/server.c
+++ b/server.c
@@ -63,6 +63,52 @@ void server_setPlainLdap(const char *server, const char *enabledStr)
|| strcmp(enabledStr, "True") == 0 || strcmp(enabledStr, "TRUE") == 0;
}
+static void strtolower(char *str)
+{
+ while (*str != '\0') {
+ *str = tolower(*str);
+ ++str;
+ }
+}
+
+void server_setMap(const char *server, const char *attribute, const char *value)
+{
+ if (value == NULL || *value == '\0') {
+ printf("Warning: Ignoring empty mapping option '%s'\n", attribute);
+ return;
+ }
+ server_t *entry = server_create(server);
+ if (entry == NULL) return;
+ struct string *s = NULL;
+ BOOL lower = TRUE;
+ if (strcmp(attribute, "homemount") == 0) {
+ s = &entry->map.homemount;
+ } else if (strcmp(attribute, "localhome") == 0) {
+ s = &entry->map.localhome;
+ } else if (strcmp(attribute, "posixAccount") == 0) {
+ s = &entry->map.posixAccount;
+ lower = FALSE;
+ } else if (strcmp(attribute, "shadowAccount") == 0) {
+ s = &entry->map.shadowAccount;
+ lower = FALSE;
+ } else if (strcmp(attribute, "uid") == 0) {
+ s = &entry->map.uid;
+ } else if (strcmp(attribute, "uidnumber") == 0) {
+ s = &entry->map.uidnumber;
+ }
+ if (s == NULL) {
+ printf("Warning: Invalid mapping option: '%s'\n", attribute);
+ return;
+ }
+ free((void*)s->s);
+ char *tmp = strdup(value);
+ if (lower) {
+ strtolower(tmp);
+ }
+ s->s = tmp;
+ s->l = strlen(value);
+}
+
void server_setBind(const char *server, const char *bind)
{
server_t *entry = server_create(server);
@@ -126,16 +172,9 @@ void server_setHomeAttribute(const char *server, const char *homeattribute)
{
server_t *entry = server_create(server);
if (entry == NULL || entry->sslContext != NULL) return;
- free((void*)entry->homeAttr.s);
- free((void*)entry->homeAttrLower.s);
- entry->homeAttr.l = strlen(homeattribute);
- entry->homeAttrLower.l = entry->homeAttr.l;
- entry->homeAttr.s = strdup(homeattribute);
- char *tmp = strdup(homeattribute);
- for (size_t i = 0; i < entry->homeAttrLower.l; ++i) {
- tmp[i] = tolower(tmp[i]);
- }
- entry->homeAttrLower.s = tmp;
+ free((void*)entry->map.homemount.s);
+ entry->map.homemount.s = strdup(homeattribute);
+ entry->map.homemount.l = strlen(homeattribute);
}
void server_setFingerprint(const char *server, const char *fingerprint)
@@ -183,12 +222,24 @@ BOOL server_initServers()
int i;
printf("%d servers configured.\n", serverCount);
for (i = 0; i < serverCount; ++i) {
- if (servers[i].cabundle[0] != '\0' || memcmp(servers[i].fingerprint, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) != 0) {
- servers[i].sslContext = ssl_newClientCtx(servers[i].cabundle);
+ server_t *server = &servers[i];
+ if (server->cabundle[0] != '\0' || memcmp(server->fingerprint, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) != 0) {
+ // Have cabundle or fingerprint - use SSL to talk to server
+ server->sslContext = ssl_newClientCtx(server->cabundle);
+ }
+ printf("%s:\n Bind: %s\n Base: %s\n", server->addr, server->bind, server->base);
+ printf("Plain LDAP-LDAP: %d\n", (int)server->plainLdap);
+ // Fixup & print attribute map
+ proxy_initDefaultMap(server);
+ printf("uid: '%.*s'\n", (int)server->map.uid.l, server->map.uid.s);
+ printf("uidnumber: '%.*s'\n", (int)server->map.uidnumber.l, server->map.uidnumber.s);
+ printf("homemount: '%.*s'\n", (int)server->map.homemount.l, server->map.homemount.s);
+ if (server->plainLdap) {
+ printf("localhome: '%.*s'\n", (int)server->map.localhome.l, server->map.localhome.s);
}
- printf("%s:\n Bind: %s\n Base: %s\n", servers[i].addr, servers[i].bind, servers[i].base);
- printf("Plain LDAP-LDAP: %d\n", (int)servers[i].plainLdap);
- if (!server_ensureConnected(&servers[i]))
+ printf("objectClass posixAccount: '%.*s'\n", (int)server->map.posixAccount.l, server->map.posixAccount.s);
+ printf("objectClass shadowAccount: '%.*s'\n", (int)server->map.shadowAccount.l, server->map.shadowAccount.s);
+ if (!server_ensureConnected(server))
return FALSE;
}
connectionInitDone = TRUE;
diff --git a/server.h b/server.h
index 3d9d73b..6e5ac88 100644
--- a/server.h
+++ b/server.h
@@ -10,6 +10,8 @@ void server_setPort(const char *server, const char *portStr);
void server_setPlainLdap(const char *server, const char *enabledStr);
+void server_setMap(const char *server, const char *attribute, const char *value);
+
void server_setBind(const char *server, const char *bind);
void server_setPassword(const char *server, const char *password);
diff --git a/types.h b/types.h
index 57f790f..19477fb 100644
--- a/types.h
+++ b/types.h
@@ -93,6 +93,18 @@ struct _epoll_server_t_ {
};
/**
+ * Struct for mapping attribute names/values
+ */
+typedef struct {
+ struct string uid; // AD: sAMAccountName
+ struct string homemount; // AD: homeDirectory
+ struct string localhome; // AD: none, LDAP: homeDirectory
+ struct string posixAccount; // AD: user
+ struct string shadowAccount; // AD: user
+ struct string uidnumber; // AD: objectSid
+} attr_map_t;
+
+/**
* Configuration data for an ADS we're proxying.
*/
struct _server_t_ {
@@ -105,14 +117,13 @@ struct _server_t_ {
char base[BASELEN];
char sid[SIDLEN];
char homeTemplate[MOUNTLEN];
- struct string homeAttr;
- struct string homeAttrLower;
unsigned char fingerprint[FINGERPRINTLEN];
char cabundle[MAXPATH];
BOOL plainLdap;
uint16_t port;
SSL_CTX *sslContext;
epoll_server_t con;
+ attr_map_t map;
};
#endif