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