d0d1cf710f091140b0dea6527ece4c0fb6807b4f
[claws.git] / src / syldap.c
1 /*
2  * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3  * Copyright (C) 2001 Match Grun
4  *
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.
9  *
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.
14  *
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.
18  */
19
20 /*
21  * Functions necessary to access LDAP servers.
22  */
23
24 #ifdef HAVE_CONFIG_H
25 #  include "config.h"
26 #endif
27
28 #ifdef USE_LDAP
29
30 #include <glib.h>
31 #include <sys/time.h>
32 #include <string.h>
33 #include <ldap.h>
34 #include <lber.h>
35 #include <pthread.h>
36 #include <dlfcn.h>
37
38 #include "mgutils.h"
39 #include "addritem.h"
40 #include "addrcache.h"
41 #include "syldap.h"
42 #include "utils.h"
43
44 /*
45 * Create new LDAP server interface object.
46 */
47 SyldapServer *syldap_create() {
48         SyldapServer *ldapServer;
49
50         debug_print("Creating LDAP server interface object\n");
51
52         ldapServer = g_new0( SyldapServer, 1 );
53         ldapServer->name = NULL;
54         ldapServer->hostName = NULL;
55         ldapServer->port = SYLDAP_DFL_PORT;
56         ldapServer->baseDN = NULL;
57         ldapServer->bindDN = NULL;
58         ldapServer->bindPass = NULL;
59         ldapServer->searchCriteria = NULL;
60         ldapServer->searchValue = NULL;
61         ldapServer->entriesRead = 0;
62         ldapServer->maxEntries = SYLDAP_MAX_ENTRIES;
63         ldapServer->timeOut = SYLDAP_DFL_TIMEOUT;
64         ldapServer->newSearch = TRUE;
65         ldapServer->addressCache = addrcache_create();
66         ldapServer->thread = NULL;
67         ldapServer->busyFlag = FALSE;
68         ldapServer->retVal = MGU_SUCCESS;
69         ldapServer->callBack = NULL;
70         ldapServer->accessFlag = FALSE;
71         return ldapServer;
72 }
73
74 /*
75 * Specify name to be used.
76 */
77 void syldap_set_name( SyldapServer* ldapServer, const gchar *value ) {
78         ldapServer->name = mgu_replace_string( ldapServer->name, value );
79         g_strstrip( ldapServer->name );
80 }
81
82 /*
83 * Specify hostname to be used.
84 */
85 void syldap_set_host( SyldapServer* ldapServer, const gchar *value ) {
86         addrcache_refresh( ldapServer->addressCache );
87         ldapServer->hostName = mgu_replace_string( ldapServer->hostName, value );
88         g_strstrip( ldapServer->hostName );
89 }
90
91 /*
92 * Specify port to be used.
93 */
94 void syldap_set_port( SyldapServer* ldapServer, const gint value ) {
95         addrcache_refresh( ldapServer->addressCache );
96         if( value > 0 ) {
97                 ldapServer->port = value;
98         }
99         else {
100                 ldapServer->port = SYLDAP_DFL_PORT;
101         }
102 }
103
104 /*
105 * Specify base DN to be used.
106 */
107 void syldap_set_base_dn( SyldapServer* ldapServer, const gchar *value ) {
108         addrcache_refresh( ldapServer->addressCache );
109         ldapServer->baseDN = mgu_replace_string( ldapServer->baseDN, value );
110         g_strstrip( ldapServer->baseDN );
111 }
112
113 /*
114 * Specify bind DN to be used.
115 */
116 void syldap_set_bind_dn( SyldapServer* ldapServer, const gchar *value ) {
117         addrcache_refresh( ldapServer->addressCache );
118         ldapServer->bindDN = mgu_replace_string( ldapServer->bindDN, value );
119         g_strstrip( ldapServer->bindDN );
120 }
121
122 /*
123 * Specify bind password to be used.
124 */
125 void syldap_set_bind_password( SyldapServer* ldapServer, const gchar *value ) {
126         addrcache_refresh( ldapServer->addressCache );
127         ldapServer->bindPass = mgu_replace_string( ldapServer->bindPass, value );
128         g_strstrip( ldapServer->bindPass );
129 }
130
131 /*
132 * Specify search criteria to be used.
133 */
134 void syldap_set_search_criteria( SyldapServer* ldapServer, const gchar *value ) {
135         addrcache_refresh( ldapServer->addressCache );
136         ldapServer->searchCriteria = mgu_replace_string( ldapServer->searchCriteria, value );
137         g_strstrip( ldapServer->searchCriteria );
138         ldapServer->newSearch = TRUE;
139 }
140
141 /*
142 * Specify search value to be searched for.
143 */
144 void syldap_set_search_value( SyldapServer* ldapServer, const gchar *value ) {
145         addrcache_refresh( ldapServer->addressCache );
146         ldapServer->searchValue = mgu_replace_string( ldapServer->searchValue, value );
147         g_strstrip( ldapServer->searchValue );
148         ldapServer->newSearch = TRUE;
149 }
150
151 /*
152 * Specify maximum number of entries to retrieve.
153 */
154 void syldap_set_max_entries( SyldapServer* ldapServer, const gint value ) {
155         addrcache_refresh( ldapServer->addressCache );
156         if( value > 0 ) {
157                 ldapServer->maxEntries = value;
158         }
159         else {
160                 ldapServer->maxEntries = SYLDAP_MAX_ENTRIES;
161         }
162 }
163
164 /*
165 * Specify timeout value for LDAP operation (in seconds).
166 */
167 void syldap_set_timeout( SyldapServer* ldapServer, const gint value ) {
168         addrcache_refresh( ldapServer->addressCache );
169         if( value > 0 ) {
170                 ldapServer->timeOut = value;
171         }
172         else {
173                 ldapServer->timeOut = SYLDAP_DFL_TIMEOUT;
174         }
175 }
176
177 /*
178 * Register a callback function. When called, the function will be passed
179 * this object as an argument.
180 */
181 void syldap_set_callback( SyldapServer *ldapServer, void *func ) {
182         ldapServer->callBack = func;
183 }
184
185 void syldap_set_accessed( SyldapServer *ldapServer, const gboolean value ) {
186         g_return_if_fail( ldapServer != NULL );
187         ldapServer->accessFlag = value;
188 }
189
190 /*
191 * Refresh internal variables to force a file read.
192 */
193 void syldap_force_refresh( SyldapServer *ldapServer ) {
194         addrcache_refresh( ldapServer->addressCache );
195         ldapServer->newSearch = TRUE;
196 }
197
198 gint syldap_get_status( SyldapServer *ldapServer ) {
199         g_return_val_if_fail( ldapServer != NULL, -1 );
200         return ldapServer->retVal;
201 }
202
203 ItemFolder *syldap_get_root_folder( SyldapServer *ldapServer ) {
204         g_return_val_if_fail( ldapServer != NULL, NULL );
205         return addrcache_get_root_folder( ldapServer->addressCache );
206 }
207
208 gchar *syldap_get_name( SyldapServer *ldapServer ) {
209         g_return_val_if_fail( ldapServer != NULL, NULL );
210         return ldapServer->name;
211 }
212
213 gboolean syldap_get_accessed( SyldapServer *ldapServer ) {
214         g_return_val_if_fail( ldapServer != NULL, FALSE );
215         return ldapServer->accessFlag;
216 }
217
218 /*
219 * Free up LDAP server interface object by releasing internal memory.
220 */
221 void syldap_free( SyldapServer *ldapServer ) {
222         g_return_if_fail( ldapServer != NULL );
223
224         debug_print("Freeing LDAP server interface object\n");
225
226         ldapServer->callBack = NULL;
227
228         /* Free internal stuff */
229         g_free( ldapServer->name );
230         g_free( ldapServer->hostName );
231         g_free( ldapServer->baseDN );
232         g_free( ldapServer->bindDN );
233         g_free( ldapServer->bindPass );
234         g_free( ldapServer->searchCriteria );
235         g_free( ldapServer->searchValue );
236
237         ldapServer->port = 0;
238         ldapServer->entriesRead = 0;
239         ldapServer->maxEntries = 0;
240         ldapServer->newSearch = FALSE;
241
242         /* Clear cache */
243         addrcache_clear( ldapServer->addressCache );
244         addrcache_free( ldapServer->addressCache );
245
246         /* Clear pointers */
247         ldapServer->name = NULL;
248         ldapServer->hostName = NULL;
249         ldapServer->baseDN = NULL;
250         ldapServer->bindDN = NULL;
251         ldapServer->bindPass = NULL;
252         ldapServer->searchCriteria = NULL;
253         ldapServer->searchValue = NULL;
254         ldapServer->addressCache = NULL;
255         g_free(ldapServer->thread);
256         ldapServer->thread = NULL;
257         ldapServer->busyFlag = FALSE;
258         ldapServer->retVal = MGU_SUCCESS;
259         ldapServer->accessFlag = FALSE;
260
261         /* Now release LDAP object */
262         g_free( ldapServer );
263
264 }
265
266 /*
267 * Display object to specified stream.
268 */
269 void syldap_print_data( SyldapServer *ldapServer, FILE *stream ) {
270         g_return_if_fail( ldapServer != NULL );
271
272         fprintf( stream, "SyldapServer:\n" );
273         fprintf( stream, "     name: '%s'\n", ldapServer->name );
274         fprintf( stream, "host name: '%s'\n", ldapServer->hostName );
275         fprintf( stream, "     port: %d\n",   ldapServer->port );
276         fprintf( stream, "  base dn: '%s'\n", ldapServer->baseDN );
277         fprintf( stream, "  bind dn: '%s'\n", ldapServer->bindDN );
278         fprintf( stream, "bind pass: '%s'\n", ldapServer->bindPass );
279         fprintf( stream, " criteria: '%s'\n", ldapServer->searchCriteria );
280         fprintf( stream, "searchval: '%s'\n", ldapServer->searchValue );
281         fprintf( stream, "max entry: %d\n",   ldapServer->maxEntries );
282         fprintf( stream, " num read: %d\n",   ldapServer->entriesRead );
283         fprintf( stream, "  ret val: %d\n",   ldapServer->retVal );
284         addrcache_print( ldapServer->addressCache, stream );
285         addritem_print_item_folder( ldapServer->addressCache->rootFolder, stream );
286 }
287
288 /*
289 * Display object to specified stream.
290 */
291 void syldap_print_short( SyldapServer *ldapServer, FILE *stream ) {
292         g_return_if_fail( ldapServer != NULL );
293
294         fprintf( stream, "SyldapServer:\n" );
295         fprintf( stream, "     name: '%s'\n", ldapServer->name );
296         fprintf( stream, "host name: '%s'\n", ldapServer->hostName );
297         fprintf( stream, "     port: %d\n",   ldapServer->port );
298         fprintf( stream, "  base dn: '%s'\n", ldapServer->baseDN );
299         fprintf( stream, "  bind dn: '%s'\n", ldapServer->bindDN );
300         fprintf( stream, "bind pass: '%s'\n", ldapServer->bindPass );
301         fprintf( stream, " criteria: '%s'\n", ldapServer->searchCriteria );
302         fprintf( stream, "searchval: '%s'\n", ldapServer->searchValue );
303         fprintf( stream, "max entry: %d\n",   ldapServer->maxEntries );
304         fprintf( stream, " num read: %d\n",   ldapServer->entriesRead );
305         fprintf( stream, "  ret val: %d\n",   ldapServer->retVal );
306 }
307
308 /*
309 * Build an address list entry and append to list of address items. Name is formatted
310 * as it appears in the common name (cn) attribute.
311 */
312 static void syldap_build_items_cn( SyldapServer *ldapServer, GSList *listName, GSList *listAddr ) {
313         ItemPerson *person;
314         ItemEMail *email;
315         GSList *nodeName = listName;
316
317         while( nodeName ) {
318                 GSList *nodeAddress = listAddr;
319                 person = addritem_create_item_person();
320                 addritem_person_set_common_name( person, nodeName->data );
321                 addrcache_id_person( ldapServer->addressCache, person );
322                 addrcache_add_person( ldapServer->addressCache, person );
323
324                 while( nodeAddress ) {
325                         email = addritem_create_item_email();
326                         addritem_email_set_address( email, nodeAddress->data );
327                         addrcache_id_email( ldapServer->addressCache, email );
328                         addrcache_person_add_email( ldapServer->addressCache, person, email );
329                         nodeAddress = g_slist_next( nodeAddress );
330                         ldapServer->entriesRead++;
331                 }
332                 nodeName = g_slist_next( nodeName );
333         }
334 }
335
336 /*
337 * Build an address list entry and append to list of address items. Name is formatted
338 * as "<first-name> <last-name>".
339 */
340 static void syldap_build_items_fl( SyldapServer *ldapServer, GSList *listAddr, GSList *listFirst, GSList *listLast  ) {
341         GSList *nodeFirst = listFirst;
342         GSList *nodeAddress = listAddr;
343         gchar *firstName = NULL, *lastName = NULL, *fullName = NULL;
344         gint iLen = 0, iLenT = 0;
345         ItemPerson *person;
346         ItemEMail *email;
347
348         /* Find longest first name in list */
349         while( nodeFirst ) {
350                 if( firstName == NULL ) {
351                         firstName = nodeFirst->data;
352                         iLen = strlen( firstName );
353                 }
354                 else {
355                         if( ( iLenT = strlen( nodeFirst->data ) ) > iLen ) {
356                                 firstName = nodeFirst->data;
357                                 iLen = iLenT;
358                         }
359                 }
360                 nodeFirst = g_slist_next( nodeFirst );
361         }
362
363         /* Format name */
364         if( listLast ) {
365                 lastName = listLast->data;
366         }
367
368         if( firstName ) {
369                 if( lastName ) {
370                         fullName = g_strdup_printf( "%s %s", firstName, lastName );
371                 }
372                 else {
373                         fullName = g_strdup_printf( "%s", firstName );
374                 }
375         }
376         else {
377                 if( lastName ) {
378                         fullName = g_strdup_printf( "%s", lastName );
379                 }
380         }
381         if( fullName ) {
382                 g_strchug( fullName ); g_strchomp( fullName );
383         }
384
385         if( nodeAddress ) {
386                 person = addritem_create_item_person();
387                 addritem_person_set_common_name( person, fullName );
388                 addritem_person_set_first_name( person, firstName );
389                 addritem_person_set_last_name( person, lastName );
390                 addrcache_id_person( ldapServer->addressCache, person );
391                 addrcache_add_person( ldapServer->addressCache, person );
392         }
393
394         /* Add address item */
395         while( nodeAddress ) {
396                 email = addritem_create_item_email();
397                 addritem_email_set_address( email, nodeAddress->data );
398                 addrcache_id_email( ldapServer->addressCache, email );
399                 addrcache_person_add_email( ldapServer->addressCache, person, email );
400                 nodeAddress = g_slist_next( nodeAddress );
401                 ldapServer->entriesRead++;
402         }
403         g_free( fullName );
404         fullName = firstName = lastName = NULL;
405
406 }
407
408 /*
409 * Add all attribute values to a list.
410 */
411 static GSList *syldap_add_list_values( LDAP *ld, LDAPMessage *entry, char *attr ) {
412         GSList *list = NULL;
413         gint i;
414         gchar **vals;
415
416         if( ( vals = ldap_get_values( ld, entry, attr ) ) != NULL ) {
417                 for( i = 0; vals[i] != NULL; i++ ) {
418                         /* printf( "lv\t%s: %s\n", attr, vals[i] ); */
419                         list = g_slist_append( list, g_strdup( vals[i] ) );
420                 }
421         }
422         ldap_value_free( vals );
423         return list;
424 }
425
426 /*
427 * Add a single attribute value to a list.
428 */
429 static GSList *syldap_add_single_value( LDAP *ld, LDAPMessage *entry, char *attr ) {
430         GSList *list = NULL;
431         gchar **vals;
432
433         if( ( vals = ldap_get_values( ld, entry, attr ) ) != NULL ) {
434                 if( vals[0] != NULL ) {
435                         /* printf( "sv\t%s: %s\n", attr, vals[0] ); */
436                         list = g_slist_append( list, g_strdup( vals[0] ) );
437                 }
438         }
439         ldap_value_free( vals );
440         return list;
441 }
442
443 /*
444 * Free linked lists of character strings.
445 */
446 static void syldap_free_lists( GSList *listName, GSList *listAddr, GSList *listID, GSList *listDN, GSList *listFirst, GSList *listLast ) {
447         mgu_free_list( listName );
448         mgu_free_list( listAddr );
449         mgu_free_list( listID );
450         mgu_free_list( listDN );
451         mgu_free_list( listFirst );
452         mgu_free_list( listLast );
453 }
454
455 /*
456 * Check parameters that are required for a search. This should
457 * be called before performing a search.
458 * Return: TRUE if search criteria appear OK.
459 */
460 gboolean syldap_check_search( SyldapServer *ldapServer ) {
461         g_return_val_if_fail( ldapServer != NULL, FALSE );
462
463         ldapServer->retVal = MGU_LDAP_CRITERIA;
464
465         /* Test search criteria */
466         if( ldapServer->searchCriteria == NULL ) {
467                 return FALSE;
468         }
469         if( strlen( ldapServer->searchCriteria ) < 1 ) {
470                 return FALSE;
471         }
472
473         if( ldapServer->searchValue == NULL ) {
474                 return FALSE;
475         }
476         if( strlen( ldapServer->searchValue ) < 1 ) {
477                 return FALSE;
478         }
479
480         ldapServer->retVal = MGU_SUCCESS;
481         return TRUE;
482 }
483
484 /*
485 * Perform the LDAP search, reading LDAP entries into cache.
486 * Note that one LDAP entry can have multiple values for many of its
487 * attributes. If these attributes are E-Mail addresses; these are
488 * broken out into separate address items. For any other attribute,
489 * only the first occurrence is read.
490 */
491 gint syldap_search( SyldapServer *ldapServer ) {
492         LDAP *ld;
493         LDAPMessage *result, *e;
494         char *attribs[10];
495         char *attribute;
496         gchar *criteria;
497         BerElement *ber;
498         gint rc;
499         GSList *listName = NULL, *listAddress = NULL, *listID = NULL;
500         GSList *listFirst = NULL, *listLast = NULL, *listDN = NULL;
501         struct timeval timeout;
502         gboolean entriesFound = FALSE;
503
504         g_return_val_if_fail( ldapServer != NULL, -1 );
505
506         ldapServer->retVal = MGU_SUCCESS;
507         if( ! syldap_check_search( ldapServer ) ) {
508                 return ldapServer->retVal;
509         }
510
511         /* Set timeout */
512         timeout.tv_sec = ldapServer->timeOut;
513         timeout.tv_usec = 0L;
514
515         ldapServer->entriesRead = 0;
516         if( ( ld = ldap_init( ldapServer->hostName, ldapServer->port ) ) == NULL ) {
517                 ldapServer->retVal = MGU_LDAP_INIT;
518                 return ldapServer->retVal;
519         }
520
521         /* printf( "connected to LDAP host %s on port %d\n", ldapServer->hostName, ldapServer->port ); */
522
523         /* Bind to the server, if required */
524         if( ldapServer->bindDN ) {
525                 if( * ldapServer->bindDN != '\0' ) {
526                         /* printf( "binding...\n" ); */
527                         rc = ldap_simple_bind_s( ld, ldapServer->bindDN, ldapServer->bindPass );
528                         /* printf( "rc=%d\n", rc ); */
529                         if( rc != LDAP_SUCCESS ) {
530                                 /* printf( "LDAP Error: ldap_simple_bind_s: %s\n", ldap_err2string( rc ) ); */
531                                 ldap_unbind( ld );
532                                 ldapServer->retVal = MGU_LDAP_BIND;
533                                 return ldapServer->retVal;
534                         }
535                 }
536         }
537
538         /* Define all attributes we are interested in. */
539         attribs[0] = SYLDAP_ATTR_DN;
540         attribs[1] = SYLDAP_ATTR_COMMONNAME;
541         attribs[2] = SYLDAP_ATTR_GIVENNAME;
542         attribs[3] = SYLDAP_ATTR_SURNAME;
543         attribs[4] = SYLDAP_ATTR_EMAIL;
544         attribs[5] = SYLDAP_ATTR_UID;
545         attribs[6] = NULL;
546
547         /* Create LDAP search string and apply search criteria */
548         criteria = g_strdup_printf( ldapServer->searchCriteria, ldapServer->searchValue );
549         rc = ldap_search_ext_s( ld, ldapServer->baseDN, LDAP_SCOPE_SUBTREE, criteria, attribs, 0, NULL, NULL,
550                        &timeout, 0, &result );
551         g_free( criteria );
552         criteria = NULL;
553         if( rc == LDAP_TIMEOUT ) {
554                 ldap_unbind( ld );
555                 ldapServer->retVal = MGU_LDAP_TIMEOUT;
556                 return ldapServer->retVal;
557         }
558         if( rc != LDAP_SUCCESS ) {
559                 /* printf( "LDAP Error: ldap_search_st: %s\n", ldap_err2string( rc ) ); */
560                 ldap_unbind( ld );
561                 ldapServer->retVal = MGU_LDAP_SEARCH;
562                 return ldapServer->retVal;
563         }
564
565         /* printf( "Total results are: %d\n", ldap_count_entries( ld, result ) ); */
566
567         /* Clear the cache if we have new entries, otherwise leave untouched. */
568         if( ldap_count_entries( ld, result ) > 0 ) {
569                 addrcache_clear( ldapServer->addressCache );
570         }
571
572         /* Process results */
573         ldapServer->entriesRead = 0;
574         for( e = ldap_first_entry( ld, result ); e != NULL; e = ldap_next_entry( ld, e ) ) {
575                 entriesFound = TRUE;
576                 if( ldapServer->entriesRead >= ldapServer->maxEntries ) break;          
577                 /* printf( "DN: %s\n", ldap_get_dn( ld, e ) ); */
578
579                 /* Process all attributes */
580                 for( attribute = ldap_first_attribute( ld, e, &ber ); attribute != NULL;
581                                attribute = ldap_next_attribute( ld, e, ber ) ) {
582                         if( strcasecmp( attribute, SYLDAP_ATTR_COMMONNAME ) == 0 ) {
583                                 listName = syldap_add_list_values( ld, e, attribute );
584                         }
585                         if( strcasecmp( attribute, SYLDAP_ATTR_EMAIL ) == 0 ) {
586                                 listAddress = syldap_add_list_values( ld, e, attribute );
587                         }
588                         if( strcasecmp( attribute, SYLDAP_ATTR_UID ) == 0 ) {
589                                 listID = syldap_add_single_value( ld, e, attribute );
590                         }
591                         if( strcasecmp( attribute, SYLDAP_ATTR_GIVENNAME ) == 0 ) {
592                                 listFirst = syldap_add_list_values( ld, e, attribute );
593                         }
594                         if( strcasecmp( attribute, SYLDAP_ATTR_SURNAME ) == 0 ) {
595                                 listLast = syldap_add_single_value( ld, e, attribute );
596                         }
597                         if( strcasecmp( attribute, SYLDAP_ATTR_DN ) == 0 ) {
598                                 listDN = syldap_add_single_value( ld, e, attribute );
599                         }
600                 }
601
602                 /* Free memory used to store attribute */
603                 ldap_memfree( attribute );
604
605                 /* Format and add items to cache */
606                 syldap_build_items_fl( ldapServer, listAddress, listFirst, listLast );
607
608                 /* Free up */
609                 syldap_free_lists( listName, listAddress, listID, listDN, listFirst, listLast );
610                 listName = listAddress = listID = listFirst = listLast = listDN = NULL;
611
612                 if( ber != NULL ) {
613                         ber_free( ber, 0 );
614                 }
615         }
616
617         syldap_free_lists( listName, listAddress, listID, listDN, listFirst, listLast );
618         listName = listAddress = listID = listFirst = listLast = listDN = NULL;
619         
620         /* Free up and disconnect */
621         ldap_msgfree( result );
622         ldap_unbind( ld );
623         ldapServer->newSearch = FALSE;
624         if( entriesFound ) {
625                 ldapServer->retVal = MGU_SUCCESS;
626         }
627         else {
628                 ldapServer->retVal = MGU_LDAP_NOENTRIES;
629         }
630         return ldapServer->retVal;
631 }
632
633 /* ============================================================================================ */
634 /*
635 * Read data into list. Main entry point
636 * Return: TRUE if file read successfully.
637 */
638 /* ============================================================================================ */
639 gint syldap_read_data( SyldapServer *ldapServer ) {
640         g_return_val_if_fail( ldapServer != NULL, -1 );
641
642         ldapServer->accessFlag = FALSE;
643         pthread_detach( pthread_self() );
644         if( ldapServer->newSearch ) {
645                 /* Read data into the list */
646                 syldap_search( ldapServer );
647
648                 /* Mark cache */
649                 ldapServer->addressCache->modified = FALSE;
650                 ldapServer->addressCache->dataRead = TRUE;
651                 ldapServer->accessFlag = FALSE;
652         }
653
654         /* Callback */
655         ldapServer->busyFlag = FALSE;
656         if( ldapServer->callBack ) {
657                 ( ldapServer->callBack )( ldapServer );
658         }
659         /* The thread struct should not be freed inside the thread
660         g_free(ldapServer->thread);
661         ldapServer->thread = NULL;
662         pthread_exit( NULL );
663         */
664         return ldapServer->retVal;
665 }
666
667 /* ============================================================================================ */
668 /*
669 * Cancel read with thread.
670 */
671 /* ============================================================================================ */
672 void syldap_cancel_read( SyldapServer *ldapServer ) {
673         g_return_if_fail( ldapServer != NULL );
674
675         if( ldapServer->thread ) {
676                 /* printf( "thread cancelled\n" ); */
677                 /* The thread is cancleing itself, ok?
678                 pthread_cancel( *ldapServer->thread );
679                 */
680         }
681         /* The thread struct should not be freed inside the thread
682         g_free(ldapServer->thread);
683         ldapServer->thread = NULL;
684         */
685         ldapServer->busyFlag = FALSE;
686 }
687
688 /* ============================================================================================ */
689 /*
690 * Read data into list using a background thread.
691 * Return: TRUE if file read successfully. Callback function will be
692 * notified when search is complete.
693 */
694 /* ============================================================================================ */
695 gint syldap_read_data_th( SyldapServer *ldapServer ) {
696         g_return_val_if_fail( ldapServer != NULL, -1 );
697
698         ldapServer->busyFlag = FALSE;
699         syldap_check_search( ldapServer );
700         if( ldapServer->retVal == MGU_SUCCESS ) {
701                 debug_print("Staring LDAP read thread\n");
702
703                 ldapServer->busyFlag = TRUE;
704                 ldapServer->thread = g_new0(pthread_t, 1);
705                 pthread_create( ldapServer->thread, NULL, (void *) &syldap_read_data, (void *) ldapServer );
706         }
707         return ldapServer->retVal;
708 }
709
710 /*
711 * Return link list of persons.
712 */
713 GList *syldap_get_list_person( SyldapServer *ldapServer ) {
714         g_return_val_if_fail( ldapServer != NULL, NULL );
715         return addrcache_get_list_person( ldapServer->addressCache );
716 }
717
718 /*
719 * Return link list of folders. This is always NULL since there are
720 * no folders in GnomeCard.
721 * Return: NULL.
722 */
723 GList *syldap_get_list_folder( SyldapServer *ldapServer ) {
724         g_return_val_if_fail( ldapServer != NULL, NULL );
725         return NULL;
726 }
727
728 #define SYLDAP_TEST_FILTER   "(objectclass=*)"
729 #define SYLDAP_SEARCHBASE_V2 "cn=config"
730 #define SYLDAP_SEARCHBASE_V3 ""
731 #define SYLDAP_V2_TEST_ATTR  "database"
732 #define SYLDAP_V3_TEST_ATTR  "namingcontexts"
733
734 /*
735 * Attempt to discover the base DN for the server.
736 * Enter:
737 *       host    Host name
738 *       port    Port number
739 *       bindDN  Bind DN (optional).
740 *       bindPW  Bind PW (optional).
741 *       tov     Timeout value (seconds), or 0 for none, default 30 secs.
742 * Return: List of Base DN's, or NULL if could not read. Base DN should
743 * be g_free() when done.
744 */
745 GList *syldap_read_basedn_s( const gchar *host, const gint port, const gchar *bindDN, const gchar *bindPW, const gint tov ) {
746         GList *baseDN = NULL;
747         LDAP *ld;
748         gint rc, i;
749         LDAPMessage *result, *e;
750         gchar *attribs[10];
751         BerElement *ber;
752         gchar *attribute;
753         gchar **vals;
754         struct timeval timeout;
755
756         if( host == NULL ) return baseDN;
757         if( port < 1 ) return baseDN;
758
759         /* Set timeout */
760         timeout.tv_usec = 0L;
761         if( tov > 0 ) {
762                 timeout.tv_sec = tov;
763         }
764         else {
765                 timeout.tv_sec = 30L;
766         }
767
768         /* Connect to server. */
769         if( ( ld = ldap_init( host, port ) ) == NULL ) {
770                 return baseDN;
771         }
772
773         /* Bind to the server, if required */
774         if( bindDN ) {
775                 if( *bindDN != '\0' ) {
776                         rc = ldap_simple_bind_s( ld, bindDN, bindPW );
777                         if( rc != LDAP_SUCCESS ) {
778                                 /* printf( "LDAP Error: ldap_simple_bind_s: %s\n", ldap_err2string( rc ) ); */
779                                 ldap_unbind( ld );
780                                 return baseDN;
781                         }
782                 }
783         }
784
785         /* Test for LDAP version 3 */
786         attribs[0] = SYLDAP_V3_TEST_ATTR;
787         attribs[1] = NULL;
788         rc = ldap_search_ext_s( ld, SYLDAP_SEARCHBASE_V3, LDAP_SCOPE_BASE, SYLDAP_TEST_FILTER, attribs,
789                        0, NULL, NULL, &timeout, 0, &result );
790         if( rc == LDAP_SUCCESS ) {
791                 /* Process entries */
792                 for( e = ldap_first_entry( ld, result ); e != NULL; e = ldap_next_entry( ld, e ) ) {
793                         /* printf( "DN: %s\n", ldap_get_dn( ld, e ) ); */
794
795                         /* Process attributes */
796                         for( attribute = ldap_first_attribute( ld, e, &ber ); attribute != NULL;
797                                         attribute = ldap_next_attribute( ld, e, ber ) ) {
798                                 if( strcasecmp( attribute, SYLDAP_V3_TEST_ATTR ) == 0 ) {
799                                         if( ( vals = ldap_get_values( ld, e, attribute ) ) != NULL ) {
800                                                 for( i = 0; vals[i] != NULL; i++ ) {
801                                                         /* printf( "\t%s: %s\n", attribute, vals[i] ); */
802                                                         baseDN = g_list_append( baseDN, g_strdup( vals[i] ) );
803                                                 }
804                                         }
805                                         ldap_value_free( vals );
806                                 }
807                         }
808                         ldap_memfree( attribute );
809                         if( ber != NULL ) {
810                                 ber_free( ber, 0 );
811                         }
812                 }
813                 ldap_msgfree( result );
814         }
815         else {
816         }
817
818         if( baseDN == NULL ) {
819                 /* Test for LDAP version 2 */
820                 attribs[0] = NULL;
821                 rc = ldap_search_ext_s( ld, SYLDAP_SEARCHBASE_V2, LDAP_SCOPE_BASE, SYLDAP_TEST_FILTER, attribs,
822                                0, NULL, NULL, &timeout, 0, &result );
823                 if( rc == LDAP_SUCCESS ) {
824                         /* Process entries */
825                         for( e = ldap_first_entry( ld, result ); e != NULL; e = ldap_next_entry( ld, e ) ) {
826                                 /* if( baseDN ) break;                   */
827                                 /* printf( "DN: %s\n", ldap_get_dn( ld, e ) ); */
828
829                                 /* Process attributes */
830                                 for( attribute = ldap_first_attribute( ld, e, &ber ); attribute != NULL;
831                                                attribute = ldap_next_attribute( ld, e, ber ) ) {
832                                         /* if( baseDN ) break;                   */
833                                         if( strcasecmp( attribute, SYLDAP_V2_TEST_ATTR ) == 0 ) {
834                                                 if( ( vals = ldap_get_values( ld, e, attribute ) ) != NULL ) {
835                                                         for( i = 0; vals[i] != NULL; i++ ) {
836                                                                 char *ch;
837                                                                 /* Strip the 'ldb:' from the front of the value */
838                                                                 ch = ( char * ) strchr( vals[i], ':' );
839                                                                 if( ch ) {
840                                                                         gchar *bn = g_strdup( ++ch );
841                                                                         g_strchomp( bn );
842                                                                         g_strchug( bn );
843                                                                         baseDN = g_list_append( baseDN, g_strdup( bn ) );
844                                                                 }
845                                                         }
846                                                 }
847                                                 ldap_value_free( vals );
848                                         }
849                                 }
850                                 ldap_memfree( attribute );
851                                 if( ber != NULL ) {
852                                         ber_free( ber, 0 );
853                                 }
854                         }
855                         ldap_msgfree( result );
856                 }
857         }
858         ldap_unbind( ld );
859         return baseDN;
860 }
861
862 /*
863 * Attempt to discover the base DN for the server.
864 * Enter:  ldapServer Server to test.
865 * Return: List of Base DN's, or NULL if could not read. Base DN should
866 * be g_free() when done. Return code set in ldapServer.
867 */
868 GList *syldap_read_basedn( SyldapServer *ldapServer ) {
869         GList *baseDN = NULL;
870         LDAP *ld;
871         gint rc, i;
872         LDAPMessage *result, *e;
873         gchar *attribs[10];
874         BerElement *ber;
875         gchar *attribute;
876         gchar **vals;
877         struct timeval timeout;
878
879         ldapServer->retVal = MGU_BAD_ARGS;
880         if( ldapServer == NULL ) return baseDN;
881         if( ldapServer->hostName == NULL ) return baseDN;
882         if( ldapServer->port < 1 ) return baseDN;
883
884         /* Set timeout */
885         timeout.tv_usec = 0L;
886         if( ldapServer->timeOut > 0 ) {
887                 timeout.tv_sec = ldapServer->timeOut;
888         }
889         else {
890                 timeout.tv_sec = 30L;
891         }
892
893         /* Connect to server. */
894         if( ( ld = ldap_init( ldapServer->hostName, ldapServer->port ) ) == NULL ) {
895                 ldapServer->retVal = MGU_LDAP_INIT;
896                 return baseDN;
897         }
898
899         /* Bind to the server, if required */
900         if( ldapServer->bindDN ) {
901                 if( *ldapServer->bindDN != '\0' ) {
902                         rc = ldap_simple_bind_s( ld, ldapServer->bindDN, ldapServer->bindPass );
903                         if( rc != LDAP_SUCCESS ) {
904                                 /* printf( "LDAP Error: ldap_simple_bind_s: %s\n", ldap_err2string( rc ) ); */
905                                 ldap_unbind( ld );
906                                 ldapServer->retVal = MGU_LDAP_BIND;
907                                 return baseDN;
908                         }
909                 }
910         }
911
912         ldapServer->retVal = MGU_LDAP_SEARCH;
913
914         /* Test for LDAP version 3 */
915         attribs[0] = SYLDAP_V3_TEST_ATTR;
916         attribs[1] = NULL;
917         rc = ldap_search_ext_s( ld, SYLDAP_SEARCHBASE_V3, LDAP_SCOPE_BASE, SYLDAP_TEST_FILTER, attribs,
918                        0, NULL, NULL, &timeout, 0, &result );
919         if( rc == LDAP_SUCCESS ) {
920                 /* Process entries */
921                 for( e = ldap_first_entry( ld, result ); e != NULL; e = ldap_next_entry( ld, e ) ) {
922                         /* printf( "DN: %s\n", ldap_get_dn( ld, e ) ); */
923
924                         /* Process attributes */
925                         for( attribute = ldap_first_attribute( ld, e, &ber ); attribute != NULL;
926                                         attribute = ldap_next_attribute( ld, e, ber ) ) {
927                                 if( strcasecmp( attribute, SYLDAP_V3_TEST_ATTR ) == 0 ) {
928                                         if( ( vals = ldap_get_values( ld, e, attribute ) ) != NULL ) {
929                                                 for( i = 0; vals[i] != NULL; i++ ) {
930                                                         /* printf( "\t%s: %s\n", attribute, vals[i] ); */
931                                                         baseDN = g_list_append( baseDN, g_strdup( vals[i] ) );
932                                                 }
933                                         }
934                                         ldap_value_free( vals );
935                                 }
936                         }
937                         ldap_memfree( attribute );
938                         if( ber != NULL ) {
939                                 ber_free( ber, 0 );
940                         }
941                 }
942                 ldap_msgfree( result );
943                 ldapServer->retVal = MGU_SUCCESS;
944         }
945         else if( rc == LDAP_TIMEOUT ) {
946                 ldapServer->retVal = MGU_LDAP_TIMEOUT;
947         }
948
949         if( baseDN == NULL ) {
950                 /* Test for LDAP version 2 */
951                 attribs[0] = NULL;
952                 rc = ldap_search_ext_s( ld, SYLDAP_SEARCHBASE_V2, LDAP_SCOPE_BASE, SYLDAP_TEST_FILTER, attribs,
953                                0, NULL, NULL, &timeout, 0, &result );
954                 if( rc == LDAP_SUCCESS ) {
955                         /* Process entries */
956                         for( e = ldap_first_entry( ld, result ); e != NULL; e = ldap_next_entry( ld, e ) ) {
957                                 /* if( baseDN ) break;                   */
958                                 /* printf( "DN: %s\n", ldap_get_dn( ld, e ) ); */
959
960                                 /* Process attributes */
961                                 for( attribute = ldap_first_attribute( ld, e, &ber ); attribute != NULL;
962                                                attribute = ldap_next_attribute( ld, e, ber ) ) {
963                                         /* if( baseDN ) break;                   */
964                                         if( strcasecmp( attribute, SYLDAP_V2_TEST_ATTR ) == 0 ) {
965                                                 if( ( vals = ldap_get_values( ld, e, attribute ) ) != NULL ) {
966                                                         for( i = 0; vals[i] != NULL; i++ ) {
967                                                                 char *ch;
968                                                                 /* Strip the 'ldb:' from the front of the value */
969                                                                 ch = ( char * ) strchr( vals[i], ':' );
970                                                                 if( ch ) {
971                                                                         gchar *bn = g_strdup( ++ch );
972                                                                         g_strchomp( bn );
973                                                                         g_strchug( bn );
974                                                                         baseDN = g_list_append( baseDN, g_strdup( bn ) );
975                                                                 }
976                                                         }
977                                                 }
978                                                 ldap_value_free( vals );
979                                         }
980                                 }
981                                 ldap_memfree( attribute );
982                                 if( ber != NULL ) {
983                                         ber_free( ber, 0 );
984                                 }
985                         }
986                         ldap_msgfree( result );
987                         ldapServer->retVal = MGU_SUCCESS;
988                 }
989                 else if( rc == LDAP_TIMEOUT ) {
990                         ldapServer->retVal = MGU_LDAP_TIMEOUT;
991                 }
992         }
993         ldap_unbind( ld );
994
995         return baseDN;
996 }
997
998 /*
999 * Attempt to connect to the server.
1000 * Enter:
1001 *       host    Host name
1002 *       port    Port number
1003 * Return: TRUE if connected successfully.
1004 */
1005 gboolean syldap_test_connect_s( const gchar *host, const gint port ) {
1006         gboolean retVal = FALSE;
1007         LDAP *ld;
1008
1009         if( host == NULL ) return retVal;
1010         if( port < 1 ) return retVal;
1011         if( ( ld = ldap_open( host, port ) ) != NULL ) {
1012                 retVal = TRUE;
1013         }
1014         if( ld != NULL ) {
1015                 ldap_unbind( ld );
1016         }
1017         return retVal;
1018 }
1019
1020 /*
1021 * Attempt to connect to the server.
1022 * Enter:  ldapServer Server to test.
1023 * Return: TRUE if connected successfully. Return code set in ldapServer.
1024 */
1025 gboolean syldap_test_connect( SyldapServer *ldapServer ) {
1026         gboolean retVal = FALSE;
1027         LDAP *ld;
1028
1029         ldapServer->retVal = MGU_BAD_ARGS;
1030         if( ldapServer == NULL ) return retVal;
1031         if( ldapServer->hostName == NULL ) return retVal;
1032         if( ldapServer->port < 1 ) return retVal;
1033         ldapServer->retVal = MGU_LDAP_INIT;
1034         if( ( ld = ldap_open( ldapServer->hostName, ldapServer->port ) ) != NULL ) {
1035                 ldapServer->retVal = MGU_SUCCESS;
1036                 retVal = TRUE;
1037         }
1038         if( ld != NULL ) {
1039                 ldap_unbind( ld );
1040         }
1041         return retVal;
1042 }
1043
1044 #define LDAP_LINK_LIB_NAME_1 "libldap.so"
1045 #define LDAP_LINK_LIB_NAME_2 "liblber.so"
1046 #define LDAP_LINK_LIB_NAME_3 "libresolv.so"
1047 #define LDAP_LINK_LIB_NAME_4 "libpthread.so"
1048
1049 /*
1050 * Test whether LDAP libraries installed.
1051 * Return: TRUE if library available.
1052 */
1053 gboolean syldap_test_ldap_lib() {
1054         void *handle, *fun;
1055         
1056         /* Get library */
1057         handle = dlopen( LDAP_LINK_LIB_NAME_1, RTLD_LAZY );
1058         if( ! handle ) {
1059                 return FALSE;
1060         }
1061
1062         /* Test for symbols we need */
1063         fun = dlsym( handle, "ldap_init" );
1064         if( ! fun ) {
1065                 dlclose( handle );
1066                 return FALSE;
1067         }
1068         dlclose( handle ); handle = NULL; fun = NULL;
1069
1070         handle = dlopen( LDAP_LINK_LIB_NAME_2, RTLD_LAZY );
1071         if( ! handle ) {
1072                 return FALSE;
1073         }
1074         fun = dlsym( handle, "ber_init" );
1075         if( ! fun ) {
1076                 dlclose( handle );
1077                 return FALSE;
1078         }
1079         dlclose( handle ); handle = NULL; fun = NULL;
1080
1081         handle = dlopen( LDAP_LINK_LIB_NAME_3, RTLD_LAZY );
1082         if( ! handle ) {
1083                 return FALSE;
1084         }
1085         fun = dlsym( handle, "res_query" );
1086         if( ! fun ) {
1087                 dlclose( handle );
1088                 return FALSE;
1089         }
1090         dlclose( handle ); handle = NULL; fun = NULL;
1091
1092         handle = dlopen( LDAP_LINK_LIB_NAME_4, RTLD_LAZY );
1093         if( ! handle ) {
1094                 return FALSE;
1095         }
1096         fun = dlsym( handle, "pthread_create" );
1097         if( ! fun ) {
1098                 dlclose( handle );
1099                 return FALSE;
1100         }
1101         dlclose( handle ); handle = NULL; fun = NULL;
1102
1103         return TRUE;
1104 }
1105
1106 #endif  /* USE_LDAP */
1107
1108 /*
1109 * End of Source.
1110 */