2 * Sylpheed -- a GTK+ based, lightweight, and fast e-mail client
3 * Copyright (C) 2003-2009 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 define and perform LDAP queries.
37 #include "ldapquery.h"
42 #include "addrcache.h"
43 #include "common/utils.h"
46 * Key for thread specific data.
48 static pthread_key_t _queryThreadKey_;
49 static gboolean _queryThreadInit_ = FALSE;
51 static gboolean callbackend (gpointer data)
53 LdapQuery *qry = (LdapQuery *)data;
54 qry->callBackEnd( qry, ADDRQUERY_ID(qry), ADDRQUERY_RETVAL(qry), qry->data );
60 * Create new LDAP query object.
61 * \return Initialized query object.
63 LdapQuery *ldapqry_create( void ) {
66 qry = g_new0( LdapQuery, 1 );
67 ADDRQUERY_TYPE(qry) = ADDRQUERY_LDAP;
68 ADDRQUERY_ID(qry) = 0;
69 ADDRQUERY_SEARCHTYPE(qry) = ADDRSEARCH_NONE;
70 ADDRQUERY_NAME(qry) = NULL;
71 ADDRQUERY_RETVAL(qry) = LDAPRC_SUCCESS;
72 ADDRQUERY_FOLDER(qry) = NULL;
73 ADDRQUERY_SEARCHVALUE(qry) = NULL;
78 qry->stopFlag = FALSE;
79 qry->busyFlag = FALSE;
80 qry->agedFlag = FALSE;
81 qry->completed = FALSE;
83 qry->callBackEntry = NULL;
84 qry->callBackEnd = NULL;
88 /* Mutex to protect stop and busy flags */
89 qry->mutexStop = g_malloc0( sizeof( pthread_mutex_t ) );
90 pthread_mutex_init( qry->mutexStop, NULL );
91 qry->mutexBusy = g_malloc0( sizeof( pthread_mutex_t ) );
92 pthread_mutex_init( qry->mutexBusy, NULL );
94 /* Mutex to protect critical section */
95 qry->mutexEntry = g_malloc0( sizeof( pthread_mutex_t ) );
96 pthread_mutex_init( qry->mutexEntry, NULL );
102 * Specify the reference to control data that will be used for the query. The calling
103 * module should be responsible for creating and destroying this control object.
104 * \param qry Query object.
105 * \param ctl Control object.
107 void ldapqry_set_control( LdapQuery *qry, LdapControl *ctl ) {
108 cm_return_if_fail( qry != NULL );
113 * Specify query name to be used.
114 * \param qry Query object.
117 void ldapqry_set_name( LdapQuery* qry, const gchar *value ) {
118 cm_return_if_fail( qry != NULL );
119 ADDRQUERY_NAME(qry) = mgu_replace_string( ADDRQUERY_NAME(qry), value );
120 if (ADDRQUERY_NAME(qry) == NULL)
122 g_strstrip( ADDRQUERY_NAME(qry) );
123 debug_print("set name: %s\n", ADDRQUERY_NAME(qry));
127 * Specify search value to be used.
128 * \param qry Query object.
131 void ldapqry_set_search_value( LdapQuery *qry, const gchar *value ) {
132 cm_return_if_fail( qry != NULL );
133 ADDRQUERY_SEARCHVALUE(qry) = mgu_replace_string( ADDRQUERY_SEARCHVALUE(qry), value );
134 if (ADDRQUERY_SEARCHVALUE(qry) == NULL)
136 g_strstrip( ADDRQUERY_SEARCHVALUE(qry) );
137 debug_print("search value: %s\n", ADDRQUERY_SEARCHVALUE(qry));
141 * Specify query type.
142 * \param qry Query object.
143 * \param value Query type, either:
145 * <li><code>LDAPQUERY_NONE</code></li>
146 * <li><code>LDAPQUERY_STATIC</code></li>
147 * <li><code>LDAPQUERY_DYNAMIC</code></li>
151 void ldapqry_set_query_type( LdapQuery* qry, const gint value ) {
152 ADDRQUERY_TYPE(qry) = value;
157 * Specify search type.
158 * \param qry Query object.
161 void ldapqry_set_search_type( LdapQuery *qry, const AddrSearchType value ) {
162 cm_return_if_fail( qry != NULL );
163 ADDRQUERY_SEARCHTYPE(qry) = value;
168 * \param qry Query object.
169 * \param value ID for the query.
171 void ldapqry_set_query_id( LdapQuery* qry, const gint value ) {
172 cm_return_if_fail( qry != NULL );
173 ADDRQUERY_ID(qry) = value;
177 * Register a callback function that will be executed when each entry
178 * has been read and processed. When called, the function will be passed
179 * this query object and a GList of ItemEMail objects as arguments. An
180 * example of typical usage is shown below.
183 * ------------------------------------------------------------
184 * void myCallbackEntry( LdapQuery *qry, GList *listEMail ) {
189 * ItemEMail *email = node->data;
190 * ... process email object ...
191 * node = g_list_next( node );
193 * g_list_free( listEMail );
197 * ldapqry_set_callback_entry( qry, myCallbackEntry );
198 * ------------------------------------------------------------
201 * \param qry Query object.
202 * \param func Function.
204 void ldapqry_set_callback_entry( LdapQuery *qry, void *func ) {
205 pthread_mutex_lock( qry->mutexEntry );
206 qry->callBackEntry = func;
207 pthread_mutex_unlock( qry->mutexEntry );
211 * Register a callback function that will be executed when the search
212 * is complete. When called, the function will be passed this query
213 * object as an argument.
214 * \param qry Query object.
215 * \param func Function.
217 void ldapqry_set_callback_end( LdapQuery *qry, void *func ) {
218 qry->callBackEnd = func;
222 * Notify query to start/stop executing. This method should be called with a
223 * value if <i>TRUE</i> to terminate an existing running query.
225 * \param qry Query object.
226 * \param value Value of stop flag.
228 void ldapqry_set_stop_flag( LdapQuery *qry, const gboolean value ) {
229 cm_return_if_fail( qry != NULL );
231 pthread_mutex_lock( qry->mutexStop );
232 qry->stopFlag = value;
233 pthread_mutex_unlock( qry->mutexStop );
237 * Test value of stop flag. This method should be used to determine whether a
238 * query has stopped running.
239 * \param qry Query object.
240 * \return Value of stop flag.
242 static gboolean ldapqry_get_stop_flag( LdapQuery *qry ) {
244 cm_return_val_if_fail( qry != NULL, TRUE );
246 pthread_mutex_lock( qry->mutexStop );
247 value = qry->stopFlag;
248 pthread_mutex_unlock( qry->mutexStop );
254 * \param qry Query object.
255 * \param value Value of busy flag.
257 static void ldapqry_set_busy_flag( LdapQuery *qry, const gboolean value ) {
258 cm_return_if_fail( qry != NULL );
259 if (qry->mutexBusy == NULL)
260 return; /* exiting, mutex already freed */
262 pthread_mutex_lock( qry->mutexBusy );
263 qry->busyFlag = value;
264 pthread_mutex_unlock( qry->mutexBusy );
268 * Test value of busy flag. This method will return a value of <i>FALSE</i>
269 * when a query has completed running.
270 * \param qry Query object.
271 * \return Value of busy flag.
273 static gboolean ldapqry_get_busy_flag( LdapQuery *qry ) {
275 cm_return_val_if_fail( qry != NULL, FALSE );
277 pthread_mutex_lock( qry->mutexBusy );
278 value = qry->busyFlag;
279 pthread_mutex_unlock( qry->mutexBusy );
284 * Set query aged flag.
285 * \param qry Query object.
286 * \param value Value of aged flag.
288 static void ldapqry_set_aged_flag( LdapQuery *qry, const gboolean value ) {
289 cm_return_if_fail( qry != NULL );
290 qry->agedFlag = value;
294 * Clear LDAP query member variables.
295 * \param qry Query object.
297 static void ldapqry_clear( LdapQuery *qry ) {
298 cm_return_if_fail( qry != NULL );
300 /* Free internal stuff */
301 g_free( ADDRQUERY_NAME(qry) );
302 g_free( ADDRQUERY_SEARCHVALUE(qry) );
304 /* Clear pointers and value */
305 ADDRQUERY_NAME(qry) = NULL;
306 ADDRQUERY_SEARCHVALUE(qry) = NULL;
307 ADDRQUERY_ID(qry) = 0;
308 ADDRQUERY_SEARCHTYPE(qry) = ADDRSEARCH_NONE;
309 ADDRQUERY_RETVAL(qry) = LDAPRC_SUCCESS;
310 qry->entriesRead = 0;
311 qry->elapsedTime = 0;
312 qry->stopFlag = FALSE;
313 qry->busyFlag = FALSE;
314 qry->agedFlag = FALSE;
315 qry->completed = FALSE;
316 qry->callBackEntry = NULL;
317 qry->callBackEnd = NULL;
323 * Free up LDAP query object by releasing internal memory. Note that
324 * the thread object will be freed by the OS.
325 * \param qry Query object to process.
327 void ldapqry_free( LdapQuery *qry ) {
328 cm_return_if_fail( qry != NULL );
330 /* Clear out internal members */
331 ADDRQUERY_TYPE(qry) = ADDRQUERY_NONE;
332 ldapqry_clear( qry );
335 pthread_mutex_destroy( qry->mutexStop );
336 pthread_mutex_destroy( qry->mutexBusy );
337 pthread_mutex_destroy( qry->mutexEntry );
338 g_free( qry->mutexStop );
339 g_free( qry->mutexBusy );
340 g_free( qry->mutexEntry );
341 qry->mutexEntry = NULL;
342 qry->mutexBusy = NULL;
343 qry->mutexStop = NULL;
345 /* Do not free folder - parent server object should free */
346 ADDRQUERY_FOLDER(qry) = NULL;
348 /* Do not free thread - thread should be terminated before freeing */
351 /* Do not free LDAP control - should be destroyed before freeing */
354 /* Now release object */
359 * Free linked lists of character strings.
360 * \param listName List of common names.
361 * \param listAddr List of addresses.
362 * \param listFirst List of first names.
363 * \param listLast List of last names.
365 static void ldapqry_free_lists(
366 GSList *listName, GSList *listAddr, GSList *listFirst,
367 GSList *listLast, GSList *listDisplay, GSList *other_attrs )
369 GSList *cur = other_attrs;
370 mgu_free_list( listName );
371 mgu_free_list( listAddr );
372 mgu_free_list( listFirst );
373 mgu_free_list( listLast );
374 mgu_free_list( listDisplay );
375 for(;cur; cur = cur->next)
376 addritem_free_attribute((UserAttribute *)cur->data);
377 g_slist_free(other_attrs);
381 * Add all LDAP attribute values to a list.
382 * \param ld LDAP handle.
383 * \param entry LDAP entry to process.
384 * \param attr LDAP attribute.
385 * \return List of values.
387 static GSList *ldapqry_add_list_values(
388 LDAP *ld, LDAPMessage *entry, char *attr )
392 struct berval **vals;
394 if( ( vals = ldap_get_values_len( ld, entry, attr ) ) != NULL ) {
395 for( i = 0; vals[i] != NULL; i++ ) {
396 /*debug_print("lv\t%s: %s\n", attr?attr:"null",
397 vals[i]->bv_val?vals[i]->bv_val:"null");*/
398 list = g_slist_append( list, g_strndup( vals[i]->bv_val, vals[i]->bv_len) );
401 ldap_value_free_len( vals );
406 * Add a single attribute value to a list.
407 * \param ld LDAP handle.
408 * \param entry LDAP entry to process.
409 * \param attr LDAP attribute name to process.
410 * \return List of values; only one value will be present.
412 static GSList *ldapqry_add_single_value( LDAP *ld, LDAPMessage *entry, char *attr ) {
414 struct berval **vals;
416 if( ( vals = ldap_get_values_len( ld, entry, attr ) ) != NULL ) {
417 if( vals[0] != NULL ) {
418 if (strcmp(attr, "jpegPhoto")) {
419 debug_print("sv\t%s: %s\n", attr?attr:"null",
420 vals[0]->bv_val?vals[0]->bv_val:"null");
421 list = g_slist_append( list, g_strndup( vals[0]->bv_val, vals[0]->bv_len ));
423 char *file = get_tmp_file();
424 FILE *fp = g_fopen(file, "wb");
426 fwrite(vals[0]->bv_val, 1, vals[0]->bv_len, fp);
429 list = g_slist_append( list, file);
433 ldap_value_free_len( vals );
438 * Build an address list entry and append to list of address items. Name is formatted
439 * as "<first-name> <last-name>".
441 * \param cache Address cache to load.
442 * \param qry Query object to process.
443 * \param dn DN for entry found on server.
444 * \param listName List of common names for entry; see notes below.
445 * \param listAddr List of EMail addresses for entry.
446 * \param listFirst List of first names for entry.
447 * \param listLast List of last names for entry.
449 * \return List of ItemEMail objects.
452 * 1) Each LDAP server entry may have multiple LDAP attributes with the same
453 * name. For example, a single entry for a person may have more than one
454 * common name, email address, etc.
456 * 2) The DN for the entry is unique for the server.
458 static GList *ldapqry_build_items_fl(
459 AddressCache *cache, LdapQuery *qry, gchar *dn,
460 GSList *listName, GSList *listAddr, GSList *listFirst,
461 GSList *listLast, GSList *listDisplay, GSList *attributes )
463 GSList *nodeAddress, *cur;
464 gchar *firstName = NULL, *lastName = NULL, *fullName = NULL;
465 gboolean allocated = FALSE;
469 gchar *picfile = NULL;
470 GList *listReturn = NULL;
472 folder = ADDRQUERY_FOLDER(qry);
473 if( folder == NULL ) return listReturn;
474 if( listAddr == NULL ) return listReturn;
478 fullName = listDisplay->data;
481 /* Find longest first name in list */
482 firstName = mgu_slist_longest_entry( listFirst );
484 /* Format last name */
486 lastName = listLast->data;
489 if ( fullName == NULL ) {
490 /* Find longest common name */
492 fullName = mgu_slist_longest_entry( listName );
493 if( fullName == NULL ) {
494 /* Format a full name from first and last names */
497 fullName = g_strdup_printf( "%s %s", firstName, lastName );
500 fullName = g_strdup_printf( "%s", firstName );
505 fullName = g_strdup_printf( "%s", lastName );
509 g_strchug( fullName ); g_strchomp( fullName );
515 /* Add person into folder */
516 person = addritem_create_item_person();
517 addritem_person_set_common_name( person, fullName );
518 addritem_person_set_first_name( person, firstName );
519 addritem_person_set_last_name( person, lastName );
520 addritem_person_set_nick_name( person, fullName );
521 addrcache_id_person( cache, person );
522 addritem_person_set_external_id( person, dn );
524 for (cur = attributes; cur; cur = cur->next) {
525 UserAttribute *attrib = addritem_copy_attribute((UserAttribute *)cur->data);
526 if (attrib->name && strcmp(attrib->name, "jpegPhoto")) {
527 addritem_person_add_attribute( person, attrib );
529 if (qry && qry->server && qry->server->control) {
530 gchar *dir = g_strconcat( get_rc_dir(), G_DIR_SEPARATOR_S,
531 ADDRBOOK_DIR, G_DIR_SEPARATOR_S, NULL );
532 gchar *filename = g_strdup_printf("%s-%s-%s",
533 qry->server->control->hostName?qry->server->control->hostName:"nohost",
534 qry->server->control->baseDN?qry->server->control->baseDN:"nobase",
536 picfile = g_strdup_printf("%s%s.png", dir, filename);
537 addritem_person_set_picture( person, filename );
538 rename_force(attrib->value, picfile);
546 addrcache_folder_add_person( cache, ADDRQUERY_FOLDER(qry), person );
550 /* Add each address item */
551 nodeAddress = listAddr;
552 while( nodeAddress ) {
553 email = addritem_create_item_email();
554 addritem_email_set_address( email, nodeAddress->data );
555 addrcache_id_email( cache, email );
556 addrcache_person_add_email( cache, person, email );
557 addritem_person_add_email( person, email );
558 /*if (debug_get_mode()) {
559 addritem_print_item_email(email, stdout);
561 listReturn = g_list_append( listReturn, email );
562 nodeAddress = g_slist_next( nodeAddress );
565 /* Free any allocated memory */
569 fullName = firstName = lastName = NULL;
575 * Process a single search entry.
576 * \param cache Address cache to load.
577 * \param qry Query object to process.
578 * \param ld LDAP handle.
579 * \param e LDAP message.
580 * \return List of EMail objects found.
582 static GList *ldapqry_process_single_entry(
583 AddressCache *cache, LdapQuery *qry, LDAP *ld, LDAPMessage *e )
589 GSList *listName = NULL, *listAddress = NULL;
590 GSList *listFirst = NULL, *listLast = NULL;
591 GSList *listDisplay = NULL;
592 GSList *other_attrs = NULL;
597 dnEntry = ldap_get_dn( ld, e );
598 debug_print( "DN: %s\n", dnEntry?dnEntry:"null" );
600 /* Process all attributes */
601 for( attribute = ldap_first_attribute( ld, e, &ber ); attribute != NULL;
602 attribute = ldap_next_attribute( ld, e, ber ) ) {
603 if( strcasecmp( attribute, ctl->attribEMail ) == 0 ) {
604 listAddress = ldapqry_add_list_values( ld, e, attribute );
606 else if( strcasecmp( attribute, ctl->attribCName ) == 0 ) {
607 listName = ldapqry_add_list_values( ld, e, attribute );
609 else if( strcasecmp( attribute, ctl->attribFName ) == 0 ) {
610 listFirst = ldapqry_add_list_values( ld, e, attribute );
612 else if( strcasecmp( attribute, ctl->attribLName ) == 0 ) {
613 listLast = ldapqry_add_single_value( ld, e, attribute );
614 } else if( strcasecmp( attribute, ctl->attribDName ) == 0 ) {
615 listDisplay = ldapqry_add_single_value( ld, e, attribute );
617 GSList *attlist = ldapqry_add_single_value( ld, e, attribute );
618 UserAttribute *attrib = addritem_create_attribute();
619 const gchar *attvalue = attlist?((gchar *)attlist->data):NULL;
621 addritem_attrib_set_name( attrib, attribute );
622 addritem_attrib_set_value( attrib, attvalue );
623 other_attrs = g_slist_prepend(other_attrs, attrib);
625 mgu_free_list(attlist);
627 /* Free memory used to store attribute */
628 ldap_memfree( attribute );
631 /* Format and add items to cache */
632 listReturn = ldapqry_build_items_fl(
633 cache, qry, dnEntry, listName, listAddress, listFirst, listLast, listDisplay, other_attrs );
636 ldapqry_free_lists( listName, listAddress, listFirst, listLast, listDisplay, other_attrs );
637 listName = listAddress = listFirst = listLast = listDisplay = other_attrs = NULL;
648 * Check parameters that are required for a search. This should
649 * be called before performing a search.
650 * \param qry Query object to process.
651 * \return <i>TRUE</i> if search criteria appear OK.
653 gboolean ldapqry_check_search( LdapQuery *qry ) {
655 ADDRQUERY_RETVAL(qry) = LDAPRC_CRITERIA;
657 /* Test for control data */
663 /* Test for search value */
664 if( ADDRQUERY_SEARCHVALUE(qry) == NULL ) {
667 if( strlen( ADDRQUERY_SEARCHVALUE(qry) ) < 1 ) {
670 ADDRQUERY_RETVAL(qry) = LDAPRC_SUCCESS;
675 * Touch the query. This nudges the touch time with the current time.
676 * \param qry Query object to process.
678 void ldapqry_touch( LdapQuery *qry ) {
679 qry->touchTime = time( NULL );
680 qry->agedFlag = FALSE;
684 * Connect to LDAP server.
685 * \param qry Query object to process.
686 * \return Error/status code.
688 static gint ldapqry_connect( LdapQuery *qry ) {
696 /* Initialize connection */
697 if (debug_get_mode()) {
698 debug_print("===ldapqry_connect===\n");
699 /*ldapqry_print(qry, stdout);*/
702 /*if (debug_get_mode()) {
703 ldapctl_print(ctl, stdout);
704 debug_print("======\n");
706 ldapqry_touch( qry );
707 qry->startTime = qry->touchTime;
708 qry->elapsedTime = -1;
709 ADDRQUERY_RETVAL(qry) = LDAPRC_INIT;
711 ldapsrv_set_options (ctl->timeOut, NULL);
713 uri = g_strdup_printf("ldap%s://%s:%d",
714 ctl->enableSSL?"s":"",
715 ctl->hostName, ctl->port);
716 ldap_initialize(&ld, uri);
720 return ADDRQUERY_RETVAL(qry);
723 ADDRQUERY_RETVAL(qry) = LDAPRC_STOP_FLAG;
724 if( ldapqry_get_stop_flag( qry ) ) {
725 return ADDRQUERY_RETVAL(qry);
727 ldapqry_touch( qry );
729 debug_print("connected to LDAP host %s on port %d\n",
730 ctl->hostName?ctl->hostName:"null", ctl->port);
734 version = LDAP_VERSION3;
735 rc = ldap_set_option( ld, LDAP_OPT_PROTOCOL_VERSION, &version );
736 if( rc == LDAP_OPT_SUCCESS ) {
737 ctl->version = LDAP_VERSION3;
740 if( ctl->version == LDAP_VERSION3 ) {
741 if( ctl->enableTLS && !ctl->enableSSL ) {
742 ADDRQUERY_RETVAL(qry) = LDAPRC_TLS;
743 rc = ldap_start_tls_s( ld, NULL, NULL );
745 debug_print("rc=%d\n", rc);
746 debug_print("LDAP Status: set_option: %s\n", ldap_err2string(rc));
748 if( rc != LDAP_SUCCESS ) {
749 return ADDRQUERY_RETVAL(qry);
755 /* Bind to the server, if required */
756 ADDRQUERY_RETVAL(qry) = LDAPRC_BIND;
758 if( * ctl->bindDN != '\0' ) {
759 debug_print("binding...\n");
760 pwd = ldapctl_get_bind_password(ctl);
761 rc = claws_ldap_simple_bind_s(ld, ctl->bindDN, pwd);
763 debug_print("rc=%d\n", rc);
764 if( rc != LDAP_SUCCESS ) {
765 debug_print("LDAP Error: ldap_simple_bind_s: %s\n", ldap_err2string(rc));
766 return ADDRQUERY_RETVAL(qry);
770 ADDRQUERY_RETVAL(qry) = LDAPRC_STOP_FLAG;
771 if( ldapqry_get_stop_flag( qry ) ) {
772 return ADDRQUERY_RETVAL(qry);
774 ldapqry_touch( qry );
776 ADDRQUERY_RETVAL(qry) = LDAP_SUCCESS;
778 return ADDRQUERY_RETVAL(qry);
782 * Connect to LDAP server.
783 * \param qry Query object to process.
784 * \return Error/status code.
786 static gint ldapqry_disconnect( LdapQuery *qry ) {
788 if( qry->ldap ) ldap_unbind_ext( qry->ldap, NULL, NULL );
791 ldapqry_touch( qry );
792 qry->elapsedTime = qry->touchTime - qry->startTime;
794 return ADDRQUERY_RETVAL(qry);
798 * Perform the LDAP search, reading LDAP entries into cache.
799 * Note that one LDAP entry can have multiple values for many of its
800 * attributes. If these attributes are E-Mail addresses; these are
801 * broken out into separate address items. For any other attribute,
802 * only the first occurrence is read.
804 * \param qry Query object to process.
805 * \return Error/status code.
807 static gint ldapqry_search_retrieve( LdapQuery *qry ) {
810 LDAPMessage *result = NULL, *e = NULL;
814 gboolean entriesFound;
816 struct timeval timeout;
821 /* Initialize some variables */
824 cache = qry->server->addressCache;
825 timeout.tv_sec = ctl->timeOut;
826 timeout.tv_usec = 0L;
827 entriesFound = FALSE;
828 ADDRQUERY_RETVAL(qry) = LDAPRC_SUCCESS;
830 /* Define all attributes we are interested in. */
831 attribs = ldapctl_full_attribute_array( ctl );
833 /* Create LDAP search string */
834 criteria = ldapctl_format_criteria( ctl, ADDRQUERY_SEARCHVALUE(qry) );
835 debug_print("Search criteria ::%s::\n", criteria?criteria:"null");
838 * Execute the search - this step may take some time to complete
839 * depending on network traffic and server response time.
841 ADDRQUERY_RETVAL(qry) = LDAPRC_TIMEOUT;
842 rc = ldap_search_ext_s( ld, ctl->baseDN, LDAP_SCOPE_SUBTREE, criteria,
843 attribs, 0, NULL, NULL, &timeout, 0, &result );
844 debug_print("LDAP Error: ldap_search_st: %d\n", rc);
845 debug_print("LDAP Error: ldap_search_st: %s\n", ldap_err2string(rc));
846 ldapctl_free_attribute_array( attribs );
849 if( rc == LDAP_TIMEOUT ) {
850 return ADDRQUERY_RETVAL(qry);
852 ADDRQUERY_RETVAL(qry) = LDAPRC_SEARCH;
854 /* Test valid returns */
856 if( rc == LDAP_ADMINLIMIT_EXCEEDED ) {
859 else if( rc == LDAP_SUCCESS ) {
862 else if( rc == LDAP_PARTIAL_RESULTS || (result && ldap_count_entries(ld, result) > 0) ) {
866 debug_print("LDAP Error: ldap_search_st: %d\n", rc);
867 debug_print("LDAP Error: ldap_search_st: %s\n", ldap_err2string(rc));
868 return ADDRQUERY_RETVAL(qry);
870 ADDRQUERY_RETVAL(qry) = LDAPRC_STOP_FLAG;
872 debug_print("Total results are: %d\n", ldap_count_entries(ld, result));
874 /* Process results */
876 while( searchFlag ) {
877 ldapqry_touch( qry );
878 if( qry->entriesRead >= ctl->maxEntries ) break;
881 if( ldapqry_get_stop_flag( qry ) ) {
888 e = ldap_first_entry( ld, result );
891 e = ldap_next_entry( ld, e );
893 if( e == NULL ) break;
896 /* Setup a critical section here */
897 pthread_mutex_lock( qry->mutexEntry );
900 listEMail = ldapqry_process_single_entry( cache, qry, ld, e );
902 /* Process callback */
903 if( qry->callBackEntry ) {
904 qry->callBackEntry( qry, ADDRQUERY_ID(qry), listEMail, qry->data );
907 /*if (debug_get_mode()) {
908 GList *node = listEMail;
910 addritem_print_item_email(node->data, stdout);
911 node = g_list_next(node);
914 g_list_free( listEMail );
916 pthread_mutex_unlock( qry->mutexEntry );
919 /* Free up and disconnect */
920 ldap_msgfree( result );
924 ADDRQUERY_RETVAL(qry) = LDAPRC_SUCCESS;
927 ADDRQUERY_RETVAL(qry) = LDAPRC_NOENTRIES;
931 return ADDRQUERY_RETVAL(qry);
935 * Connection, perform search and disconnect.
936 * \param qry Query object to process.
937 * \return Error/status code.
939 static gint ldapqry_perform_search( LdapQuery *qry ) {
940 /* Check search criteria */
941 if( ! ldapqry_check_search( qry ) ) {
942 return ADDRQUERY_RETVAL(qry);
947 ldapqry_connect( qry );
948 if( ADDRQUERY_RETVAL(qry) == LDAPRC_SUCCESS ) {
950 ldapqry_search_retrieve( qry );
953 ldapqry_disconnect( qry );
956 return ADDRQUERY_RETVAL(qry);
959 static gint ldapqry_perform_locate( LdapQuery *qry );
962 * Wrapper around search.
963 * \param qry Query object to process.
964 * \return Error/status code.
966 static gint ldapqry_search( LdapQuery *qry ) {
969 cm_return_val_if_fail( qry != NULL, -1 );
970 cm_return_val_if_fail( qry->control != NULL, -1 );
972 ldapqry_touch( qry );
973 qry->completed = FALSE;
975 /* Setup pointer to thread specific area */
976 pthread_setspecific( _queryThreadKey_, qry );
978 pthread_detach( pthread_self() );
980 /* Now perform the search */
981 qry->entriesRead = 0;
982 ADDRQUERY_RETVAL(qry) = LDAPRC_SUCCESS;
983 ldapqry_set_busy_flag( qry, TRUE );
984 ldapqry_set_stop_flag( qry, FALSE );
985 if( ADDRQUERY_SEARCHTYPE(qry) == ADDRSEARCH_LOCATE ) {
986 retVal = ldapqry_perform_locate( qry );
989 retVal = ldapqry_perform_search( qry );
991 if( retVal == LDAPRC_SUCCESS ) {
992 qry->server->addressCache->dataRead = TRUE;
993 qry->server->addressCache->accessFlag = FALSE;
994 if( ldapqry_get_stop_flag( qry ) ) {
995 debug_print("Search was terminated prematurely\n");
998 ldapqry_touch( qry );
999 qry->completed = TRUE;
1000 debug_print("Search ran to completion\n");
1003 ldapqry_set_stop_flag( qry, TRUE );
1004 ldapqry_set_busy_flag( qry, FALSE );
1006 /* Process callback */
1007 if( qry->callBackEnd ) {
1008 g_timeout_add(0, callbackend, qry);
1011 return ADDRQUERY_RETVAL(qry);
1015 * Read data into list using a background thread. Callback function will be
1016 * notified when search is complete.
1017 * \param qry Query object to process.
1018 * \return Error/status code.
1020 gint ldapqry_read_data_th( LdapQuery *qry ) {
1021 cm_return_val_if_fail( qry != NULL, -1 );
1022 cm_return_val_if_fail( qry->control != NULL, -1 );
1024 ldapqry_set_stop_flag( qry, FALSE );
1025 ldapqry_touch( qry );
1026 if( ldapqry_check_search( qry ) ) {
1027 if( ADDRQUERY_RETVAL(qry) == LDAPRC_SUCCESS ) {
1028 debug_print("Starting LDAP search thread\n");
1029 ldapqry_set_busy_flag( qry, TRUE );
1030 qry->thread = g_malloc0( sizeof( pthread_t ) );
1033 pthread_create( qry->thread, NULL,
1034 (void *) ldapqry_search, (void *) qry );
1037 return ADDRQUERY_RETVAL(qry);
1041 * Cleanup LDAP thread data. This function will be called when each thread
1042 * exits. Note that the thread object will be freed by the kernel.
1043 * \param ptr Pointer to object being destroyed (a query object in this case).
1045 static void ldapqry_destroyer( void * ptr ) {
1048 qry = ( LdapQuery * ) ptr;
1049 cm_return_if_fail( qry != NULL );
1051 debug_print("ldapqry_destroyer::%d::%s\n", (int) pthread_self(),
1052 ADDRQUERY_NAME(qry)?ADDRQUERY_NAME(qry):"null");
1054 /* Perform any destruction here */
1055 if( qry->control != NULL ) {
1056 ldapctl_free( qry->control );
1058 qry->control = NULL;
1060 ldapqry_set_busy_flag( qry, FALSE );
1064 * Cancel thread associated with query.
1065 * \param qry Query object to process.
1067 void ldapqry_cancel( LdapQuery *qry ) {
1068 cm_return_if_fail( qry != NULL );
1070 debug_print("cancelling::%d::%s\n", (int) pthread_self(),
1071 ADDRQUERY_NAME(qry)?ADDRQUERY_NAME(qry):"null");
1072 if( ldapqry_get_busy_flag( qry ) ) {
1074 debug_print("calling pthread_cancel\n");
1075 pthread_cancel( * qry->thread );
1081 * Initialize LDAP query. This function should be called once before executing
1082 * any LDAP queries to initialize thread specific data.
1084 void ldapqry_initialize( void ) {
1085 debug_print("ldapqry_initialize...\n");
1086 if( ! _queryThreadInit_ ) {
1087 debug_print("ldapqry_initialize::creating thread specific area\n");
1088 pthread_key_create( &_queryThreadKey_, ldapqry_destroyer );
1089 _queryThreadInit_ = TRUE;
1091 debug_print("ldapqry_initialize... done!\n");
1095 * Age the query based on LDAP control parameters.
1096 * \param qry Query object to process.
1097 * \param maxAge Maximum age of query (in seconds).
1099 void ldapqry_age( LdapQuery *qry, gint maxAge ) {
1102 cm_return_if_fail( qry != NULL );
1104 /* Limit the time that queries can hang around */
1105 if( maxAge < 1 ) maxAge = LDAPCTL_MAX_QUERY_AGE;
1107 /* Check age of query */
1108 age = time( NULL ) - qry->touchTime;
1109 if( age > maxAge ) {
1110 qry->agedFlag = TRUE;
1115 * Delete folder associated with query results.
1116 * \param qry Query object to process.
1118 void ldapqry_delete_folder( LdapQuery *qry ) {
1119 AddressCache *cache;
1122 cm_return_if_fail( qry != NULL );
1124 folder = ADDRQUERY_FOLDER(qry);
1126 cache = qry->server->addressCache;
1127 folder = addrcache_remove_folder_delete( cache, folder );
1129 addritem_free_item_folder( folder );
1131 ADDRQUERY_FOLDER(qry) = NULL;
1136 * Create a name/value pair object.
1139 * \return Initialized object.
1141 static NameValuePair *ldapqry_create_name_value( const gchar *n, const gchar *v ) {
1142 NameValuePair *nvp = g_new0( NameValuePair, 1 );
1144 nvp->name = g_strdup( n );
1145 nvp->value = g_strdup( v );
1150 * Free up name/value pair object.
1151 * \param nvp Name/value object.
1153 void ldapqry_free_name_value( NameValuePair *nvp ) {
1155 g_free( nvp->name );
1156 g_free( nvp->value );
1157 nvp->name = nvp->value = NULL;
1163 * Free up a list name/value pair objects.
1164 * \param list List of name/value objects.
1166 void ldapqry_free_list_name_value( GList *list ) {
1171 NameValuePair *nvp = ( NameValuePair * ) node->data;
1172 ldapqry_free_name_value( nvp );
1174 node = g_list_next( node );
1176 g_list_free( list );
1180 * Load a list of name/value pairs from LDAP attributes.
1181 * \param ld LDAP handle.
1182 * \param e LDAP message.
1183 * \param attr Attribute name.
1184 * \param listValues List to populate.
1185 * \return List of attribute name/value pairs.
1187 static GList *ldapqry_load_attrib_values(
1188 LDAP *ld, LDAPMessage *entry, char *attr,
1193 struct berval **vals;
1197 if( ( vals = ldap_get_values_len( ld, entry, attr ) ) != NULL ) {
1198 for( i = 0; vals[i] != NULL; i++ ) {
1199 gchar *tmp = g_strndup( vals[i]->bv_val, vals[i]->bv_len);
1200 nvp = ldapqry_create_name_value( attr, tmp );
1202 list = g_list_append( list, nvp );
1205 ldap_value_free_len( vals );
1210 * Fetch a list of all attributes.
1211 * \param ld LDAP handle.
1212 * \param e LDAP message.
1213 * \return List of attribute name/value pairs.
1215 static GList *ldapqry_fetch_attribs( LDAP *ld, LDAPMessage *e )
1219 GList *listValues = NULL;
1221 /* Process all attributes */
1222 for( attribute = ldap_first_attribute( ld, e, &ber ); attribute != NULL;
1223 attribute = ldap_next_attribute( ld, e, ber ) ) {
1224 listValues = ldapqry_load_attrib_values( ld, e, attribute, listValues );
1225 ldap_memfree( attribute );
1235 #define CRITERIA_SINGLE "(objectclass=*)"
1238 * Perform the data retrieval for a specific LDAP record.
1240 * \param qry Query object to process.
1241 * \return Error/status code.
1243 static gint ldapqry_locate_retrieve( LdapQuery *qry ) {
1246 LDAPMessage *result, *e = NULL;
1247 gboolean entriesFound;
1249 struct timeval timeout;
1254 /* Initialize some variables */
1257 dn = ADDRQUERY_SEARCHVALUE(qry);
1258 timeout.tv_sec = ctl->timeOut;
1259 timeout.tv_usec = 0L;
1260 entriesFound = FALSE;
1263 * Execute the search - this step may take some time to complete
1264 * depending on network traffic and server response time.
1266 ADDRQUERY_RETVAL(qry) = LDAPRC_TIMEOUT;
1267 rc = ldap_search_ext_s( ld, dn, LDAP_SCOPE_BASE, CRITERIA_SINGLE,
1268 NULL, 0, NULL, NULL, &timeout, 0, &result );
1269 if( rc == LDAP_TIMEOUT ) {
1270 return ADDRQUERY_RETVAL(qry);
1272 ADDRQUERY_RETVAL(qry) = LDAPRC_SEARCH;
1273 if( rc != LDAP_SUCCESS ) {
1274 debug_print("LDAP Error: ldap_search_st: %s\n", ldap_err2string(rc));
1275 return ADDRQUERY_RETVAL(qry);
1278 debug_print("Total results are: %d\n", ldap_count_entries(ld, result));
1280 /* Process results */
1281 ADDRQUERY_RETVAL(qry) = LDAPRC_STOP_FLAG;
1284 ldapqry_touch( qry );
1285 if( qry->entriesRead >= ctl->maxEntries ) break;
1288 if( ldapqry_get_stop_flag( qry ) ) {
1292 /* Retrieve entry */
1295 e = ldap_first_entry( ld, result );
1298 e = ldap_next_entry( ld, e );
1300 if( e == NULL ) break;
1302 entriesFound = TRUE;
1304 /* Setup a critical section here */
1305 pthread_mutex_lock( qry->mutexEntry );
1308 listValues = ldapqry_fetch_attribs( ld, e );
1310 /* Process callback */
1311 if( qry->callBackEntry ) {
1312 qry->callBackEntry( qry, ADDRQUERY_ID(qry), listValues, qry->data );
1314 ldapqry_free_list_name_value( listValues );
1317 pthread_mutex_unlock( qry->mutexEntry );
1320 /* Free up and disconnect */
1321 ldap_msgfree( result );
1323 if( entriesFound ) {
1324 ADDRQUERY_RETVAL(qry) = LDAPRC_SUCCESS;
1327 ADDRQUERY_RETVAL(qry) = LDAPRC_NOENTRIES;
1330 return ADDRQUERY_RETVAL(qry);
1334 * Perform the search to locate a specific LDAP record identified by
1335 * distinguished name (dn).
1337 * \param qry Query object to process.
1338 * \return Error/status code.
1340 static gint ldapqry_perform_locate( LdapQuery *qry ) {
1343 ldapqry_connect( qry );
1344 if( ADDRQUERY_RETVAL(qry) == LDAPRC_SUCCESS ) {
1345 /* Perform search */
1346 ldapqry_locate_retrieve( qry );
1349 ldapqry_disconnect( qry );
1352 /* Process callback */
1353 if( qry->callBackEnd ) {
1354 g_timeout_add(0, callbackend, qry);
1357 return ADDRQUERY_RETVAL(qry);
1361 * Remove results (folder and data) for specified LDAP query.
1362 * \param qry Query object to process.
1363 * \return TRUE if folder deleted successfully.
1365 gboolean ldapquery_remove_results( LdapQuery *qry ) {
1366 gboolean retVal = FALSE;
1368 ldapqry_set_aged_flag( qry, TRUE );
1370 if( ldapqry_get_busy_flag( qry ) ) {
1371 ldapqry_set_stop_flag( qry, TRUE );
1374 LdapServer *server = qry->server;
1375 server->listQuery = g_list_remove(server->listQuery, qry);
1382 void ldapqry_print(LdapQuery *qry, FILE *stream) {
1383 cm_return_if_fail( qry != NULL );
1385 ldapsvr_print_data(qry->server, stream);
1386 ldapctl_print(qry->control, stream);
1387 fprintf(stream, "entriesRead: %d\n", qry->entriesRead);
1388 fprintf(stream, "elapsedTime: %d\n", qry->elapsedTime);
1389 fprintf(stream, "stopFlag: %d\n", qry->stopFlag);
1390 fprintf(stream, "busyFlag: %d\n", qry->busyFlag);
1391 fprintf(stream, "agedFlag: %d\n", qry->agedFlag);
1392 fprintf(stream, "completed: %d\n", qry->completed);
1393 fprintf(stream, "startTime: %d\n", (int) qry->startTime);
1394 fprintf(stream, "touchTime: %d\n", (int) qry->touchTime);
1395 fprintf(stream, "data: %s\n", qry->data?(gchar *)qry->data:"null");
1398 #endif /* USE_LDAP */