From 87a5f72b2eef3beb10ad50bfbd2a131bd278e67b Mon Sep 17 00:00:00 2001 From: Simon Rettberg Date: Wed, 19 Mar 2014 14:14:06 +0100 Subject: Work --- ldadp.c | 3 +++ proxy.c | 74 +++++++++++++++++++++++++++++++++++++++++++++++++++++----------- server.c | 21 ++++++++++++++++++ server.h | 2 ++ types.h | 2 ++ 5 files changed, 90 insertions(+), 12 deletions(-) diff --git a/ldadp.c b/ldadp.c index 90647df..9c9a579 100644 --- a/ldadp.c +++ b/ldadp.c @@ -75,6 +75,9 @@ static int loadConfig_handler(void *stuff, const char *section, const char *key, if (strcmp(key, "base") == 0) { server_setBase(section, value); } + if (strcmp(key, "home") == 0) { + server_setHomeTemplate(section, value); + } return 1; } diff --git a/proxy.c b/proxy.c index c396cc7..b49946c 100644 --- a/proxy.c +++ b/proxy.c @@ -15,11 +15,14 @@ typedef struct { BOOL homeDirectory; + BOOL homeMount; BOOL gidNumber; BOOL gecos; BOOL loginShell; BOOL uid; BOOL uidNumber; + // Internal + BOOL hasUser; } attr_t; typedef struct @@ -42,7 +45,7 @@ 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; +static struct string s_1001, s_homeMount; static struct string str_ADUSER; // @@ -73,6 +76,7 @@ void proxy_init() SETSTR(objectClass); SETSTR(objectclass); SETSTR(homeDirectory); + SETSTR(homeMount); SETSTR(gidNumber); SETSTR(gecos); SETSTR(loginShell); @@ -196,7 +200,7 @@ static BOOL request_isUserFilter(struct Filter *filter); static BOOL request_getGroupFilter(struct Filter *filter, struct string *wantedGroupName, uint32_t *wantedGroupId); 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); +static void request_replaceAttribute(server_t *server, struct string *attribute, struct string *value, attr_t *attr); static BOOL request_isUserFilter(struct Filter *filter) { @@ -229,6 +233,11 @@ static BOOL request_isUserFilter(struct Filter *filter) * 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 * with EQUAL. + * You could actually get real group memberships using the memberOf attributes of the user, and do additional + * queries for these groups, but for that to make any sense you'd also have to implement useful permission + * handling.... So as all we really want is authentication and optionally mounting a home directory, we pretend + * there is just one group with id 1001 and name ad_user. + * This function will try to figure out if the given filter is a lookup for a group name or group id. */ static BOOL request_getGroupFilter(struct Filter *filter, struct string *wantedGroupName, uint32_t *wantedGroupId) { @@ -267,13 +276,13 @@ static void request_replaceFilter(server_t *server, struct Filter *filter) break; case PRESENT: case SUBSTRING: - request_replaceAttribute(server, &filter->ava.desc, NULL); + request_replaceAttribute(server, &filter->ava.desc, NULL, NULL); break; case EQUAL: case GREATEQUAL: case LESSEQUAL: case APPROX: - request_replaceAttribute(server, &filter->ava.desc, &filter->ava.value); + request_replaceAttribute(server, &filter->ava.desc, &filter->ava.value, NULL); break; default: break; } @@ -290,17 +299,29 @@ static void request_replaceAdl(server_t *server, struct AttributeDescriptionList elifSETATTR(gidNumber); elifSETATTR(gecos); elifSETATTR(loginShell); - else request_replaceAttribute(server, &(*adl)->a, NULL); + else request_replaceAttribute(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_sAMAccountName; + user->next = *adl; + *adl = user; + } + } } #undef elifSETATTR -static void request_replaceAttribute(server_t *server, struct string *attribute, struct string *value) +static void 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; + } 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 (equals(value, &s_shadowAccount)) *value = s_user; @@ -321,6 +342,7 @@ static void request_replaceAttribute(server_t *server, struct string *attribute, 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 struct PartialAttributeList* response_filterHomeDir(struct PartialAttributeList *pal); static struct PartialAttributeList* response_addPal(struct PartialAttributeList *pal, struct string *attribute, const char *format, ...); #define ADDATTR(x,...) do { if (attr->x) last = response_addPal(last, &s_ ## x, __VA_ARGS__); } while (0) @@ -333,13 +355,19 @@ static void response_replacePal(server_t *server, struct PartialAttributeList ** while (*pal != NULL) { last = *pal; struct PartialAttributeList *next = NULL; - if (0) { } - elifDELATTR(homeDirectory); + if (0) { } // Remove fields we don't want from AD elifDELATTR(gidNumber); elifDELATTR(gecos); elifDELATTR(loginShell); elifDELATTR(uidNumber); elifDELATTR(mail); + else if (equals(&(*pal)->type, &s_homeDirectory)) { + // 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 + next = response_filterHomeDir(*pal); + if (next == NULL) attr->homeMount = FALSE; + } + // Entry should be removed, free structs if (next != NULL) { free_ldapadl((*pal)->values); free(*pal); @@ -362,12 +390,18 @@ static void response_replacePal(server_t *server, struct PartialAttributeList ** pal = &(*pal)->next; } if (username != NULL) { - ADDATTR(homeDirectory, "/home/%.*s", (int)username->l, username->s); - ADDATTR(gecos, "%.*s,,,", (int)username->l, username->s); - ADDATTR(loginShell, "/bin/bash"); - ADDATTR(gidNumber, "1001"); + char *user = tmpbuffer_get(); + snprintf(user, TMPLEN, "%.*s", (int)username->l, username->s); + ADDATTR(homeDirectory, "/home/%s", user); + ADDATTR(gecos, "%.*s,,,", user); + if (attr->homeMount && server->homeTemplate[0] != '\0') { + ADDATTR(homeMount, server->homeTemplate, user, user, user, user, user, 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; @@ -412,6 +446,22 @@ static void response_replaceAttribute(server_t *server, struct string *attribute } } +static struct PartialAttributeList* response_filterHomeDir(struct PartialAttributeList *pal) +{ + for (struct AttributeDescriptionList *adl = pal->values; adl != NULL; adl = pal->values /* sic */) { + if (adl->a.l > 2 && adl->a.s[0] == '\\' && adl->a.s[1] == '\\') { + for (size_t i = 0; i < adl->a.l; ++i) if (adl->a.s[i] == '\\') *((char*)adl->a.s + i) = '/'; + free_ldapadl(adl->next); + adl->next = NULL; + pal->type = s_homeMount; + return NULL; + } + pal->values = adl->next; + free(adl); + } + return pal->next; +} + static struct PartialAttributeList* response_addPal(struct PartialAttributeList *pal, struct string *attribute, const char *format, ...) { struct PartialAttributeList *next = malloc(sizeof(struct PartialAttributeList)); diff --git a/server.c b/server.c index 2c3aebe..13202f8 100644 --- a/server.c +++ b/server.c @@ -59,6 +59,27 @@ void server_setBase(const char *server, const char *base) entry->base[entry->baseLen] = '\0'; } +void server_setHomeTemplate(const char *server, const char *hometemplate) +{ + server_t *entry = server_create(server); + if (entry == NULL) return; + if (snprintf(entry->homeTemplate, MOUNTLEN, "%s", hometemplate) >= MOUNTLEN) printf("Warning: Home Template for %s is too long.\n", server); + // TODO: Better template system. Using a format string is too lazy + BOOL b = FALSE; + char *s = entry->homeTemplate; + int count = 0; + while (*s) { + if (b) { + if (*s != '%') count++; + b = FALSE; + } else if (*s == '%') b = TRUE; + if (count > 5) *s = '_'; + if (*s == '\\') *s = '/'; + s++; + } + if (count > 5) printf("WARNING: Too many '%%' in Home Template for %s. Don't forget to replace literal '%%' with '%%%%'\n", server); +} + void server_initServers() { int i; diff --git a/server.h b/server.h index 5252048..4923d6e 100644 --- a/server.h +++ b/server.h @@ -12,6 +12,8 @@ void server_setPassword(const char *server, const char *password); void server_setBase(const char *server, const char *base); +void server_setHomeTemplate(const char *server, const char *hometemplate); + void server_initServers(); int server_send(epoll_server_t *server, const char *buffer, size_t len, const BOOL cork); diff --git a/types.h b/types.h index 6959197..692042a 100644 --- a/types.h +++ b/types.h @@ -10,6 +10,7 @@ #define PWLEN 40 #define BASELEN 250 #define SIDLEN 28 +#define MOUNTLEN 100 #define REQLEN 4000 #define MAXMSGLEN 100000 @@ -68,6 +69,7 @@ struct _server_t_ { char password[PWLEN]; char base[BASELEN]; char sid[SIDLEN]; + char homeTemplate[MOUNTLEN]; epoll_server_t con; }; -- cgit v1.2.3-55-g7522