+/*
+ * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
+ * Copyright (C) 2001 Match Grun
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * Functions necessary to access LDAP servers.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#ifdef USE_LDAP
+
+#include <sys/time.h>
+#include <glib.h>
+#include <ldap.h>
+#include <lber.h>
+#include <pthread.h>
+#include <dlfcn.h>
+
+#include "mgutils.h"
+#include "syldap.h"
+
+/*
+* Specify name to be used.
+*/
+void syldap_set_name( SyldapServer* ldapServer, const gchar *value ) {
+ if( ldapServer->name ) g_free( ldapServer->name );
+ if( value ) ldapServer->name = g_strdup( value );
+ g_strstrip( ldapServer->name );
+}
+
+/*
+* Specify hostname to be used.
+*/
+void syldap_set_host( SyldapServer* ldapServer, const gchar *value ) {
+ mgu_refresh_cache( ldapServer->addressCache );
+
+ if( ldapServer->hostName ) g_free( ldapServer->hostName );
+ if( value ) ldapServer->hostName = g_strdup( value );
+ g_strstrip( ldapServer->hostName );
+}
+
+/*
+* Specify port to be used.
+*/
+void syldap_set_port( SyldapServer* ldapServer, const gint value ) {
+ mgu_refresh_cache( ldapServer->addressCache );
+
+ if( value > 0 ) {
+ ldapServer->port = value;
+ }
+ else {
+ ldapServer->port = SYLDAP_DFL_PORT;
+ }
+}
+
+/*
+* Specify base DN to be used.
+*/
+void syldap_set_base_dn( SyldapServer* ldapServer, const gchar *value ) {
+ mgu_refresh_cache( ldapServer->addressCache );
+
+ if( ldapServer->baseDN ) g_free( ldapServer->baseDN );
+ if( value ) ldapServer->baseDN = g_strdup( value );
+ g_strstrip( ldapServer->baseDN );
+}
+
+/*
+* Specify bind DN to be used.
+*/
+void syldap_set_bind_dn( SyldapServer* ldapServer, const gchar *value ) {
+ mgu_refresh_cache( ldapServer->addressCache );
+
+ if( ldapServer->bindDN ) g_free( ldapServer->bindDN );
+ if( value ) ldapServer->bindDN = g_strdup( value );
+ g_strstrip( ldapServer->bindDN );
+}
+
+/*
+* Specify bind password to be used.
+*/
+void syldap_set_bind_password( SyldapServer* ldapServer, const gchar *value ) {
+ mgu_refresh_cache( ldapServer->addressCache );
+
+ if( ldapServer->bindPass ) g_free( ldapServer->bindPass );
+ if( value ) ldapServer->bindPass = g_strdup( value );
+ g_strstrip( ldapServer->bindPass );
+}
+
+/*
+* Specify search criteria to be used.
+*/
+void syldap_set_search_criteria( SyldapServer* ldapServer, const gchar *value ) {
+ mgu_refresh_cache( ldapServer->addressCache );
+
+ if( ldapServer->searchCriteria ) g_free( ldapServer->searchCriteria );
+ if( value ) ldapServer->searchCriteria = g_strdup( value );
+ g_strstrip( ldapServer->searchCriteria );
+ ldapServer->newSearch = TRUE;
+}
+
+/*
+* Specify search value to be searched for.
+*/
+void syldap_set_search_value( SyldapServer* ldapServer, const gchar *value ) {
+ mgu_refresh_cache( ldapServer->addressCache );
+
+ if( ldapServer->searchValue ) g_free( ldapServer->searchValue );
+ if( value ) ldapServer->searchValue = g_strdup( value );
+ g_strstrip( ldapServer->searchValue );
+ ldapServer->newSearch = TRUE;
+}
+
+/*
+* Specify maximum number of entries to retrieve.
+*/
+void syldap_set_max_entries( SyldapServer* ldapServer, const gint value ) {
+ mgu_refresh_cache( ldapServer->addressCache );
+ if( value > 0 ) {
+ ldapServer->maxEntries = value;
+ }
+ else {
+ ldapServer->maxEntries = SYLDAP_MAX_ENTRIES;
+ }
+}
+
+/*
+* Specify timeout value for LDAP operation (in seconds).
+*/
+void syldap_set_timeout( SyldapServer* ldapServer, const gint value ) {
+ mgu_refresh_cache( ldapServer->addressCache );
+ if( value > 0 ) {
+ ldapServer->timeOut = value;
+ }
+ else {
+ ldapServer->timeOut = SYLDAP_DFL_TIMEOUT;
+ }
+}
+
+/*
+* Register a callback function. When called, the function will be passed
+* this object as an argument.
+*/
+void syldap_set_callback( SyldapServer *ldapServer, void *func ) {
+ ldapServer->callBack = func;
+}
+
+/*
+* Create new LDAP server interface object.
+*/
+SyldapServer *syldap_create() {
+ SyldapServer *ldapServer;
+ ldapServer = g_new( SyldapServer, 1 );
+ ldapServer->name = NULL;
+ ldapServer->hostName = NULL;
+ ldapServer->port = SYLDAP_DFL_PORT;
+ ldapServer->baseDN = NULL;
+ ldapServer->bindDN = NULL;
+ ldapServer->bindPass = NULL;
+ ldapServer->searchCriteria = NULL;
+ ldapServer->searchValue = NULL;
+ ldapServer->entriesRead = 0;
+ ldapServer->maxEntries = SYLDAP_MAX_ENTRIES;
+ ldapServer->timeOut = SYLDAP_DFL_TIMEOUT;
+ ldapServer->newSearch = TRUE;
+ ldapServer->addressCache = mgu_create_cache();
+ ldapServer->thread = NULL;
+ ldapServer->busyFlag = FALSE;
+ ldapServer->retVal = MGU_SUCCESS;
+ ldapServer->callBack = NULL;
+ return ldapServer;
+}
+
+/*
+* Refresh internal variables to force a file read.
+*/
+void syldap_force_refresh( SyldapServer *ldapServer ) {
+ mgu_refresh_cache( ldapServer->addressCache );
+ ldapServer->newSearch = TRUE;
+}
+
+/*
+* Free up LDAP server interface object by releasing internal memory.
+*/
+void syldap_free( SyldapServer *ldapServer ) {
+ g_return_if_fail( ldapServer != NULL );
+
+ ldapServer->callBack = NULL;
+ // fprintf( stdout, "freeing... SyldapServer\n" );
+
+ /* Free internal stuff */
+ g_free( ldapServer->name );
+ g_free( ldapServer->hostName );
+ g_free( ldapServer->baseDN );
+ g_free( ldapServer->bindDN );
+ g_free( ldapServer->bindPass );
+ g_free( ldapServer->searchCriteria );
+ g_free( ldapServer->searchValue );
+
+ ldapServer->port = 0;
+ ldapServer->entriesRead = 0;
+ ldapServer->maxEntries = 0;
+ ldapServer->newSearch = FALSE;
+
+ /* Clear cache */
+ mgu_clear_cache( ldapServer->addressCache );
+ mgu_free_cache( ldapServer->addressCache );
+
+ // Clear pointers
+ ldapServer->name = NULL;
+ ldapServer->hostName = NULL;
+ ldapServer->baseDN = NULL;
+ ldapServer->bindDN = NULL;
+ ldapServer->bindPass = NULL;
+ ldapServer->searchCriteria = NULL;
+ ldapServer->searchValue = NULL;
+ ldapServer->addressCache = NULL;
+ ldapServer->thread = NULL;
+ ldapServer->busyFlag = FALSE;
+ ldapServer->retVal = MGU_SUCCESS;
+
+ /* Now release file object */
+ g_free( ldapServer );
+
+ // fprintf( stdout, "freeing... SyldapServer done\n" );
+
+}
+
+/*
+* Display object to specified stream.
+*/
+void syldap_print_data( SyldapServer *ldapServer, FILE *stream ) {
+ GSList *node;
+ g_return_if_fail( ldapServer != NULL );
+ fprintf( stream, "SyldapServer:\n" );
+ fprintf( stream, " name: '%s'\n", ldapServer->name );
+ fprintf( stream, "host name: '%s'\n", ldapServer->hostName );
+ fprintf( stream, " port: %d\n", ldapServer->port );
+ fprintf( stream, " base dn: '%s'\n", ldapServer->baseDN );
+ fprintf( stream, " bind dn: '%s'\n", ldapServer->bindDN );
+ fprintf( stream, "bind pass: '%s'\n", ldapServer->bindPass );
+ fprintf( stream, " criteria: '%s'\n", ldapServer->searchCriteria );
+ fprintf( stream, "searchval: '%s'\n", ldapServer->searchValue );
+ fprintf( stream, "max entry: %d\n", ldapServer->maxEntries );
+ fprintf( stream, " num read: %d\n", ldapServer->entriesRead );
+ fprintf( stream, " ret val: %d\n", ldapServer->retVal );
+ mgu_print_cache( ldapServer->addressCache, stream );
+}
+
+/*
+* Display object to specified stream.
+*/
+void syldap_print_short( SyldapServer *ldapServer, FILE *stream ) {
+ GSList *node;
+ g_return_if_fail( ldapServer != NULL );
+ fprintf( stream, "SyldapServer:\n" );
+ fprintf( stream, " name: '%s'\n", ldapServer->name );
+ fprintf( stream, "host name: '%s'\n", ldapServer->hostName );
+ fprintf( stream, " port: %d\n", ldapServer->port );
+ fprintf( stream, " base dn: '%s'\n", ldapServer->baseDN );
+ fprintf( stream, " bind dn: '%s'\n", ldapServer->bindDN );
+ fprintf( stream, "bind pass: '%s'\n", ldapServer->bindPass );
+ fprintf( stream, " criteria: '%s'\n", ldapServer->searchCriteria );
+ fprintf( stream, "searchval: '%s'\n", ldapServer->searchValue );
+ fprintf( stream, "max entry: %d\n", ldapServer->maxEntries );
+ fprintf( stream, " num read: %d\n", ldapServer->entriesRead );
+ fprintf( stream, " ret val: %d\n", ldapServer->retVal );
+}
+
+/*
+* Build an address list entry and append to list of address items. Name is formatted
+* as it appears in the common name (cn) attribute.
+*/
+void syldap_build_items_cn( SyldapServer *ldapServer, GSList *listName, GSList *listAddr ) {
+ AddressItem *addrItem = NULL;
+ GSList *nodeName = listName;
+ while( nodeName ) {
+ GSList *nodeAddress = listAddr;
+ while( nodeAddress ) {
+ addrItem = mgu_create_address();
+ addrItem->name = g_strdup( nodeName->data );
+ addrItem->address = g_strdup( nodeAddress->data );
+ addrItem->remarks = g_strdup( "" );
+ mgu_add_cache( ldapServer->addressCache, addrItem );
+ nodeAddress = g_slist_next( nodeAddress );
+ ldapServer->entriesRead++;
+ }
+ nodeName = g_slist_next( nodeName );
+ }
+ addrItem = NULL;
+}
+
+/*
+* Build an address list entry and append to list of address items. Name is formatted
+* as "<first-name> <last-name>".
+*/
+void syldap_build_items_fl( SyldapServer *ldapServer, GSList *listAddr, GSList *listFirst, GSList *listLast ) {
+ AddressItem *addrItem = NULL;
+ GSList *nodeFirst = listFirst;
+ GSList *nodeAddress = listAddr;
+ gchar *firstName = NULL, *lastName = NULL, *fullName = NULL;
+ gint iLen = 0, iLenT = 0;
+
+ // Find longest first name in list
+ while( nodeFirst ) {
+ if( firstName == NULL ) {
+ firstName = nodeFirst->data;
+ iLen = strlen( firstName );
+ }
+ else {
+ if( ( iLenT = strlen( nodeFirst->data ) ) > iLen ) {
+ firstName = nodeFirst->data;
+ iLen = iLenT;
+ }
+ }
+ nodeFirst = g_slist_next( nodeFirst );
+ }
+
+ // Format name
+ if( listLast ) {
+ lastName = listLast->data;
+ }
+
+ if( firstName ) {
+ if( lastName ) {
+ fullName = g_strdup_printf( "%s %s", firstName, lastName );
+ }
+ else {
+ fullName = g_strdup_printf( "%s", firstName );
+ }
+ }
+ else {
+ if( lastName ) {
+ fullName = g_strdup_printf( "%s", lastName );
+ }
+ }
+ if( fullName ) {
+ g_strchug( fullName ); g_strchomp( fullName );
+ }
+
+ // Add address item
+ while( nodeAddress ) {
+ addrItem = mgu_create_address();
+ if( fullName ) {
+ addrItem->name = g_strdup( fullName );
+ }
+ else {
+ addrItem->name = g_strdup( "" );
+ }
+ addrItem->address = g_strdup( nodeAddress->data );
+ addrItem->remarks = g_strdup( "" );
+ mgu_add_cache( ldapServer->addressCache, addrItem );
+
+ nodeAddress = g_slist_next( nodeAddress );
+ ldapServer->entriesRead++;
+ }
+ g_free( fullName );
+ fullName = firstName = lastName = NULL;
+ addrItem = NULL;
+}
+
+/*
+* Add all attribute values to a list.
+*/
+GSList *syldap_add_list_values( LDAP *ld, LDAPMessage *entry, char *attr ) {
+ GSList *list = NULL;
+ gint i;
+ char **vals;
+ if( ( vals = ldap_get_values( ld, entry, attr ) ) != NULL ) {
+ for( i = 0; vals[i] != NULL; i++ ) {
+ // printf( "lv\t%s: %s\n", attr, vals[i] );
+ list = g_slist_append( list, g_strdup( vals[i] ) );
+ }
+ }
+ ldap_value_free( vals );
+ return list;
+}
+
+/*
+* Add a single attribute value to a list.
+*/
+GSList *syldap_add_single_value( LDAP *ld, LDAPMessage *entry, char *attr ) {
+ GSList *list = NULL;
+ char **vals;
+ if( ( vals = ldap_get_values( ld, entry, attr ) ) != NULL ) {
+ if( vals[0] != NULL ) {
+ // printf( "sv\t%s: %s\n", attr, vals[0] );
+ list = g_slist_append( list, g_strdup( vals[0] ) );
+ }
+ }
+ ldap_value_free( vals );
+ return list;
+}
+
+/*
+* Free linked lists of character strings.
+*/
+void syldap_free_lists( GSList *listName, GSList *listAddr, GSList *listID, GSList *listDN, GSList *listFirst, GSList *listLast ) {
+ mgu_free_list( listName );
+ mgu_free_list( listAddr );
+ mgu_free_list( listID );
+ mgu_free_list( listDN );
+ mgu_free_list( listFirst );
+ mgu_free_list( listLast );
+}
+
+/*
+* Check parameters that are required for a search. This should
+* be called before performing a search.
+* Return: TRUE if search criteria appear OK.
+*/
+gboolean syldap_check_search( SyldapServer *ldapServer ) {
+ g_return_if_fail( ldapServer != NULL );
+ ldapServer->retVal = MGU_LDAP_CRITERIA;
+
+ // Test search criteria
+ if( ldapServer->searchCriteria == NULL ) {
+ return FALSE;
+ }
+ if( strlen( ldapServer->searchCriteria ) < 1 ) {
+ return FALSE;
+ }
+
+ if( ldapServer->searchValue == NULL ) {
+ return FALSE;
+ }
+ if( strlen( ldapServer->searchValue ) < 1 ) {
+ return FALSE;
+ }
+
+ ldapServer->retVal = MGU_SUCCESS;
+ return TRUE;
+}
+
+/*
+* Perform the LDAP search, reading LDAP entries into cache.
+* Note that one LDAP entry can have multiple values for many of its
+* attributes. If these attributes are E-Mail addresses; these are
+* broken out into separate address items. For any other attribute,
+* only the first occurrence is read.
+*/
+gint syldap_search( SyldapServer *ldapServer ) {
+ LDAP *ld;
+ LDAPMessage *result, *e;
+ char *attribs[10];
+ char *attribute;
+ gchar *criteria;
+ BerElement *ber;
+ int rc, cnt;
+ GSList *listName = NULL, *listAddress = NULL, *listID = NULL;
+ GSList *listFirst = NULL, *listLast = NULL, *listDN = NULL;
+ struct timeval timeout;
+ gboolean entriesFound = FALSE;
+
+ g_return_if_fail( ldapServer != NULL );
+
+ ldapServer->retVal = MGU_SUCCESS;
+ if( ! syldap_check_search( ldapServer ) ) {
+ return ldapServer->retVal;
+ }
+
+ // Set timeout
+ timeout.tv_sec = ldapServer->timeOut;
+ timeout.tv_usec = 0L;
+
+ ldapServer->entriesRead = 0;
+ if( ( ld = ldap_init( ldapServer->hostName, ldapServer->port ) ) == NULL ) {
+ ldapServer->retVal = MGU_LDAP_INIT;
+ return ldapServer->retVal;
+ }
+
+ // printf( "connected to LDAP host %s on port %d\n", ldapServer->hostName, ldapServer->port );
+
+ // Bind to the server, if required
+ if( ldapServer->bindDN ) {
+ if( * ldapServer->bindDN != '\0' ) {
+ // printf( "binding...\n" );
+ rc = ldap_simple_bind_s( ld, ldapServer->bindDN, ldapServer->bindPass );
+ // printf( "rc=%d\n", rc );
+ if( rc != LDAP_SUCCESS ) {
+ // printf( "LDAP Error: ldap_simple_bind_s: %s\n", ldap_err2string( rc ) );
+ ldap_unbind( ld );
+ ldapServer->retVal = MGU_LDAP_BIND;
+ return ldapServer->retVal;
+ }
+ }
+ }
+
+ // Define all attributes we are interested in.
+ attribs[0] = SYLDAP_ATTR_DN;
+ attribs[1] = SYLDAP_ATTR_COMMONNAME;
+ attribs[2] = SYLDAP_ATTR_GIVENNAME;
+ attribs[3] = SYLDAP_ATTR_SURNAME;
+ attribs[4] = SYLDAP_ATTR_EMAIL;
+ attribs[5] = SYLDAP_ATTR_UID;
+ attribs[6] = NULL;
+
+ // Create LDAP search string and apply search criteria
+ criteria = g_strdup_printf( ldapServer->searchCriteria, ldapServer->searchValue );
+ rc = ldap_search_ext_s( ld, ldapServer->baseDN, LDAP_SCOPE_SUBTREE, criteria, attribs, 0, NULL, NULL,
+ &timeout, 0, &result );
+ g_free( criteria );
+ criteria = NULL;
+ if( rc == LDAP_TIMEOUT ) {
+ ldap_unbind( ld );
+ ldapServer->retVal = MGU_LDAP_TIMEOUT;
+ return ldapServer->retVal;
+ }
+ if( rc != LDAP_SUCCESS ) {
+ // printf( "LDAP Error: ldap_search_st: %s\n", ldap_err2string( rc ) );
+ ldap_unbind( ld );
+ ldapServer->retVal = MGU_LDAP_SEARCH;
+ return ldapServer->retVal;
+ }
+
+ // printf( "Total results are: %d\n", ldap_count_entries( ld, result ) );
+
+ // Clear the cache if we have new entries, otherwise leave untouched.
+ if( ldap_count_entries( ld, result ) > 0 ) {
+ mgu_clear_cache( ldapServer->addressCache );
+ }
+
+ // Process results
+ ldapServer->entriesRead = 0;
+ for( e = ldap_first_entry( ld, result ); e != NULL; e = ldap_next_entry( ld, e ) ) {
+ entriesFound = TRUE;
+ if( ldapServer->entriesRead >= ldapServer->maxEntries ) break;
+ // printf( "DN: %s\n", ldap_get_dn( ld, e ) );
+
+ // Process all attributes
+ for( attribute = ldap_first_attribute( ld, e, &ber ); attribute != NULL;
+ attribute = ldap_next_attribute( ld, e, ber ) ) {
+ if( strcasecmp( attribute, SYLDAP_ATTR_COMMONNAME ) == 0 ) {
+ listName = syldap_add_list_values( ld, e, attribute );
+ }
+ if( strcasecmp( attribute, SYLDAP_ATTR_EMAIL ) == 0 ) {
+ listAddress = syldap_add_list_values( ld, e, attribute );
+ }
+ if( strcasecmp( attribute, SYLDAP_ATTR_UID ) == 0 ) {
+ listID = syldap_add_single_value( ld, e, attribute );
+ }
+ if( strcasecmp( attribute, SYLDAP_ATTR_GIVENNAME ) == 0 ) {
+ listFirst = syldap_add_list_values( ld, e, attribute );
+ }
+ if( strcasecmp( attribute, SYLDAP_ATTR_SURNAME ) == 0 ) {
+ listLast = syldap_add_single_value( ld, e, attribute );
+ }
+ if( strcasecmp( attribute, SYLDAP_ATTR_DN ) == 0 ) {
+ listDN = syldap_add_single_value( ld, e, attribute );
+ }
+ }
+
+ // Free memory used to store attribute
+ ldap_memfree( attribute );
+
+ // Format and add items to cache
+ syldap_build_items_fl( ldapServer, listAddress, listFirst, listLast );
+
+ // Free up
+ syldap_free_lists( listName, listAddress, listID, listDN, listFirst, listLast );
+ listName = listAddress = listID = listFirst = listLast = listDN = NULL;
+
+ if( ber != NULL ) {
+ ber_free( ber, 0 );
+ }
+ }
+
+ syldap_free_lists( listName, listAddress, listID, listDN, listFirst, listLast );
+ listName = listAddress = listID = listFirst = listLast = listDN = NULL;
+
+ // Free up and disconnect
+ ldap_msgfree( result );
+ ldap_unbind( ld );
+ ldapServer->newSearch = FALSE;
+ if( entriesFound ) {
+ ldapServer->retVal = MGU_SUCCESS;
+ }
+ else {
+ ldapServer->retVal = MGU_LDAP_NOENTRIES;
+ }
+ return ldapServer->retVal;
+}
+
+// ============================================================================================
+/*
+* Read data into list. Main entry point
+* Return: TRUE if file read successfully.
+*/
+// ============================================================================================
+gint syldap_read_data( SyldapServer *ldapServer ) {
+ g_return_if_fail( ldapServer != NULL );
+
+ pthread_detach( pthread_self() );
+ if( ldapServer->newSearch ) {
+ // Read data into the list
+ syldap_search( ldapServer );
+
+ // Mark cache
+ ldapServer->addressCache->modified = FALSE;
+ ldapServer->addressCache->dataRead = TRUE;
+ }
+
+ // Callback
+ ldapServer->busyFlag = FALSE;
+ if( ldapServer->callBack ) {
+ sched_yield();
+ ( ldapServer->callBack )( ldapServer );
+ }
+ ldapServer->thread = NULL;
+ pthread_exit( NULL );
+ return ldapServer->retVal;
+}
+
+// ============================================================================================
+/*
+* Cancel read with thread.
+*/
+// ============================================================================================
+void syldap_cancel_read( SyldapServer *ldapServer ) {
+ g_return_if_fail( ldapServer != NULL );
+ if( ldapServer->thread ) {
+printf( "thread cancelled\n" );
+ pthread_cancel( *ldapServer->thread );
+ }
+ ldapServer->thread = NULL;
+ ldapServer->busyFlag = FALSE;
+}
+
+// ============================================================================================
+/*
+* Read data into list using a background thread.
+* Return: TRUE if file read successfully. Callback function will be
+* notified when search is complete.
+*/
+// ============================================================================================
+gint syldap_read_data_th( SyldapServer *ldapServer ) {
+ pthread_t thread;
+ g_return_if_fail( ldapServer != NULL );
+
+ ldapServer->busyFlag = FALSE;
+ syldap_check_search( ldapServer );
+ if( ldapServer->retVal == MGU_SUCCESS ) {
+ ldapServer->busyFlag = TRUE;
+ ldapServer->thread = &thread;
+ pthread_create( ldapServer->thread, NULL, (void *) &syldap_read_data, (void *) ldapServer );
+ }
+ return ldapServer->retVal;
+}
+
+/*
+* Return link list of address items.
+* Return: TRUE if file read successfully.
+*/
+GList *syldap_get_address_list( const SyldapServer *ldapServer ) {
+ g_return_if_fail( ldapServer != NULL );
+ return ldapServer->addressCache->addressList;
+}
+
+#define SYLDAP_TEST_FILTER "(objectclass=*)"
+#define SYLDAP_SEARCHBASE_V2 "cn=config"
+#define SYLDAP_SEARCHBASE_V3 ""
+#define SYLDAP_V2_TEST_ATTR "database"
+#define SYLDAP_V3_TEST_ATTR "namingcontexts"
+
+/*
+* Attempt to discover the base DN for the server.
+* Enter:
+* host Host name
+* port Port number
+* bindDN Bind DN (optional).
+* bindPW Bind PW (optional).
+* tov Timeout value (seconds), or 0 for none, default 30 secs.
+* Return: List of Base DN's, or NULL if could not read. Base DN should
+* be g_free() when done.
+*/
+GList *syldap_read_basedn_s( const gchar *host, const gint port, const gchar *bindDN, const gchar *bindPW, const gint tov ) {
+ GList *baseDN = NULL;
+ LDAP *ld;
+ int rc, i;
+ LDAPMessage *result, *e;
+ char *attribs[10];
+ BerElement *ber;
+ char *attribute;
+ char **vals;
+ struct timeval timeout;
+
+ if( host == NULL ) return baseDN;
+ if( port < 1 ) return baseDN;
+
+ // Set timeout
+ timeout.tv_usec = 0L;
+ if( tov > 0 ) {
+ timeout.tv_sec = tov;
+ }
+ else {
+ timeout.tv_sec = 30L;
+ }
+
+ // Connect to server.
+ if( ( ld = ldap_init( host, port ) ) == NULL ) {
+ return baseDN;
+ }
+
+ // Bind to the server, if required
+ if( bindDN ) {
+ if( *bindDN != '\0' ) {
+ rc = ldap_simple_bind_s( ld, bindDN, bindPW );
+ if( rc != LDAP_SUCCESS ) {
+ // printf( "LDAP Error: ldap_simple_bind_s: %s\n", ldap_err2string( rc ) );
+ ldap_unbind( ld );
+ return baseDN;
+ }
+ }
+ }
+
+ // Test for LDAP version 3
+ attribs[0] = SYLDAP_V3_TEST_ATTR;
+ attribs[1] = NULL;
+ rc = ldap_search_ext_s( ld, SYLDAP_SEARCHBASE_V3, LDAP_SCOPE_BASE, SYLDAP_TEST_FILTER, attribs,
+ 0, NULL, NULL, &timeout, 0, &result );
+ if( rc == LDAP_SUCCESS ) {
+ // Process entries
+ for( e = ldap_first_entry( ld, result ); e != NULL; e = ldap_next_entry( ld, e ) ) {
+ // printf( "DN: %s\n", ldap_get_dn( ld, e ) );
+
+ // Process attributes
+ for( attribute = ldap_first_attribute( ld, e, &ber ); attribute != NULL;
+ attribute = ldap_next_attribute( ld, e, ber ) ) {
+ if( strcasecmp( attribute, SYLDAP_V3_TEST_ATTR ) == 0 ) {
+ if( ( vals = ldap_get_values( ld, e, attribute ) ) != NULL ) {
+ for( i = 0; vals[i] != NULL; i++ ) {
+ // printf( "\t%s: %s\n", attribute, vals[i] );
+ baseDN = g_list_append( baseDN, g_strdup( vals[i] ) );
+ }
+ }
+ ldap_value_free( vals );
+ }
+ }
+ ldap_memfree( attribute );
+ if( ber != NULL ) {
+ ber_free( ber, 0 );
+ }
+ }
+ ldap_msgfree( result );
+ }
+ else {
+ }
+
+ if( baseDN == NULL ) {
+ // Test for LDAP version 2
+ attribs[0] = NULL;
+ rc = ldap_search_ext_s( ld, SYLDAP_SEARCHBASE_V2, LDAP_SCOPE_BASE, SYLDAP_TEST_FILTER, attribs,
+ 0, NULL, NULL, &timeout, 0, &result );
+ if( rc == LDAP_SUCCESS ) {
+ // Process entries
+ for( e = ldap_first_entry( ld, result ); e != NULL; e = ldap_next_entry( ld, e ) ) {
+ // if( baseDN ) break;
+ // printf( "DN: %s\n", ldap_get_dn( ld, e ) );
+
+ // Process attributes
+ for( attribute = ldap_first_attribute( ld, e, &ber ); attribute != NULL;
+ attribute = ldap_next_attribute( ld, e, ber ) ) {
+ // if( baseDN ) break;
+ if( strcasecmp( attribute, SYLDAP_V2_TEST_ATTR ) == 0 ) {
+ if( ( vals = ldap_get_values( ld, e, attribute ) ) != NULL ) {
+ for( i = 0; vals[i] != NULL; i++ ) {
+ char *ch;
+ // Strip the 'ldb:' from the front of the value
+ ch = ( char * ) strchr( vals[i], ':' );
+ if( ch ) {
+ gchar *bn = g_strdup( ++ch );
+ g_strchomp( bn );
+ g_strchug( bn );
+ baseDN = g_list_append( baseDN, g_strdup( bn ) );
+ }
+ }
+ }
+ ldap_value_free( vals );
+ }
+ }
+ ldap_memfree( attribute );
+ if( ber != NULL ) {
+ ber_free( ber, 0 );
+ }
+ }
+ ldap_msgfree( result );
+ }
+ }
+ ldap_unbind( ld );
+ return baseDN;
+}
+
+/*
+* Attempt to discover the base DN for the server.
+* Enter: ldapServer Server to test.
+* Return: List of Base DN's, or NULL if could not read. Base DN should
+* be g_free() when done. Return code set in ldapServer.
+*/
+GList *syldap_read_basedn( SyldapServer *ldapServer ) {
+ GList *baseDN = NULL;
+ LDAP *ld;
+ int rc, i;
+ LDAPMessage *result, *e;
+ char *attribs[10];
+ BerElement *ber;
+ char *attribute;
+ char **vals;
+ struct timeval timeout;
+
+ ldapServer->retVal = MGU_BAD_ARGS;
+ if( ldapServer == NULL ) return baseDN;
+ if( ldapServer->hostName == NULL ) return baseDN;
+ if( ldapServer->port < 1 ) return baseDN;
+
+ // Set timeout
+ timeout.tv_usec = 0L;
+ if( ldapServer->timeOut > 0 ) {
+ timeout.tv_sec = ldapServer->timeOut;
+ }
+ else {
+ timeout.tv_sec = 30L;
+ }
+
+ // Connect to server.
+ if( ( ld = ldap_init( ldapServer->hostName, ldapServer->port ) ) == NULL ) {
+ ldapServer->retVal = MGU_LDAP_INIT;
+ return baseDN;
+ }
+
+ // Bind to the server, if required
+ if( ldapServer->bindDN ) {
+ if( *ldapServer->bindDN != '\0' ) {
+ rc = ldap_simple_bind_s( ld, ldapServer->bindDN, ldapServer->bindPass );
+ if( rc != LDAP_SUCCESS ) {
+ //printf( "LDAP Error: ldap_simple_bind_s: %s\n", ldap_err2string( rc ) );
+ ldap_unbind( ld );
+ ldapServer->retVal = MGU_LDAP_BIND;
+ return baseDN;
+ }
+ }
+ }
+
+ ldapServer->retVal = MGU_LDAP_SEARCH;
+
+ // Test for LDAP version 3
+ attribs[0] = SYLDAP_V3_TEST_ATTR;
+ attribs[1] = NULL;
+ rc = ldap_search_ext_s( ld, SYLDAP_SEARCHBASE_V3, LDAP_SCOPE_BASE, SYLDAP_TEST_FILTER, attribs,
+ 0, NULL, NULL, &timeout, 0, &result );
+ if( rc == LDAP_SUCCESS ) {
+ // Process entries
+ for( e = ldap_first_entry( ld, result ); e != NULL; e = ldap_next_entry( ld, e ) ) {
+ // printf( "DN: %s\n", ldap_get_dn( ld, e ) );
+
+ // Process attributes
+ for( attribute = ldap_first_attribute( ld, e, &ber ); attribute != NULL;
+ attribute = ldap_next_attribute( ld, e, ber ) ) {
+ if( strcasecmp( attribute, SYLDAP_V3_TEST_ATTR ) == 0 ) {
+ if( ( vals = ldap_get_values( ld, e, attribute ) ) != NULL ) {
+ for( i = 0; vals[i] != NULL; i++ ) {
+ // printf( "\t%s: %s\n", attribute, vals[i] );
+ baseDN = g_list_append( baseDN, g_strdup( vals[i] ) );
+ }
+ }
+ ldap_value_free( vals );
+ }
+ }
+ ldap_memfree( attribute );
+ if( ber != NULL ) {
+ ber_free( ber, 0 );
+ }
+ }
+ ldap_msgfree( result );
+ ldapServer->retVal = MGU_SUCCESS;
+ }
+ else if( rc == LDAP_TIMEOUT ) {
+ ldapServer->retVal = MGU_LDAP_TIMEOUT;
+ }
+
+ if( baseDN == NULL ) {
+ // Test for LDAP version 2
+ attribs[0] = NULL;
+ rc = ldap_search_ext_s( ld, SYLDAP_SEARCHBASE_V2, LDAP_SCOPE_BASE, SYLDAP_TEST_FILTER, attribs,
+ 0, NULL, NULL, &timeout, 0, &result );
+ if( rc == LDAP_SUCCESS ) {
+ // Process entries
+ for( e = ldap_first_entry( ld, result ); e != NULL; e = ldap_next_entry( ld, e ) ) {
+ // if( baseDN ) break;
+ // printf( "DN: %s\n", ldap_get_dn( ld, e ) );
+
+ // Process attributes
+ for( attribute = ldap_first_attribute( ld, e, &ber ); attribute != NULL;
+ attribute = ldap_next_attribute( ld, e, ber ) ) {
+ // if( baseDN ) break;
+ if( strcasecmp( attribute, SYLDAP_V2_TEST_ATTR ) == 0 ) {
+ if( ( vals = ldap_get_values( ld, e, attribute ) ) != NULL ) {
+ for( i = 0; vals[i] != NULL; i++ ) {
+ char *ch;
+ // Strip the 'ldb:' from the front of the value
+ ch = ( char * ) strchr( vals[i], ':' );
+ if( ch ) {
+ gchar *bn = g_strdup( ++ch );
+ g_strchomp( bn );
+ g_strchug( bn );
+ baseDN = g_list_append( baseDN, g_strdup( bn ) );
+ }
+ }
+ }
+ ldap_value_free( vals );
+ }
+ }
+ ldap_memfree( attribute );
+ if( ber != NULL ) {
+ ber_free( ber, 0 );
+ }
+ }
+ ldap_msgfree( result );
+ ldapServer->retVal = MGU_SUCCESS;
+ }
+ else if( rc == LDAP_TIMEOUT ) {
+ ldapServer->retVal = MGU_LDAP_TIMEOUT;
+ }
+ }
+ ldap_unbind( ld );
+
+ return baseDN;
+}
+
+/*
+* Attempt to connect to the server.
+* Enter:
+* host Host name
+* port Port number
+* Return: TRUE if connected successfully.
+*/
+gboolean syldap_test_connect_s( const gchar *host, const gint port ) {
+ gboolean retVal = FALSE;
+ LDAP *ld;
+ if( host == NULL ) return retVal;
+ if( port < 1 ) return retVal;
+ if( ( ld = ldap_open( host, port ) ) != NULL ) {
+ retVal = TRUE;
+ }
+ if( ld != NULL ) {
+ ldap_unbind( ld );
+ }
+ return retVal;
+}
+
+/*
+* Attempt to connect to the server.
+* Enter: ldapServer Server to test.
+* Return: TRUE if connected successfully. Return code set in ldapServer.
+*/
+gboolean syldap_test_connect( SyldapServer *ldapServer ) {
+ gboolean retVal = FALSE;
+ LDAP *ld;
+ ldapServer->retVal = MGU_BAD_ARGS;
+ if( ldapServer == NULL ) return retVal;
+ if( ldapServer->hostName == NULL ) return retVal;
+ if( ldapServer->port < 1 ) return retVal;
+ ldapServer->retVal = MGU_LDAP_INIT;
+ if( ( ld = ldap_open( ldapServer->hostName, ldapServer->port ) ) != NULL ) {
+ ldapServer->retVal = MGU_SUCCESS;
+ retVal = TRUE;
+ }
+ if( ld != NULL ) {
+ ldap_unbind( ld );
+ }
+ return retVal;
+}
+
+#define LDAP_LINK_LIB_NAME_1 "libldap.so"
+#define LDAP_LINK_LIB_NAME_2 "liblber.so"
+#define LDAP_LINK_LIB_NAME_3 "libresolv.so"
+#define LDAP_LINK_LIB_NAME_4 "libpthread.so"
+
+/*
+* Test whether LDAP libraries installed.
+* Return: TRUE if library available.
+*/
+gboolean syldap_test_ldap_lib() {
+ void *handle, *fun;
+
+ // Get library
+ handle = dlopen( LDAP_LINK_LIB_NAME_1, RTLD_LAZY );
+ if( ! handle ) {
+ return FALSE;
+ }
+
+ // Test for symbols we need
+ fun = dlsym( handle, "ldap_init" );
+ if( ! fun ) {
+ dlclose( handle );
+ return FALSE;
+ }
+ dlclose( handle ); handle = NULL; fun = NULL;
+
+ handle = dlopen( LDAP_LINK_LIB_NAME_2, RTLD_LAZY );
+ if( ! handle ) {
+ return FALSE;
+ }
+ fun = dlsym( handle, "ber_init" );
+ if( ! fun ) {
+ dlclose( handle );
+ return FALSE;
+ }
+ dlclose( handle ); handle = NULL; fun = NULL;
+
+ handle = dlopen( LDAP_LINK_LIB_NAME_3, RTLD_LAZY );
+ if( ! handle ) {
+ return FALSE;
+ }
+ fun = dlsym( handle, "res_query" );
+ if( ! fun ) {
+ dlclose( handle );
+ return FALSE;
+ }
+ dlclose( handle ); handle = NULL; fun = NULL;
+
+ handle = dlopen( LDAP_LINK_LIB_NAME_4, RTLD_LAZY );
+ if( ! handle ) {
+ return FALSE;
+ }
+ fun = dlsym( handle, "pthread_create" );
+ if( ! fun ) {
+ dlclose( handle );
+ return FALSE;
+ }
+ dlclose( handle ); handle = NULL; fun = NULL;
+
+ return TRUE;
+}
+
+#endif /* USE_LDAP */
+
+/*
+* End of Source.
+*/