1 /*
2  * Claws Mail -- a GTK+ based, lightweight, and fast e-mail client
3  * Copyright (C) 2003-2018 Match Grun and the Claws Mail team
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 3 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, see <http://www.gnu.org/licenses/>.
17  */
18 
19 /*
20  * Functions necessary to access LDAP servers.
21  */
22 
23 #ifdef HAVE_CONFIG_H
24 #  include "config.h"
25 #include "claws-features.h"
26 #endif
27 
28 #ifdef USE_LDAP
29 
30 #include <glib.h>
31 #include <glib/gi18n.h>
32 #include <sys/time.h>
33 #include <string.h>
34 
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"
46 
47 /**
48  * Create new LDAP server interface object with no control object.
49  * \return Initialized LDAP server object.
50  */
ldapsvr_create_noctl(void)51 LdapServer *ldapsvr_create_noctl( void ) {
52 	LdapServer *server;
53 
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;
62 }
63 
64 /**
65  * Create new LDAP server interface object.
66  * \return Initialized LDAP server object.
67  */
ldapsvr_create(void)68 LdapServer *ldapsvr_create( void ) {
69 	LdapServer *server;
70 	server = ldapsvr_create_noctl();
71 	server->control = ldapctl_create();
72 	return server;
73 }
74 
75 /**
76  * Return name of server.
77  * \param  server Server object.
78  * \return Name for server.
79  */
ldapsvr_get_name(LdapServer * server)80 gchar *ldapsvr_get_name( LdapServer *server ) {
81 	cm_return_val_if_fail( server != NULL, NULL );
82 	return addrcache_get_name( server->addressCache );
83 }
84 
85 /**
86  * Specify name to be used.
87  * \param server Server object.
88  * \param value      Name for server.
89  */
ldapsvr_set_name(LdapServer * server,const gchar * value)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");
94 }
95 
96 /**
97  * Refresh internal variables to force a file read.
98  * \param server Server object.
99  */
ldapsvr_force_refresh(LdapServer * server)100 void ldapsvr_force_refresh( LdapServer *server ) {
101 	cm_return_if_fail( server != NULL );
102 	addrcache_refresh( server->addressCache );
103 }
104 
105 /**
106  * Return status/error code.
107  * \param  server Server object.
108  * \return Status/error code.
109  */
ldapsvr_get_status(LdapServer * server)110 gint ldapsvr_get_status( LdapServer *server ) {
111 	cm_return_val_if_fail( server != NULL, -1 );
112 	return server->retVal;
113 }
114 
115 /**
116  * Return reference to root level folder.
117  * \param  server Server object.
118  * \return Root level folder.
119  */
ldapsvr_get_root_folder(LdapServer * server)120 ItemFolder *ldapsvr_get_root_folder( LdapServer *server ) {
121 	cm_return_val_if_fail( server != NULL, NULL );
122 	/*
123 	g_print( "ldapsvr_get_root_folder/start\n" );
124 	ldapsvr_print_data( server, stdout );
125 	g_print( "ldapsvr_get_root_folder/done\n" );
126 	*/
127 	return addrcache_get_root_folder( server->addressCache );
128 }
129 
130 /**
131  * Test whether server data has been accessed.
132  * \param  server Server object.
133  * \return <i>TRUE</i> if data was accessed.
134  */
ldapsvr_get_accessed(LdapServer * server)135 gboolean ldapsvr_get_accessed( LdapServer *server ) {
136 	cm_return_val_if_fail( server != NULL, FALSE );
137 	return server->addressCache->accessFlag;
138 }
139 
140 /**
141  * Specify that server's data whas beed accessed.
142  * \param server Server object.
143  * \param value      Value for flag.
144  */
ldapsvr_set_accessed(LdapServer * server,const gboolean value)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);
149 }
150 
151 /**
152  * Test whether server data has been modified.
153  * \param  server Server object.
154  * \return <i>TRUE</i> if data was modified.
155  */
ldapsvr_get_modified(LdapServer * server)156 gboolean ldapsvr_get_modified( LdapServer *server ) {
157 	cm_return_val_if_fail( server != NULL, FALSE );
158 	return server->addressCache->modified;
159 }
160 
161 /**
162  * Specify modify flag.
163  * \param server Server object.
164  * \param value      Value for flag.
165  */
ldapsvr_set_modified(LdapServer * server,const gboolean value)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);
170 }
171 
172 /**
173  * Test whether data was read from server.
174  * \param server Server object.
175  * \return <i>TRUE</i> if data was read.
176  */
ldapsvr_get_read_flag(LdapServer * server)177 gboolean ldapsvr_get_read_flag( LdapServer *server ) {
178 	cm_return_val_if_fail( server != NULL, FALSE );
179 	return server->addressCache->dataRead;
180 }
181 
182 /**
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.
186  */
ldapsvr_get_search_flag(LdapServer * server)187 gboolean ldapsvr_get_search_flag( LdapServer *server ) {
188 	cm_return_val_if_fail( server != NULL, FALSE );
189 	return server->searchFlag;
190 }
191 
192 /**
193  * Specify that server is to be used for dynamic searches.
194  * \param server Server object.
195  * \param value      Name for server.
196  */
ldapsvr_set_search_flag(LdapServer * server,const gboolean value)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);
201 }
202 
203 /**
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.
208  */
ldapsvr_set_control(LdapServer * server,LdapControl * ctl)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;
213 }
214 
215 /**
216  * Free all queries.
217  * \param server Server object.
218  */
ldapsvr_free_all_query(LdapServer * server)219 void ldapsvr_free_all_query( LdapServer *server ) {
220 	GList *node;
221 	cm_return_if_fail( server != NULL );
222 
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 );
229 	}
230 	g_list_free( server->listQuery );
231 	server->listQuery = NULL;
232 }
233 
234 /**
235  * Add query to server.
236  * \param server Server object.
237  * \param qry    Query object.
238  */
ldapsvr_add_query(LdapServer * server,LdapQuery * qry)239 void ldapsvr_add_query( LdapServer *server, LdapQuery *qry ) {
240 	cm_return_if_fail( server != NULL );
241 	cm_return_if_fail( qry != NULL );
242 
243 	server->listQuery = g_list_append( server->listQuery, qry );
244 	qry->server = server;
245 }
246 
247 /**
248  * Free up LDAP server interface object by releasing internal memory.
249  * \param server Server object.
250  */
ldapsvr_free(LdapServer * server)251 void ldapsvr_free( LdapServer *server ) {
252 	cm_return_if_fail( server != NULL );
253 
254 	/* Stop and cancel any queries that may be active */
255 	ldapsvr_stop_all_query( server );
256 	ldapsvr_cancel_all_query( server );
257 
258 	/* Clear cache */
259 	addrcache_clear( server->addressCache );
260 	addrcache_free( server->addressCache );
261 
262 	/* Free LDAP control block */
263 	ldapctl_free( server->control );
264 	server->control = NULL;
265 
266 	/* Free all queries */
267 	ldapsvr_free_all_query( server );
268 
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;
275 
276 	/* Now release LDAP object */
277 	g_free( server );
278 }
279 
280 /**
281  * Display object to specified stream.
282  * \param server Server object.
283  * \param stream     Output stream.
284  */
ldapsvr_print_data(LdapServer * server,FILE * stream)285 void ldapsvr_print_data( LdapServer *server, FILE *stream ) {
286 	GList *node;
287 	gint  i;
288 
289 	cm_return_if_fail( server != NULL );
290 
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 );
297 	}
298 	else {
299 		fprintf( stream, "  control: NULL\n" );
300 	}
301 	addrcache_print( server->addressCache, stream );
302 	addritem_print_item_folder( server->addressCache->rootFolder, stream );
303 
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 );
312 	}
313 }
314 
315 /**
316  * Return link list of persons.
317  * \param server Server object.
318  * \return List of persons.
319  */
ldapsvr_get_list_person(LdapServer * server)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 );
323 }
324 
325 /**
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.
330  */
ldapsvr_get_list_folder(LdapServer * server)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;
335 }
336 
337 /**
338  * Execute specified query.
339  * \param server LDAP server.
340  * \param qry    LDAP query.
341  */
ldapsvr_execute_query(LdapServer * server,LdapQuery * qry)342 void ldapsvr_execute_query( LdapServer *server, LdapQuery *qry ) {
343 	LdapControl *ctlCopy;
344 
345 	cm_return_if_fail( server != NULL );
346 	cm_return_if_fail( qry != NULL );
347 
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();
353 
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");
361 		}
362 	}
363 	debug_print("ldapsvr_execute_query... terminated\n");
364 }
365 
366 /**
367  * Stop all queries for specified ID.
368  * \param server Server object.
369  * \param queryID    Query ID to stop.
370  */
ldapsvr_stop_query_id(LdapServer * server,const gint queryID)371 void ldapsvr_stop_query_id( LdapServer *server, const gint queryID ) {
372 	GList *node;
373 	cm_return_if_fail( server != NULL );
374 
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 );
381 		}
382 		node = g_list_next( node );
383 	}
384 }
385 
386 /**
387  * Stop all queries by notifying each thread to stop.
388  * \param server Server object.
389  */
ldapsvr_stop_all_query(LdapServer * server)390 void ldapsvr_stop_all_query( LdapServer *server ) {
391 	GList *node;
392 	cm_return_if_fail( server != NULL );
393 
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 );
399 	}
400 }
401 
402 /**
403  * Cancel all query threads for server.
404  * \param server Server object.
405  */
ldapsvr_cancel_all_query(LdapServer * server)406 void ldapsvr_cancel_all_query( LdapServer *server ) {
407 	GList *node;
408 	cm_return_if_fail( server != NULL );
409 
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 );
418 	}
419 }
420 
421 /**
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.
428  */
ldapsvr_locate_query(const LdapServer * server,const gchar * searchTerm)429 static LdapQuery *ldapsvr_locate_query(
430 	const LdapServer *server, const gchar *searchTerm )
431 {
432 	LdapQuery *incomplete = NULL;
433 	GList *node;
434 	cm_return_val_if_fail( server != NULL, NULL );
435 
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;
446 			}
447 			if( ! incomplete ) {
448 				incomplete = qry;
449 			}
450 		}
451 		node = g_list_previous( node );
452 	}
453 	return incomplete;
454 }
455 
456 /**
457  * Retire aged queries. Only the following queries are retired:
458  *
459  * a) Dynamic queries.
460  * b) Explicit searches that have a hidden folders.
461  * c) Locate searches that have a hidden folder.
462  *
463  * \param server LdapServer.
464  */
ldapsvr_retire_query(LdapServer * server)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;
472 
473 	debug_print("ldapsvr_retire_query\n");
474 	cm_return_if_fail( server != NULL );
475 	ctl = server->control;
476 	maxAge = ctl->maxQueryAge;
477 
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;
483 
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;
490 		}
491 
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 );
499 		}
500 	}
501 
502 	/* Delete queries */
503 	listQuery = server->listQuery;
504 	node = listDelete;
505 	while( node ) {
506 		LdapQuery *qry = node->data;
507 
508 		listQuery = g_list_remove( listQuery, qry );
509 		ldapqry_free( qry );
510 		node->data = NULL;
511 		node = g_list_next( node );
512 	}
513 	server->listQuery = listQuery;
514 
515 	/* Free up deletion list */
516 	g_list_free( listDelete );
517 }
518 
519 /**
520  * Return results of a previous query by executing callback for each address
521  * contained in specified folder.
522  *
523  * \param folder  Address book folder to process.
524  * \param req Address query request object.
525  */
ldapsvr_previous_query(const ItemFolder * folder,const QueryRequest * req,AddrQueryObject * aqo)526 static void ldapsvr_previous_query(
527 	const ItemFolder *folder, const QueryRequest *req, AddrQueryObject *aqo )
528 {
529 	AddrSearchCallbackEntry *callBack;
530 	GList *listEMail;
531 	GList *node;
532 	GList *nodeEM;
533 	gpointer sender;
534 
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;
547 
548 					nodeEM = g_list_next( nodeEM );
549 					listEMail = g_list_append( listEMail, email );
550 				}
551 			}
552 			node = g_list_next( node );
553 		}
554 		( callBack ) ( sender, req->queryID, listEMail, NULL );
555 		/* // g_list_free( listEMail ); */
556 	}
557 }
558 
559 /**
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.
563  *
564  * \param server  LDAP server object.
565  * \param req Address query object.
566  * \return <i>TRUE</i> if previous query was used.
567  */
ldapsvr_reuse_previous(const LdapServer * server,const QueryRequest * req)568 gboolean ldapsvr_reuse_previous( const LdapServer *server, const QueryRequest *req ) {
569 	LdapQuery *qry;
570 	gchar *searchTerm;
571 	ItemFolder *folder;
572 
573 	cm_return_val_if_fail( server != NULL, FALSE );
574 	cm_return_val_if_fail( req != NULL, FALSE );
575 
576 	searchTerm = req->searchTerm;
577 
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;
587 		}
588 	}
589 	return FALSE;
590 }
591 
592 /**
593  * Construct a new LdapQuery object that will be used to perform an dynamic
594  * search request.
595  *
596  * \param server LdapServer.
597  * \param req    Query request.
598  * \return LdapQuery object, or <i>NULL</i> if none created.
599  */
ldapsvr_new_dynamic_search(LdapServer * server,QueryRequest * req)600 LdapQuery *ldapsvr_new_dynamic_search( LdapServer *server, QueryRequest *req )
601 {
602 	LdapQuery *qry;
603 	gchar *name;
604 	gchar *searchTerm;
605 	ItemFolder *folder;
606 
607 	cm_return_val_if_fail( server != NULL, NULL );
608 	cm_return_val_if_fail( req != NULL, NULL );
609 
610 	/* Retire any aged queries */
611 	/* // ldapsvr_retire_query( server ); */
612 
613 	/* Name of folder and query */
614 	searchTerm = req->searchTerm;
615 	name = g_strdup_printf( "Search '%s'", searchTerm );
616 
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, "" );
621 
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 );
629 
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;
635 
636 	/* Name the query */
637 	ldapqry_set_name( qry, name );
638 	g_free( name );
639 
640 	/* Add query to request */
641 	qryreq_add_query( req, ADDRQUERY_OBJECT(qry) );
642 
643 	/* Now start the search */
644 	ldapsvr_add_query( server, qry );
645 
646 	return qry;
647 }
648 
649 /**
650  * Construct a new LdapQuery object that will be used to perform an explicit
651  * search request.
652  *
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.
657  */
ldapsvr_new_explicit_search(LdapServer * server,QueryRequest * req,ItemFolder * folder)658 LdapQuery *ldapsvr_new_explicit_search(
659 		LdapServer *server, QueryRequest *req, ItemFolder *folder )
660 {
661 	LdapQuery *qry;
662 	gchar *searchTerm;
663 	gchar *name;
664 
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 );
668 
669 	/* Retire any aged queries */
670 	/* // ldapsvr_retire_query( server ); */
671 
672 	/* Name the query */
673 	searchTerm = req->searchTerm;
674 	name = g_strdup_printf( "Explicit search for '%s'", searchTerm );
675 
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 );
684 
685 	/* Specify folder type and back reference */
686 	ADDRQUERY_FOLDER(qry) = folder;
687 	folder->folderType = ADDRFOLDER_QUERY_RESULTS;
688 	folder->folderData = ( gpointer ) qry;
689 
690 	/* Setup server */
691 	ldapsvr_add_query( server, qry );
692 
693 	/* Set up query request */
694 	qryreq_add_query( req, ADDRQUERY_OBJECT(qry) );
695 
696 	g_free( name );
697 
698 	return qry;
699 }
700 
ldapsvr_read_data(LdapServer * server)701 gint ldapsvr_read_data( LdapServer *server )
702 {
703 	gchar *name;
704 
705 	cm_return_val_if_fail( server != NULL, -1 );
706 
707 	name = addrcache_get_name(server->addressCache);
708 	debug_print("...addrbook_read_data :%s:\n", name?name:"null");
709 
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;
718 }
719 
ldapsrv_set_options(gint secs,LDAP * ld)720 void ldapsrv_set_options (gint secs, LDAP *ld)
721 {
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
740 }
741 
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
752 
753 /**
754  * Connect to LDAP server.
755  * \param  ctl Control object to process.
756  * \return LDAP Resource to LDAP.
757  */
ldapsvr_connect(LdapControl * ctl)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;
767 
768 	cm_return_val_if_fail(ctl != NULL, NULL);
769 
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));
790 		}
791 
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 SSL/TLS state\n"));
795 			debug_print("Can't get SSL/TLS state\n");
796 		}
797 
798 		if ((void *)op != LDAP_OPT_ON) {
799 			debug_print("Enabling SSL/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): SSL/TLS enabled (%d)\n"), (gint)op);
812 				}
813 				debug_print("SSL/TLS now %d\n", (gint)op);
814 			}
815 		}
816 
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"));
823 		}
824 	}
825 #endif
826 	g_free(uri);
827 
828 	if (ld == NULL)
829 		return NULL;
830 
831 	debug_print("Got handle to LDAP host %s on port %d\n", ctl->hostName, ctl->port);
832 
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));
842 	}
843 
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;
858 				}
859 			}
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");
875 			}
876 		}
877 	}
878 #endif
879 
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;
892 			}
893 			log_print(LOG_PROTOCOL, _("LDAP (bind): successfully for DN '%s'\n"),
894 					ctl->bindDN);
895 		}
896 	}
897 	return ld;
898 }
899 
900 /**
901  * Disconnect to LDAP server.
902  * \param ld Resource to LDAP.
903  */
ldapsvr_disconnect(LDAP * ld)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"));
914 	}
915 }
916 
917 #endif	/* USE_LDAP */
918 
919 /*
920  * End of Source.
921  */
922 
923