Fix bug #3574: Template addressing
[claws.git] / src / ldapserver.c
blob545e7f4d92906e4cc86bbcf9f6632dcfe31c46d7
1 /*
2 * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3 * Copyright (C) 2003-2012 Match Grun and the Claws Mail team
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 3 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, see <http://www.gnu.org/licenses/>.
21 * Functions necessary to access LDAP servers.
24 #ifdef HAVE_CONFIG_H
25 # include "config.h"
26 #include "claws-features.h"
27 #endif
29 #ifdef USE_LDAP
31 #include <glib.h>
32 #include <sys/time.h>
33 #include <string.h>
35 #include "mgutils.h"
36 #include "addritem.h"
37 #include "addrcache.h"
38 #include "ldapctrl.h"
39 #include "ldapquery.h"
40 #include "ldapserver.h"
41 #include "ldaputil.h"
42 #include "utils.h"
43 #include "adbookbase.h"
44 #include "passwordstore.h"
46 /**
47 * Create new LDAP server interface object with no control object.
48 * \return Initialized LDAP server object.
50 LdapServer *ldapsvr_create_noctl( void ) {
51 LdapServer *server;
53 server = g_new0( LdapServer, 1 );
54 server->type = ADBOOKTYPE_LDAP;
55 server->addressCache = addrcache_create();
56 server->retVal = MGU_SUCCESS;
57 server->control = NULL;
58 server->listQuery = NULL;
59 server->searchFlag = FALSE;
60 return server;
63 /**
64 * Create new LDAP server interface object.
65 * \return Initialized LDAP server object.
67 LdapServer *ldapsvr_create( void ) {
68 LdapServer *server;
69 server = ldapsvr_create_noctl();
70 server->control = ldapctl_create();
71 return server;
74 /**
75 * Return name of server.
76 * \param server Server object.
77 * \return Name for server.
79 gchar *ldapsvr_get_name( LdapServer *server ) {
80 cm_return_val_if_fail( server != NULL, NULL );
81 return addrcache_get_name( server->addressCache );
84 /**
85 * Specify name to be used.
86 * \param server Server object.
87 * \param value Name for server.
89 void ldapsvr_set_name( LdapServer* server, const gchar *value ) {
90 cm_return_if_fail( server != NULL );
91 addrcache_set_name( server->addressCache, value );
92 debug_print("setting name: %s\n", value?value:"null");
95 /**
96 * Refresh internal variables to force a file read.
97 * \param server Server object.
99 void ldapsvr_force_refresh( LdapServer *server ) {
100 cm_return_if_fail( server != NULL );
101 addrcache_refresh( server->addressCache );
105 * Return status/error code.
106 * \param server Server object.
107 * \return Status/error code.
109 gint ldapsvr_get_status( LdapServer *server ) {
110 cm_return_val_if_fail( server != NULL, -1 );
111 return server->retVal;
115 * Return reference to root level folder.
116 * \param server Server object.
117 * \return Root level folder.
119 ItemFolder *ldapsvr_get_root_folder( LdapServer *server ) {
120 cm_return_val_if_fail( server != NULL, NULL );
122 g_print( "ldapsvr_get_root_folder/start\n" );
123 ldapsvr_print_data( server, stdout );
124 g_print( "ldapsvr_get_root_folder/done\n" );
126 return addrcache_get_root_folder( server->addressCache );
130 * Test whether server data has been accessed.
131 * \param server Server object.
132 * \return <i>TRUE</i> if data was accessed.
134 gboolean ldapsvr_get_accessed( LdapServer *server ) {
135 cm_return_val_if_fail( server != NULL, FALSE );
136 return server->addressCache->accessFlag;
140 * Specify that server's data whas beed accessed.
141 * \param server Server object.
142 * \param value Value for flag.
144 void ldapsvr_set_accessed( LdapServer *server, const gboolean value ) {
145 cm_return_if_fail( server != NULL );
146 server->addressCache->accessFlag = value;
147 debug_print("setting accessFlag: %d\n", value);
151 * Test whether server data has been modified.
152 * \param server Server object.
153 * \return <i>TRUE</i> if data was modified.
155 gboolean ldapsvr_get_modified( LdapServer *server ) {
156 cm_return_val_if_fail( server != NULL, FALSE );
157 return server->addressCache->modified;
161 * Specify modify flag.
162 * \param server Server object.
163 * \param value Value for flag.
165 void ldapsvr_set_modified( LdapServer *server, const gboolean value ) {
166 cm_return_if_fail( server != NULL );
167 server->addressCache->modified = value;
168 debug_print("setting modified: %d\n", value);
172 * Test whether data was read from server.
173 * \param server Server object.
174 * \return <i>TRUE</i> if data was read.
176 gboolean ldapsvr_get_read_flag( LdapServer *server ) {
177 cm_return_val_if_fail( server != NULL, FALSE );
178 return server->addressCache->dataRead;
182 * Test whether server is to be used for dynamic searches.
183 * \param server Server object.
184 * \return <i>TRUE</i> if server is used for dynamic searches.
186 gboolean ldapsvr_get_search_flag( LdapServer *server ) {
187 cm_return_val_if_fail( server != NULL, FALSE );
188 return server->searchFlag;
192 * Specify that server is to be used for dynamic searches.
193 * \param server Server object.
194 * \param value Name for server.
196 void ldapsvr_set_search_flag( LdapServer *server, const gboolean value ) {
197 cm_return_if_fail( server != NULL );
198 server->searchFlag = value;
199 debug_print("setting searchFlag: %d\n", value);
203 * Specify the reference to control data that will be used for the query. The calling
204 * module should be responsible for creating and destroying this control object.
205 * \param server Server object.
206 * \param ctl Control data.
208 void ldapsvr_set_control( LdapServer *server, LdapControl *ctl ) {
209 cm_return_if_fail( server != NULL );
210 addrcache_refresh( server->addressCache );
211 server->control = ctl;
215 * Free all queries.
216 * \param server Server object.
218 void ldapsvr_free_all_query( LdapServer *server ) {
219 GList *node;
220 cm_return_if_fail( server != NULL );
222 node = server->listQuery;
223 while( node ) {
224 LdapQuery *qry = node->data;
225 ldapqry_free( qry );
226 node->data = NULL;
227 node = g_list_next( node );
229 g_list_free( server->listQuery );
230 server->listQuery = NULL;
234 * Add query to server.
235 * \param server Server object.
236 * \param qry Query object.
238 void ldapsvr_add_query( LdapServer *server, LdapQuery *qry ) {
239 cm_return_if_fail( server != NULL );
240 cm_return_if_fail( qry != NULL );
242 server->listQuery = g_list_append( server->listQuery, qry );
243 qry->server = server;
247 * Free up LDAP server interface object by releasing internal memory.
248 * \param server Server object.
250 void ldapsvr_free( LdapServer *server ) {
251 cm_return_if_fail( server != NULL );
253 /* Stop and cancel any queries that may be active */
254 ldapsvr_stop_all_query( server );
255 ldapsvr_cancel_all_query( server );
257 /* Clear cache */
258 addrcache_clear( server->addressCache );
259 addrcache_free( server->addressCache );
261 /* Free LDAP control block */
262 ldapctl_free( server->control );
263 server->control = NULL;
265 /* Free all queries */
266 ldapsvr_free_all_query( server );
268 /* Clear pointers */
269 server->type = ADBOOKTYPE_NONE;
270 server->addressCache = NULL;
271 server->retVal = MGU_SUCCESS;
272 server->listQuery = NULL;
273 server->searchFlag = FALSE;
275 /* Now release LDAP object */
276 g_free( server );
280 * Display object to specified stream.
281 * \param server Server object.
282 * \param stream Output stream.
284 void ldapsvr_print_data( LdapServer *server, FILE *stream ) {
285 GList *node;
286 gint i;
288 cm_return_if_fail( server != NULL );
290 fprintf( stream, "LdapServer:\n" );
291 fprintf( stream, " ret val: %d\n", server->retVal );
292 fprintf( stream, "srch flag: %s\n",
293 server->searchFlag ? "yes" : "no" );
294 if( server->control ) {
295 ldapctl_print( server->control, stream );
297 else {
298 fprintf( stream, " control: NULL\n" );
300 addrcache_print( server->addressCache, stream );
301 addritem_print_item_folder( server->addressCache->rootFolder, stream );
303 /* Dump queries */
304 i = 1;
305 node = server->listQuery;
306 while( node ) {
307 LdapQuery *qry = node->data;
308 fprintf( stream, " query: %2d : %s\n", i, ADDRQUERY_NAME(qry) );
309 i++;
310 node = g_list_next( node );
315 * Return link list of persons.
316 * \param server Server object.
317 * \return List of persons.
319 GList *ldapsvr_get_list_person( LdapServer *server ) {
320 cm_return_val_if_fail( server != NULL, NULL );
321 return addrcache_get_list_person( server->addressCache );
325 * Return link list of folders. There are no "real" folders that are returned
326 * from the server.
327 * \param server Server object.
328 * \return List of folders.
330 GList *ldapsvr_get_list_folder( LdapServer *server ) {
331 cm_return_val_if_fail( server != NULL, NULL );
332 /* return addrcache_get_list_folder( server->addressCache ); */
333 return NULL;
337 * Execute specified query.
338 * \param server LDAP server.
339 * \param qry LDAP query.
341 void ldapsvr_execute_query( LdapServer *server, LdapQuery *qry ) {
342 LdapControl *ctlCopy;
344 cm_return_if_fail( server != NULL );
345 cm_return_if_fail( qry != NULL );
347 /* Copy server's control data to the query */
348 ctlCopy = ldapctl_create();
349 ldapctl_copy( server->control, ctlCopy );
350 ldapqry_set_control( qry, ctlCopy );
351 ldapqry_initialize();
353 /* Perform query */
354 debug_print("ldapsvr_execute_query::checking query...\n");
355 if( ldapqry_check_search( qry ) ) {
356 debug_print("ldapsvr_execute_query::reading with thread...\n");
357 ldapqry_read_data_th( qry );
358 if(qry->server->retVal == LDAPRC_SUCCESS) {
359 debug_print("ldapsvr_execute_query::SUCCESS with thread...\n");
362 debug_print("ldapsvr_execute_query... terminated\n");
366 * Stop all queries for specified ID.
367 * \param server Server object.
368 * \param queryID Query ID to stop.
370 void ldapsvr_stop_query_id( LdapServer *server, const gint queryID ) {
371 GList *node;
372 cm_return_if_fail( server != NULL );
374 node = server->listQuery;
375 while( node ) {
376 LdapQuery *qry = node->data;
377 if( ADDRQUERY_ID(qry) == queryID ) {
378 /* Notify thread to stop */
379 ldapqry_set_stop_flag( qry, TRUE );
381 node = g_list_next( node );
386 * Stop all queries by notifying each thread to stop.
387 * \param server Server object.
389 void ldapsvr_stop_all_query( LdapServer *server ) {
390 GList *node;
391 cm_return_if_fail( server != NULL );
393 node = server->listQuery;
394 while( node ) {
395 LdapQuery *qry = node->data;
396 ldapqry_set_stop_flag( qry, TRUE );
397 node = g_list_next( node );
402 * Cancel all query threads for server.
403 * \param server Server object.
405 void ldapsvr_cancel_all_query( LdapServer *server ) {
406 GList *node;
407 cm_return_if_fail( server != NULL );
409 node = server->listQuery;
410 while( node ) {
411 LdapQuery *qry = node->data;
412 /* Notify thread to stop */
413 ldapqry_set_stop_flag( qry, TRUE );
414 /* Now cancel thread */
415 ldapqry_cancel( qry );
416 node = g_list_next( node );
421 * Search most recent query for specified search term. The most recent
422 * completed query is returned. If no completed query is found, the most recent
423 * incomplete is returned.
424 * \param server LdapServer.
425 * \param searchTerm Search term to locate.
426 * \return Query object, or <i>NULL</i> if none found.
428 static LdapQuery *ldapsvr_locate_query(
429 const LdapServer *server, const gchar *searchTerm )
431 LdapQuery *incomplete = NULL;
432 GList *node;
433 cm_return_val_if_fail( server != NULL, NULL );
435 node = server->listQuery;
436 node = g_list_last( node );
437 /* Search backwards for query */
438 while( node ) {
439 LdapQuery *qry = node->data;
440 if( g_utf8_collate( ADDRQUERY_SEARCHVALUE(qry), searchTerm ) == 0 ) {
441 if( qry->agedFlag ) continue;
442 if( qry->completed ) {
443 /* Found */
444 return qry;
446 if( ! incomplete ) {
447 incomplete = qry;
450 node = g_list_previous( node );
452 return incomplete;
456 * Retire aged queries. Only the following queries are retired:
458 * a) Dynamic queries.
459 * b) Explicit searches that have a hidden folders.
460 * c) Locate searches that have a hidden folder.
462 * \param server LdapServer.
464 void ldapsvr_retire_query( LdapServer *server ) {
465 GList *node;
466 GList *listDelete;
467 GList *listQuery;
468 gint maxAge;
469 LdapControl *ctl;
470 ItemFolder *folder;
472 debug_print("ldapsvr_retire_query\n");
473 cm_return_if_fail( server != NULL );
474 ctl = server->control;
475 maxAge = ctl->maxQueryAge;
477 /* Identify queries to age and move to deletion list */
478 listDelete = NULL;
479 node = server->listQuery;
480 while( node ) {
481 LdapQuery *qry = node->data;
483 node = g_list_next( node );
484 folder = ADDRQUERY_FOLDER(qry);
485 if( folder == NULL ) continue;
486 if( ! folder->isHidden ) {
487 if( ADDRQUERY_SEARCHTYPE(qry) == ADDRSEARCH_EXPLICIT ) continue;
488 if( ADDRQUERY_SEARCHTYPE(qry) == ADDRSEARCH_LOCATE ) continue;
491 ldapqry_age( qry, maxAge );
492 if( qry->agedFlag ) {
493 /* Delete folder associated with query */
494 debug_print("deleting folder... ::%s::\n",
495 ADDRQUERY_NAME(qry)?ADDRQUERY_NAME(qry):"null");
496 ldapqry_delete_folder( qry );
497 listDelete = g_list_append( listDelete, qry );
501 /* Delete queries */
502 listQuery = server->listQuery;
503 node = listDelete;
504 while( node ) {
505 LdapQuery *qry = node->data;
507 listQuery = g_list_remove( listQuery, qry );
508 ldapqry_free( qry );
509 node->data = NULL;
510 node = g_list_next( node );
512 server->listQuery = listQuery;
514 /* Free up deletion list */
515 g_list_free( listDelete );
519 * Return results of a previous query by executing callback for each address
520 * contained in specified folder.
522 * \param folder Address book folder to process.
523 * \param req Address query request object.
525 static void ldapsvr_previous_query(
526 const ItemFolder *folder, const QueryRequest *req, AddrQueryObject *aqo )
528 AddrSearchCallbackEntry *callBack;
529 GList *listEMail;
530 GList *node;
531 GList *nodeEM;
532 gpointer sender;
534 sender = aqo;
535 callBack = ( AddrSearchCallbackEntry * ) req->callBackEntry;
536 if( callBack ) {
537 listEMail = NULL;
538 node = folder->listPerson;
539 while( node ) {
540 AddrItemObject *aio = node->data;
541 if( aio && aio->type == ITEMTYPE_PERSON ) {
542 ItemPerson *person = node->data;
543 nodeEM = person->listEMail;
544 while( nodeEM ) {
545 ItemEMail *email = nodeEM->data;
547 nodeEM = g_list_next( nodeEM );
548 listEMail = g_list_append( listEMail, email );
551 node = g_list_next( node );
553 ( callBack ) ( sender, req->queryID, listEMail, NULL );
554 /* // g_list_free( listEMail ); */
559 * Reuse search results from a previous LDAP query. If there is a query that
560 * has the same search term as specified in the query request, then the query
561 * will be reused.
563 * \param server LDAP server object.
564 * \param req Address query object.
565 * \return <i>TRUE</i> if previous query was used.
567 gboolean ldapsvr_reuse_previous( const LdapServer *server, const QueryRequest *req ) {
568 LdapQuery *qry;
569 gchar *searchTerm;
570 ItemFolder *folder;
572 cm_return_val_if_fail( server != NULL, FALSE );
573 cm_return_val_if_fail( req != NULL, FALSE );
575 searchTerm = req->searchTerm;
577 /* Test whether any queries for the same term exist */
578 qry = ldapsvr_locate_query( server, searchTerm );
579 if( qry ) {
580 /* Touch query to ensure it hangs around for a bit longer */
581 ldapqry_touch( qry );
582 folder = ADDRQUERY_FOLDER(qry);
583 if( folder ) {
584 ldapsvr_previous_query( folder, req, ADDRQUERY_OBJECT(qry) );
585 return TRUE;
588 return FALSE;
592 * Construct a new LdapQuery object that will be used to perform an dynamic
593 * search request.
595 * \param server LdapServer.
596 * \param req Query request.
597 * \return LdapQuery object, or <i>NULL</i> if none created.
599 LdapQuery *ldapsvr_new_dynamic_search( LdapServer *server, QueryRequest *req )
601 LdapQuery *qry;
602 gchar *name;
603 gchar *searchTerm;
604 ItemFolder *folder;
606 cm_return_val_if_fail( server != NULL, NULL );
607 cm_return_val_if_fail( req != NULL, NULL );
609 /* Retire any aged queries */
610 /* // ldapsvr_retire_query( server ); */
612 /* Name of folder and query */
613 searchTerm = req->searchTerm;
614 name = g_strdup_printf( "Search '%s'", searchTerm );
616 /* Create a folder for the search results */
617 folder = addrcache_add_new_folder( server->addressCache, NULL );
618 addritem_folder_set_name( folder, name );
619 addritem_folder_set_remarks( folder, "" );
621 /* Construct a query */
622 qry = ldapqry_create();
623 ldapqry_set_query_id( qry, req->queryID );
624 ldapqry_set_search_value( qry, searchTerm );
625 ldapqry_set_search_type( qry, ADDRSEARCH_DYNAMIC );
626 ldapqry_set_callback_entry( qry, req->callBackEntry );
627 ldapqry_set_callback_end( qry, req->callBackEnd );
629 /* Specify folder type and back reference */
630 ADDRQUERY_FOLDER(qry) = folder;
631 folder->folderType = ADDRFOLDER_QUERY_RESULTS;
632 folder->folderData = ( gpointer ) qry;
633 folder->isHidden = TRUE;
635 /* Name the query */
636 ldapqry_set_name( qry, name );
637 g_free( name );
639 /* Add query to request */
640 qryreq_add_query( req, ADDRQUERY_OBJECT(qry) );
642 /* Now start the search */
643 ldapsvr_add_query( server, qry );
645 return qry;
649 * Construct a new LdapQuery object that will be used to perform an explicit
650 * search request.
652 * \param server LdapServer.
653 * \param req Query request.
654 * \param folder Folder that will be used to contain search results.
655 * \return LdapQuery object, or <i>NULL</i> if none created.
657 LdapQuery *ldapsvr_new_explicit_search(
658 LdapServer *server, QueryRequest *req, ItemFolder *folder )
660 LdapQuery *qry;
661 gchar *searchTerm;
662 gchar *name;
664 cm_return_val_if_fail( server != NULL, NULL );
665 cm_return_val_if_fail( req != NULL, NULL );
666 cm_return_val_if_fail( folder != NULL, NULL );
668 /* Retire any aged queries */
669 /* // ldapsvr_retire_query( server ); */
671 /* Name the query */
672 searchTerm = req->searchTerm;
673 name = g_strdup_printf( "Explicit search for '%s'", searchTerm );
675 /* Construct a query */
676 qry = ldapqry_create();
677 ldapqry_set_query_id( qry, req->queryID );
678 ldapqry_set_name( qry, name );
679 ldapqry_set_search_value( qry, searchTerm );
680 ldapqry_set_search_type( qry, ADDRSEARCH_EXPLICIT );
681 ldapqry_set_callback_end( qry, req->callBackEnd );
682 ldapqry_set_callback_entry( qry, req->callBackEntry );
684 /* Specify folder type and back reference */
685 ADDRQUERY_FOLDER(qry) = folder;
686 folder->folderType = ADDRFOLDER_QUERY_RESULTS;
687 folder->folderData = ( gpointer ) qry;
689 /* Setup server */
690 ldapsvr_add_query( server, qry );
692 /* Set up query request */
693 qryreq_add_query( req, ADDRQUERY_OBJECT(qry) );
695 g_free( name );
697 return qry;
700 gint ldapsvr_read_data( LdapServer *server )
702 gchar *name;
704 cm_return_val_if_fail( server != NULL, -1 );
706 name = addrcache_get_name(server->addressCache);
707 debug_print("...addrbook_read_data :%s:\n", name?name:"null");
709 addrcache_clear(server->addressCache);
710 ldapsvr_free_all_query( server );
711 server->listQuery = NULL;
712 server->addressCache->modified = FALSE;
713 server->addressCache->accessFlag = FALSE;
714 server->addressCache->dataRead = TRUE;
715 addrcache_set_dirty(server->addressCache, FALSE);
716 return 0;
719 void ldapsrv_set_options (gint secs, LDAP *ld)
721 #ifdef G_OS_UNIX
722 static struct timeval timeout;
723 timeout.tv_sec = secs;
724 timeout.tv_usec = 0;
725 int i, rc;
726 i = LDAP_OPT_X_TLS_ALLOW;
727 rc = ldap_set_option(NULL, LDAP_OPT_X_TLS_REQUIRE_CERT, &i);
728 if (ld)
729 debug_print("cert %s\n", ldaputil_get_error(ld));
730 else
731 debug_print("cert %s\n", ldap_err2string(rc));
732 /* can crash old libldaps... */
733 rc = ldap_set_option(NULL, LDAP_OPT_NETWORK_TIMEOUT, &timeout);
734 if (ld)
735 debug_print("tm %s\n", ldaputil_get_error(ld));
736 else
737 debug_print("tm %s\n", ldap_err2string(rc));
738 #endif
741 #ifdef G_OS_WIN32
742 #if LDAP_UNICODE
743 #define LDAP_START_TLS_S "ldap_start_tls_sW"
744 typedef ULONG (* PFldap_start_tls_s) (LDAP *, PULONG, LDAPMessage **, PLDAPControlW *, PLDAPControlW *);
745 #else
746 #define LDAP_START_TLS_S "ldap_start_tls_sA"
747 typedef ULONG (* PFldap_start_tls_s) (LDAP *, PULONG, LDAPMessage **, PLDAPControlA *, PLDAPControlA *);
748 #endif /* LDAP_UNICODE */
749 PFldap_start_tls_s Win32_ldap_start_tls_s = NULL;
750 #endif
753 * Connect to LDAP server.
754 * \param ctl Control object to process.
755 * \return LDAP Resource to LDAP.
757 LDAP *ldapsvr_connect(LdapControl *ctl) {
758 LDAP *ld = NULL;
759 gint rc;
760 gint version;
761 gchar *uri = NULL;
762 gchar *pwd;
764 cm_return_val_if_fail(ctl != NULL, NULL);
766 ldapsrv_set_options (ctl->timeOut, NULL);
767 uri = g_strdup_printf("ldap%s://%s:%d",
768 (ctl->enableSSL || ctl->enableTLS)?"s":"",
769 ctl->hostName, ctl->port);
770 #ifdef G_OS_UNIX
771 ldap_initialize(&ld, uri);
772 #else
773 ld = ldap_sslinit(ctl->hostName, ctl->port, ctl->enableSSL);
774 if (ld && ctl->enableSSL) {
775 version = LDAP_VERSION3;
776 debug_print("Setting version 3\n");
777 rc = ldap_set_option(ld, LDAP_OPT_PROTOCOL_VERSION, (void *)&version);
778 if (rc == LDAP_SUCCESS)
779 ctl->version = LDAP_VERSION3;
780 else
781 debug_print("Failed: %s\n", ldaputil_get_error(ld));
783 if (ldap_get_option(ld,LDAP_OPT_SSL,(void*)&rc) != LDAP_SUCCESS)
784 debug_print("Can't get SSL/TLS state\n");
786 if ((void *)rc != LDAP_OPT_ON) {
787 debug_print("Enabling SSL/TLS\n");
788 if (ldap_set_option(ld,LDAP_OPT_SSL,LDAP_OPT_ON) != LDAP_SUCCESS)
789 debug_print("Failed: %s\n", ldaputil_get_error(ld));
790 else {
791 ldap_get_option(ld,LDAP_OPT_SSL,(void*)&rc);
792 debug_print("SSL/TLS now %d\n", rc);
796 if (!ld || (rc = ldap_connect(ld, NULL)) != LDAP_SUCCESS)
797 debug_print("ldap_connect failed: %d %s\n", rc, ldaputil_get_error(ld));
799 #endif
800 g_free(uri);
802 if (ld == NULL)
803 return NULL;
806 debug_print("Got handle to LDAP host %s on port %d\n", ctl->hostName, ctl->port);
808 version = LDAP_VERSION3;
809 debug_print("Setting version 3\n");
810 rc = ldap_set_option(ld, LDAP_OPT_PROTOCOL_VERSION, &version);
811 if (rc == LDAP_OPT_SUCCESS) {
812 ctl->version = LDAP_VERSION3;
813 } else
814 g_printerr("LDAP: Error %d (%s)\n",
815 rc, ldaputil_get_error(ld));
817 #if (defined USE_LDAP_TLS || defined G_OS_WIN32)
818 /* Handle TLS */
819 if (ctl->version == LDAP_VERSION3) {
820 if (ctl->enableTLS && !ctl->enableSSL) {
821 #ifdef G_OS_WIN32
822 ULONG serv_rc;
823 if (Win32_ldap_start_tls_s == NULL) {
824 void *lib = LoadLibrary("wldap32.dll");
825 if (!lib || (Win32_ldap_start_tls_s = (PFldap_start_tls_s) GetProcAddress(lib, LDAP_START_TLS_S)) == NULL) {
826 g_printerr("LDAP Error(tls): ldap_start_tls_s: not supported on this platform");
827 if (lib)
828 FreeLibrary(lib);
829 return NULL;
832 debug_print("Setting STARTTLS\n");
833 rc = Win32_ldap_start_tls_s(ld, &serv_rc, NULL, NULL, NULL);
834 debug_print("ldap_start_tls_s: %d server %d %s\n",
835 rc, serv_rc, ldaputil_get_error(ld));
836 #else
837 debug_print("Setting STARTTLS\n");
838 rc = ldap_start_tls_s(ld, NULL, NULL);
839 #endif
840 if (rc != LDAP_SUCCESS) {
841 g_printerr("LDAP Error(tls): ldap_start_tls_s: %d %s\n",
842 rc, ldaputil_get_error(ld));
843 return NULL;
844 } else {
845 debug_print("Done\n");
849 #endif
851 /* Bind to the server, if required */
852 if (ctl->bindDN) {
853 if (* ctl->bindDN != '\0') {
854 pwd = passwd_store_get(PWS_CORE, "LDAP", ctl->hostName);
855 rc = claws_ldap_simple_bind_s(ld, ctl->bindDN, pwd);
856 if (pwd != NULL && strlen(pwd) > 0)
857 memset(pwd, 0, strlen(pwd));
858 g_free(pwd);
859 if (rc != LDAP_SUCCESS) {
860 g_printerr("bindDN: %s, bindPass xxx\n", ctl->bindDN);
861 g_printerr("LDAP Error(bind): ldap_simple_bind_s: %s\n",
862 ldaputil_get_error(ld));
863 return NULL;
867 return ld;
871 * Disconnect to LDAP server.
872 * \param ld Resource to LDAP.
874 void ldapsvr_disconnect(LDAP *ld) {
875 /* Disconnect */
876 cm_return_if_fail(ld != NULL);
877 ldap_unbind_ext(ld, NULL, NULL);
880 #endif /* USE_LDAP */
883 * End of Source.