summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSimon Rettberg2018-11-14 14:37:31 +0100
committerSimon Rettberg2018-11-14 14:37:31 +0100
commit8b8ed36516e9a40df6ac9ac46ab355fee0e5b5f0 (patch)
treeb0267df71f0807319e7e80cf18a27dde1382cc90
parentStarted work on proxy-side uid generation/tracking (diff)
downloadldadp-8b8ed36516e9a40df6ac9ac46ab355fee0e5b5f0.tar.gz
ldadp-8b8ed36516e9a40df6ac9ac46ab355fee0e5b5f0.tar.xz
ldadp-8b8ed36516e9a40df6ac9ac46ab355fee0e5b5f0.zip
Support generating uidNumbers on proxy
-rw-r--r--Makefile6
-rw-r--r--ldadp.c37
-rw-r--r--proxy.c32
-rw-r--r--server.c55
-rw-r--r--server.h8
-rw-r--r--types.h9
-rw-r--r--uidmap.c85
-rw-r--r--uidmap.h9
8 files changed, 183 insertions, 58 deletions
diff --git a/Makefile b/Makefile
index 338f787..b1c322f 100644
--- a/Makefile
+++ b/Makefile
@@ -41,7 +41,7 @@ LIBS+=-g -lowfat -lssl -lcrypto
%: %.c
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS) ${LIBS}
-ldadp: version.in.h tmpbuffer.o ini.o client.o server.o helper.o proxy.o epoll.o openssl.o lstring.o ldap.a asn1.a
+ldadp: version.in.h tmpbuffer.o ini.o client.o server.o helper.o proxy.o epoll.o openssl.o lstring.o uidmap.o hashmap.o ldap.a asn1.a
version.in.h:
./gen-version
@@ -60,10 +60,12 @@ ini.o: ini.c ini.h
client.o: client.c client.h types.h
server.o: server.c server.h types.h
helper.o: helper.c helper.h types.h
-proxy.o: proxy.c proxy.h types.h helper.h
+proxy.o: proxy.c proxy.h types.h helper.h lstring.h
epoll.o: epoll.c epoll.h types.h
openssl.o: openssl.c openssl.h types.h
lstring.o: lstring.c asn1.h types.h
+uidmap.o: uidmap.c uidmap.h hashmap.h lstring.h
+hashmap.o: hashmap.c hashmap.h
fmt_asn1int.o: fmt_asn1int.c asn1.h
fmt_asn1intpayload.o: fmt_asn1intpayload.c asn1.h
diff --git a/ldadp.c b/ldadp.c
index bc5cdf9..c203362 100644
--- a/ldadp.c
+++ b/ldadp.c
@@ -20,16 +20,25 @@
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
+#include <time.h>
+
+#define SAVE_INTERVAL_SEC (1200)
static void listen_callback(void *data, int haveIn, int haveOut, int doCleanup);
static BOOL loadConfig(char *file);
static int localPort = 1234;
static char *certFile = NULL, *keyFile = NULL;
+static BOOL keepRunning = TRUE;
+
+static void sigTerm(int sn)
+{
+ keepRunning = FALSE;
+}
int main(int argc, char **argv)
{
- BOOL isdaemon = TRUE;
+ BOOL isdaemon = TRUE, useUidMapping;
printf("Starting up ldadp %s\n", LDADP_VERSION);
printf("Commit: %s\n", LDADP_COMMIT);
printf("Commit time: %s\n", LDADP_COMMITTIME);
@@ -42,6 +51,11 @@ int main(int argc, char **argv)
}
setbuf(stdout, NULL);
signal(SIGPIPE, SIG_IGN);
+ struct sigaction sact;
+ memset(&sact, 0, sizeof(sact));
+ sact.sa_handler = sigTerm;
+ sigaction(SIGTERM, &sact, NULL);
+ sigaction(SIGINT, &sact, NULL);
if (strcmp(argv[1], "-n") == 0 && argc > 2) {
isdaemon = FALSE;
argv++;
@@ -49,6 +63,7 @@ int main(int argc, char **argv)
}
if (!loadConfig(argv[1])) bail("Cannot read config file %s", argv[1]);
if (localPort < 1 || localPort > 65535) bail("Invalid port given in config");
+ useUidMapping = server_initUidMaps();
proxy_init();
char listen_addr[4] = {0, 0, 0, 0};
// Setup socket
@@ -76,9 +91,21 @@ int main(int argc, char **argv)
// Daeaeaemon
if (isdaemon && daemon(1, 0) == -1) bail("daemon() failed.");
// Do the mainloop
- for (;;) {
+ struct timespec last, now;
+ clock_gettime(CLOCK_MONOTONIC, &now);
+ last = now;
+ while (keepRunning) {
if (ePoll_wait(-1) == -1) bail("ePoll wait failed.");
+ if (useUidMapping) {
+ clock_gettime(CLOCK_MONOTONIC, &now);
+ if ((uint64_t)now.tv_sec - (uint64_t)last.tv_sec > SAVE_INTERVAL_SEC) { // Signed overflow not a good idea in C
+ last = now;
+ server_saveUidMaps();
+ }
+ }
}
+ plog(DEBUG_FATAL, "Shutting down...");
+ server_saveUidMaps();
return 0;
}
@@ -152,10 +179,14 @@ static int loadConfig_handler(void *stuff, const char *section, const char *key,
server_setPlainLdap(section, value);
} else if (strcmp(key, "fixnumeric") == 0) {
server_setFixNumeric(section, value);
+ } else if (strcmp(key, "uidmapstore") == 0) {
+ server_setUidMapStore(section, value);
+ } else if (strcmp(key, "genuidnumber") == 0) {
+ server_setGenUidNumber(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);
+ plog(DEBUG_WARNING, "WARNING: Unknown ADS config option '%s' for server '%s'\n", key, section);
}
}
return 1;
diff --git a/proxy.c b/proxy.c
index 98151a4..275b4d1 100644
--- a/proxy.c
+++ b/proxy.c
@@ -4,6 +4,7 @@
#include "helper.h"
#include "tmpbuffer.h"
#include "ldap.h"
+#include "uidmap.h"
#include "lstring.h"
#include <stdio.h>
#include <string.h>
@@ -511,16 +512,18 @@ static void request_replaceAdl(server_t *server, struct AttributeDescriptionList
*adl = next;
}
}
+ // Set simple flag for there
elifSETATTR(gidnumber, gidNumber);
elifSETATTR(gecos, gecos);
elifSETATTR(realaccount, realAccount);
elifSETATTR(loginshell, loginShell);
+ // Further handling (uid, homeMount, objectClass, uidNumber)
else request_replaceAttribute(server, &(*adl)->a, NULL, attr, FALSE);
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) {
+ if (attr->homeDirectory || attr->gecos || attr->homeMount || (server->genUidNumber && attr->uidNumber)) {
struct AttributeDescriptionList *user = calloc(1, sizeof(struct AttributeDescriptionList));
user->a = server->map.uid;
user->next = *adl;
@@ -564,8 +567,21 @@ static BOOL request_replaceAttribute(server_t *server, struct string *attribute,
else if (equals(value, &s_posixAccount)) *value = server->map.posixAccount;
} else if (iequals(attribute, &s_uidnumber)) {
*attribute = server->map.uidnumber;
+ if (attr) attr->uidNumber = TRUE;
if (value == NULL) return TRUE;
- if (value != NULL && !negated && value->l == 1 && value->s[0] == '0') {
+ if (server->genUidNumber && !(value->l == 1 && value->s[0] == '0')) {
+ // We're managing uidNumbers on the proxy
+ const struct string *name = uidmap_getNameForNumber(&server->uidmap, value);
+ if (name != NULL) { // Mapped to uid, so query will return all the requested fields
+ *attribute = server->map.uid;
+ *value = *name;
+ } else {
+ // Nothing, make sure query doesn't match
+ *value = s_uid;
+ }
+ return TRUE;
+ }
+ if (!negated && value->l == 1 && value->s[0] == '0') {
// Saftey measure: Query for user with uidNumber == 0 - root; replace with something that
// should never return anything
*value = s_uid;
@@ -657,9 +673,12 @@ static void response_replacePal(server_t *server, struct PartialAttributeList **
elifDELATTR(gidnumber, gidNumber);
elifDELATTR(gecos, gecos);
elifDELATTR(loginshell, loginShell);
- elifDELATTR(uidnumber, uidNumber, !server->plainLdap &&);
+ elifDELATTR(uidnumber, uidNumber, (!server->plainLdap || server->genUidNumber) &&);
elifDEL(mail);
elifDELATTR(cn, cn, !iequals(&server->map.uid, &s_cn) &&);
+ else if (server->genUidNumber && iequals(&(*pal)->type, &server->map.uidnumber)) {
+ del = TRUE;
+ }
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
@@ -698,6 +717,13 @@ static void response_replacePal(server_t *server, struct PartialAttributeList **
pal = &(*pal)->next;
}
if (username != NULL) {
+ if (server->genUidNumber && attr->uidNumber) {
+ // Let's supply some uidNumber
+ uint32_t num = uidmap_getNumberForName(&server->uidmap, username);
+ if (num >= 2000) {
+ ADDATTR(uidNumber, "%"PRIu32, num);
+ }
+ }
char *user = tmpbuffer_get();
snprintf(user, TMPLEN, "%.*s", (int)username->l, username->s);
if (attr->homeDirectory) {
diff --git a/server.c b/server.c
index f22c5bf..54fd154 100644
--- a/server.c
+++ b/server.c
@@ -4,6 +4,7 @@
#include "epoll.h"
#include "tmpbuffer.h"
#include "openssl.h"
+#include "uidmap.h"
#include <time.h>
#include <stdio.h>
#include <stdlib.h>
@@ -41,6 +42,13 @@ static inline uint32_t msgId()
return id;
}
+static BOOL parseBool(const char *str)
+{
+ return atoi(str) != 0 || strcmp(str, "true") == 0
+ || strcmp(str, "True") == 0 || strcmp(str, "TRUE") == 0
+ || strcmp(str, "on") == 0 || strcmp(str, "On") == 0;
+}
+
// Setting up server(s)
void server_setPort(const char *server, const char *portStr)
@@ -59,15 +67,30 @@ void server_setPlainLdap(const char *server, const char *enabledStr)
{
server_t *entry = server_create(server);
if (entry == NULL) return;
- entry->plainLdap = atoi(enabledStr) != 0 || strcmp(enabledStr, "true") == 0
- || strcmp(enabledStr, "True") == 0 || strcmp(enabledStr, "TRUE") == 0;
+ entry->plainLdap = parseBool(enabledStr);
}
void server_setFixNumeric(const char *server, const char *enabledStr)
{
server_t *entry = server_create(server);
if (entry == NULL) return;
- entry->fixNumeric = *enabledStr != '\0' || atoi(enabledStr) != 0;
+ entry->fixNumeric = parseBool(enabledStr);
+}
+
+void server_setUidMapStore(const char *server, const char *fileName)
+{
+ server_t *entry = server_create(server);
+ if (entry == NULL) return;
+ if (fileName == NULL || *fileName == '\0') return;
+ entry->uidmap.fileName = strdup(fileName);
+}
+
+void server_setGenUidNumber(const char *server, const char *enabledStr)
+{
+ server_t *entry = server_create(server);
+ if (entry == NULL) return;
+ entry->genUidNumber = parseBool(enabledStr);
+ plog(DEBUG_VERBOSE, "Using UID mapping for %s: %d", server, (int)entry->genUidNumber);
}
static void strtolower(char *str)
@@ -226,6 +249,32 @@ void server_setFingerprint(const char *server, const char *fingerprint)
ssl_init();
}
+/**
+ * Initialize hashmaps for uid mapping.
+ * Returns TRUE if at least one server is
+ * configured to use uid mapping.
+ */
+BOOL server_initUidMaps()
+{
+ BOOL ret = FALSE;
+ for (int i = 0; i < serverCount; ++i) {
+ if (servers[i].genUidNumber) {
+ uidmap_init(&servers[i].uidmap);
+ ret = TRUE;
+ }
+ }
+ return ret;
+}
+
+void server_saveUidMaps()
+{
+ for (int i = 0; i < serverCount; ++i) {
+ if (servers[i].genUidNumber) {
+ uidmap_cleanupSave(&servers[i].uidmap);
+ }
+ }
+}
+
BOOL server_initServers()
{
int i;
diff --git a/server.h b/server.h
index 10ebb9f..1a01935 100644
--- a/server.h
+++ b/server.h
@@ -12,6 +12,10 @@ void server_setPlainLdap(const char *server, const char *enabledStr);
void server_setFixNumeric(const char *server, const char *enabledStr);
+void server_setUidMapStore(const char *server, const char *fileName);
+
+void server_setGenUidNumber(const char *server, const char *value);
+
void server_setMap(const char *server, const char *attribute, const char *value);
void server_setBind(const char *server, const char *bind);
@@ -28,6 +32,10 @@ void server_setFingerprint(const char *server, const char *fingerprint);
void server_setCaBundle(const char *server, const char *file);
+BOOL server_initUidMaps();
+
+void server_saveUidMaps();
+
BOOL server_initServers();
void server_free(epoll_server_t *server);
diff --git a/types.h b/types.h
index 4030902..94e2ddd 100644
--- a/types.h
+++ b/types.h
@@ -104,6 +104,13 @@ typedef struct {
struct string uidnumber; // AD: objectSid
} attr_map_t;
+struct hashmap;
+struct uidmap {
+ const char *fileName;
+ struct hashmap *nameToNum;
+ struct hashmap *numToName;
+};
+
/**
* Configuration data for an ADS we're proxying.
*/
@@ -121,10 +128,12 @@ struct _server_t_ {
char cabundle[MAXPATH];
BOOL plainLdap;
BOOL fixNumeric; // prefix numeric account names with an 's'
+ BOOL genUidNumber; // generate uidNumber attribute locally (and keep track)
uint16_t port;
SSL_CTX *sslContext;
epoll_server_t con;
attr_map_t map;
+ struct uidmap uidmap;
};
#endif
diff --git a/uidmap.c b/uidmap.c
index 8315be2..a1cb9f7 100644
--- a/uidmap.c
+++ b/uidmap.c
@@ -9,10 +9,6 @@
#include <stdio.h>
#include <unistd.h>
-static struct hashmap _numToName, _nameToNum;
-static BOOL _initDone = FALSE;
-static const char *_saveFileName = NULL;
-
static const uint16_t MAGIC = 1234;
static const int64_t MAX_AGE = 86400 * 2; // 2 days
#define MAX_NAME_LEN 1024
@@ -27,7 +23,7 @@ struct user
int64_t lastUse;
};
-static void insertTime(const struct string *name, const uint32_t number, const int64_t lastUse)
+static void insertTime(struct uidmap *uidmap, const struct string *name, const uint32_t number, const int64_t lastUse)
{
uint8_t *buffer = malloc(sizeof(struct user) + sizeof(struct string) + name->l);
struct user *u = (struct user*)buffer;
@@ -39,18 +35,18 @@ static void insertTime(const struct string *name, const uint32_t number, const i
u->name = s;
u->number = number;
u->lastUse = lastUse;
- if (name_hashmap_put(&_nameToNum, u->name, u) != u) {
+ if (name_hashmap_put(uidmap->nameToNum, u->name, u) != u) {
plog(DEBUG_WARNING, "[uidmap] Collision when inserting %.*s by name (%"PRIu32")", (int)s->l, s->s, number);
}
- if (number_hashmap_put(&_numToName, &u->number, u) != u) {
+ if (number_hashmap_put(uidmap->numToName, &u->number, u) != u) {
plog(DEBUG_WARNING, "[uidmap] Collision when inserting %.*s by number (%"PRIu32")", (int)s->l, s->s, number);
}
// TODO: Leak
}
-static void insert(const struct string *name, const uint32_t number)
+static void insert(struct uidmap *uidmap, const struct string *name, const uint32_t number)
{
- insertTime(name, number, time(NULL));
+ insertTime(uidmap, name, number, time(NULL));
}
static int uint32_compare(const void *a, const void *b)
@@ -84,7 +80,7 @@ static size_t string_hash(const void *key)
return hash;
}
-uint32_t uidmap_getNumberForName(const struct string *name)
+uint32_t uidmap_getNumberForName(struct uidmap *uidmap, const struct string *name)
{
// Try string matching
char buf[name->l];
@@ -93,7 +89,7 @@ uint32_t uidmap_getNumberForName(const struct string *name)
buf[i] = tolower(name->s[i]);
}
// Get
- struct user *u = name_hashmap_get(&_nameToNum, &lower);
+ struct user *u = name_hashmap_get(uidmap->nameToNum, &lower);
if (u != NULL) {
u->lastUse = time(NULL);
return u->number;
@@ -101,10 +97,10 @@ uint32_t uidmap_getNumberForName(const struct string *name)
// Not known yet - try numeric
uint32_t asNumber = parseUInt32(name);
if (asNumber >= 2000) {
- u = number_hashmap_get(&_numToName, &asNumber);
+ u = number_hashmap_get(uidmap->numToName, &asNumber);
if (u == NULL) {
// No collision, use name as number
- insert(&lower, asNumber);
+ insert(uidmap, &lower, asNumber);
return asNumber;
}
plog(DEBUG_WARNING, "%.*s is numeric (%u) but collides", (int)name->l, name->s, asNumber);
@@ -116,49 +112,52 @@ uint32_t uidmap_getNumberForName(const struct string *name)
}
for (;;) {
//plog(DEBUG_WARNING, "Using number %u for %.*s", asNumber, (int)name->l, name->s);
- u = number_hashmap_get(&_numToName, &asNumber);
+ u = number_hashmap_get(uidmap->numToName, &asNumber);
if (u == NULL)
break;
do {
asNumber = rand() + 2000;
} while (asNumber < 2000);
}
- insert(&lower, asNumber);
+ insert(uidmap, &lower, asNumber);
return asNumber;
}
-const struct string *uidmap_getNameForNumber(const uint32_t number)
+const struct string *uidmap_getNameForNumber(struct uidmap *uidmap, const struct string *numberString)
{
- struct user *u = number_hashmap_get(&_numToName, &number);
+ uint32_t number = parseUInt32(numberString);
+ if (number < 2000)
+ return NULL;
+ struct user *u = number_hashmap_get(uidmap->numToName, &number);
if (u == NULL)
return NULL;
u->lastUse = time(NULL);
return u->name;
}
-void uidmap_init(const char *fileName)
+void uidmap_init(struct uidmap *uidmap)
{
- if (_initDone)
+ if (uidmap->nameToNum != NULL)
return;
- _initDone = TRUE;
- hashmap_init(&_numToName, uint32_hash, uint32_compare, 0);
- hashmap_init(&_nameToNum, string_hash, string_compare, 0);
- if (fileName == NULL)
+ uidmap->numToName = calloc(2, sizeof(struct hashmap));
+ uidmap->nameToNum = uidmap->numToName + 1;
+ hashmap_init(uidmap->numToName, uint32_hash, uint32_compare, 0);
+ hashmap_init(uidmap->nameToNum, string_hash, string_compare, 0);
+ if (uidmap->fileName == NULL)
return;
- // We have a filename, remember it and try to load DB
- _saveFileName = strdup(fileName);
- FILE *fh = fopen(_saveFileName, "rb");
+ // We have a filename, try to load DB
+ FILE *fh = fopen(uidmap->fileName, "rb");
if (fh == NULL)
return;
fseek(fh, 0, SEEK_END);
const int fsize = ftell(fh);
fseek(fh, 0, SEEK_SET);
- if (fsize > 0) {
+ if (fsize > 0) { // Guess required map size
const size_t entries = (size_t)fsize / 25;
- hashmap_destroy(&_numToName);
- hashmap_destroy(&_nameToNum);
- hashmap_init(&_numToName, uint32_hash, uint32_compare, entries);
- hashmap_init(&_nameToNum, string_hash, string_compare, entries);
+ hashmap_destroy(uidmap->numToName);
+ hashmap_destroy(uidmap->nameToNum);
+ hashmap_init(uidmap->numToName, uint32_hash, uint32_compare, entries);
+ hashmap_init(uidmap->nameToNum, string_hash, string_compare, entries);
}
// Not endian safe, do not copy file around...
uint16_t len = 0;
@@ -196,38 +195,38 @@ void uidmap_init(const char *fileName)
lastUse = now;
// Add
name.l = len;
- insertTime(&name, uidNumber, lastUse);
+ insertTime(uidmap, &name, uidNumber, lastUse);
loaded++;
}
fclose(fh);
- plog(DEBUG_INFO, "Loaded %d entries from %s", loaded, _saveFileName);
+ plog(DEBUG_INFO, "Loaded %d entries from %s", loaded, uidmap->fileName);
}
-void uidmap_cleanupSave()
+void uidmap_cleanupSave(struct uidmap *uidmap)
{
- if (!_initDone)
+ if (uidmap->nameToNum == NULL)
return;
FILE *fh = NULL;
- if (_saveFileName != NULL) {
- fh = fopen(_saveFileName, "wb");
+ if (uidmap->fileName != NULL) {
+ fh = fopen(uidmap->fileName, "wb");
if (fh != NULL) {
if (fwrite(&MAGIC, sizeof(MAGIC), 1, fh) != 1) {
- plog(DEBUG_WARNING, "Cannot write magic to %s", _saveFileName);
+ plog(DEBUG_WARNING, "Cannot write magic to %s", uidmap->fileName);
fclose(fh);
fh = NULL;
}
}
}
const int64_t deadline = time(NULL) - MAX_AGE;
- struct hashmap_iter *it = hashmap_iter(&_nameToNum);
+ struct hashmap_iter *it = hashmap_iter(uidmap->nameToNum);
struct user *u = NULL;
int saved = 0, removed = 0;
uint16_t len;
while (it != NULL) {
u = name_hashmap_iter_get_data(it);
if (u->lastUse < deadline) {
- it = hashmap_iter_remove(&_nameToNum, it);
- if (number_hashmap_remove(&_numToName, &u->number) != u) {
+ it = hashmap_iter_remove(uidmap->nameToNum, it);
+ if (number_hashmap_remove(uidmap->numToName, &u->number) != u) {
plog(DEBUG_WARNING, "Could not remove user from numToName that was in nameToNum");
}
free(u);
@@ -242,14 +241,14 @@ void uidmap_cleanupSave()
|| fwrite(&u->number, sizeof(u->number), 1, fh) != 1
|| fwrite(u->name->s, len, 1, fh) != 1
) {
- plog(DEBUG_WARNING, "Could not write record to %s", _saveFileName);
+ plog(DEBUG_WARNING, "Could not write record to %s", uidmap->fileName);
fclose(fh);
fh = NULL;
} else {
saved++;
}
}
- it = hashmap_iter_next(&_nameToNum, it);
+ it = hashmap_iter_next(uidmap->nameToNum, it);
}
if (fh != NULL) {
fsync(fileno(fh));
diff --git a/uidmap.h b/uidmap.h
index a126e39..1145175 100644
--- a/uidmap.h
+++ b/uidmap.h
@@ -1,16 +1,17 @@
#ifndef _UIDMAP_H_
#define _UIDMAP_H_
+#include "types.h"
#include <stdint.h>
struct string;
-uint32_t uidmap_getNumberForName(const struct string *name);
+uint32_t uidmap_getNumberForName(struct uidmap *uidmap, const struct string *name);
-const struct string *uidmap_getNameForNumber(const uint32_t number);
+const struct string *uidmap_getNameForNumber(struct uidmap *uidmap, const struct string *number);
-void uidmap_init(const char *fileName);
+void uidmap_init(struct uidmap *uidmap);
-void uidmap_cleanupSave();
+void uidmap_cleanupSave(struct uidmap *uidmap);
#endif