initial message templates support
[claws.git] / src / syldap.c
blob188f8c48ef07f1c6d79f118ed74bbbe3aedd786a
1 /*
2 * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3 * Copyright (C) 2001 Match Grun
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
21 * Functions necessary to access LDAP servers.
24 #ifdef HAVE_CONFIG_H
25 # include "config.h"
26 #endif
28 #ifdef USE_LDAP
30 #include <sys/time.h>
31 #include <glib.h>
32 #include <ldap.h>
33 #include <lber.h>
34 #include <pthread.h>
35 #include <dlfcn.h>
37 #include "mgutils.h"
38 #include "syldap.h"
41 * Specify name to be used.
43 void syldap_set_name( SyldapServer* ldapServer, const gchar *value ) {
44 if( ldapServer->name ) g_free( ldapServer->name );
45 if( value ) ldapServer->name = g_strdup( value );
46 g_strstrip( ldapServer->name );
50 * Specify hostname to be used.
52 void syldap_set_host( SyldapServer* ldapServer, const gchar *value ) {
53 mgu_refresh_cache( ldapServer->addressCache );
55 if( ldapServer->hostName ) g_free( ldapServer->hostName );
56 if( value ) ldapServer->hostName = g_strdup( value );
57 g_strstrip( ldapServer->hostName );
61 * Specify port to be used.
63 void syldap_set_port( SyldapServer* ldapServer, const gint value ) {
64 mgu_refresh_cache( ldapServer->addressCache );
66 if( value > 0 ) {
67 ldapServer->port = value;
69 else {
70 ldapServer->port = SYLDAP_DFL_PORT;
75 * Specify base DN to be used.
77 void syldap_set_base_dn( SyldapServer* ldapServer, const gchar *value ) {
78 mgu_refresh_cache( ldapServer->addressCache );
80 if( ldapServer->baseDN ) g_free( ldapServer->baseDN );
81 if( value ) ldapServer->baseDN = g_strdup( value );
82 g_strstrip( ldapServer->baseDN );
86 * Specify bind DN to be used.
88 void syldap_set_bind_dn( SyldapServer* ldapServer, const gchar *value ) {
89 mgu_refresh_cache( ldapServer->addressCache );
91 if( ldapServer->bindDN ) g_free( ldapServer->bindDN );
92 if( value ) ldapServer->bindDN = g_strdup( value );
93 g_strstrip( ldapServer->bindDN );
97 * Specify bind password to be used.
99 void syldap_set_bind_password( SyldapServer* ldapServer, const gchar *value ) {
100 mgu_refresh_cache( ldapServer->addressCache );
102 if( ldapServer->bindPass ) g_free( ldapServer->bindPass );
103 if( value ) ldapServer->bindPass = g_strdup( value );
104 g_strstrip( ldapServer->bindPass );
108 * Specify search criteria to be used.
110 void syldap_set_search_criteria( SyldapServer* ldapServer, const gchar *value ) {
111 mgu_refresh_cache( ldapServer->addressCache );
113 if( ldapServer->searchCriteria ) g_free( ldapServer->searchCriteria );
114 if( value ) ldapServer->searchCriteria = g_strdup( value );
115 g_strstrip( ldapServer->searchCriteria );
116 ldapServer->newSearch = TRUE;
120 * Specify search value to be searched for.
122 void syldap_set_search_value( SyldapServer* ldapServer, const gchar *value ) {
123 mgu_refresh_cache( ldapServer->addressCache );
125 if( ldapServer->searchValue ) g_free( ldapServer->searchValue );
126 if( value ) ldapServer->searchValue = g_strdup( value );
127 g_strstrip( ldapServer->searchValue );
128 ldapServer->newSearch = TRUE;
132 * Specify maximum number of entries to retrieve.
134 void syldap_set_max_entries( SyldapServer* ldapServer, const gint value ) {
135 mgu_refresh_cache( ldapServer->addressCache );
136 if( value > 0 ) {
137 ldapServer->maxEntries = value;
139 else {
140 ldapServer->maxEntries = SYLDAP_MAX_ENTRIES;
145 * Specify timeout value for LDAP operation (in seconds).
147 void syldap_set_timeout( SyldapServer* ldapServer, const gint value ) {
148 mgu_refresh_cache( ldapServer->addressCache );
149 if( value > 0 ) {
150 ldapServer->timeOut = value;
152 else {
153 ldapServer->timeOut = SYLDAP_DFL_TIMEOUT;
158 * Register a callback function. When called, the function will be passed
159 * this object as an argument.
161 void syldap_set_callback( SyldapServer *ldapServer, void *func ) {
162 ldapServer->callBack = func;
166 * Create new LDAP server interface object.
168 SyldapServer *syldap_create() {
169 SyldapServer *ldapServer;
170 ldapServer = g_new( SyldapServer, 1 );
171 ldapServer->name = NULL;
172 ldapServer->hostName = NULL;
173 ldapServer->port = SYLDAP_DFL_PORT;
174 ldapServer->baseDN = NULL;
175 ldapServer->bindDN = NULL;
176 ldapServer->bindPass = NULL;
177 ldapServer->searchCriteria = NULL;
178 ldapServer->searchValue = NULL;
179 ldapServer->entriesRead = 0;
180 ldapServer->maxEntries = SYLDAP_MAX_ENTRIES;
181 ldapServer->timeOut = SYLDAP_DFL_TIMEOUT;
182 ldapServer->newSearch = TRUE;
183 ldapServer->addressCache = mgu_create_cache();
184 ldapServer->thread = NULL;
185 ldapServer->busyFlag = FALSE;
186 ldapServer->retVal = MGU_SUCCESS;
187 ldapServer->callBack = NULL;
188 return ldapServer;
192 * Refresh internal variables to force a file read.
194 void syldap_force_refresh( SyldapServer *ldapServer ) {
195 mgu_refresh_cache( ldapServer->addressCache );
196 ldapServer->newSearch = TRUE;
200 * Free up LDAP server interface object by releasing internal memory.
202 void syldap_free( SyldapServer *ldapServer ) {
203 g_return_if_fail( ldapServer != NULL );
205 ldapServer->callBack = NULL;
206 // fprintf( stdout, "freeing... SyldapServer\n" );
208 /* Free internal stuff */
209 g_free( ldapServer->name );
210 g_free( ldapServer->hostName );
211 g_free( ldapServer->baseDN );
212 g_free( ldapServer->bindDN );
213 g_free( ldapServer->bindPass );
214 g_free( ldapServer->searchCriteria );
215 g_free( ldapServer->searchValue );
217 ldapServer->port = 0;
218 ldapServer->entriesRead = 0;
219 ldapServer->maxEntries = 0;
220 ldapServer->newSearch = FALSE;
222 /* Clear cache */
223 mgu_clear_cache( ldapServer->addressCache );
224 mgu_free_cache( ldapServer->addressCache );
226 // Clear pointers
227 ldapServer->name = NULL;
228 ldapServer->hostName = NULL;
229 ldapServer->baseDN = NULL;
230 ldapServer->bindDN = NULL;
231 ldapServer->bindPass = NULL;
232 ldapServer->searchCriteria = NULL;
233 ldapServer->searchValue = NULL;
234 ldapServer->addressCache = NULL;
235 ldapServer->thread = NULL;
236 ldapServer->busyFlag = FALSE;
237 ldapServer->retVal = MGU_SUCCESS;
239 /* Now release file object */
240 g_free( ldapServer );
242 // fprintf( stdout, "freeing... SyldapServer done\n" );
247 * Display object to specified stream.
249 void syldap_print_data( SyldapServer *ldapServer, FILE *stream ) {
250 GSList *node;
251 g_return_if_fail( ldapServer != NULL );
252 fprintf( stream, "SyldapServer:\n" );
253 fprintf( stream, " name: '%s'\n", ldapServer->name );
254 fprintf( stream, "host name: '%s'\n", ldapServer->hostName );
255 fprintf( stream, " port: %d\n", ldapServer->port );
256 fprintf( stream, " base dn: '%s'\n", ldapServer->baseDN );
257 fprintf( stream, " bind dn: '%s'\n", ldapServer->bindDN );
258 fprintf( stream, "bind pass: '%s'\n", ldapServer->bindPass );
259 fprintf( stream, " criteria: '%s'\n", ldapServer->searchCriteria );
260 fprintf( stream, "searchval: '%s'\n", ldapServer->searchValue );
261 fprintf( stream, "max entry: %d\n", ldapServer->maxEntries );
262 fprintf( stream, " num read: %d\n", ldapServer->entriesRead );
263 fprintf( stream, " ret val: %d\n", ldapServer->retVal );
264 mgu_print_cache( ldapServer->addressCache, stream );
268 * Display object to specified stream.
270 void syldap_print_short( SyldapServer *ldapServer, FILE *stream ) {
271 GSList *node;
272 g_return_if_fail( ldapServer != NULL );
273 fprintf( stream, "SyldapServer:\n" );
274 fprintf( stream, " name: '%s'\n", ldapServer->name );
275 fprintf( stream, "host name: '%s'\n", ldapServer->hostName );
276 fprintf( stream, " port: %d\n", ldapServer->port );
277 fprintf( stream, " base dn: '%s'\n", ldapServer->baseDN );
278 fprintf( stream, " bind dn: '%s'\n", ldapServer->bindDN );
279 fprintf( stream, "bind pass: '%s'\n", ldapServer->bindPass );
280 fprintf( stream, " criteria: '%s'\n", ldapServer->searchCriteria );
281 fprintf( stream, "searchval: '%s'\n", ldapServer->searchValue );
282 fprintf( stream, "max entry: %d\n", ldapServer->maxEntries );
283 fprintf( stream, " num read: %d\n", ldapServer->entriesRead );
284 fprintf( stream, " ret val: %d\n", ldapServer->retVal );
288 * Build an address list entry and append to list of address items. Name is formatted
289 * as it appears in the common name (cn) attribute.
291 void syldap_build_items_cn( SyldapServer *ldapServer, GSList *listName, GSList *listAddr ) {
292 AddressItem *addrItem = NULL;
293 GSList *nodeName = listName;
294 while( nodeName ) {
295 GSList *nodeAddress = listAddr;
296 while( nodeAddress ) {
297 addrItem = mgu_create_address();
298 addrItem->name = g_strdup( nodeName->data );
299 addrItem->address = g_strdup( nodeAddress->data );
300 addrItem->remarks = g_strdup( "" );
301 mgu_add_cache( ldapServer->addressCache, addrItem );
302 nodeAddress = g_slist_next( nodeAddress );
303 ldapServer->entriesRead++;
305 nodeName = g_slist_next( nodeName );
307 addrItem = NULL;
311 * Build an address list entry and append to list of address items. Name is formatted
312 * as "<first-name> <last-name>".
314 void syldap_build_items_fl( SyldapServer *ldapServer, GSList *listAddr, GSList *listFirst, GSList *listLast ) {
315 AddressItem *addrItem = NULL;
316 GSList *nodeFirst = listFirst;
317 GSList *nodeAddress = listAddr;
318 gchar *firstName = NULL, *lastName = NULL, *fullName = NULL;
319 gint iLen = 0, iLenT = 0;
321 // Find longest first name in list
322 while( nodeFirst ) {
323 if( firstName == NULL ) {
324 firstName = nodeFirst->data;
325 iLen = strlen( firstName );
327 else {
328 if( ( iLenT = strlen( nodeFirst->data ) ) > iLen ) {
329 firstName = nodeFirst->data;
330 iLen = iLenT;
333 nodeFirst = g_slist_next( nodeFirst );
336 // Format name
337 if( listLast ) {
338 lastName = listLast->data;
341 if( firstName ) {
342 if( lastName ) {
343 fullName = g_strdup_printf( "%s %s", firstName, lastName );
345 else {
346 fullName = g_strdup_printf( "%s", firstName );
349 else {
350 if( lastName ) {
351 fullName = g_strdup_printf( "%s", lastName );
354 if( fullName ) {
355 g_strchug( fullName ); g_strchomp( fullName );
358 // Add address item
359 while( nodeAddress ) {
360 addrItem = mgu_create_address();
361 if( fullName ) {
362 addrItem->name = g_strdup( fullName );
364 else {
365 addrItem->name = g_strdup( "" );
367 addrItem->address = g_strdup( nodeAddress->data );
368 addrItem->remarks = g_strdup( "" );
369 mgu_add_cache( ldapServer->addressCache, addrItem );
371 nodeAddress = g_slist_next( nodeAddress );
372 ldapServer->entriesRead++;
374 g_free( fullName );
375 fullName = firstName = lastName = NULL;
376 addrItem = NULL;
380 * Add all attribute values to a list.
382 GSList *syldap_add_list_values( LDAP *ld, LDAPMessage *entry, char *attr ) {
383 GSList *list = NULL;
384 gint i;
385 char **vals;
386 if( ( vals = ldap_get_values( ld, entry, attr ) ) != NULL ) {
387 for( i = 0; vals[i] != NULL; i++ ) {
388 // printf( "lv\t%s: %s\n", attr, vals[i] );
389 list = g_slist_append( list, g_strdup( vals[i] ) );
392 ldap_value_free( vals );
393 return list;
397 * Add a single attribute value to a list.
399 GSList *syldap_add_single_value( LDAP *ld, LDAPMessage *entry, char *attr ) {
400 GSList *list = NULL;
401 char **vals;
402 if( ( vals = ldap_get_values( ld, entry, attr ) ) != NULL ) {
403 if( vals[0] != NULL ) {
404 // printf( "sv\t%s: %s\n", attr, vals[0] );
405 list = g_slist_append( list, g_strdup( vals[0] ) );
408 ldap_value_free( vals );
409 return list;
413 * Free linked lists of character strings.
415 void syldap_free_lists( GSList *listName, GSList *listAddr, GSList *listID, GSList *listDN, GSList *listFirst, GSList *listLast ) {
416 mgu_free_list( listName );
417 mgu_free_list( listAddr );
418 mgu_free_list( listID );
419 mgu_free_list( listDN );
420 mgu_free_list( listFirst );
421 mgu_free_list( listLast );
425 * Check parameters that are required for a search. This should
426 * be called before performing a search.
427 * Return: TRUE if search criteria appear OK.
429 gboolean syldap_check_search( SyldapServer *ldapServer ) {
430 g_return_if_fail( ldapServer != NULL );
431 ldapServer->retVal = MGU_LDAP_CRITERIA;
433 // Test search criteria
434 if( ldapServer->searchCriteria == NULL ) {
435 return FALSE;
437 if( strlen( ldapServer->searchCriteria ) < 1 ) {
438 return FALSE;
441 if( ldapServer->searchValue == NULL ) {
442 return FALSE;
444 if( strlen( ldapServer->searchValue ) < 1 ) {
445 return FALSE;
448 ldapServer->retVal = MGU_SUCCESS;
449 return TRUE;
453 * Perform the LDAP search, reading LDAP entries into cache.
454 * Note that one LDAP entry can have multiple values for many of its
455 * attributes. If these attributes are E-Mail addresses; these are
456 * broken out into separate address items. For any other attribute,
457 * only the first occurrence is read.
459 gint syldap_search( SyldapServer *ldapServer ) {
460 LDAP *ld;
461 LDAPMessage *result, *e;
462 char *attribs[10];
463 char *attribute;
464 gchar *criteria;
465 BerElement *ber;
466 int rc, cnt;
467 GSList *listName = NULL, *listAddress = NULL, *listID = NULL;
468 GSList *listFirst = NULL, *listLast = NULL, *listDN = NULL;
469 struct timeval timeout;
470 gboolean entriesFound = FALSE;
472 g_return_if_fail( ldapServer != NULL );
474 ldapServer->retVal = MGU_SUCCESS;
475 if( ! syldap_check_search( ldapServer ) ) {
476 return ldapServer->retVal;
479 // Set timeout
480 timeout.tv_sec = ldapServer->timeOut;
481 timeout.tv_usec = 0L;
483 ldapServer->entriesRead = 0;
484 if( ( ld = ldap_init( ldapServer->hostName, ldapServer->port ) ) == NULL ) {
485 ldapServer->retVal = MGU_LDAP_INIT;
486 return ldapServer->retVal;
489 // printf( "connected to LDAP host %s on port %d\n", ldapServer->hostName, ldapServer->port );
491 // Bind to the server, if required
492 if( ldapServer->bindDN ) {
493 if( * ldapServer->bindDN != '\0' ) {
494 // printf( "binding...\n" );
495 rc = ldap_simple_bind_s( ld, ldapServer->bindDN, ldapServer->bindPass );
496 // printf( "rc=%d\n", rc );
497 if( rc != LDAP_SUCCESS ) {
498 // printf( "LDAP Error: ldap_simple_bind_s: %s\n", ldap_err2string( rc ) );
499 ldap_unbind( ld );
500 ldapServer->retVal = MGU_LDAP_BIND;
501 return ldapServer->retVal;
506 // Define all attributes we are interested in.
507 attribs[0] = SYLDAP_ATTR_DN;
508 attribs[1] = SYLDAP_ATTR_COMMONNAME;
509 attribs[2] = SYLDAP_ATTR_GIVENNAME;
510 attribs[3] = SYLDAP_ATTR_SURNAME;
511 attribs[4] = SYLDAP_ATTR_EMAIL;
512 attribs[5] = SYLDAP_ATTR_UID;
513 attribs[6] = NULL;
515 // Create LDAP search string and apply search criteria
516 criteria = g_strdup_printf( ldapServer->searchCriteria, ldapServer->searchValue );
517 rc = ldap_search_ext_s( ld, ldapServer->baseDN, LDAP_SCOPE_SUBTREE, criteria, attribs, 0, NULL, NULL,
518 &timeout, 0, &result );
519 g_free( criteria );
520 criteria = NULL;
521 if( rc == LDAP_TIMEOUT ) {
522 ldap_unbind( ld );
523 ldapServer->retVal = MGU_LDAP_TIMEOUT;
524 return ldapServer->retVal;
526 if( rc != LDAP_SUCCESS ) {
527 // printf( "LDAP Error: ldap_search_st: %s\n", ldap_err2string( rc ) );
528 ldap_unbind( ld );
529 ldapServer->retVal = MGU_LDAP_SEARCH;
530 return ldapServer->retVal;
533 // printf( "Total results are: %d\n", ldap_count_entries( ld, result ) );
535 // Clear the cache if we have new entries, otherwise leave untouched.
536 if( ldap_count_entries( ld, result ) > 0 ) {
537 mgu_clear_cache( ldapServer->addressCache );
540 // Process results
541 ldapServer->entriesRead = 0;
542 for( e = ldap_first_entry( ld, result ); e != NULL; e = ldap_next_entry( ld, e ) ) {
543 entriesFound = TRUE;
544 if( ldapServer->entriesRead >= ldapServer->maxEntries ) break;
545 // printf( "DN: %s\n", ldap_get_dn( ld, e ) );
547 // Process all attributes
548 for( attribute = ldap_first_attribute( ld, e, &ber ); attribute != NULL;
549 attribute = ldap_next_attribute( ld, e, ber ) ) {
550 if( strcasecmp( attribute, SYLDAP_ATTR_COMMONNAME ) == 0 ) {
551 listName = syldap_add_list_values( ld, e, attribute );
553 if( strcasecmp( attribute, SYLDAP_ATTR_EMAIL ) == 0 ) {
554 listAddress = syldap_add_list_values( ld, e, attribute );
556 if( strcasecmp( attribute, SYLDAP_ATTR_UID ) == 0 ) {
557 listID = syldap_add_single_value( ld, e, attribute );
559 if( strcasecmp( attribute, SYLDAP_ATTR_GIVENNAME ) == 0 ) {
560 listFirst = syldap_add_list_values( ld, e, attribute );
562 if( strcasecmp( attribute, SYLDAP_ATTR_SURNAME ) == 0 ) {
563 listLast = syldap_add_single_value( ld, e, attribute );
565 if( strcasecmp( attribute, SYLDAP_ATTR_DN ) == 0 ) {
566 listDN = syldap_add_single_value( ld, e, attribute );
570 // Free memory used to store attribute
571 ldap_memfree( attribute );
573 // Format and add items to cache
574 syldap_build_items_fl( ldapServer, listAddress, listFirst, listLast );
576 // Free up
577 syldap_free_lists( listName, listAddress, listID, listDN, listFirst, listLast );
578 listName = listAddress = listID = listFirst = listLast = listDN = NULL;
580 if( ber != NULL ) {
581 ber_free( ber, 0 );
585 syldap_free_lists( listName, listAddress, listID, listDN, listFirst, listLast );
586 listName = listAddress = listID = listFirst = listLast = listDN = NULL;
588 // Free up and disconnect
589 ldap_msgfree( result );
590 ldap_unbind( ld );
591 ldapServer->newSearch = FALSE;
592 if( entriesFound ) {
593 ldapServer->retVal = MGU_SUCCESS;
595 else {
596 ldapServer->retVal = MGU_LDAP_NOENTRIES;
598 return ldapServer->retVal;
601 // ============================================================================================
603 * Read data into list. Main entry point
604 * Return: TRUE if file read successfully.
606 // ============================================================================================
607 gint syldap_read_data( SyldapServer *ldapServer ) {
608 g_return_if_fail( ldapServer != NULL );
610 pthread_detach( pthread_self() );
611 if( ldapServer->newSearch ) {
612 // Read data into the list
613 syldap_search( ldapServer );
615 // Mark cache
616 ldapServer->addressCache->modified = FALSE;
617 ldapServer->addressCache->dataRead = TRUE;
620 // Callback
621 ldapServer->busyFlag = FALSE;
622 if( ldapServer->callBack ) {
623 sched_yield();
624 ( ldapServer->callBack )( ldapServer );
626 ldapServer->thread = NULL;
627 pthread_exit( NULL );
628 return ldapServer->retVal;
631 // ============================================================================================
633 * Cancel read with thread.
635 // ============================================================================================
636 void syldap_cancel_read( SyldapServer *ldapServer ) {
637 g_return_if_fail( ldapServer != NULL );
638 if( ldapServer->thread ) {
639 printf( "thread cancelled\n" );
640 pthread_cancel( *ldapServer->thread );
642 ldapServer->thread = NULL;
643 ldapServer->busyFlag = FALSE;
646 // ============================================================================================
648 * Read data into list using a background thread.
649 * Return: TRUE if file read successfully. Callback function will be
650 * notified when search is complete.
652 // ============================================================================================
653 gint syldap_read_data_th( SyldapServer *ldapServer ) {
654 pthread_t thread;
655 g_return_if_fail( ldapServer != NULL );
657 ldapServer->busyFlag = FALSE;
658 syldap_check_search( ldapServer );
659 if( ldapServer->retVal == MGU_SUCCESS ) {
660 ldapServer->busyFlag = TRUE;
661 ldapServer->thread = &thread;
662 pthread_create( ldapServer->thread, NULL, (void *) &syldap_read_data, (void *) ldapServer );
664 return ldapServer->retVal;
668 * Return link list of address items.
669 * Return: TRUE if file read successfully.
671 GList *syldap_get_address_list( const SyldapServer *ldapServer ) {
672 g_return_if_fail( ldapServer != NULL );
673 return ldapServer->addressCache->addressList;
676 #define SYLDAP_TEST_FILTER "(objectclass=*)"
677 #define SYLDAP_SEARCHBASE_V2 "cn=config"
678 #define SYLDAP_SEARCHBASE_V3 ""
679 #define SYLDAP_V2_TEST_ATTR "database"
680 #define SYLDAP_V3_TEST_ATTR "namingcontexts"
683 * Attempt to discover the base DN for the server.
684 * Enter:
685 * host Host name
686 * port Port number
687 * bindDN Bind DN (optional).
688 * bindPW Bind PW (optional).
689 * tov Timeout value (seconds), or 0 for none, default 30 secs.
690 * Return: List of Base DN's, or NULL if could not read. Base DN should
691 * be g_free() when done.
693 GList *syldap_read_basedn_s( const gchar *host, const gint port, const gchar *bindDN, const gchar *bindPW, const gint tov ) {
694 GList *baseDN = NULL;
695 LDAP *ld;
696 int rc, i;
697 LDAPMessage *result, *e;
698 char *attribs[10];
699 BerElement *ber;
700 char *attribute;
701 char **vals;
702 struct timeval timeout;
704 if( host == NULL ) return baseDN;
705 if( port < 1 ) return baseDN;
707 // Set timeout
708 timeout.tv_usec = 0L;
709 if( tov > 0 ) {
710 timeout.tv_sec = tov;
712 else {
713 timeout.tv_sec = 30L;
716 // Connect to server.
717 if( ( ld = ldap_init( host, port ) ) == NULL ) {
718 return baseDN;
721 // Bind to the server, if required
722 if( bindDN ) {
723 if( *bindDN != '\0' ) {
724 rc = ldap_simple_bind_s( ld, bindDN, bindPW );
725 if( rc != LDAP_SUCCESS ) {
726 // printf( "LDAP Error: ldap_simple_bind_s: %s\n", ldap_err2string( rc ) );
727 ldap_unbind( ld );
728 return baseDN;
733 // Test for LDAP version 3
734 attribs[0] = SYLDAP_V3_TEST_ATTR;
735 attribs[1] = NULL;
736 rc = ldap_search_ext_s( ld, SYLDAP_SEARCHBASE_V3, LDAP_SCOPE_BASE, SYLDAP_TEST_FILTER, attribs,
737 0, NULL, NULL, &timeout, 0, &result );
738 if( rc == LDAP_SUCCESS ) {
739 // Process entries
740 for( e = ldap_first_entry( ld, result ); e != NULL; e = ldap_next_entry( ld, e ) ) {
741 // printf( "DN: %s\n", ldap_get_dn( ld, e ) );
743 // Process attributes
744 for( attribute = ldap_first_attribute( ld, e, &ber ); attribute != NULL;
745 attribute = ldap_next_attribute( ld, e, ber ) ) {
746 if( strcasecmp( attribute, SYLDAP_V3_TEST_ATTR ) == 0 ) {
747 if( ( vals = ldap_get_values( ld, e, attribute ) ) != NULL ) {
748 for( i = 0; vals[i] != NULL; i++ ) {
749 // printf( "\t%s: %s\n", attribute, vals[i] );
750 baseDN = g_list_append( baseDN, g_strdup( vals[i] ) );
753 ldap_value_free( vals );
756 ldap_memfree( attribute );
757 if( ber != NULL ) {
758 ber_free( ber, 0 );
761 ldap_msgfree( result );
763 else {
766 if( baseDN == NULL ) {
767 // Test for LDAP version 2
768 attribs[0] = NULL;
769 rc = ldap_search_ext_s( ld, SYLDAP_SEARCHBASE_V2, LDAP_SCOPE_BASE, SYLDAP_TEST_FILTER, attribs,
770 0, NULL, NULL, &timeout, 0, &result );
771 if( rc == LDAP_SUCCESS ) {
772 // Process entries
773 for( e = ldap_first_entry( ld, result ); e != NULL; e = ldap_next_entry( ld, e ) ) {
774 // if( baseDN ) break;
775 // printf( "DN: %s\n", ldap_get_dn( ld, e ) );
777 // Process attributes
778 for( attribute = ldap_first_attribute( ld, e, &ber ); attribute != NULL;
779 attribute = ldap_next_attribute( ld, e, ber ) ) {
780 // if( baseDN ) break;
781 if( strcasecmp( attribute, SYLDAP_V2_TEST_ATTR ) == 0 ) {
782 if( ( vals = ldap_get_values( ld, e, attribute ) ) != NULL ) {
783 for( i = 0; vals[i] != NULL; i++ ) {
784 char *ch;
785 // Strip the 'ldb:' from the front of the value
786 ch = ( char * ) strchr( vals[i], ':' );
787 if( ch ) {
788 gchar *bn = g_strdup( ++ch );
789 g_strchomp( bn );
790 g_strchug( bn );
791 baseDN = g_list_append( baseDN, g_strdup( bn ) );
795 ldap_value_free( vals );
798 ldap_memfree( attribute );
799 if( ber != NULL ) {
800 ber_free( ber, 0 );
803 ldap_msgfree( result );
806 ldap_unbind( ld );
807 return baseDN;
811 * Attempt to discover the base DN for the server.
812 * Enter: ldapServer Server to test.
813 * Return: List of Base DN's, or NULL if could not read. Base DN should
814 * be g_free() when done. Return code set in ldapServer.
816 GList *syldap_read_basedn( SyldapServer *ldapServer ) {
817 GList *baseDN = NULL;
818 LDAP *ld;
819 int rc, i;
820 LDAPMessage *result, *e;
821 char *attribs[10];
822 BerElement *ber;
823 char *attribute;
824 char **vals;
825 struct timeval timeout;
827 ldapServer->retVal = MGU_BAD_ARGS;
828 if( ldapServer == NULL ) return baseDN;
829 if( ldapServer->hostName == NULL ) return baseDN;
830 if( ldapServer->port < 1 ) return baseDN;
832 // Set timeout
833 timeout.tv_usec = 0L;
834 if( ldapServer->timeOut > 0 ) {
835 timeout.tv_sec = ldapServer->timeOut;
837 else {
838 timeout.tv_sec = 30L;
841 // Connect to server.
842 if( ( ld = ldap_init( ldapServer->hostName, ldapServer->port ) ) == NULL ) {
843 ldapServer->retVal = MGU_LDAP_INIT;
844 return baseDN;
847 // Bind to the server, if required
848 if( ldapServer->bindDN ) {
849 if( *ldapServer->bindDN != '\0' ) {
850 rc = ldap_simple_bind_s( ld, ldapServer->bindDN, ldapServer->bindPass );
851 if( rc != LDAP_SUCCESS ) {
852 //printf( "LDAP Error: ldap_simple_bind_s: %s\n", ldap_err2string( rc ) );
853 ldap_unbind( ld );
854 ldapServer->retVal = MGU_LDAP_BIND;
855 return baseDN;
860 ldapServer->retVal = MGU_LDAP_SEARCH;
862 // Test for LDAP version 3
863 attribs[0] = SYLDAP_V3_TEST_ATTR;
864 attribs[1] = NULL;
865 rc = ldap_search_ext_s( ld, SYLDAP_SEARCHBASE_V3, LDAP_SCOPE_BASE, SYLDAP_TEST_FILTER, attribs,
866 0, NULL, NULL, &timeout, 0, &result );
867 if( rc == LDAP_SUCCESS ) {
868 // Process entries
869 for( e = ldap_first_entry( ld, result ); e != NULL; e = ldap_next_entry( ld, e ) ) {
870 // printf( "DN: %s\n", ldap_get_dn( ld, e ) );
872 // Process attributes
873 for( attribute = ldap_first_attribute( ld, e, &ber ); attribute != NULL;
874 attribute = ldap_next_attribute( ld, e, ber ) ) {
875 if( strcasecmp( attribute, SYLDAP_V3_TEST_ATTR ) == 0 ) {
876 if( ( vals = ldap_get_values( ld, e, attribute ) ) != NULL ) {
877 for( i = 0; vals[i] != NULL; i++ ) {
878 // printf( "\t%s: %s\n", attribute, vals[i] );
879 baseDN = g_list_append( baseDN, g_strdup( vals[i] ) );
882 ldap_value_free( vals );
885 ldap_memfree( attribute );
886 if( ber != NULL ) {
887 ber_free( ber, 0 );
890 ldap_msgfree( result );
891 ldapServer->retVal = MGU_SUCCESS;
893 else if( rc == LDAP_TIMEOUT ) {
894 ldapServer->retVal = MGU_LDAP_TIMEOUT;
897 if( baseDN == NULL ) {
898 // Test for LDAP version 2
899 attribs[0] = NULL;
900 rc = ldap_search_ext_s( ld, SYLDAP_SEARCHBASE_V2, LDAP_SCOPE_BASE, SYLDAP_TEST_FILTER, attribs,
901 0, NULL, NULL, &timeout, 0, &result );
902 if( rc == LDAP_SUCCESS ) {
903 // Process entries
904 for( e = ldap_first_entry( ld, result ); e != NULL; e = ldap_next_entry( ld, e ) ) {
905 // if( baseDN ) break;
906 // printf( "DN: %s\n", ldap_get_dn( ld, e ) );
908 // Process attributes
909 for( attribute = ldap_first_attribute( ld, e, &ber ); attribute != NULL;
910 attribute = ldap_next_attribute( ld, e, ber ) ) {
911 // if( baseDN ) break;
912 if( strcasecmp( attribute, SYLDAP_V2_TEST_ATTR ) == 0 ) {
913 if( ( vals = ldap_get_values( ld, e, attribute ) ) != NULL ) {
914 for( i = 0; vals[i] != NULL; i++ ) {
915 char *ch;
916 // Strip the 'ldb:' from the front of the value
917 ch = ( char * ) strchr( vals[i], ':' );
918 if( ch ) {
919 gchar *bn = g_strdup( ++ch );
920 g_strchomp( bn );
921 g_strchug( bn );
922 baseDN = g_list_append( baseDN, g_strdup( bn ) );
926 ldap_value_free( vals );
929 ldap_memfree( attribute );
930 if( ber != NULL ) {
931 ber_free( ber, 0 );
934 ldap_msgfree( result );
935 ldapServer->retVal = MGU_SUCCESS;
937 else if( rc == LDAP_TIMEOUT ) {
938 ldapServer->retVal = MGU_LDAP_TIMEOUT;
941 ldap_unbind( ld );
943 return baseDN;
947 * Attempt to connect to the server.
948 * Enter:
949 * host Host name
950 * port Port number
951 * Return: TRUE if connected successfully.
953 gboolean syldap_test_connect_s( const gchar *host, const gint port ) {
954 gboolean retVal = FALSE;
955 LDAP *ld;
956 if( host == NULL ) return retVal;
957 if( port < 1 ) return retVal;
958 if( ( ld = ldap_open( host, port ) ) != NULL ) {
959 retVal = TRUE;
961 if( ld != NULL ) {
962 ldap_unbind( ld );
964 return retVal;
968 * Attempt to connect to the server.
969 * Enter: ldapServer Server to test.
970 * Return: TRUE if connected successfully. Return code set in ldapServer.
972 gboolean syldap_test_connect( SyldapServer *ldapServer ) {
973 gboolean retVal = FALSE;
974 LDAP *ld;
975 ldapServer->retVal = MGU_BAD_ARGS;
976 if( ldapServer == NULL ) return retVal;
977 if( ldapServer->hostName == NULL ) return retVal;
978 if( ldapServer->port < 1 ) return retVal;
979 ldapServer->retVal = MGU_LDAP_INIT;
980 if( ( ld = ldap_open( ldapServer->hostName, ldapServer->port ) ) != NULL ) {
981 ldapServer->retVal = MGU_SUCCESS;
982 retVal = TRUE;
984 if( ld != NULL ) {
985 ldap_unbind( ld );
987 return retVal;
990 #define LDAP_LINK_LIB_NAME_1 "libldap.so"
991 #define LDAP_LINK_LIB_NAME_2 "liblber.so"
992 #define LDAP_LINK_LIB_NAME_3 "libresolv.so"
993 #define LDAP_LINK_LIB_NAME_4 "libpthread.so"
996 * Test whether LDAP libraries installed.
997 * Return: TRUE if library available.
999 gboolean syldap_test_ldap_lib() {
1000 void *handle, *fun;
1002 // Get library
1003 handle = dlopen( LDAP_LINK_LIB_NAME_1, RTLD_LAZY );
1004 if( ! handle ) {
1005 return FALSE;
1008 // Test for symbols we need
1009 fun = dlsym( handle, "ldap_init" );
1010 if( ! fun ) {
1011 dlclose( handle );
1012 return FALSE;
1014 dlclose( handle ); handle = NULL; fun = NULL;
1016 handle = dlopen( LDAP_LINK_LIB_NAME_2, RTLD_LAZY );
1017 if( ! handle ) {
1018 return FALSE;
1020 fun = dlsym( handle, "ber_init" );
1021 if( ! fun ) {
1022 dlclose( handle );
1023 return FALSE;
1025 dlclose( handle ); handle = NULL; fun = NULL;
1027 handle = dlopen( LDAP_LINK_LIB_NAME_3, RTLD_LAZY );
1028 if( ! handle ) {
1029 return FALSE;
1031 fun = dlsym( handle, "res_query" );
1032 if( ! fun ) {
1033 dlclose( handle );
1034 return FALSE;
1036 dlclose( handle ); handle = NULL; fun = NULL;
1038 handle = dlopen( LDAP_LINK_LIB_NAME_4, RTLD_LAZY );
1039 if( ! handle ) {
1040 return FALSE;
1042 fun = dlsym( handle, "pthread_create" );
1043 if( ! fun ) {
1044 dlclose( handle );
1045 return FALSE;
1047 dlclose( handle ); handle = NULL; fun = NULL;
1049 return TRUE;
1052 #endif /* USE_LDAP */
1055 * End of Source.