From e4e948523f6bc49c0869b7c5cd217acc60a03cb9 Mon Sep 17 00:00:00 2001 From: reenoo Date: Thu, 25 Dec 2003 15:02:34 +0000 Subject: [PATCH] LDAP support added - This patch enables LCDd to retrieve its configuration options from an LDAP directory. - The code was tested with OpenLDAP 2.1.x (21<=x<=22) only. - LDAP support is disabled by default and has to be enabled with ./configure --enable-ldap. (See ./configure --help for other options. Not all options have any effect yet.) - Currently only anonymous LDAP binds are supported. - The DN of the main configuration object has to be passed to LCDd instead of the configuration file location: LCDd -c "ldap://yourhost.yourcompany.com/cn=config1,cn=lcdproc,dc=yourcompany dc=COM" The basic idea behind the LCDproc object classes is that they are more or less verbatim copies of the corresponding sections in a generic LCDd.conf - Unfortunately schema files cannot be provided yet, because LCDproc does not have a registered OID namespace and OID hijacking is prohibited. --- clients/lcdexec/Makefile.am | 2 +- clients/lcdproc/Makefile.am | 2 +- configure.in | 180 +++++++++++++++++++++++++++ server/Makefile.am | 2 +- shared/Makefile.am | 5 +- shared/configfile.c | 235 ++++++++++++++++++++++++++++++++++++ 6 files changed, 422 insertions(+), 4 deletions(-) diff --git a/clients/lcdexec/Makefile.am b/clients/lcdexec/Makefile.am index 4dfac58..6bc5454 100644 --- a/clients/lcdexec/Makefile.am +++ b/clients/lcdexec/Makefile.am @@ -1,4 +1,4 @@ bin_PROGRAMS = lcdexec lcdexec_SOURCES = lcdexec.c menu.c menu.h -lcdexec_LDADD = ../../shared/libLCDstuff.a +lcdexec_LDADD = @ldap_libs@ ../../shared/libLCDstuff.a INCLUDES = -I$(top_srcdir) diff --git a/clients/lcdproc/Makefile.am b/clients/lcdproc/Makefile.am index 7d23a54..aed6c86 100644 --- a/clients/lcdproc/Makefile.am +++ b/clients/lcdproc/Makefile.am @@ -1,4 +1,4 @@ bin_PROGRAMS = lcdproc lcdproc_SOURCES = main.c main.h mode.c mode.h batt.c batt.h chrono.c chrono.h cpu.c cpu.h cpu_smp.c cpu_smp.h disk.c disk.h load.c load.h mem.c mem.h machine_Linux.c machine_OpenBSD.c machine_FreeBSD.c machine_NetBSD.c machine_SunOS.c -lcdproc_LDADD = ../../shared/libLCDstuff.a +lcdproc_LDADD = @ldap_libs@ ../../shared/libLCDstuff.a INCLUDES = -I$(top_srcdir) diff --git a/configure.in b/configure.in index 3fc32cb..e265d90 100644 --- a/configure.in +++ b/configure.in @@ -202,6 +202,186 @@ AC_MODULES_INFO LCD_DRIVERS_SELECT +dnl ###################################################################### +dnl Open LDAP +dnl based on code from perdition http://www.vergenet.net/linux/perdition/ +dnl +dnl not all options have effect at the moment + +AC_SUBST(ldap_libs) +AC_SUBST(ldap_includes) +AC_SUBST(ldap_schemadir) + +AC_MSG_CHECKING([if LDAP support has been enabled]); +AC_ARG_ENABLE( + ldap, + [ --enable-ldap compile with LDAP support. ], + [ + if test "$enable_ldap" = "yes"; then + AC_MSG_RESULT("yes") + else + AC_MSG_RESULT("no") + fi + ], + [ + enable_ldap="no"; + AC_MSG_RESULT("no") + ] +) + +if test "$enable_ldap" = "yes"; then +AC_ARG_WITH( + ldap-includes, + [ --with-ldap-includes=DIR + Open LDAP include files are in DIR. ], + [ + if test "$withval" = "no"; then + ldap_build_dir=""; + else + ldap_includepath="$withval" + fi + ], + [ + AC_MSG_CHECKING(OpenLDAP include path) + for ldap_includepath in /usr/openldap/include /usr/local/openldap/include \ + /usr/include/openldap /usr/local/include/openldap \ + /usr/include /usr/local/include; do + if test -f "${ldap_includepath}/ldap.h"; then + break + fi + done + AC_MSG_RESULT($ldap_includepath) + ] +) +fi + +ldap_includes="-I$ldap_includepath" + +if test "$enable_ldap" = "yes"; then +AC_ARG_WITH( + ldap-libraries, + [ --with-ldap-libraries=DIR + Open LDAP library files are in DIR. ], + [ + if test "$withval" = "no"; then + ldap_build_dir=""; + else + ldap_libpath="$withval" + fi + ], + [ + AC_MSG_CHECKING(OpenLDAP library path) + for ldap_libpath in /usr/openldap/lib /usr/local/openldap/lib \ + /usr/lib/openldap /usr/local/lib/openldap \ + /usr/lib /usr/local/lib; do + if test -f "${ldap_libpath}/libldap.a" \ + -o -f "${ldap_libpath}/libldap.so"; then + break + fi + done + AC_MSG_RESULT($ldap_libpath) + ] +) +fi + +ldap_libs="-L$ldap_libpath -lldap -llber" + +if test "$enable_ldap" = "yes"; then +AC_CHECK_FILE( + $ldap_includepath/ldap.h, + [ : ] , + [ enable_ldap="no" ] +) +fi + +if test "$enable_ldap" = "yes"; then +AC_CHECK_LIB( + ldap, + ldap_url_parse, + [ : ], + [ enable_ldap="no" ], + $ldap_libs +) +fi + +if test "$enable_ldap" = "yes"; then + AC_MSG_CHECKING(OpenLDAP lud_exts in LDAPURLDesc) + AC_TRY_COMPILE([#include + #include + #include ], + [LDAPURLDesc ludp; + ludp.lud_exts[0] = NULL;], + AC_MSG_RESULT("yes") + AC_DEFINE(WITH_LDAP_LUD_EXTS, 1, Compile with LDAP lud_exts), + AC_MSG_RESULT("no") +AC_MSG_WARN( +"" +"************************************************************" +"* Password and Username support will not be built in the" +"* LDAP module. For Password and Username support compile" +"* openldap2. Available from openldap.org" +"************************************************************" +) + ) +fi + +if test "$enable_ldap" = "yes"; then + AC_CHECK_LIB(ldap, ldap_set_option, + AC_DEFINE(WITH_LDAP_SET_OPTION, 1, Compile with LDAP set_option), +AC_MSG_WARN( +"" +"************************************************************" +"* Cannot expicitly set network timeout or ldap protocol" +"* version. For ldap_set_option support please use openlap2." +"* Available from openldap.org" +"************************************************************" +),) +fi + +if test "$enable_ldap" = "yes"; then +AC_ARG_WITH( + ldap-schema-directory, + [ --with-ldap-schema-directory=DIR + Open LDAP schema files are in DIR. ], + [ + if test "$withval" = "no"; then + ldap_schemadir=""; + else + ldap_schemadir="$withval" + fi + ], + [ + AC_MSG_CHECKING(OpenLDAP schema path) + for ldap_schemadir in /etc/openldap/schema /etc/ldap/schema \ + /usr/local/openldap/etc/schema; do + if test -f "${ldap_schemadir}/openldap.schema"; then + break + fi + ldap_schemadir="Not found" + done + AC_MSG_RESULT($ldap_schemadir) + if test "$ldap_schemadir" = "Not found"; then +AC_MSG_WARN( +"" +"************************************************************" +"* Could not find OpenLDAP schema directory." +"* lcdproc.schema will not be installed" +"************************************************************" +) + ldap_schemadir="" + fi + ] +) +fi + +if test "$enable_ldap" = "yes"; then + AC_DEFINE(WITH_LDAP_SUPPORT, 1, Compile in LDAP support) +else + ldab_libs=""; + ldap_includes=""; +fi + + AC_OUTPUT(Makefile shared/Makefile server/Makefile diff --git a/server/Makefile.am b/server/Makefile.am index 7dfdff7..acd6a32 100644 --- a/server/Makefile.am +++ b/server/Makefile.am @@ -1,6 +1,6 @@ SUBDIRS=drivers commands sbin_PROGRAMS=LCDd LCDd_SOURCES= client.c client.h clients.c clients.h input.c input.h main.c main.h menuitem.c menuitem.h menu.c menu.h menuscreens.c menuscreens.h parse.c parse.h render.c render.h screen.c screen.h screenlist.c screenlist.h serverscreens.c serverscreens.h sock.c sock.h widget.c widget.h drivers.c drivers.h driver.c driver.h -LCDd_LDADD = ../shared/libLCDstuff.a commands/libLCDcommands.a +LCDd_LDADD = @ldap_libs@ ../shared/libLCDstuff.a commands/libLCDcommands.a LCDd_LDFLAGS = -rdynamic -uget_args INCLUDES = -I$(top_srcdir) diff --git a/shared/Makefile.am b/shared/Makefile.am index 719908c..40c7f72 100644 --- a/shared/Makefile.am +++ b/shared/Makefile.am @@ -1,3 +1,6 @@ noinst_LIBRARIES = libLCDstuff.a libLCDstuff_a_SOURCES = LL.c LL.h sockets.c sockets.h str.c str.h configfile.c configfile.h debug.h report.c report.h snprintf.c snprintf.h -INCLUDES = -I$(top_srcdir) + +INCLUDES = @ldap_includes@ -I$(top_srcdir) + +EXTRA_DIST = Makefile.in diff --git a/shared/configfile.c b/shared/configfile.c index 83accf9..cbf0907 100644 --- a/shared/configfile.c +++ b/shared/configfile.c @@ -6,17 +6,24 @@ * COPYING file distributed with this package. * * Copyright (c) 2001, Joris Robijn + * (c) 2003, Rene Wagner * * * Defines routines to read ini-file-like files. + * Optionally retrieves settings from an LDAP directory (OpenLDAP 2.1.x) */ +#include "config.h" #include #include #include #include +#ifdef WITH_LDAP_SUPPORT +# include +#endif /* WITH_LDAP_SUPPORT */ + #include "shared/report.h" @@ -43,6 +50,20 @@ key * find_key( section * s, char * keyname, int skip ); key * add_key( section * s, char * keyname, char * value ); int process_config( section ** current_section, char (*get_next_char)(), char modify_section_allowed, char * source_descr ); +#ifdef WITH_LDAP_SUPPORT +int connect_to_ldap(void); + +static LDAP * ld = NULL; +int use_ldap=0; + +static char * ldap_host=NULL, * ldap_base_dn=NULL; +int ldap_port; + +/* not supported for now + * char ldap_user[255] = "", + * ldap_pwd[255] = ""; + */ +#endif /* WITH_LDAP_SUPPORT */ /**** EXTERNAL FUNCTIONS ****/ @@ -56,6 +77,41 @@ int config_read_file( char *filename ) int pos=0; section * curr_section = NULL; +#ifdef WITH_LDAP_SUPPORT + LDAPURLDesc * url = NULL; + int retval; +#endif /* WITH_LDAP_SUPPORT */ + + report( RPT_NOTICE, "Using Configuration File: %s", filename); + +#ifdef WITH_LDAP_SUPPORT + if (ldap_is_ldap_url( filename )) { + use_ldap=1; + + if (0 != (retval = ldap_url_parse( filename, &url))) { + report( RPT_ERR, "Errors parsing LDAP URL %s: %s", filename, ldap_err2string(retval)); + ldap_free_urldesc(url); + return (-1); + } + + ldap_host=strdup(url->lud_host); + ldap_port=url->lud_port; + report( RPT_INFO, "Using LDAP server: %s:%d", ldap_host, ldap_port); + + ldap_base_dn=strdup(url->lud_dn); + report( RPT_INFO, "Using LDAP base DN: %s", ldap_base_dn); + + ldap_free_urldesc(url); + + if (connect_to_ldap() < 0 ) { + debug( RPT_DEBUG, "connect_to_ldap returned errors."); + return (-1); + } + + return 0; + } +#endif /* WITH_LDAP_SUPPORT */ + /* We use a nested fuction to transfer the characters from buffer to parser*/ char get_next_char() { if( pos>=bytesread ) { @@ -258,10 +314,94 @@ void config_clear() /**** INTERNAL FUNCTIONS ****/ +#ifdef WITH_LDAP_SUPPORT +int +connect_to_ldap (void) +{ + int retval; + LDAPMessage * res; + + debug( RPT_INFO, "Connecting to LDAP server: %s:%d", ldap_host, ldap_port); + + if (!(ld = ldap_init(ldap_host, ldap_port))) { + report(RPT_ERR, "LDAP session could not be initialized."); + return (-1); + } + +/***************************************************** + * disabled unless you really have a DN/pwd to bind to + * WARNING: LCDd should not have LDAP write access!! + * + * if (LDAP_SUCCESS != (retval = ldap_simple_bind_s (ld, ldap_user, ldap_pwd))) { + * report (RPT_ERR, "LDAP login on %s:%d failed: %s", ldap_host, ldap_port, ldap_err2string (retval)); + * ldap_unbind (ld); + * ld = NULL; + * + * return (-1); + * } + * fprintf(stderr, "LDAP login successful on %s:%d\n", ldap_host, ldap_port); + ********************************************************/ + + /* check for the existence of the config object... */ + if (LDAP_SUCCESS != (retval = ldap_search_s (ld, ldap_base_dn, LDAP_SCOPE_BASE, "objectClass=lcdprocConfig", NULL, 0, &res))) { + report( RPT_ERR, "Could not access LDAP server on %s:%d", ldap_host, ldap_port); + return (-1); + } + if (0 == ldap_count_entries(ld, res)) { + report( RPT_ERR, "No configuration object found in LDAP at: %s", ldap_base_dn); + return (-1); + } + debug( RPT_DEBUG, "Configuration LDAP object found."); + return 0; +} + +#define BUFSIZE 255 +#endif /* WITH_LDAP_SUPPORT */ + section * find_section( char * sectionname ) { section * s; +#ifdef WITH_LDAP_SUPPORT + LDAPMessage * res; + int retval; + char *filter=NULL; + + if (use_ldap) { + debug( RPT_DEBUG, "Searching LDAP for section [%s]", sectionname); + if (NULL == (filter = malloc(BUFSIZE))){ + report( RPT_ERR, "Could not allocate memory in find_section()"); + return NULL; + } + strcpy(filter, "cn="); + strncat(filter, sectionname, BUFSIZE); + if (LDAP_SUCCESS != (retval = ldap_search_s (ld, ldap_base_dn, LDAP_SCOPE_ONELEVEL, filter, NULL, 0, &res))) { + if (NULL != filter) { + free(filter); + filter=NULL; + } + ldap_msgfree(res); + report( RPT_ERR, "Could not access LDAP server on %s:%d", ldap_host, ldap_port); + return NULL; + } + if (NULL != filter) { + free(filter); + filter=NULL; + } + if (0 == ldap_count_entries( ld, res )) { + debug( RPT_DEBUG, "Section [%s] not found in LDAP.", sectionname); + return NULL; + } + ldap_msgfree(res); + debug( RPT_DEBUG, "Found section [%s] in LDAP", sectionname); + s = (section*) malloc( sizeof( section )); + s->name=strdup( sectionname ); + s->first_key = NULL; + s->next_section = NULL; + return s; + } +#endif /* WITH_LDAP_SUPPORT */ + for( s=first_section; s; s=s->next_section ) { if( strcasecmp( s->name, sectionname ) == 0 ) { return s; @@ -292,9 +432,104 @@ key * find_key( section * s, char * keyname, int skip ) int count = 0; key * last_key = NULL; +#ifdef WITH_LDAP_SUPPORT + LDAPMessage * res; + LDAPMessage * entry; + int retval; + char *buf=NULL; + char **vals; +#endif /* WITH_LDAP_SUPPORT */ + /* Check for NULL section*/ if(!s) return NULL; +#ifdef WITH_LDAP_SUPPORT + if (use_ldap) { + debug( RPT_DEBUG, "Searching LDAP for key '%s' in section [%s] skipping %d entries.", keyname, s->name, skip); + + if (NULL == (buf = malloc(BUFSIZE))){ + report (RPT_ERR, "Could not allocate memory in find_key()."); + } + strcpy(buf, "cn="); + strncat(buf, s->name, BUFSIZE); + if (LDAP_SUCCESS != (retval = ldap_search_s (ld, ldap_base_dn, LDAP_SCOPE_ONELEVEL, buf, NULL, 0, &res))) { + if (NULL != buf) { + free(buf); + buf=NULL; + } + ldap_msgfree(res); + report( RPT_ERR, "Could not access LDAP server on %s:%d", ldap_host, ldap_port); + return NULL; + } + if (NULL == (entry = ldap_first_entry( ld, res ))) { + debug( RPT_DEBUG, "Section [%s] not found in LDAP.", s->name); + if (NULL != buf) { + free(buf); + buf=NULL; + } + /* DON'T enable the following + * ldap_msgfree(entry); + * ldap_msgfree below does that already + */ + ldap_msgfree(res); + return NULL; + } + + + strcpy(buf, "lcdproc"); + strncat(buf, keyname, BUFSIZE); + /* debug( RPT_DEBUG, "Key name translated to attribute name: %s", buf); */ + vals = ldap_get_values (ld, entry, buf); + + if (skip+1 > ldap_count_values (vals)) { + debug( RPT_DEBUG, "No such entry found."); + if (NULL != buf) { + free(buf); + buf=NULL; + } + ldap_value_free(vals); + /* DON'T enable the following + * ldap_msgfree(entry); + * ldap_msgfree below does that already + */ + ldap_msgfree(res); + return NULL; + } + /* DON'T enable the following + * ldap_msgfree(entry); + * ldap_msgfree below does that already + */ + ldap_msgfree(res); + if (vals && vals[skip]) { + if (NULL != buf) { + free(buf); + buf=NULL; + } + buf=strdup(vals[skip]); + debug( RPT_DEBUG, "Entry found. Value is: %s", buf); + ldap_value_free (vals); + + k=(key*) malloc( sizeof( key )); + k->name = strdup( keyname ); + k->value = strdup( buf ); + k->next_key = NULL; + + if (NULL != buf) { + free(buf); + buf=NULL; + } + return k; + } + report( RPT_ERR, "LDAP server encountered errors."); + ldap_value_free (vals); + if (NULL != buf) { + free(buf); + buf=NULL; + } + return NULL; + } +#endif /* WITH_LDAP_SUPPORT */ + for( k=s->first_key; k; k=k->next_key ) { /* Did we find the right key ?*/