replace some deprecated functions
[claws.git] / src / ldapserver.c
blobfec392cb38c13c8167768f529aa8008c7c3c9fc0
1 /*
2 * Claws Mail -- a GTK+ based, lightweight, and fast e-mail client
3 * Copyright (C) 2003-2021 the Claws Mail team and Match Grun
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 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/>.
20 * Functions necessary to access LDAP servers.
23 #ifdef HAVE_CONFIG_H
24 # include "config.h"
25 #include "claws-features.h"
26 #endif
28 #ifdef USE_LDAP
30 #include <glib.h>
31 #include <glib/gi18n.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"
45 #include "log.h"
47 /**
48 * Create new LDAP server interface object with no control object.
49 * \return Initialized LDAP server object.
51 LdapServer *ldapsvr_create_noctl( void ) {
52 LdapServer *server;
54 server = g_new0( LdapServer, 1 );
55 server->type = ADBOOKTYPE_LDAP;
56 server->addressCache = addrcache_create();
57 server->retVal = MGU_SUCCESS;
58 server->control = NULL;
59 server->listQuery = NULL;
60 server->searchFlag = FALSE;
61 return server;
64 /**
65 * Create new LDAP server interface object.
66 * \return Initialized LDAP server object.
68 LdapServer *ldapsvr_create( void ) {
69 LdapServer *server;
70 server = ldapsvr_create_noctl();
71 server->control = ldapctl_create();
72 return server;
75 /**
76 * Return name of server.
77 * \param server Server object.
78 * \return Name for server.
80 gchar *ldapsvr_get_name( LdapServer *server ) {
81 cm_return_val_if_fail( server != NULL, NULL );
82 return addrcache_get_name( server->addressCache );
85 /**
86 * Specify name to be used.
87 * \param server Server object.
88 * \param value Name for server.
90 void ldapsvr_set_name( LdapServer* server, const gchar *value ) {
91 cm_return_if_fail( server != NULL );
92 addrcache_set_name( server->addressCache, value );
93 debug_print("setting name: %s\n", value?value:"null");
96 /**
97 * Refresh internal variables to force a file read.
98 * \param server Server object.
100 void ldapsvr_force_refresh( LdapServer *server ) {
101 cm_return_if_fail( server != NULL );
102 addrcache_refresh( server->addressCache );
106 * Return status/error code.
107 * \param server Server object.
108 * \return Status/error code.
110 gint ldapsvr_get_status( LdapServer *server ) {
111 cm_return_val_if_fail( server != NULL, -1 );
112 return server->retVal;
116 * Return reference to root level folder.
117 * \param server Server object.
118 * \return Root level folder.
120 ItemFolder *ldapsvr_get_root_folder( LdapServer *server ) {
121 cm_return_val_if_fail( server != NULL, NULL );
123 g_print( "ldapsvr_get_root_folder/start\n" );
124 ldapsvr_print_data( server, stdout );
125 g_print( "ldapsvr_get_root_folder/done\n" );
127 return addrcache_get_root_folder( server->addressCache );
131 * Test whether server data has been accessed.
132 * \param server Server object.
133 * \return <i>TRUE</i> if data was accessed.
135 gboolean ldapsvr_get_accessed( LdapServer *server ) {
136 cm_return_val_if_fail( server != NULL, FALSE );
137 return server->addressCache->accessFlag;
141 * Specify that server's data whas beed accessed.
142 * \param server Server object.
143 * \param value Value for flag.
145 void ldapsvr_set_accessed( LdapServer *server, const gboolean value ) {
146 cm_return_if_fail( server != NULL );
147 server->addressCache->accessFlag = value;
148 debug_print("setting accessFlag: %d\n", value);
152 * Test whether server data has been modified.
153 * \param server Server object.
154 * \return <i>TRUE</i> if data was modified.
156 gboolean ldapsvr_get_modified( LdapServer *server ) {
157 cm_return_val_if_fail( server != NULL, FALSE );
158 return server->addressCache->modified;
162 * Specify modify flag.
163 * \param server Server object.
164 * \param value Value for flag.
166 void ldapsvr_set_modified( LdapServer *server, const gboolean value ) {
167 cm_return_if_fail( server != NULL );
168 server->addressCache->modified = value;
169 debug_print("setting modified: %d\n", value);
173 * Test whether data was read from server.
174 * \param server Server object.
175 * \return <i>TRUE</i> if data was read.
177 gboolean ldapsvr_get_read_flag( LdapServer *server ) {
178 cm_return_val_if_fail( server != NULL, FALSE );
179 return server->addressCache->dataRead;
183 * Test whether server is to be used for dynamic searches.
184 * \param server Server object.
185 * \return <i>TRUE</i> if server is used for dynamic searches.
187 gboolean ldapsvr_get_search_flag( LdapServer *server ) {
188 cm_return_val_if_fail( server != NULL, FALSE );
189 return server->searchFlag;
193 * Specify that server is to be used for dynamic searches.
194 * \param server Server object.
195 * \param value Name for server.
197 void ldapsvr_set_search_flag( LdapServer *server, const gboolean value ) {
198 cm_return_if_fail( server != NULL );
199 server->searchFlag = value;
200 debug_print("setting searchFlag: %d\n", value);
204 * Specify the reference to control data that will be used for the query. The calling
205 * module should be responsible for creating and destroying this control object.
206 * \param server Server object.
207 * \param ctl Control data.
209 void ldapsvr_set_control( LdapServer *server, LdapControl *ctl ) {
210 cm_return_if_fail( server != NULL );
211 addrcache_refresh( server->addressCache );
212 server->control = ctl;
216 * Free all queries.
217 * \param server Server object.
219 void ldapsvr_free_all_query( LdapServer *server ) {
220 GList *node;
221 cm_return_if_fail( server != NULL );
223 node = server->listQuery;
224 while( node ) {
225 LdapQuery *qry = node->data;
226 ldapqry_free( qry );
227 node->data = NULL;
228 node = g_list_next( node );
230 g_list_free( server->listQuery );
231 server->listQuery = NULL;
235 * Add query to server.
236 * \param server Server object.
237 * \param qry Query object.
239 void ldapsvr_add_query( LdapServer *server, LdapQuery *qry ) {
240 cm_return_if_fail( server != NULL );
241 cm_return_if_fail( qry != NULL );
243 server->listQuery = g_list_append( server->listQuery, qry );
244 qry->server = server;
248 * Free up LDAP server interface object by releasing internal memory.
249 * \param server Server object.
251 void ldapsvr_free( LdapServer *server ) {
252 cm_return_if_fail( server != NULL );
254 /* Stop and cancel any queries that may be active */
255 ldapsvr_stop_all_query( server );
256 ldapsvr_cancel_all_query( server );
258 /* Clear cache */
259 addrcache_clear( server->addressCache );
260 addrcache_free( server->addressCache );
262 /* Free LDAP control block */
263 ldapctl_free( server->control );
264 server->control = NULL;
266 /* Free all queries */
267 ldapsvr_free_all_query( server );
269 /* Clear pointers */
270 server->type = ADBOOKTYPE_NONE;
271 server->addressCache = NULL;
272 server->retVal = MGU_SUCCESS;
273 server->listQuery = NULL;
274 server->searchFlag = FALSE;
276 /* Now release LDAP object */
277 g_free( server );
281 * Display object to specified stream.
282 * \param server Server object.
283 * \param stream Output stream.
285 void ldapsvr_print_data( LdapServer *server, FILE *stream ) {
286 GList *node;
287 gint i;
289 cm_return_if_fail( server != NULL );
291 fprintf( stream, "LdapServer:\n" );
292 fprintf( stream, " ret val: %d\n", server->retVal );
293 fprintf( stream, "srch flag: %s\n",
294 server->searchFlag ? "yes" : "no" );
295 if( server->control ) {
296 ldapctl_print( server->control, stream );
298 else {
299 fprintf( stream, " control: NULL\n" );
301 addrcache_print( server->addressCache, stream );
302 addritem_print_item_folder( server->addressCache->rootFolder, stream );
304 /* Dump queries */
305 i = 1;
306 node = server->listQuery;
307 while( node ) {
308 LdapQuery *qry = node->data;
309 fprintf( stream, " query: %2d : %s\n", i, ADDRQUERY_NAME(qry) );
310 i++;
311 node = g_list_next( node );
316 * Return link list of persons.
317 * \param server Server object.
318 * \return List of persons.
320 GList *ldapsvr_get_list_person( LdapServer *server ) {
321 cm_return_val_if_fail( server != NULL, NULL );
322 return addrcache_get_list_person( server->addressCache );
326 * Return link list of folders. There are no "real" folders that are returned
327 * from the server.
328 * \param server Server object.
329 * \return List of folders.
331 GList *ldapsvr_get_list_folder( LdapServer *server ) {
332 cm_return_val_if_fail( server != NULL, NULL );
333 /* return addrcache_get_list_folder( server->addressCache ); */
334 return NULL;
338 * Execute specified query.
339 * \param server LDAP server.
340 * \param qry LDAP query.
342 void ldapsvr_execute_query( LdapServer *server, LdapQuery *qry ) {
343 LdapControl *ctlCopy;
345 cm_return_if_fail( server != NULL );
346 cm_return_if_fail( qry != NULL );
348 /* Copy server's control data to the query */
349 ctlCopy = ldapctl_create();
350 ldapctl_copy( server->control, ctlCopy );
351 ldapqry_set_control( qry, ctlCopy );
352 ldapqry_initialize();
354 /* Perform query */
355 debug_print("ldapsvr_execute_query::checking query...\n");
356 if( ldapqry_check_search( qry ) ) {
357 debug_print("ldapsvr_execute_query::reading with thread...\n");
358 ldapqry_read_data_th( qry );
359 if(qry->server->retVal == LDAPRC_SUCCESS) {
360 debug_print("ldapsvr_execute_query::SUCCESS with thread...\n");
363 debug_print("ldapsvr_execute_query... terminated\n");
367 * Stop all queries for specified ID.
368 * \param server Server object.
369 * \param queryID Query ID to stop.
371 void ldapsvr_stop_query_id( LdapServer *server, const gint queryID ) {
372 GList *node;
373 cm_return_if_fail( server != NULL );
375 node = server->listQuery;
376 while( node ) {
377 LdapQuery *qry = node->data;
378 if( ADDRQUERY_ID(qry) == queryID ) {
379 /* Notify thread to stop */
380 ldapqry_set_stop_flag( qry, TRUE );
382 node = g_list_next( node );
387 * Stop all queries by notifying each thread to stop.
388 * \param server Server object.
390 void ldapsvr_stop_all_query( LdapServer *server ) {
391 GList *node;
392 cm_return_if_fail( server != NULL );
394 node = server->listQuery;
395 while( node ) {
396 LdapQuery *qry = node->data;
397 ldapqry_set_stop_flag( qry, TRUE );
398 node = g_list_next( node );
403 * Cancel all query threads for server.
404 * \param server Server object.
406 void ldapsvr_cancel_all_query( LdapServer *server ) {
407 GList *node;
408 cm_return_if_fail( server != NULL );
410 node = server->listQuery;
411 while( node ) {
412 LdapQuery *qry = node->data;
413 /* Notify thread to stop */
414 ldapqry_set_stop_flag( qry, TRUE );
415 /* Now cancel thread */
416 ldapqry_cancel( qry );
417 node = g_list_next( node );
422 * Search most recent query for specified search term. The most recent
423 * completed query is returned. If no completed query is found, the most recent
424 * incomplete is returned.
425 * \param server LdapServer.
426 * \param searchTerm Search term to locate.
427 * \return Query object, or <i>NULL</i> if none found.
429 static LdapQuery *ldapsvr_locate_query(
430 const LdapServer *server, const gchar *searchTerm )
432 LdapQuery *incomplete = NULL;
433 GList *node;
434 cm_return_val_if_fail( server != NULL, NULL );
436 node = server->listQuery;
437 node = g_list_last( node );
438 /* Search backwards for query */
439 while( node ) {
440 LdapQuery *qry = node->data;
441 if( g_utf8_collate( ADDRQUERY_SEARCHVALUE(qry), searchTerm ) == 0 ) {
442 if( qry->agedFlag ) continue;
443 if( qry->completed ) {
444 /* Found */
445 return qry;
447 if( ! incomplete ) {
448 incomplete = qry;
451 node = g_list_previous( node );
453 return incomplete;
457 * Retire aged queries. Only the following queries are retired:
459 * a) Dynamic queries.
460 * b) Explicit searches that have a hidden folders.
461 * c) Locate searches that have a hidden folder.
463 * \param server LdapServer.
465 void ldapsvr_retire_query( LdapServer *server ) {
466 GList *node;
467 GList *listDelete;
468 GList *listQuery;
469 gint maxAge;
470 LdapControl *ctl;
471 ItemFolder *folder;
473 debug_print("ldapsvr_retire_query\n");
474 cm_return_if_fail( server != NULL );
475 ctl = server->control;
476 maxAge = ctl->maxQueryAge;
478 /* Identify queries to age and move to deletion list */
479 listDelete = NULL;
480 node = server->listQuery;
481 while( node ) {
482 LdapQuery *qry = node->data;
484 node = g_list_next( node );
485 folder = ADDRQUERY_FOLDER(qry);
486 if( folder == NULL ) continue;
487 if( ! folder->isHidden ) {
488 if( ADDRQUERY_SEARCHTYPE(qry) == ADDRSEARCH_EXPLICIT ) continue;
489 if( ADDRQUERY_SEARCHTYPE(qry) == ADDRSEARCH_LOCATE ) continue;
492 ldapqry_age( qry, maxAge );
493 if( qry->agedFlag ) {
494 /* Delete folder associated with query */
495 debug_print("deleting folder... ::%s::\n",
496 ADDRQUERY_NAME(qry)?ADDRQUERY_NAME(qry):"null");
497 ldapqry_delete_folder( qry );
498 listDelete = g_list_append( listDelete, qry );
502 /* Delete queries */
503 listQuery = server->listQuery;
504 node = listDelete;
505 while( node ) {
506 LdapQuery *qry = node->data;
508 listQuery = g_list_remove( listQuery, qry );
509 ldapqry_free( qry );
510 node->data = NULL;
511 node = g_list_next( node );
513 server->listQuery = listQuery;
515 /* Free up deletion list */
516 g_list_free( listDelete );
520 * Return results of a previous query by executing callback for each address
521 * contained in specified folder.
523 * \param folder Address book folder to process.
524 * \param req Address query request object.
526 static void ldapsvr_previous_query(
527 const ItemFolder *folder, const QueryRequest *req, AddrQueryObject *aqo )
529 AddrSearchCallbackEntry *callBack;
530 GList *listEMail;
531 GList *node;
532 GList *nodeEM;
533 gpointer sender;
535 sender = aqo;
536 callBack = ( AddrSearchCallbackEntry * ) req->callBackEntry;
537 if( callBack ) {
538 listEMail = NULL;
539 node = folder->listPerson;
540 while( node ) {
541 AddrItemObject *aio = node->data;
542 if( aio && aio->type == ITEMTYPE_PERSON ) {
543 ItemPerson *person = node->data;
544 nodeEM = person->listEMail;
545 while( nodeEM ) {
546 ItemEMail *email = nodeEM->data;
548 nodeEM = g_list_next( nodeEM );
549 listEMail = g_list_append( listEMail, email );
552 node = g_list_next( node );
554 ( callBack ) ( sender, req->queryID, listEMail, NULL );
555 /* // g_list_free( listEMail ); */
560 * Reuse search results from a previous LDAP query. If there is a query that
561 * has the same search term as specified in the query request, then the query
562 * will be reused.
564 * \param server LDAP server object.
565 * \param req Address query object.
566 * \return <i>TRUE</i> if previous query was used.
568 gboolean ldapsvr_reuse_previous( const LdapServer *server, const QueryRequest *req ) {
569 LdapQuery *qry;
570 gchar *searchTerm;
571 ItemFolder *folder;
573 cm_return_val_if_fail( server != NULL, FALSE );
574 cm_return_val_if_fail( req != NULL, FALSE );
576 searchTerm = req->searchTerm;
578 /* Test whether any queries for the same term exist */
579 qry = ldapsvr_locate_query( server, searchTerm );
580 if( qry ) {
581 /* Touch query to ensure it hangs around for a bit longer */
582 ldapqry_touch( qry );
583 folder = ADDRQUERY_FOLDER(qry);
584 if( folder ) {
585 ldapsvr_previous_query( folder, req, ADDRQUERY_OBJECT(qry) );
586 return TRUE;
589 return FALSE;
593 * Construct a new LdapQuery object that will be used to perform an dynamic
594 * search request.
596 * \param server LdapServer.
597 * \param req Query request.
598 * \return LdapQuery object, or <i>NULL</i> if none created.
600 LdapQuery *ldapsvr_new_dynamic_search( LdapServer *server, QueryRequest *req )
602 LdapQuery *qry;
603 gchar *name;
604 gchar *searchTerm;
605 ItemFolder *folder;
607 cm_return_val_if_fail( server != NULL, NULL );
608 cm_return_val_if_fail( req != NULL, NULL );
610 /* Retire any aged queries */
611 /* // ldapsvr_retire_query( server ); */
613 /* Name of folder and query */
614 searchTerm = req->searchTerm;
615 name = g_strdup_printf( "Search '%s'", searchTerm );
617 /* Create a folder for the search results */
618 folder = addrcache_add_new_folder( server->addressCache, NULL );
619 addritem_folder_set_name( folder, name );
620 addritem_folder_set_remarks( folder, "" );
622 /* Construct a query */
623 qry = ldapqry_create();
624 ldapqry_set_query_id( qry, req->queryID );
625 ldapqry_set_search_value( qry, searchTerm );
626 ldapqry_set_search_type( qry, ADDRSEARCH_DYNAMIC );
627 ldapqry_set_callback_entry( qry, req->callBackEntry );
628 ldapqry_set_callback_end( qry, req->callBackEnd );
630 /* Specify folder type and back reference */
631 ADDRQUERY_FOLDER(qry) = folder;
632 folder->folderType = ADDRFOLDER_QUERY_RESULTS;
633 folder->folderData = ( gpointer ) qry;
634 folder->isHidden = TRUE;
636 /* Name the query */
637 ldapqry_set_name( qry, name );
638 g_free( name );
640 /* Add query to request */
641 qryreq_add_query( req, ADDRQUERY_OBJECT(qry) );
643 /* Now start the search */
644 ldapsvr_add_query( server, qry );
646 return qry;
650 * Construct a new LdapQuery object that will be used to perform an explicit
651 * search request.
653 * \param server LdapServer.
654 * \param req Query request.
655 * \param folder Folder that will be used to contain search results.
656 * \return LdapQuery object, or <i>NULL</i> if none created.
658 LdapQuery *ldapsvr_new_explicit_search(
659 LdapServer *server, QueryRequest *req, ItemFolder *folder )
661 LdapQuery *qry;
662 gchar *searchTerm;
663 gchar *name;
665 cm_return_val_if_fail( server != NULL, NULL );
666 cm_return_val_if_fail( req != NULL, NULL );
667 cm_return_val_if_fail( folder != NULL, NULL );
669 /* Retire any aged queries */
670 /* // ldapsvr_retire_query( server ); */
672 /* Name the query */
673 searchTerm = req->searchTerm;
674 name = g_strdup_printf( "Explicit search for '%s'", searchTerm );
676 /* Construct a query */
677 qry = ldapqry_create();
678 ldapqry_set_query_id( qry, req->queryID );
679 ldapqry_set_name( qry, name );
680 ldapqry_set_search_value( qry, searchTerm );
681 ldapqry_set_search_type( qry, ADDRSEARCH_EXPLICIT );
682 ldapqry_set_callback_end( qry, req->callBackEnd );
683 ldapqry_set_callback_entry( qry, req->callBackEntry );
685 /* Specify folder type and back reference */
686 ADDRQUERY_FOLDER(qry) = folder;
687 folder->folderType = ADDRFOLDER_QUERY_RESULTS;
688 folder->folderData = ( gpointer ) qry;
690 /* Setup server */
691 ldapsvr_add_query( server, qry );
693 /* Set up query request */
694 qryreq_add_query( req, ADDRQUERY_OBJECT(qry) );
696 g_free( name );
698 return qry;
701 gint ldapsvr_read_data( LdapServer *server )
703 gchar *name;
705 cm_return_val_if_fail( server != NULL, -1 );
707 name = addrcache_get_name(server->addressCache);
708 debug_print("...addrbook_read_data :%s:\n", name?name:"null");
710 addrcache_clear(server->addressCache);
711 ldapsvr_free_all_query( server );
712 server->listQuery = NULL;
713 server->addressCache->modified = FALSE;
714 server->addressCache->accessFlag = FALSE;
715 server->addressCache->dataRead = TRUE;
716 addrcache_set_dirty(server->addressCache, FALSE);
717 return 0;
720 void ldapsrv_set_options (gint secs, LDAP *ld)
722 #ifdef G_OS_UNIX
723 static struct timeval timeout;
724 timeout.tv_sec = secs;
725 timeout.tv_usec = 0;
726 int i, rc;
727 i = LDAP_OPT_X_TLS_ALLOW;
728 rc = ldap_set_option(NULL, LDAP_OPT_X_TLS_REQUIRE_CERT, &i);
729 if (ld)
730 debug_print("cert %s\n", ldaputil_get_error(ld));
731 else
732 debug_print("cert %s\n", ldap_err2string(rc));
733 /* can crash old libldaps... */
734 rc = ldap_set_option(NULL, LDAP_OPT_NETWORK_TIMEOUT, &timeout);
735 if (ld)
736 debug_print("tm %s\n", ldaputil_get_error(ld));
737 else
738 debug_print("tm %s\n", ldap_err2string(rc));
739 #endif
742 #ifdef G_OS_WIN32
743 #if LDAP_UNICODE
744 #define LDAP_START_TLS_S "ldap_start_tls_sW"
745 typedef ULONG (* PFldap_start_tls_s) (LDAP *, PULONG, LDAPMessage **, PLDAPControlW *, PLDAPControlW *);
746 #else
747 #define LDAP_START_TLS_S "ldap_start_tls_sA"
748 typedef ULONG (* PFldap_start_tls_s) (LDAP *, PULONG, LDAPMessage **, PLDAPControlA *, PLDAPControlA *);
749 #endif /* LDAP_UNICODE */
750 PFldap_start_tls_s Win32_ldap_start_tls_s = NULL;
751 #endif
754 * Connect to LDAP server.
755 * \param ctl Control object to process.
756 * \return LDAP Resource to LDAP.
758 LDAP *ldapsvr_connect(LdapControl *ctl) {
759 LDAP *ld = NULL;
760 gint rc;
761 #ifndef G_OS_UNIX
762 intptr_t op;
763 #endif
764 gint version;
765 gchar *uri = NULL;
766 gchar *pwd;
768 cm_return_val_if_fail(ctl != NULL, NULL);
770 ldapsrv_set_options (ctl->timeOut, NULL);
771 if (ctl->enableSSL)
772 uri = g_strdup_printf("ldaps://%s:%d", ctl->hostName, ctl->port);
773 else
774 uri = g_strdup_printf("ldap://%s:%d", ctl->hostName, ctl->port);
775 #ifdef G_OS_UNIX
776 ldap_initialize(&ld, uri);
777 #else
778 ld = ldap_sslinit(ctl->hostName, ctl->port, ctl->enableSSL);
779 if (ld && ctl->enableSSL) {
780 version = LDAP_VERSION3;
781 debug_print("Setting version 3\n");
782 rc = ldap_set_option(ld, LDAP_OPT_PROTOCOL_VERSION, (void *)&version);
783 if (rc == LDAP_SUCCESS) {
784 ctl->version = LDAP_VERSION3;
785 log_print(LOG_PROTOCOL, "LDAP (options): set version 3\n");
786 } else {
787 log_error(LOG_PROTOCOL, _("LDAP error (options): %d (%s)\n"),
788 rc, ldaputil_get_error(ld));
789 debug_print("Failed: %s\n", ldaputil_get_error(ld));
792 rc = ldap_get_option(ld, LDAP_OPT_SSL, (void*)&op);
793 if (rc != LDAP_SUCCESS) {
794 log_warning(LOG_PROTOCOL, _("LDAP warning (options): can't get TLS state\n"));
795 debug_print("Can't get TLS state\n");
798 if ((void *)op != LDAP_OPT_ON) {
799 debug_print("Enabling TLS\n");
800 rc = ldap_set_option(ld, LDAP_OPT_SSL, LDAP_OPT_ON);
801 if (rc != LDAP_SUCCESS) {
802 log_error(LOG_PROTOCOL, _("LDAP error (options): %d (%s)\n"),
803 rc, ldaputil_get_error(ld));
804 debug_print("Failed: %s\n", ldaputil_get_error(ld));
805 } else {
806 rc = ldap_get_option(ld, LDAP_OPT_SSL, (void*)&op);
807 if (rc != LDAP_SUCCESS) {
808 log_error(LOG_PROTOCOL, _("LDAP error (options): %d (%s)\n"),
809 rc, ldaputil_get_error(ld));
810 } else {
811 log_print(LOG_PROTOCOL, _("LDAP (options): TLS enabled (%d)\n"), (gint)op);
813 debug_print("TLS now %d\n", (gint)op);
817 if (!ld || (rc = ldap_connect(ld, NULL)) != LDAP_SUCCESS) {
818 log_error(LOG_PROTOCOL, _("LDAP error (connect): %d (%s)\n"),
819 rc, ldaputil_get_error(ld));
820 debug_print("ldap_connect failed: %d %s\n", rc, ldaputil_get_error(ld));
821 } else {
822 log_print(LOG_PROTOCOL, _("LDAP (connect): completed successfully\n"));
825 #endif
826 g_free(uri);
828 if (ld == NULL)
829 return NULL;
831 debug_print("Got handle to LDAP host %s on port %d\n", ctl->hostName, ctl->port);
833 version = LDAP_VERSION3;
834 debug_print("Setting version 3\n");
835 rc = ldap_set_option(ld, LDAP_OPT_PROTOCOL_VERSION, &version);
836 if (rc == LDAP_OPT_SUCCESS) {
837 ctl->version = LDAP_VERSION3;
838 log_print(LOG_PROTOCOL, "LDAP (options): set version 3\n");
839 } else {
840 log_error(LOG_PROTOCOL, _("LDAP error (options): %d (%s)\n"),
841 rc, ldaputil_get_error(ld));
844 #if (defined USE_LDAP_TLS || defined G_OS_WIN32)
845 /* Handle TLS */
846 if (ctl->version == LDAP_VERSION3) {
847 if (ctl->enableTLS && !ctl->enableSSL) {
848 #ifdef G_OS_WIN32
849 ULONG serv_rc;
850 if (Win32_ldap_start_tls_s == NULL) {
851 void *lib = LoadLibrary("wldap32.dll");
852 if (!lib || (Win32_ldap_start_tls_s = (PFldap_start_tls_s) GetProcAddress(lib, LDAP_START_TLS_S)) == NULL) {
853 log_error(LOG_PROTOCOL, _("LDAP error (TLS): "
854 "ldap_start_tls_s not supported on this platform\n"));
855 if (lib)
856 FreeLibrary(lib);
857 return NULL;
860 debug_print("Setting STARTTLS\n");
861 rc = Win32_ldap_start_tls_s(ld, &serv_rc, NULL, NULL, NULL);
862 debug_print("ldap_start_tls_s: %d server %ld %s\n",
863 rc, serv_rc, ldaputil_get_error(ld));
864 #else
865 debug_print("Setting STARTTLS\n");
866 rc = ldap_start_tls_s(ld, NULL, NULL);
867 #endif
868 if (rc != LDAP_SUCCESS) {
869 log_error(LOG_PROTOCOL, _("LDAP error (TLS): ldap_start_tls_s: %d (%s)\n"),
870 rc, ldaputil_get_error(ld));
871 return NULL;
872 } else {
873 log_print(LOG_PROTOCOL, _("LDAP (TLS): started successfully\n"));
874 debug_print("Done\n");
878 #endif
880 /* Bind to the server, if required */
881 if (ctl->bindDN) {
882 if (* ctl->bindDN != '\0') {
883 pwd = passwd_store_get(PWS_CORE, "LDAP", ctl->hostName);
884 rc = claws_ldap_simple_bind_s(ld, ctl->bindDN, pwd);
885 if (pwd != NULL && strlen(pwd) > 0)
886 memset(pwd, 0, strlen(pwd));
887 g_free(pwd);
888 if (rc != LDAP_SUCCESS) {
889 log_error(LOG_PROTOCOL, _("LDAP error (bind): binding DN '%s': %d (%s)\n" ),
890 ctl->bindDN, rc, ldaputil_get_error(ld));
891 return NULL;
893 log_print(LOG_PROTOCOL, _("LDAP (bind): successfully for DN '%s'\n"),
894 ctl->bindDN);
897 return ld;
901 * Disconnect to LDAP server.
902 * \param ld Resource to LDAP.
904 void ldapsvr_disconnect(LDAP *ld) {
905 gint rc;
906 /* Disconnect */
907 cm_return_if_fail(ld != NULL);
908 rc = ldap_unbind_ext(ld, NULL, NULL);
909 if (rc != LDAP_SUCCESS) {
910 log_error(LOG_PROTOCOL, _("LDAP error (unbind): %d (%s)\n"),
911 rc, ldaputil_get_error(ld));
912 } else {
913 log_print(LOG_PROTOCOL, _("LDAP (unbind): successful\n"));
917 #endif /* USE_LDAP */
920 * End of Source.