Remove inclusion of sys/socket.h from nntp-thread.c
[claws.git] / src / ldapserver.c
bloba14968370b0bb6dd4b50b67b4d77f102fe8b438d
1 /*
2 * Claws Mail -- a GTK based, lightweight, and fast e-mail client
3 * Copyright (C) 2003-2022 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 );
122 #ifdef DEBUG_LDAP
123 debug_print( "ldapsvr_get_root_folder/start\n" );
124 ldapsvr_print_data( server, stdout );
125 debug_print( "ldapsvr_get_root_folder/done\n" );
126 #endif
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 );
280 #ifdef DEBUG_LDAP
282 * Display object to specified stream.
283 * \param server Server object.
284 * \param stream Output stream.
286 void ldapsvr_print_data( LdapServer *server, FILE *stream ) {
287 GList *node;
288 gint i;
290 cm_return_if_fail( server != NULL );
292 fprintf( stream, "LdapServer:\n" );
293 fprintf( stream, " ret val: %d\n", server->retVal );
294 fprintf( stream, "srch flag: %s\n",
295 server->searchFlag ? "yes" : "no" );
296 if( server->control ) {
297 ldapctl_print( server->control, stream );
299 else {
300 fprintf( stream, " control: NULL\n" );
302 addrcache_print( server->addressCache, stream );
303 addritem_print_item_folder( server->addressCache->rootFolder, stream );
305 /* Dump queries */
306 i = 1;
307 node = server->listQuery;
308 while( node ) {
309 LdapQuery *qry = node->data;
310 fprintf( stream, " query: %2d : %s\n", i, ADDRQUERY_NAME(qry) );
311 i++;
312 node = g_list_next( node );
315 #endif
318 * Return link list of persons.
319 * \param server Server object.
320 * \return List of persons.
322 GList *ldapsvr_get_list_person( LdapServer *server ) {
323 cm_return_val_if_fail( server != NULL, NULL );
324 return addrcache_get_list_person( server->addressCache );
328 * Return link list of folders. There are no "real" folders that are returned
329 * from the server.
330 * \param server Server object.
331 * \return List of folders.
333 GList *ldapsvr_get_list_folder( LdapServer *server ) {
334 cm_return_val_if_fail( server != NULL, NULL );
335 /* return addrcache_get_list_folder( server->addressCache ); */
336 return NULL;
340 * Execute specified query.
341 * \param server LDAP server.
342 * \param qry LDAP query.
344 void ldapsvr_execute_query( LdapServer *server, LdapQuery *qry ) {
345 LdapControl *ctlCopy;
347 cm_return_if_fail( server != NULL );
348 cm_return_if_fail( qry != NULL );
350 /* Copy server's control data to the query */
351 ctlCopy = ldapctl_create();
352 ldapctl_copy( server->control, ctlCopy );
353 ldapqry_set_control( qry, ctlCopy );
354 ldapqry_initialize();
356 /* Perform query */
357 debug_print("ldapsvr_execute_query::checking query...\n");
358 if( ldapqry_check_search( qry ) ) {
359 debug_print("ldapsvr_execute_query::reading with thread...\n");
360 ldapqry_read_data_th( qry );
361 if(qry->server->retVal == LDAPRC_SUCCESS) {
362 debug_print("ldapsvr_execute_query::SUCCESS with thread...\n");
365 debug_print("ldapsvr_execute_query... terminated\n");
369 * Stop all queries for specified ID.
370 * \param server Server object.
371 * \param queryID Query ID to stop.
373 void ldapsvr_stop_query_id( LdapServer *server, const gint queryID ) {
374 GList *node;
375 cm_return_if_fail( server != NULL );
377 node = server->listQuery;
378 while( node ) {
379 LdapQuery *qry = node->data;
380 if( ADDRQUERY_ID(qry) == queryID ) {
381 /* Notify thread to stop */
382 ldapqry_set_stop_flag( qry, TRUE );
384 node = g_list_next( node );
389 * Stop all queries by notifying each thread to stop.
390 * \param server Server object.
392 void ldapsvr_stop_all_query( LdapServer *server ) {
393 GList *node;
394 cm_return_if_fail( server != NULL );
396 node = server->listQuery;
397 while( node ) {
398 LdapQuery *qry = node->data;
399 ldapqry_set_stop_flag( qry, TRUE );
400 node = g_list_next( node );
405 * Cancel all query threads for server.
406 * \param server Server object.
408 void ldapsvr_cancel_all_query( LdapServer *server ) {
409 GList *node;
410 cm_return_if_fail( server != NULL );
412 node = server->listQuery;
413 while( node ) {
414 LdapQuery *qry = node->data;
415 /* Notify thread to stop */
416 ldapqry_set_stop_flag( qry, TRUE );
417 /* Now cancel thread */
418 ldapqry_cancel( qry );
419 node = g_list_next( node );
424 * Search most recent query for specified search term. The most recent
425 * completed query is returned. If no completed query is found, the most recent
426 * incomplete is returned.
427 * \param server LdapServer.
428 * \param searchTerm Search term to locate.
429 * \return Query object, or <i>NULL</i> if none found.
431 static LdapQuery *ldapsvr_locate_query(
432 const LdapServer *server, const gchar *searchTerm )
434 LdapQuery *incomplete = NULL;
435 GList *node;
436 cm_return_val_if_fail( server != NULL, NULL );
438 node = server->listQuery;
439 node = g_list_last( node );
440 /* Search backwards for query */
441 while( node ) {
442 LdapQuery *qry = node->data;
443 if( g_utf8_collate( ADDRQUERY_SEARCHVALUE(qry), searchTerm ) == 0 ) {
444 if( qry->agedFlag ) continue;
445 if( qry->completed ) {
446 /* Found */
447 return qry;
449 if( ! incomplete ) {
450 incomplete = qry;
453 node = g_list_previous( node );
455 return incomplete;
459 * Retire aged queries. Only the following queries are retired:
461 * a) Dynamic queries.
462 * b) Explicit searches that have a hidden folders.
463 * c) Locate searches that have a hidden folder.
465 * \param server LdapServer.
467 void ldapsvr_retire_query( LdapServer *server ) {
468 GList *node;
469 GList *listDelete;
470 GList *listQuery;
471 gint maxAge;
472 LdapControl *ctl;
473 ItemFolder *folder;
475 debug_print("ldapsvr_retire_query\n");
476 cm_return_if_fail( server != NULL );
477 ctl = server->control;
478 maxAge = ctl->maxQueryAge;
480 /* Identify queries to age and move to deletion list */
481 listDelete = NULL;
482 node = server->listQuery;
483 while( node ) {
484 LdapQuery *qry = node->data;
486 node = g_list_next( node );
487 folder = ADDRQUERY_FOLDER(qry);
488 if( folder == NULL ) continue;
489 if( ! folder->isHidden ) {
490 if( ADDRQUERY_SEARCHTYPE(qry) == ADDRSEARCH_EXPLICIT ) continue;
491 if( ADDRQUERY_SEARCHTYPE(qry) == ADDRSEARCH_LOCATE ) continue;
494 ldapqry_age( qry, maxAge );
495 if( qry->agedFlag ) {
496 /* Delete folder associated with query */
497 debug_print("deleting folder... ::%s::\n",
498 ADDRQUERY_NAME(qry)?ADDRQUERY_NAME(qry):"null");
499 ldapqry_delete_folder( qry );
500 listDelete = g_list_append( listDelete, qry );
504 /* Delete queries */
505 listQuery = server->listQuery;
506 node = listDelete;
507 while( node ) {
508 LdapQuery *qry = node->data;
510 listQuery = g_list_remove( listQuery, qry );
511 ldapqry_free( qry );
512 node->data = NULL;
513 node = g_list_next( node );
515 server->listQuery = listQuery;
517 /* Free up deletion list */
518 g_list_free( listDelete );
522 * Return results of a previous query by executing callback for each address
523 * contained in specified folder.
525 * \param folder Address book folder to process.
526 * \param req Address query request object.
528 static void ldapsvr_previous_query(
529 const ItemFolder *folder, const QueryRequest *req, AddrQueryObject *aqo )
531 AddrSearchCallbackEntry *callBack;
532 GList *listEMail;
533 GList *node;
534 GList *nodeEM;
535 gpointer sender;
537 sender = aqo;
538 callBack = ( AddrSearchCallbackEntry * ) req->callBackEntry;
539 if( callBack ) {
540 listEMail = NULL;
541 node = folder->listPerson;
542 while( node ) {
543 AddrItemObject *aio = node->data;
544 if( aio && aio->type == ITEMTYPE_PERSON ) {
545 ItemPerson *person = node->data;
546 nodeEM = person->listEMail;
547 while( nodeEM ) {
548 ItemEMail *email = nodeEM->data;
550 nodeEM = g_list_next( nodeEM );
551 listEMail = g_list_append( listEMail, email );
554 node = g_list_next( node );
556 ( callBack ) ( sender, req->queryID, listEMail, NULL );
557 /* // g_list_free( listEMail ); */
562 * Reuse search results from a previous LDAP query. If there is a query that
563 * has the same search term as specified in the query request, then the query
564 * will be reused.
566 * \param server LDAP server object.
567 * \param req Address query object.
568 * \return <i>TRUE</i> if previous query was used.
570 gboolean ldapsvr_reuse_previous( const LdapServer *server, const QueryRequest *req ) {
571 LdapQuery *qry;
572 gchar *searchTerm;
573 ItemFolder *folder;
575 cm_return_val_if_fail( server != NULL, FALSE );
576 cm_return_val_if_fail( req != NULL, FALSE );
578 searchTerm = req->searchTerm;
580 /* Test whether any queries for the same term exist */
581 qry = ldapsvr_locate_query( server, searchTerm );
582 if( qry ) {
583 /* Touch query to ensure it hangs around for a bit longer */
584 ldapqry_touch( qry );
585 folder = ADDRQUERY_FOLDER(qry);
586 if( folder ) {
587 ldapsvr_previous_query( folder, req, ADDRQUERY_OBJECT(qry) );
588 return TRUE;
591 return FALSE;
595 * Construct a new LdapQuery object that will be used to perform an dynamic
596 * search request.
598 * \param server LdapServer.
599 * \param req Query request.
600 * \return LdapQuery object, or <i>NULL</i> if none created.
602 LdapQuery *ldapsvr_new_dynamic_search( LdapServer *server, QueryRequest *req )
604 LdapQuery *qry;
605 gchar *name;
606 gchar *searchTerm;
607 ItemFolder *folder;
609 cm_return_val_if_fail( server != NULL, NULL );
610 cm_return_val_if_fail( req != NULL, NULL );
612 /* Retire any aged queries */
613 /* // ldapsvr_retire_query( server ); */
615 /* Name of folder and query */
616 searchTerm = req->searchTerm;
617 name = g_strdup_printf( "Search '%s'", searchTerm );
619 /* Create a folder for the search results */
620 folder = addrcache_add_new_folder( server->addressCache, NULL );
621 addritem_folder_set_name( folder, name );
622 addritem_folder_set_remarks( folder, "" );
624 /* Construct a query */
625 qry = ldapqry_create();
626 ldapqry_set_query_id( qry, req->queryID );
627 ldapqry_set_search_value( qry, searchTerm );
628 ldapqry_set_search_type( qry, ADDRSEARCH_DYNAMIC );
629 ldapqry_set_callback_entry( qry, req->callBackEntry );
630 ldapqry_set_callback_end( qry, req->callBackEnd );
632 /* Specify folder type and back reference */
633 ADDRQUERY_FOLDER(qry) = folder;
634 folder->folderType = ADDRFOLDER_QUERY_RESULTS;
635 folder->folderData = ( gpointer ) qry;
636 folder->isHidden = TRUE;
638 /* Name the query */
639 ldapqry_set_name( qry, name );
640 g_free( name );
642 /* Add query to request */
643 qryreq_add_query( req, ADDRQUERY_OBJECT(qry) );
645 /* Now start the search */
646 ldapsvr_add_query( server, qry );
648 return qry;
652 * Construct a new LdapQuery object that will be used to perform an explicit
653 * search request.
655 * \param server LdapServer.
656 * \param req Query request.
657 * \param folder Folder that will be used to contain search results.
658 * \return LdapQuery object, or <i>NULL</i> if none created.
660 LdapQuery *ldapsvr_new_explicit_search(
661 LdapServer *server, QueryRequest *req, ItemFolder *folder )
663 LdapQuery *qry;
664 gchar *searchTerm;
665 gchar *name;
667 cm_return_val_if_fail( server != NULL, NULL );
668 cm_return_val_if_fail( req != NULL, NULL );
669 cm_return_val_if_fail( folder != NULL, NULL );
671 /* Retire any aged queries */
672 /* // ldapsvr_retire_query( server ); */
674 /* Name the query */
675 searchTerm = req->searchTerm;
676 name = g_strdup_printf( "Explicit search for '%s'", searchTerm );
678 /* Construct a query */
679 qry = ldapqry_create();
680 ldapqry_set_query_id( qry, req->queryID );
681 ldapqry_set_name( qry, name );
682 ldapqry_set_search_value( qry, searchTerm );
683 ldapqry_set_search_type( qry, ADDRSEARCH_EXPLICIT );
684 ldapqry_set_callback_end( qry, req->callBackEnd );
685 ldapqry_set_callback_entry( qry, req->callBackEntry );
687 /* Specify folder type and back reference */
688 ADDRQUERY_FOLDER(qry) = folder;
689 folder->folderType = ADDRFOLDER_QUERY_RESULTS;
690 folder->folderData = ( gpointer ) qry;
692 /* Setup server */
693 ldapsvr_add_query( server, qry );
695 /* Set up query request */
696 qryreq_add_query( req, ADDRQUERY_OBJECT(qry) );
698 g_free( name );
700 return qry;
703 gint ldapsvr_read_data( LdapServer *server )
705 gchar *name;
707 cm_return_val_if_fail( server != NULL, -1 );
709 name = addrcache_get_name(server->addressCache);
710 debug_print("...addrbook_read_data :%s:\n", name?name:"null");
712 addrcache_clear(server->addressCache);
713 ldapsvr_free_all_query( server );
714 server->listQuery = NULL;
715 server->addressCache->modified = FALSE;
716 server->addressCache->accessFlag = FALSE;
717 server->addressCache->dataRead = TRUE;
718 addrcache_set_dirty(server->addressCache, FALSE);
719 return 0;
722 void ldapsrv_set_options (gint secs, LDAP *ld)
724 #ifdef G_OS_UNIX
725 static struct timeval timeout;
726 timeout.tv_sec = secs;
727 timeout.tv_usec = 0;
728 int i, rc;
729 i = LDAP_OPT_X_TLS_ALLOW;
730 rc = ldap_set_option(NULL, LDAP_OPT_X_TLS_REQUIRE_CERT, &i);
731 if (ld)
732 debug_print("cert %s\n", ldaputil_get_error(ld));
733 else
734 debug_print("cert %s\n", ldap_err2string(rc));
735 /* can crash old libldaps... */
736 rc = ldap_set_option(NULL, LDAP_OPT_NETWORK_TIMEOUT, &timeout);
737 if (ld)
738 debug_print("tm %s\n", ldaputil_get_error(ld));
739 else
740 debug_print("tm %s\n", ldap_err2string(rc));
741 #endif
744 #ifdef G_OS_WIN32
745 #if LDAP_UNICODE
746 #define LDAP_START_TLS_S "ldap_start_tls_sW"
747 typedef ULONG (* PFldap_start_tls_s) (LDAP *, PULONG, LDAPMessage **, PLDAPControlW *, PLDAPControlW *);
748 #else
749 #define LDAP_START_TLS_S "ldap_start_tls_sA"
750 typedef ULONG (* PFldap_start_tls_s) (LDAP *, PULONG, LDAPMessage **, PLDAPControlA *, PLDAPControlA *);
751 #endif /* LDAP_UNICODE */
752 PFldap_start_tls_s Win32_ldap_start_tls_s = NULL;
753 #endif
756 * Connect to LDAP server.
757 * \param ctl Control object to process.
758 * \return LDAP Resource to LDAP.
760 LDAP *ldapsvr_connect(LdapControl *ctl) {
761 LDAP *ld = NULL;
762 gint rc;
763 #ifndef G_OS_UNIX
764 intptr_t op;
765 #endif
766 gint version;
767 gchar *uri = NULL;
768 gchar *pwd;
770 cm_return_val_if_fail(ctl != NULL, NULL);
772 ldapsrv_set_options (ctl->timeOut, NULL);
773 if (ctl->enableSSL)
774 uri = g_strdup_printf("ldaps://%s:%d", ctl->hostName, ctl->port);
775 else
776 uri = g_strdup_printf("ldap://%s:%d", ctl->hostName, ctl->port);
777 #ifdef G_OS_UNIX
778 ldap_initialize(&ld, uri);
779 #else
780 ld = ldap_sslinit(ctl->hostName, ctl->port, ctl->enableSSL);
781 if (ld && ctl->enableSSL) {
782 version = LDAP_VERSION3;
783 debug_print("Setting version 3\n");
784 rc = ldap_set_option(ld, LDAP_OPT_PROTOCOL_VERSION, (void *)&version);
785 if (rc == LDAP_SUCCESS) {
786 ctl->version = LDAP_VERSION3;
787 log_print(LOG_PROTOCOL, "LDAP (options): set version 3\n");
788 } else {
789 log_error(LOG_PROTOCOL, _("LDAP error (options): %d (%s)\n"),
790 rc, ldaputil_get_error(ld));
791 debug_print("Failed: %s\n", ldaputil_get_error(ld));
794 rc = ldap_get_option(ld, LDAP_OPT_SSL, (void*)&op);
795 if (rc != LDAP_SUCCESS) {
796 log_warning(LOG_PROTOCOL, _("LDAP warning (options): can't get TLS state\n"));
797 debug_print("Can't get TLS state\n");
800 if ((void *)op != LDAP_OPT_ON) {
801 debug_print("Enabling TLS\n");
802 rc = ldap_set_option(ld, LDAP_OPT_SSL, LDAP_OPT_ON);
803 if (rc != LDAP_SUCCESS) {
804 log_error(LOG_PROTOCOL, _("LDAP error (options): %d (%s)\n"),
805 rc, ldaputil_get_error(ld));
806 debug_print("Failed: %s\n", ldaputil_get_error(ld));
807 } else {
808 rc = ldap_get_option(ld, LDAP_OPT_SSL, (void*)&op);
809 if (rc != LDAP_SUCCESS) {
810 log_error(LOG_PROTOCOL, _("LDAP error (options): %d (%s)\n"),
811 rc, ldaputil_get_error(ld));
812 } else {
813 log_print(LOG_PROTOCOL, _("LDAP (options): TLS enabled (%d)\n"), (gint)op);
815 debug_print("TLS now %d\n", (gint)op);
819 if (!ld || (rc = ldap_connect(ld, NULL)) != LDAP_SUCCESS) {
820 log_error(LOG_PROTOCOL, _("LDAP error (connect): %d (%s)\n"),
821 rc, ldaputil_get_error(ld));
822 debug_print("ldap_connect failed: %d %s\n", rc, ldaputil_get_error(ld));
823 } else {
824 log_print(LOG_PROTOCOL, _("LDAP (connect): completed successfully\n"));
827 #endif
828 g_free(uri);
830 if (ld == NULL)
831 return NULL;
833 debug_print("Got handle to LDAP host %s on port %d\n", ctl->hostName, ctl->port);
835 version = LDAP_VERSION3;
836 debug_print("Setting version 3\n");
837 rc = ldap_set_option(ld, LDAP_OPT_PROTOCOL_VERSION, &version);
838 if (rc == LDAP_OPT_SUCCESS) {
839 ctl->version = LDAP_VERSION3;
840 log_print(LOG_PROTOCOL, "LDAP (options): set version 3\n");
841 } else {
842 log_error(LOG_PROTOCOL, _("LDAP error (options): %d (%s)\n"),
843 rc, ldaputil_get_error(ld));
846 #if (defined USE_LDAP_TLS || defined G_OS_WIN32)
847 /* Handle TLS */
848 if (ctl->version == LDAP_VERSION3) {
849 if (ctl->enableTLS && !ctl->enableSSL) {
850 #ifdef G_OS_WIN32
851 ULONG serv_rc;
852 if (Win32_ldap_start_tls_s == NULL) {
853 void *lib = LoadLibrary("wldap32.dll");
854 if (!lib || (Win32_ldap_start_tls_s = (PFldap_start_tls_s) GetProcAddress(lib, LDAP_START_TLS_S)) == NULL) {
855 log_error(LOG_PROTOCOL, _("LDAP error (TLS): "
856 "ldap_start_tls_s not supported on this platform\n"));
857 if (lib)
858 FreeLibrary(lib);
859 return NULL;
862 debug_print("Setting STARTTLS\n");
863 rc = Win32_ldap_start_tls_s(ld, &serv_rc, NULL, NULL, NULL);
864 debug_print("ldap_start_tls_s: %d server %ld %s\n",
865 rc, serv_rc, ldaputil_get_error(ld));
866 #else
867 debug_print("Setting STARTTLS\n");
868 rc = ldap_start_tls_s(ld, NULL, NULL);
869 #endif
870 if (rc != LDAP_SUCCESS) {
871 log_error(LOG_PROTOCOL, _("LDAP error (TLS): ldap_start_tls_s: %d (%s)\n"),
872 rc, ldaputil_get_error(ld));
873 return NULL;
874 } else {
875 log_print(LOG_PROTOCOL, _("LDAP (TLS): started successfully\n"));
876 debug_print("Done\n");
880 #endif
882 /* Bind to the server, if required */
883 if (ctl->bindDN) {
884 if (* ctl->bindDN != '\0') {
885 pwd = passwd_store_get(PWS_CORE, "LDAP", ctl->hostName);
886 rc = claws_ldap_simple_bind_s(ld, ctl->bindDN, pwd);
887 if (pwd != NULL && strlen(pwd) > 0)
888 memset(pwd, 0, strlen(pwd));
889 g_free(pwd);
890 if (rc != LDAP_SUCCESS) {
891 log_error(LOG_PROTOCOL, _("LDAP error (bind): binding DN '%s': %d (%s)\n" ),
892 ctl->bindDN, rc, ldaputil_get_error(ld));
893 return NULL;
895 log_print(LOG_PROTOCOL, _("LDAP (bind): successfully for DN '%s'\n"),
896 ctl->bindDN);
899 return ld;
903 * Disconnect to LDAP server.
904 * \param ld Resource to LDAP.
906 void ldapsvr_disconnect(LDAP *ld) {
907 gint rc;
908 /* Disconnect */
909 cm_return_if_fail(ld != NULL);
910 rc = ldap_unbind_ext(ld, NULL, NULL);
911 if (rc != LDAP_SUCCESS) {
912 log_error(LOG_PROTOCOL, _("LDAP error (unbind): %d (%s)\n"),
913 rc, ldaputil_get_error(ld));
914 } else {
915 log_print(LOG_PROTOCOL, _("LDAP (unbind): successful\n"));
919 #endif /* USE_LDAP */
922 * End of Source.