summaryrefslogblamecommitdiffstats
path: root/ldadp.c
blob: 2152903634d3859bcbe938c43faaa16b2eca2959 (plain) (tree)
1
2
3
4
5
6
7
8
9
10
11
12




                                                                         






                   
                    
                   
                       




                   
                   
                   


                                

                                                                                
                                   
 
                            
                                              





                               
 

                               
                                            





                                                          



                                
                             
                                 




                                        




                                                     
                                                                              
                                                                                     
                                             



                                           
                                     

                                        
                                                  
                                                 


                                                                     
                                                     
         
                                                                 
                                                                                                               





                                                                                                           

                                  
                     
                                                                     
                          



                                             
                                                                     






                                                                                                                                       
         

                                              











                                                                               
                                                                    

                       
                              

                                         
                                                        




                                    


                                                                   

                                                       
                                                                 




                              
                                                                                    



                                                                                                   






                                                         

                                                       

                                                             









                                                                          

                                                                                     

                                                                                      

                                                                                    

                                                                                 

                                                       

                                                            

                                                             



                                                               

                                                              

                                                             
                        
                                                                                                                       
                 
         


                 
                                  
 
                                                               

 
/*
 * 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 <stdio.h>
#include <socket.h>
#include <io.h>
#include <string.h>
#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, 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;
}