/* * ldadp - ldap to ad proxy * * LDAP protocol handling based on tinyldap https://www.fefe.de/tinyldap/ */ #include "types.h" #include "epoll.h" #include "client.h" #include "server.h" #include "proxy.h" #include "ini.h" #include "helper.h" #include "openssl.h" #include "helper.h" #include "version.in.h" #include #include #include #include #include #include #include #include #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, useUidMapping; printf("Starting up ldadp %s\n", LDADP_VERSION); printf("Commit: %s\n", LDADP_COMMIT); printf("Commit time: %s\n", LDADP_COMMITTIME); printf("Build time: %s\n", LDADP_BUILDTIME); if (argc > 1 && strcmp(argv[1], "--version") == 0) exit(0); if (argc < 2) { printf("Nö\n"); exit(1); } 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++; argc--; } 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 epoll_listen_t lsn; memset(&lsn, 0, sizeof(lsn)); lsn.callback = &listen_callback; lsn.fd = socket_tcp4(); if (certFile != NULL && keyFile != NULL) { printf("[Listener] Using SSL\n"); ssl_init(); lsn.sslContext = ssl_newServerCtx(certFile, keyFile); } else { printf("[Listener] Not using SSL\n"); } if (lsn.fd == -1) bail("Could not create listen socket"); if (socket_bind4_reuse(lsn.fd, listen_addr, localPort) == -1) bail("Could not bind to listening port"); if (socket_listen(lsn.fd, 10) == -1) bail("Could not listen"); // Setup epoll if (ePoll_init() == -1) bail("epoll_create failed"); // Add listener if (ePoll_add(EPOLLIN, (epoll_item_t*)&lsn) == -1) bail("Could not add listen socket to epoll fd"); // Init AD uplinks if (!server_initServers()) exit(1); // Daeaeaemon if (isdaemon && daemon(1, 0) == -1) bail("daemon() failed."); // Do the mainloop 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; } static void listen_callback(void *data, int haveIn, int haveOut, int doCleanup) { if (doCleanup) bail("doCleanup on Listen socket set."); if (!haveIn) return; epoll_listen_t *listen = (epoll_listen_t *)data; char remote[4]; uint16 port; int sock = socket_accept4(listen->fd, remote, &port); if (sock < 0) { printf("[Proxy] Error accepting new connection.\n"); return; } helper_nonblock(sock); SSL *ssl = NULL; if (listen->sslContext != NULL) { ssl = ssl_new(sock, listen->sslContext); if (ssl == NULL) { close(sock); return; } } epoll_client_t *client = calloc(1, sizeof(epoll_client_t)); client->fd = sock; client->callback = &client_callback; client->ssl = ssl; if (ssl != NULL && !ssl_acceptClient(client)) { printf("[Proxy] SSL-Accepting client failed.\n"); SSL_free(ssl); close(sock); free(client); return; } ePoll_add(EPOLLIN | EPOLLOUT | EPOLLET | EPOLLRDHUP, (epoll_item_t*)client); } static int loadConfig_handler(void *stuff, const char *section, const char *key, const char *value) { if (strcmp(section, "local") == 0) { if (strcmp(key, "port") == 0) { localPort = atoi(value); } else if (strcmp(key, "cert") == 0) { certFile = strdup(value); } else if (strcmp(key, "privkey") == 0) { keyFile = strdup(value); } else if (strcmp(key, "debug") == 0) { _debugLevel = atoi(value); } else if (strcmp(key, "autorestart") == 0) { _autoRestart = atoi(value) != 0; } else { printf("Unknown local config option '%s'\n", key); } } else { if (strcmp(key, "binddn") == 0) { server_setBind(section, value); } else if (strcmp(key, "bindpw") == 0) { server_setPassword(section, value); } else if (strcmp(key, "base") == 0) { server_setBase(section, value); } else if (strcmp(key, "home") == 0) { if (value[0] != '\0') server_setHomeTemplate(section, value); } else if (strcmp(key, "homeattr") == 0) { if (value[0] != '\0') server_setHomeAttribute(section, value); } else if (strcmp(key, "fingerprint") == 0) { if (value[0] != '\0') server_setFingerprint(section, value); } else if (strcmp(key, "cabundle") == 0) { if (value[0] != '\0') server_setCaBundle(section, value); } else if (strcmp(key, "port") == 0) { server_setPort(section, value); } else if (strcmp(key, "plainldap") == 0) { 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 (strcmp(key, "usestarttls") == 0) { server_setUseStartTls(section, value); } else if (strncmp(key, "map.", 4) == 0) { server_setMap(section, key+4, value); } else { plog(DEBUG_WARNING, "WARNING: Unknown ADS config option '%s' for server '%s'\n", key, section); } } return 1; } static BOOL loadConfig(char *file) { return ini_parse(file, &loadConfig_handler, NULL) >= 0; }