1/* ldapsearch -- a tool for searching LDAP directories */
2/* $OpenLDAP$ */
3/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
4 *
5 * Copyright 1998-2011 The OpenLDAP Foundation.
6 * Portions Copyright 1998-2003 Kurt D. Zeilenga.
7 * Portions Copyright 1998-2001 Net Boolean Incorporated.
8 * Portions Copyright 2001-2003 IBM Corporation.
9 * All rights reserved.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted only as authorized by the OpenLDAP
13 * Public License.
14 *
15 * A copy of this license is available in the file LICENSE in the
16 * top-level directory of the distribution or, alternatively, at
17 * <http://www.OpenLDAP.org/license.html>.
18 */
19/* Portions Copyright (c) 1992-1996 Regents of the University of Michigan.
20 * All rights reserved.
21 *
22 * Redistribution and use in source and binary forms are permitted
23 * provided that this notice is preserved and that due credit is given
24 * to the University of Michigan at Ann Arbor.  The name of the
25 * University may not be used to endorse or promote products derived
26 * from this software without specific prior written permission.  This
27 * software is provided ``as is'' without express or implied warranty.
28 */
29/* ACKNOWLEDGEMENTS:
30 * This work was originally developed by the University of Michigan
31 * (as part of U-MICH LDAP).  Additional significant contributors
32 * include:
33 *   Jong Hyuk Choi
34 *   Lynn Moss
35 *   Mikhail Sahalaev
36 *   Kurt D. Zeilenga
37 */
38
39#include "portable.h"
40
41#include <stdio.h>
42
43#include <ac/stdlib.h>
44
45#include <ac/ctype.h>
46#include <ac/string.h>
47#include <ac/unistd.h>
48#include <ac/errno.h>
49#include <sys/stat.h>
50
51#include <ac/signal.h>
52
53#ifdef HAVE_FCNTL_H
54#include <fcntl.h>
55#endif
56#ifdef HAVE_SYS_TYPES_H
57#include <sys/types.h>
58#endif
59#ifdef HAVE_IO_H
60#include <io.h>
61#endif
62
63#include <ldap.h>
64
65#include "ldif.h"
66#include "lutil.h"
67#include "lutil_ldap.h"
68#include "ldap_defaults.h"
69#include "ldap_pvt.h"
70
71#include "common.h"
72
73#ifdef __APPLE__
74#include "ldap_pvt_thread.h"
75#endif
76
77#if !LDAP_DEPRECATED
78/*
79 * NOTE: we use this deprecated function only because
80 * we want ldapsearch to provide some client-side sorting
81 * capability.
82 */
83/* from ldap.h */
84typedef int (LDAP_SORT_AD_CMP_PROC) LDAP_P(( /* deprecated */
85	LDAP_CONST char *left,
86	LDAP_CONST char *right ));
87
88LDAP_F( int )	/* deprecated */
89ldap_sort_entries LDAP_P(( LDAP *ld,
90	LDAPMessage **chain,
91	LDAP_CONST char *attr,
92	LDAP_SORT_AD_CMP_PROC *cmp ));
93#endif
94
95static int scope = LDAP_SCOPE_SUBTREE;
96static int deref = -1;
97static int attrsonly;
98static int timelimit = -1;
99static int sizelimit = -1;
100
101static char *control;
102
103static char *def_tmpdir;
104static char *def_urlpre;
105
106#if defined(__CYGWIN__) || defined(__MINGW32__)
107/* Turn off commandline globbing, otherwise you cannot search for
108 * attribute '*'
109 */
110int _CRT_glob = 0;
111#endif
112
113void
114usage( void )
115{
116	fprintf( stderr, _("usage: %s [options] [filter [attributes...]]\nwhere:\n"), prog);
117	fprintf( stderr, _("  filter\tRFC 4515 compliant LDAP search filter\n"));
118	fprintf( stderr, _("  attributes\twhitespace-separated list of attribute descriptions\n"));
119	fprintf( stderr, _("    which may include:\n"));
120	fprintf( stderr, _("      1.1   no attributes\n"));
121	fprintf( stderr, _("      *     all user attributes\n"));
122	fprintf( stderr, _("      +     all operational attributes\n"));
123
124
125	fprintf( stderr, _("Search options:\n"));
126	fprintf( stderr, _("  -a deref   one of never (default), always, search, or find\n"));
127	fprintf( stderr, _("  -A         retrieve attribute names only (no values)\n"));
128	fprintf( stderr, _("  -b basedn  base dn for search\n"));
129	fprintf( stderr, _("  -c         continuous operation mode (do not stop on errors)\n"));
130	fprintf( stderr, _("  -E [!]<ext>[=<extparam>] search extensions (! indicates criticality)\n"));
131	fprintf( stderr, _("             [!]domainScope              (domain scope)\n"));
132	fprintf( stderr, _("             !dontUseCopy                (Don't Use Copy)\n"));
133	fprintf( stderr, _("             [!]mv=<filter>              (RFC 3876 matched values filter)\n"));
134	fprintf( stderr, _("             [!]pr=<size>[/prompt|noprompt] (RFC 2696 paged results/prompt)\n"));
135	fprintf( stderr, _("             [!]sss=[-]<attr[:OID]>[/[-]<attr[:OID]>...]\n"));
136	fprintf( stderr, _("                                         (RFC 2891 server side sorting)\n"));
137	fprintf( stderr, _("             [!]subentries[=true|false]  (RFC 3672 subentries)\n"));
138	fprintf( stderr, _("             [!]sync=ro[/<cookie>]       (RFC 4533 LDAP Sync refreshOnly)\n"));
139	fprintf( stderr, _("                     rp[/<cookie>][/<slimit>] (refreshAndPersist)\n"));
140	fprintf( stderr, _("             [!]vlv=<before>/<after>(/<offset>/<count>|:<value>)\n"));
141	fprintf( stderr, _("                                         (ldapv3-vlv-09 virtual list views)\n"));
142#ifdef LDAP_CONTROL_X_DEREF
143	fprintf( stderr, _("             [!]deref=derefAttr:attr[,...][;derefAttr:attr[,...][;...]]\n"));
144#endif
145	fprintf( stderr, _("             [!]<oid>[=:<b64value>] (generic control; no response handling)\n"));
146	fprintf( stderr, _("  -f file    read operations from `file'\n"));
147	fprintf( stderr, _("  -F prefix  URL prefix for files (default: %s)\n"), def_urlpre);
148	fprintf( stderr, _("  -l limit   time limit (in seconds, or \"none\" or \"max\") for search\n"));
149	fprintf( stderr, _("  -L         print responses in LDIFv1 format\n"));
150	fprintf( stderr, _("  -LL        print responses in LDIF format without comments\n"));
151	fprintf( stderr, _("  -LLL       print responses in LDIF format without comments\n"));
152	fprintf( stderr, _("             and version\n"));
153	fprintf( stderr, _("  -M         enable Manage DSA IT control (-MM to make critical)\n"));
154	fprintf( stderr, _("  -P version protocol version (default: 3)\n"));
155	fprintf( stderr, _("  -s scope   one of base, one, sub or children (search scope)\n"));
156	fprintf( stderr, _("  -S attr    sort the results by attribute `attr'\n"));
157	fprintf( stderr, _("  -t         write binary values to files in temporary directory\n"));
158	fprintf( stderr, _("  -tt        write all values to files in temporary directory\n"));
159	fprintf( stderr, _("  -T path    write files to directory specified by path (default: %s)\n"), def_tmpdir);
160	fprintf( stderr, _("  -u         include User Friendly entry names in the output\n"));
161	fprintf( stderr, _("  -z limit   size limit (in entries, or \"none\" or \"max\") for search\n"));
162	tool_common_usage();
163	exit( EXIT_FAILURE );
164}
165
166static void print_entry LDAP_P((
167	LDAP	*ld,
168	LDAPMessage	*entry,
169	int		attrsonly));
170
171static void print_reference(
172	LDAP *ld,
173	LDAPMessage *reference );
174
175static void print_extended(
176	LDAP *ld,
177	LDAPMessage *extended );
178
179static void print_partial(
180	LDAP *ld,
181	LDAPMessage *partial );
182
183static int print_result(
184	LDAP *ld,
185	LDAPMessage *result,
186	int search );
187
188static int dosearch LDAP_P((
189	LDAP	*ld,
190	char	*base,
191	int		scope,
192	char	*filtpatt,
193	char	*value,
194	char	**attrs,
195	int		attrsonly,
196	LDAPControl **sctrls,
197	LDAPControl **cctrls,
198	struct timeval *timeout,
199	int	sizelimit ));
200
201#ifdef __APPLE__
202static int
203search_results_async(LDAP *ld);
204
205static void
206search_results_async_callback(
207	LDAP *ld,
208	LDAPMessage *res,
209	int rc,
210	void *context);
211#endif
212
213static char *tmpdir = NULL;
214static char *urlpre = NULL;
215static char	*base = NULL;
216static char	*sortattr = NULL;
217static int  includeufn, vals2tmp = 0;
218
219static int subentries = 0, valuesReturnFilter = 0;
220static char	*vrFilter = NULL;
221
222#ifdef LDAP_CONTROL_DONTUSECOPY
223static int dontUseCopy = 0;
224#endif
225
226static int domainScope = 0;
227
228static int sss = 0;
229static LDAPSortKey **sss_keys = NULL;
230
231static int vlv = 0;
232static LDAPVLVInfo vlvInfo;
233static struct berval vlvValue;
234
235static int ldapsync = 0;
236static struct berval sync_cookie = { 0, NULL };
237static int sync_slimit = -1;
238
239/* cookie and morePagedResults moved to common.c */
240static int pagedResults = 0;
241static int pagePrompt = 1;
242static ber_int_t pageSize = 0;
243static ber_int_t entriesLeft = 0;
244static int npagedresponses;
245static int npagedentries;
246static int npagedreferences;
247static int npagedextended;
248static int npagedpartial;
249
250static LDAPControl *c = NULL;
251static int nctrls = 0;
252static int save_nctrls = 0;
253
254#ifdef LDAP_CONTROL_X_DEREF
255static int derefcrit;
256static LDAPDerefSpec *ds;
257static struct berval derefval;
258#endif
259
260#ifdef __APPLE__
261static int use_callback = 0;
262static int callback_done = 0;
263static ldap_pvt_thread_mutex_t callback_mutex;
264static ldap_pvt_thread_cond_t callback_cond;
265#endif
266
267static int
268ctrl_add( void )
269{
270	LDAPControl	*tmpc;
271
272	nctrls++;
273	tmpc = realloc( c, sizeof( LDAPControl ) * nctrls );
274	if ( tmpc == NULL ) {
275		nctrls--;
276		fprintf( stderr,
277			_("unable to make room for control; out of memory?\n"));
278		return -1;
279	}
280	c = tmpc;
281
282	return 0;
283}
284
285static void
286urlize(char *url)
287{
288	char *p;
289
290	if (*LDAP_DIRSEP != '/') {
291		for (p = url; *p; p++) {
292			if (*p == *LDAP_DIRSEP)
293				*p = '/';
294		}
295	}
296}
297
298static int
299parse_vlv(char *cvalue)
300{
301	char *keyp, *key2;
302	int num1, num2;
303
304	keyp = cvalue;
305	if ( sscanf( keyp, "%d/%d", &num1, &num2 ) != 2 ) {
306		fprintf( stderr,
307			_("VLV control value \"%s\" invalid\n"),
308			cvalue );
309		return -1;
310	}
311	vlvInfo.ldvlv_before_count = num1;
312	vlvInfo.ldvlv_after_count = num2;
313	keyp = strchr( keyp, '/' ) + 1;
314	key2 = strchr( keyp, '/' );
315	if ( key2 ) {
316		keyp = key2 + 1;
317		if ( sscanf( keyp, "%d/%d", &num1, &num2 ) != 2 ) {
318			fprintf( stderr,
319				_("VLV control value \"%s\" invalid\n"),
320				cvalue );
321			return -1;
322		}
323		vlvInfo.ldvlv_offset = num1;
324		vlvInfo.ldvlv_count = num2;
325		vlvInfo.ldvlv_attrvalue = NULL;
326	} else {
327		key2 = strchr( keyp, ':' );
328		if ( !key2 ) {
329			fprintf( stderr,
330				_("VLV control value \"%s\" invalid\n"),
331				cvalue );
332			return -1;
333		}
334		ber_str2bv( key2+1, 0, 0, &vlvValue );
335		vlvInfo.ldvlv_attrvalue = &vlvValue;
336	}
337	return 0;
338}
339
340const char options[] = "a:ABb:cE:F:l:Ls:S:tT:uz:"
341	"Cd:D:e:f:h:H:IMnNO:o:p:P:QR:U:vVw:WxX:y:Y:Z";
342
343int
344handle_private_option( int i )
345{
346	int crit, ival;
347	char *cvalue, *next;
348	switch ( i ) {
349	case 'a':	/* set alias deref option */
350		if ( strcasecmp( optarg, "never" ) == 0 ) {
351			deref = LDAP_DEREF_NEVER;
352		} else if ( strncasecmp( optarg, "search", sizeof("search")-1 ) == 0 ) {
353			deref = LDAP_DEREF_SEARCHING;
354		} else if ( strncasecmp( optarg, "find", sizeof("find")-1 ) == 0 ) {
355			deref = LDAP_DEREF_FINDING;
356		} else if ( strcasecmp( optarg, "always" ) == 0 ) {
357			deref = LDAP_DEREF_ALWAYS;
358		} else {
359			fprintf( stderr,
360				_("alias deref should be never, search, find, or always\n") );
361			usage();
362		}
363		break;
364	case 'A':	/* retrieve attribute names only -- no values */
365		++attrsonly;
366		break;
367	case 'b': /* search base */
368		base = ber_strdup( optarg );
369		break;
370#ifdef __APPLE__
371	case 'B': /* background search (i.e. callback) */
372		use_callback = 1;
373		break;
374#endif
375	case 'E': /* search extensions */
376		if( protocol == LDAP_VERSION2 ) {
377			fprintf( stderr, _("%s: -E incompatible with LDAPv%d\n"),
378				prog, protocol );
379			exit( EXIT_FAILURE );
380		}
381
382		/* should be extended to support comma separated list of
383		 *	[!]key[=value] parameters, e.g.  -E !foo,bar=567
384		 */
385
386		crit = 0;
387		cvalue = NULL;
388		if( optarg[0] == '!' ) {
389			crit = 1;
390			optarg++;
391		}
392
393		control = ber_strdup( optarg );
394		if ( (cvalue = strchr( control, '=' )) != NULL ) {
395			*cvalue++ = '\0';
396		}
397
398		if ( strcasecmp( control, "mv" ) == 0 ) {
399			/* ValuesReturnFilter control */
400			if( valuesReturnFilter ) {
401				fprintf( stderr,
402					_("ValuesReturnFilter previously specified\n"));
403				exit( EXIT_FAILURE );
404			}
405			valuesReturnFilter= 1 + crit;
406
407			if ( cvalue == NULL ) {
408				fprintf( stderr,
409					_("missing filter in ValuesReturnFilter control\n"));
410				exit( EXIT_FAILURE );
411			}
412
413			vrFilter = cvalue;
414			protocol = LDAP_VERSION3;
415
416		} else if ( strcasecmp( control, "pr" ) == 0 ) {
417			int num, tmp;
418			/* PagedResults control */
419			if ( pagedResults != 0 ) {
420				fprintf( stderr,
421					_("PagedResultsControl previously specified\n") );
422				exit( EXIT_FAILURE );
423			}
424			if ( vlv != 0 ) {
425				fprintf( stderr,
426					_("PagedResultsControl incompatible with VLV\n") );
427				exit( EXIT_FAILURE );
428			}
429
430			if( cvalue != NULL ) {
431				char *promptp;
432
433				promptp = strchr( cvalue, '/' );
434				if ( promptp != NULL ) {
435					*promptp++ = '\0';
436					if ( strcasecmp( promptp, "prompt" ) == 0 ) {
437						pagePrompt = 1;
438					} else if ( strcasecmp( promptp, "noprompt" ) == 0) {
439						pagePrompt = 0;
440					} else {
441						fprintf( stderr,
442							_("Invalid value for PagedResultsControl,"
443							" %s/%s.\n"), cvalue, promptp );
444						exit( EXIT_FAILURE );
445					}
446				}
447				num = sscanf( cvalue, "%d", &tmp );
448				if ( num != 1 ) {
449					fprintf( stderr,
450						_("Invalid value for PagedResultsControl, %s.\n"),
451						cvalue );
452					exit( EXIT_FAILURE );
453				}
454			} else {
455				fprintf(stderr, _("Invalid value for PagedResultsControl.\n"));
456				exit( EXIT_FAILURE );
457			}
458			pageSize = (ber_int_t) tmp;
459			pagedResults = 1 + crit;
460
461#ifdef LDAP_CONTROL_DONTUSECOPY
462		} else if ( strcasecmp( control, "dontUseCopy" ) == 0 ) {
463			if( dontUseCopy ) {
464				fprintf( stderr,
465					_("dontUseCopy control previously specified\n"));
466				exit( EXIT_FAILURE );
467			}
468			if( cvalue != NULL ) {
469				fprintf( stderr,
470			         _("dontUseCopy: no control value expected\n") );
471				usage();
472			}
473			if( !crit ) {
474				fprintf( stderr,
475			         _("dontUseCopy: critical flag required\n") );
476				usage();
477			}
478
479			dontUseCopy = 1 + crit;
480#endif
481		} else if ( strcasecmp( control, "domainScope" ) == 0 ) {
482			if( domainScope ) {
483				fprintf( stderr,
484					_("domainScope control previously specified\n"));
485				exit( EXIT_FAILURE );
486			}
487			if( cvalue != NULL ) {
488				fprintf( stderr,
489			         _("domainScope: no control value expected\n") );
490				usage();
491			}
492
493			domainScope = 1 + crit;
494
495		} else if ( strcasecmp( control, "sss" ) == 0 ) {
496			char *keyp;
497			if( sss ) {
498				fprintf( stderr,
499					_("server side sorting control previously specified\n"));
500				exit( EXIT_FAILURE );
501			}
502			if( cvalue == NULL ) {
503				fprintf( stderr,
504			         _("missing specification of sss control\n") );
505				exit( EXIT_FAILURE );
506			}
507			keyp = cvalue;
508			while ( ( keyp = strchr(keyp, '/') ) != NULL ) {
509				*keyp++ = ' ';
510			}
511			if ( ldap_create_sort_keylist( &sss_keys, cvalue )) {
512				fprintf( stderr,
513					_("server side sorting control value \"%s\" invalid\n"),
514					cvalue );
515				exit( EXIT_FAILURE );
516			}
517
518			sss = 1 + crit;
519
520		} else if ( strcasecmp( control, "subentries" ) == 0 ) {
521			if( subentries ) {
522				fprintf( stderr,
523					_("subentries control previously specified\n"));
524				exit( EXIT_FAILURE );
525			}
526			if( cvalue == NULL || strcasecmp( cvalue, "true") == 0 ) {
527				subentries = 2;
528			} else if ( strcasecmp( cvalue, "false") == 0 ) {
529				subentries = 1;
530			} else {
531				fprintf( stderr,
532					_("subentries control value \"%s\" invalid\n"),
533					cvalue );
534				exit( EXIT_FAILURE );
535			}
536			if( crit ) subentries *= -1;
537
538		} else if ( strcasecmp( control, "sync" ) == 0 ) {
539			char *cookiep;
540			char *slimitp;
541			if ( ldapsync ) {
542				fprintf( stderr, _("sync control previously specified\n") );
543				exit( EXIT_FAILURE );
544			}
545			if ( cvalue == NULL ) {
546				fprintf( stderr, _("missing specification of sync control\n"));
547				exit( EXIT_FAILURE );
548			}
549			if ( strncasecmp( cvalue, "ro", 2 ) == 0 ) {
550				ldapsync = LDAP_SYNC_REFRESH_ONLY;
551				cookiep = strchr( cvalue, '/' );
552				if ( cookiep != NULL ) {
553					cookiep++;
554					if ( *cookiep != '\0' ) {
555						ber_str2bv( cookiep, 0, 0, &sync_cookie );
556					}
557				}
558			} else if ( strncasecmp( cvalue, "rp", 2 ) == 0 ) {
559				ldapsync = LDAP_SYNC_REFRESH_AND_PERSIST;
560				cookiep = strchr( cvalue, '/' );
561				if ( cookiep != NULL ) {
562					*cookiep++ = '\0';
563					cvalue = cookiep;
564				}
565				slimitp = strchr( cvalue, '/' );
566				if ( slimitp != NULL ) {
567					*slimitp++ = '\0';
568				}
569				if ( cookiep != NULL && *cookiep != '\0' )
570					ber_str2bv( cookiep, 0, 0, &sync_cookie );
571				if ( slimitp != NULL && *slimitp != '\0' ) {
572					ival = strtol( slimitp, &next, 10 );
573					if ( next == NULL || next[0] != '\0' ) {
574						fprintf( stderr, _("Unable to parse sync control value \"%s\"\n"), slimitp );
575						exit( EXIT_FAILURE );
576					}
577					sync_slimit = ival;
578				}
579			} else {
580				fprintf( stderr, _("sync control value \"%s\" invalid\n"),
581					cvalue );
582				exit( EXIT_FAILURE );
583			}
584			if ( crit ) ldapsync *= -1;
585
586		} else if ( strcasecmp( control, "vlv" ) == 0 ) {
587			if( vlv ) {
588				fprintf( stderr,
589					_("virtual list view control previously specified\n"));
590				exit( EXIT_FAILURE );
591			}
592			if ( pagedResults != 0 ) {
593				fprintf( stderr,
594					_("PagedResultsControl incompatible with VLV\n") );
595				exit( EXIT_FAILURE );
596			}
597			if( cvalue == NULL ) {
598				fprintf( stderr,
599			         _("missing specification of vlv control\n") );
600				exit( EXIT_FAILURE );
601			}
602			if ( parse_vlv( cvalue ))
603				exit( EXIT_FAILURE );
604
605			vlv = 1 + crit;
606
607#ifdef LDAP_CONTROL_X_DEREF
608		} else if ( strcasecmp( control, "deref" ) == 0 ) {
609			int ispecs;
610			char **specs;
611
612			/* cvalue is something like
613			 *
614			 * derefAttr:attr[,attr[...]][;derefAttr:attr[,attr[...]]]"
615			 */
616
617			specs = ldap_str2charray( cvalue, ";" );
618			if ( specs == NULL ) {
619				fprintf( stderr, _("deref specs \"%s\" invalid\n"),
620					cvalue );
621				exit( EXIT_FAILURE );
622			}
623			for ( ispecs = 0; specs[ ispecs ] != NULL; ispecs++ )
624				/* count'em */ ;
625
626			ds = ldap_memcalloc( ispecs + 1, sizeof( LDAPDerefSpec ) );
627			if ( ds == NULL ) {
628				perror( "malloc" );
629				exit( EXIT_FAILURE );
630			}
631
632			for ( ispecs = 0; specs[ ispecs ] != NULL; ispecs++ ) {
633				char *ptr;
634
635				ptr = strchr( specs[ ispecs ], ':' );
636				if ( ptr == NULL ) {
637					fprintf( stderr, _("deref specs \"%s\" invalid\n"),
638						cvalue );
639					exit( EXIT_FAILURE );
640				}
641
642				ds[ ispecs ].derefAttr = specs[ ispecs ];
643				*ptr++ = '\0';
644				ds[ ispecs ].attributes = ldap_str2charray( ptr, "," );
645			}
646
647			derefcrit = 1 + crit;
648
649			ldap_memfree( specs );
650#endif /* LDAP_CONTROL_X_DEREF */
651
652		} else if ( tool_is_oid( control ) ) {
653			if ( ctrl_add() ) {
654				exit( EXIT_FAILURE );
655			}
656
657			/* OID */
658			c[ nctrls - 1 ].ldctl_oid = control;
659
660			/* value */
661			if ( cvalue == NULL ) {
662				c[ nctrls - 1 ].ldctl_value.bv_val = NULL;
663				c[ nctrls - 1 ].ldctl_value.bv_len = 0;
664
665			} else if ( cvalue[ 0 ] == ':' ) {
666				struct berval type;
667				struct berval value;
668				int freeval;
669				char save_c;
670
671				cvalue++;
672
673				/* dummy type "x"
674				 * to use ldif_parse_line2() */
675				save_c = cvalue[ -2 ];
676				cvalue[ -2 ] = 'x';
677				ldif_parse_line2( &cvalue[ -2 ], &type,
678					&value, &freeval );
679				cvalue[ -2 ] = save_c;
680
681				if ( freeval ) {
682					c[ nctrls - 1 ].ldctl_value = value;
683
684				} else {
685					ber_dupbv( &c[ nctrls - 1 ].ldctl_value, &value );
686				}
687
688			} else {
689				fprintf( stderr, "unable to parse %s control value\n", control );
690				exit( EXIT_FAILURE );
691
692			}
693
694			/* criticality */
695			c[ nctrls - 1 ].ldctl_iscritical = crit;
696
697		} else {
698			fprintf( stderr, _("Invalid search extension name: %s\n"),
699				control );
700			usage();
701		}
702		break;
703	case 'F':	/* uri prefix */
704		if( urlpre ) free( urlpre );
705		urlpre = strdup( optarg );
706		break;
707	case 'l':	/* time limit */
708		if ( strcasecmp( optarg, "none" ) == 0 ) {
709			timelimit = 0;
710
711		} else if ( strcasecmp( optarg, "max" ) == 0 ) {
712			timelimit = LDAP_MAXINT;
713
714		} else {
715			ival = strtol( optarg, &next, 10 );
716			if ( next == NULL || next[0] != '\0' ) {
717				fprintf( stderr,
718					_("Unable to parse time limit \"%s\"\n"), optarg );
719				exit( EXIT_FAILURE );
720			}
721			timelimit = ival;
722		}
723		if( timelimit < 0 || timelimit > LDAP_MAXINT ) {
724			fprintf( stderr, _("%s: invalid timelimit (%d) specified\n"),
725				prog, timelimit );
726			exit( EXIT_FAILURE );
727		}
728		break;
729	case 'L':	/* print entries in LDIF format */
730		++ldif;
731		break;
732	case 's':	/* search scope */
733		if ( strncasecmp( optarg, "base", sizeof("base")-1 ) == 0 ) {
734			scope = LDAP_SCOPE_BASE;
735		} else if ( strncasecmp( optarg, "one", sizeof("one")-1 ) == 0 ) {
736			scope = LDAP_SCOPE_ONELEVEL;
737		} else if (( strcasecmp( optarg, "subordinate" ) == 0 )
738			|| ( strcasecmp( optarg, "children" ) == 0 ))
739		{
740			scope = LDAP_SCOPE_SUBORDINATE;
741		} else if ( strncasecmp( optarg, "sub", sizeof("sub")-1 ) == 0 ) {
742			scope = LDAP_SCOPE_SUBTREE;
743		} else {
744			fprintf( stderr, _("scope should be base, one, or sub\n") );
745			usage();
746		}
747		break;
748	case 'S':	/* sort attribute */
749		sortattr = strdup( optarg );
750		break;
751	case 't':	/* write attribute values to TMPDIR files */
752		++vals2tmp;
753		break;
754	case 'T':	/* tmpdir */
755		if( tmpdir ) free( tmpdir );
756		tmpdir = strdup( optarg );
757		break;
758	case 'u':	/* include UFN */
759		++includeufn;
760		break;
761	case 'z':	/* size limit */
762		if ( strcasecmp( optarg, "none" ) == 0 ) {
763			sizelimit = 0;
764
765		} else if ( strcasecmp( optarg, "max" ) == 0 ) {
766			sizelimit = LDAP_MAXINT;
767
768		} else {
769			ival = strtol( optarg, &next, 10 );
770			if ( next == NULL || next[0] != '\0' ) {
771				fprintf( stderr,
772					_("Unable to parse size limit \"%s\"\n"), optarg );
773				exit( EXIT_FAILURE );
774			}
775			sizelimit = ival;
776		}
777		if( sizelimit < 0 || sizelimit > LDAP_MAXINT ) {
778			fprintf( stderr, _("%s: invalid sizelimit (%d) specified\n"),
779				prog, sizelimit );
780			exit( EXIT_FAILURE );
781		}
782		break;
783	default:
784		return 0;
785	}
786	return 1;
787}
788
789
790static void
791private_conn_setup( LDAP *ld )
792{
793	if (deref != -1 &&
794		ldap_set_option( ld, LDAP_OPT_DEREF, (void *) &deref )
795			!= LDAP_OPT_SUCCESS )
796	{
797		fprintf( stderr, _("Could not set LDAP_OPT_DEREF %d\n"), deref );
798		tool_exit( ld, EXIT_FAILURE );
799	}
800}
801
802int
803main( int argc, char **argv )
804{
805	char		*filtpattern, **attrs = NULL, line[BUFSIZ];
806	FILE		*fp = NULL;
807	int			rc, rc1, i, first;
808	LDAP		*ld = NULL;
809	BerElement	*seber = NULL, *vrber = NULL;
810
811	BerElement      *syncber = NULL;
812	struct berval   *syncbvalp = NULL;
813	int		err;
814
815	tool_init( TOOL_SEARCH );
816
817	npagedresponses = npagedentries = npagedreferences =
818		npagedextended = npagedpartial = 0;
819
820	prog = lutil_progname( "ldapsearch", argc, argv );
821
822	if((def_tmpdir = getenv("TMPDIR")) == NULL &&
823	   (def_tmpdir = getenv("TMP")) == NULL &&
824	   (def_tmpdir = getenv("TEMP")) == NULL )
825	{
826		def_tmpdir = LDAP_TMPDIR;
827	}
828
829	if ( !*def_tmpdir )
830		def_tmpdir = LDAP_TMPDIR;
831
832	def_urlpre = malloc( sizeof("file:////") + strlen(def_tmpdir) );
833
834	if( def_urlpre == NULL ) {
835		perror( "malloc" );
836		return EXIT_FAILURE;
837	}
838
839	sprintf( def_urlpre, "file:///%s/",
840		def_tmpdir[0] == *LDAP_DIRSEP ? &def_tmpdir[1] : def_tmpdir );
841
842	urlize( def_urlpre );
843
844	tool_args( argc, argv );
845
846	if ( vlv && !sss ) {
847		fprintf( stderr,
848			_("VLV control requires server side sort control\n" ));
849		return EXIT_FAILURE;
850	}
851
852	if (( argc - optind < 1 ) ||
853		( *argv[optind] != '(' /*')'*/ &&
854		( strchr( argv[optind], '=' ) == NULL ) ) )
855	{
856		filtpattern = "(objectclass=*)";
857	} else {
858		filtpattern = argv[optind++];
859	}
860
861	if ( argv[optind] != NULL ) {
862		attrs = &argv[optind];
863	}
864
865	if ( infile != NULL ) {
866		int percent = 0;
867
868		if ( infile[0] == '-' && infile[1] == '\0' ) {
869			fp = stdin;
870		} else if (( fp = fopen( infile, "r" )) == NULL ) {
871			perror( infile );
872			return EXIT_FAILURE;
873		}
874
875		for( i=0 ; filtpattern[i] ; i++ ) {
876			if( filtpattern[i] == '%' ) {
877				if( percent ) {
878					fprintf( stderr, _("Bad filter pattern \"%s\"\n"),
879						filtpattern );
880					return EXIT_FAILURE;
881				}
882
883				percent++;
884
885				if( filtpattern[i+1] != 's' ) {
886					fprintf( stderr, _("Bad filter pattern \"%s\"\n"),
887						filtpattern );
888					return EXIT_FAILURE;
889				}
890			}
891		}
892	}
893
894	if ( tmpdir == NULL ) {
895		tmpdir = def_tmpdir;
896
897		if ( urlpre == NULL )
898			urlpre = def_urlpre;
899	}
900
901	if( urlpre == NULL ) {
902		urlpre = malloc( sizeof("file:////") + strlen(tmpdir) );
903
904		if( urlpre == NULL ) {
905			perror( "malloc" );
906			return EXIT_FAILURE;
907		}
908
909		sprintf( urlpre, "file:///%s/",
910			tmpdir[0] == *LDAP_DIRSEP ? &tmpdir[1] : tmpdir );
911
912		urlize( urlpre );
913	}
914
915	if ( debug )
916		ldif_debug = debug;
917
918	ld = tool_conn_setup( 0, &private_conn_setup );
919
920	tool_bind( ld );
921
922getNextPage:
923	/* fp may have been closed, need to reopen if code jumps
924	 * back here to getNextPage.
925	 */
926	if ( !fp && infile ) {
927		if (( fp = fopen( infile, "r" )) == NULL ) {
928			perror( infile );
929			tool_exit( ld, EXIT_FAILURE );
930		}
931	}
932	save_nctrls = nctrls;
933	i = nctrls;
934	if ( nctrls > 0
935#ifdef LDAP_CONTROL_DONTUSECOPY
936		|| dontUseCopy
937#endif
938#ifdef LDAP_CONTROL_X_DEREF
939		|| derefcrit
940#endif
941		|| domainScope
942		|| pagedResults
943		|| ldapsync
944		|| sss
945		|| subentries
946		|| valuesReturnFilter
947		|| vlv )
948	{
949
950#ifdef LDAP_CONTROL_DONTUSECOPY
951		if ( dontUseCopy ) {
952			if ( ctrl_add() ) {
953				tool_exit( ld, EXIT_FAILURE );
954			}
955
956			c[i].ldctl_oid = LDAP_CONTROL_DONTUSECOPY;
957			c[i].ldctl_value.bv_val = NULL;
958			c[i].ldctl_value.bv_len = 0;
959			c[i].ldctl_iscritical = dontUseCopy > 1;
960			i++;
961		}
962#endif
963
964		if ( domainScope ) {
965			if ( ctrl_add() ) {
966				tool_exit( ld, EXIT_FAILURE );
967			}
968
969			c[i].ldctl_oid = LDAP_CONTROL_X_DOMAIN_SCOPE;
970			c[i].ldctl_value.bv_val = NULL;
971			c[i].ldctl_value.bv_len = 0;
972			c[i].ldctl_iscritical = domainScope > 1;
973			i++;
974		}
975
976		if ( subentries ) {
977			if ( ctrl_add() ) {
978				tool_exit( ld, EXIT_FAILURE );
979			}
980
981			if (( seber = ber_alloc_t(LBER_USE_DER)) == NULL ) {
982				tool_exit( ld, EXIT_FAILURE );
983			}
984
985			err = ber_printf( seber, "b", abs(subentries) == 1 ? 0 : 1 );
986			if ( err == -1 ) {
987				ber_free( seber, 1 );
988				fprintf( stderr, _("Subentries control encoding error!\n") );
989				tool_exit( ld, EXIT_FAILURE );
990			}
991
992			if ( ber_flatten2( seber, &c[i].ldctl_value, 0 ) == -1 ) {
993				tool_exit( ld, EXIT_FAILURE );
994			}
995
996			c[i].ldctl_oid = LDAP_CONTROL_SUBENTRIES;
997			c[i].ldctl_iscritical = subentries < 1;
998			i++;
999		}
1000
1001		if ( ldapsync ) {
1002			if ( ctrl_add() ) {
1003				tool_exit( ld, EXIT_FAILURE );
1004			}
1005
1006			if (( syncber = ber_alloc_t(LBER_USE_DER)) == NULL ) {
1007				tool_exit( ld, EXIT_FAILURE );
1008			}
1009
1010			if ( sync_cookie.bv_len == 0 ) {
1011				err = ber_printf( syncber, "{e}", abs(ldapsync) );
1012			} else {
1013				err = ber_printf( syncber, "{eO}", abs(ldapsync),
1014							&sync_cookie );
1015			}
1016
1017			if ( err == -1 ) {
1018				ber_free( syncber, 1 );
1019				fprintf( stderr, _("ldap sync control encoding error!\n") );
1020				tool_exit( ld, EXIT_FAILURE );
1021			}
1022
1023			if ( ber_flatten( syncber, &syncbvalp ) == -1 ) {
1024				tool_exit( ld, EXIT_FAILURE );
1025			}
1026
1027			c[i].ldctl_oid = LDAP_CONTROL_SYNC;
1028			c[i].ldctl_value = (*syncbvalp);
1029			c[i].ldctl_iscritical = ldapsync < 0;
1030			i++;
1031		}
1032
1033		if ( valuesReturnFilter ) {
1034			if ( ctrl_add() ) {
1035				tool_exit( ld, EXIT_FAILURE );
1036			}
1037
1038			if (( vrber = ber_alloc_t(LBER_USE_DER)) == NULL ) {
1039				tool_exit( ld, EXIT_FAILURE );
1040			}
1041
1042			if ( ( err = ldap_put_vrFilter( vrber, vrFilter ) ) == -1 ) {
1043				ber_free( vrber, 1 );
1044				fprintf( stderr, _("Bad ValuesReturnFilter: %s\n"), vrFilter );
1045				tool_exit( ld, EXIT_FAILURE );
1046			}
1047
1048			if ( ber_flatten2( vrber, &c[i].ldctl_value, 0 ) == -1 ) {
1049				tool_exit( ld, EXIT_FAILURE );
1050			}
1051
1052			c[i].ldctl_oid = LDAP_CONTROL_VALUESRETURNFILTER;
1053			c[i].ldctl_iscritical = valuesReturnFilter > 1;
1054			i++;
1055		}
1056
1057		if ( pagedResults ) {
1058			if ( ctrl_add() ) {
1059				tool_exit( ld, EXIT_FAILURE );
1060			}
1061
1062			if ( ldap_create_page_control_value( ld,
1063				pageSize, &pr_cookie, &c[i].ldctl_value ) )
1064			{
1065				tool_exit( ld, EXIT_FAILURE );
1066			}
1067
1068			if ( pr_cookie.bv_val != NULL ) {
1069				ber_memfree( pr_cookie.bv_val );
1070				pr_cookie.bv_val = NULL;
1071				pr_cookie.bv_len = 0;
1072			}
1073
1074			c[i].ldctl_oid = LDAP_CONTROL_PAGEDRESULTS;
1075			c[i].ldctl_iscritical = pagedResults > 1;
1076			i++;
1077		}
1078
1079		if ( sss ) {
1080			if ( ctrl_add() ) {
1081				tool_exit( ld, EXIT_FAILURE );
1082			}
1083
1084			if ( ldap_create_sort_control_value( ld,
1085				sss_keys, &c[i].ldctl_value ) )
1086			{
1087				tool_exit( ld, EXIT_FAILURE );
1088			}
1089
1090			c[i].ldctl_oid = LDAP_CONTROL_SORTREQUEST;
1091			c[i].ldctl_iscritical = sss > 1;
1092			i++;
1093		}
1094
1095		if ( vlv ) {
1096			if ( ctrl_add() ) {
1097				tool_exit( ld, EXIT_FAILURE );
1098			}
1099
1100			if ( ldap_create_vlv_control_value( ld,
1101				&vlvInfo, &c[i].ldctl_value ) )
1102			{
1103				tool_exit( ld, EXIT_FAILURE );
1104			}
1105
1106			c[i].ldctl_oid = LDAP_CONTROL_VLVREQUEST;
1107			c[i].ldctl_iscritical = sss > 1;
1108			i++;
1109		}
1110#ifdef LDAP_CONTROL_X_DEREF
1111		if ( derefcrit ) {
1112			if ( derefval.bv_val == NULL ) {
1113				int i;
1114
1115				assert( ds != NULL );
1116
1117				if ( ldap_create_deref_control_value( ld, ds, &derefval ) != LDAP_SUCCESS ) {
1118					tool_exit( ld, EXIT_FAILURE );
1119				}
1120
1121				for ( i = 0; ds[ i ].derefAttr != NULL; i++ ) {
1122					ldap_memfree( ds[ i ].derefAttr );
1123					ldap_charray_free( ds[ i ].attributes );
1124				}
1125				ldap_memfree( ds );
1126				ds = NULL;
1127			}
1128
1129			if ( ctrl_add() ) {
1130				tool_exit( ld, EXIT_FAILURE );
1131			}
1132
1133			c[ i ].ldctl_iscritical = derefcrit > 1;
1134			c[ i ].ldctl_oid = LDAP_CONTROL_X_DEREF;
1135			c[ i ].ldctl_value = derefval;
1136			i++;
1137		}
1138#endif /* LDAP_CONTROL_X_DEREF */
1139	}
1140
1141	tool_server_controls( ld, c, i );
1142
1143	if ( seber ) ber_free( seber, 1 );
1144	if ( vrber ) ber_free( vrber, 1 );
1145
1146	/* step back to the original number of controls, so that
1147	 * those set while parsing args are preserved */
1148	nctrls = save_nctrls;
1149
1150	if ( verbose ) {
1151		fprintf( stderr, _("filter%s: %s\nrequesting: "),
1152			infile != NULL ? _(" pattern") : "",
1153			filtpattern );
1154
1155		if ( attrs == NULL ) {
1156			fprintf( stderr, _("All userApplication attributes") );
1157		} else {
1158			for ( i = 0; attrs[ i ] != NULL; ++i ) {
1159				fprintf( stderr, "%s ", attrs[ i ] );
1160			}
1161		}
1162		fprintf( stderr, "\n" );
1163	}
1164
1165	if ( ldif == 0 ) {
1166		printf( _("# extended LDIF\n") );
1167	} else if ( ldif < 3 ) {
1168		printf( _("version: %d\n\n"), 1 );
1169	}
1170
1171	if (ldif < 2 ) {
1172		char	*realbase = base;
1173
1174		if ( realbase == NULL ) {
1175			ldap_get_option( ld, LDAP_OPT_DEFBASE, (void **)(char *)&realbase );
1176		}
1177
1178		printf( "#\n" );
1179		printf(_("# LDAPv%d\n"), protocol);
1180		printf(_("# base <%s>%s with scope %s\n"),
1181			realbase ? realbase : "",
1182			( realbase == NULL || realbase != base ) ? " (default)" : "",
1183			((scope == LDAP_SCOPE_BASE) ? "baseObject"
1184				: ((scope == LDAP_SCOPE_ONELEVEL) ? "oneLevel"
1185				: ((scope == LDAP_SCOPE_SUBORDINATE) ? "children"
1186				: "subtree" ))));
1187		printf(_("# filter%s: %s\n"), infile != NULL ? _(" pattern") : "",
1188		       filtpattern);
1189		printf(_("# requesting: "));
1190
1191		if ( attrs == NULL ) {
1192			printf( _("ALL") );
1193		} else {
1194			for ( i = 0; attrs[ i ] != NULL; ++i ) {
1195				printf( "%s ", attrs[ i ] );
1196			}
1197		}
1198
1199		if ( manageDSAit ) {
1200			printf(_("\n# with manageDSAit %scontrol"),
1201				manageDSAit > 1 ? _("critical ") : "" );
1202		}
1203		if ( noop ) {
1204			printf(_("\n# with noop %scontrol"),
1205				noop > 1 ? _("critical ") : "" );
1206		}
1207		if ( subentries ) {
1208			printf(_("\n# with subentries %scontrol: %s"),
1209				subentries < 0 ? _("critical ") : "",
1210				abs(subentries) == 1 ? "false" : "true" );
1211		}
1212		if ( valuesReturnFilter ) {
1213			printf(_("\n# with valuesReturnFilter %scontrol: %s"),
1214				valuesReturnFilter > 1 ? _("critical ") : "", vrFilter );
1215		}
1216		if ( pagedResults ) {
1217			printf(_("\n# with pagedResults %scontrol: size=%d"),
1218				(pagedResults > 1) ? _("critical ") : "",
1219				pageSize );
1220		}
1221		if ( sss ) {
1222			printf(_("\n# with server side sorting %scontrol"),
1223				sss > 1 ? _("critical ") : "" );
1224		}
1225		if ( vlv ) {
1226			printf(_("\n# with virtual list view %scontrol: %d/%d"),
1227				vlv > 1 ? _("critical ") : "",
1228				vlvInfo.ldvlv_before_count, vlvInfo.ldvlv_after_count);
1229			if ( vlvInfo.ldvlv_attrvalue )
1230				printf(":%s", vlvInfo.ldvlv_attrvalue->bv_val );
1231			else
1232				printf("/%d/%d", vlvInfo.ldvlv_offset, vlvInfo.ldvlv_count );
1233		}
1234#ifdef LDAP_CONTROL_X_DEREF
1235		if ( derefcrit ) {
1236			printf(_("\n# with dereference %scontrol"),
1237				derefcrit > 1 ? _("critical ") : "" );
1238		}
1239#endif
1240
1241		printf( _("\n#\n\n") );
1242
1243		if ( realbase && realbase != base ) {
1244			ldap_memfree( realbase );
1245		}
1246	}
1247
1248	if ( infile == NULL ) {
1249		rc = dosearch( ld, base, scope, NULL, filtpattern,
1250			attrs, attrsonly, NULL, NULL, NULL, sizelimit );
1251
1252	} else {
1253		rc = 0;
1254		first = 1;
1255		while ( fgets( line, sizeof( line ), fp ) != NULL ) {
1256			line[ strlen( line ) - 1 ] = '\0';
1257			if ( !first ) {
1258				putchar( '\n' );
1259			} else {
1260				first = 0;
1261			}
1262			rc1 = dosearch( ld, base, scope, filtpattern, line,
1263				attrs, attrsonly, NULL, NULL, NULL, sizelimit );
1264
1265			if ( rc1 != 0 ) {
1266				rc = rc1;
1267				if ( !contoper )
1268					break;
1269			}
1270		}
1271		if ( fp != stdin ) {
1272			fclose( fp );
1273			fp = NULL;
1274		}
1275	}
1276
1277	if (( rc == LDAP_SUCCESS ) && pageSize && pr_morePagedResults ) {
1278		char	buf[12];
1279		int	i, moreEntries, tmpSize;
1280
1281		/* Loop to get the next pages when
1282		 * enter is pressed on the terminal.
1283		 */
1284		if ( pagePrompt != 0 ) {
1285			if ( entriesLeft > 0 ) {
1286				printf( _("Estimate entries: %d\n"), entriesLeft );
1287			}
1288			printf( _("Press [size] Enter for the next {%d|size} entries.\n"),
1289				(int)pageSize );
1290			i = 0;
1291			moreEntries = getchar();
1292			while ( moreEntries != EOF && moreEntries != '\n' ) {
1293				if ( i < (int)sizeof(buf) - 1 ) {
1294					buf[i] = moreEntries;
1295					i++;
1296				}
1297				moreEntries = getchar();
1298			}
1299			buf[i] = '\0';
1300
1301			if ( i > 0 && isdigit( (unsigned char)buf[0] ) ) {
1302				int num = sscanf( buf, "%d", &tmpSize );
1303				if ( num != 1 ) {
1304					fprintf( stderr,
1305						_("Invalid value for PagedResultsControl, %s.\n"), buf);
1306					tool_exit( ld, EXIT_FAILURE );
1307
1308				}
1309				pageSize = (ber_int_t)tmpSize;
1310			}
1311		}
1312
1313		goto getNextPage;
1314	}
1315
1316	if (( rc == LDAP_SUCCESS ) && vlv ) {
1317		char	buf[BUFSIZ];
1318		int	i, moreEntries;
1319
1320		/* Loop to get the next window when
1321		 * enter is pressed on the terminal.
1322		 */
1323		printf( _("Press [before/after(/offset/count|:value)] Enter for the next window.\n"));
1324		i = 0;
1325		moreEntries = getchar();
1326		while ( moreEntries != EOF && moreEntries != '\n' ) {
1327			if ( i < (int)sizeof(buf) - 1 ) {
1328				buf[i] = moreEntries;
1329				i++;
1330			}
1331			moreEntries = getchar();
1332		}
1333		buf[i] = '\0';
1334		if ( buf[0] ) {
1335			i = parse_vlv( strdup( buf ));
1336			if ( i )
1337				tool_exit( ld, EXIT_FAILURE );
1338		} else {
1339			vlvInfo.ldvlv_attrvalue = NULL;
1340			vlvInfo.ldvlv_count = vlvCount;
1341			vlvInfo.ldvlv_offset += vlvInfo.ldvlv_after_count;
1342		}
1343
1344		if ( vlvInfo.ldvlv_context )
1345			ber_bvfree( vlvInfo.ldvlv_context );
1346		vlvInfo.ldvlv_context = vlvContext;
1347
1348		goto getNextPage;
1349	}
1350
1351	if ( base != NULL ) {
1352		ber_memfree( base );
1353	}
1354	if ( control != NULL ) {
1355		ber_memfree( control );
1356	}
1357	if ( sss_keys != NULL ) {
1358		ldap_free_sort_keylist( sss_keys );
1359	}
1360	if ( derefval.bv_val != NULL ) {
1361		ldap_memfree( derefval.bv_val );
1362	}
1363	if ( urlpre != NULL ) {
1364		if ( def_urlpre != urlpre )
1365			free( def_urlpre );
1366		free( urlpre );
1367	}
1368
1369	if ( c ) {
1370		for ( ; save_nctrls-- > 0; ) {
1371			ber_memfree( c[ save_nctrls ].ldctl_value.bv_val );
1372		}
1373		free( c );
1374		c = NULL;
1375	}
1376
1377	tool_exit( ld, rc );
1378}
1379
1380
1381static int dosearch(
1382	LDAP	*ld,
1383	char	*base,
1384	int		scope,
1385	char	*filtpatt,
1386	char	*value,
1387	char	**attrs,
1388	int		attrsonly,
1389	LDAPControl **sctrls,
1390	LDAPControl **cctrls,
1391	struct timeval *timeout,
1392	int sizelimit )
1393{
1394	char			*filter;
1395	int			rc, rc2 = LDAP_OTHER;
1396	int			nresponses;
1397	int			nentries;
1398	int			nreferences;
1399	int			nextended;
1400	int			npartial;
1401	LDAPMessage		*res, *msg;
1402	ber_int_t		msgid;
1403	char			*retoid = NULL;
1404	struct berval		*retdata = NULL;
1405	int			nresponses_psearch = -1;
1406	int			cancel_msgid = -1;
1407	struct timeval tv, *tvp = NULL;
1408	struct timeval tv_timelimit, *tv_timelimitp = NULL;
1409
1410	if( filtpatt != NULL ) {
1411		size_t max_fsize = strlen( filtpatt ) + strlen( value ) + 1, outlen;
1412		filter = malloc( max_fsize );
1413		if( filter == NULL ) {
1414			perror( "malloc" );
1415			return EXIT_FAILURE;
1416		}
1417
1418		outlen = snprintf( filter, max_fsize, filtpatt, value );
1419		if( outlen >= max_fsize ) {
1420			fprintf( stderr, "Bad filter pattern: \"%s\"\n", filtpatt );
1421			free( filter );
1422			return EXIT_FAILURE;
1423		}
1424
1425		if ( verbose ) {
1426			fprintf( stderr, _("filter: %s\n"), filter );
1427		}
1428
1429		if( ldif < 2 ) {
1430			printf( _("#\n# filter: %s\n#\n"), filter );
1431		}
1432
1433	} else {
1434		filter = value;
1435	}
1436
1437	if ( dont ) {
1438		if ( filtpatt != NULL ) {
1439			free( filter );
1440		}
1441		return LDAP_SUCCESS;
1442	}
1443
1444	if ( timelimit > 0 ) {
1445		tv_timelimit.tv_sec = timelimit;
1446		tv_timelimit.tv_usec = 0;
1447		tv_timelimitp = &tv_timelimit;
1448	}
1449
1450	rc = ldap_search_ext( ld, base, scope, filter, attrs, attrsonly,
1451		sctrls, cctrls, tv_timelimitp, sizelimit, &msgid );
1452
1453	if ( filtpatt != NULL ) {
1454		free( filter );
1455	}
1456
1457	if( rc != LDAP_SUCCESS ) {
1458		tool_perror( "ldap_search_ext", rc, NULL, NULL, NULL, NULL );
1459		return( rc );
1460	}
1461
1462	nresponses = nentries = nreferences = nextended = npartial = 0;
1463
1464	res = NULL;
1465
1466    if ( timelimit > 0 ) {
1467		/* disable timeout */
1468		tv.tv_sec = -1;
1469		tv.tv_usec = 0;
1470		tvp = &tv;
1471	}
1472#ifdef __APPLE__
1473	if (use_callback) {
1474		return search_results_async(ld);
1475	}
1476#endif
1477	while ((rc = ldap_result( ld, LDAP_RES_ANY,
1478		sortattr ? LDAP_MSG_ALL : LDAP_MSG_ONE,
1479		tvp, &res )) > 0 )
1480	{
1481		if ( tool_check_abandon( ld, msgid ) ) {
1482			return -1;
1483		}
1484
1485		if( sortattr ) {
1486			(void) ldap_sort_entries( ld, &res,
1487				( *sortattr == '\0' ) ? NULL : sortattr, strcasecmp );
1488		}
1489
1490		for ( msg = ldap_first_message( ld, res );
1491			msg != NULL;
1492			msg = ldap_next_message( ld, msg ) )
1493		{
1494			if ( nresponses++ ) putchar('\n');
1495			if ( nresponses_psearch >= 0 )
1496				nresponses_psearch++;
1497
1498			switch( ldap_msgtype( msg ) ) {
1499			case LDAP_RES_SEARCH_ENTRY:
1500				nentries++;
1501				print_entry( ld, msg, attrsonly );
1502				break;
1503
1504			case LDAP_RES_SEARCH_REFERENCE:
1505				nreferences++;
1506				print_reference( ld, msg );
1507				break;
1508
1509			case LDAP_RES_EXTENDED:
1510				nextended++;
1511				print_extended( ld, msg );
1512
1513				if ( ldap_msgid( msg ) == 0 ) {
1514					/* unsolicited extended operation */
1515					goto done;
1516				}
1517
1518				if ( cancel_msgid != -1 &&
1519						cancel_msgid == ldap_msgid( msg ) ) {
1520					printf(_("Cancelled \n"));
1521					printf(_("cancel_msgid = %d\n"), cancel_msgid);
1522					goto done;
1523				}
1524				break;
1525
1526			case LDAP_RES_SEARCH_RESULT:
1527				/* pagedResults stuff is dealt with
1528				 * in tool_print_ctrls(), called by
1529				 * print_results(). */
1530				rc2 = print_result( ld, msg, 1 );
1531				if ( ldapsync == LDAP_SYNC_REFRESH_AND_PERSIST ) {
1532					break;
1533				}
1534
1535				goto done;
1536
1537			case LDAP_RES_INTERMEDIATE:
1538				npartial++;
1539				ldap_parse_intermediate( ld, msg,
1540					&retoid, &retdata, NULL, 0 );
1541
1542				nresponses_psearch = 0;
1543
1544				if ( strcmp( retoid, LDAP_SYNC_INFO ) == 0 ) {
1545					printf(_("SyncInfo Received\n"));
1546					ldap_memfree( retoid );
1547					ber_bvfree( retdata );
1548					break;
1549				}
1550
1551				print_partial( ld, msg );
1552				ldap_memfree( retoid );
1553				ber_bvfree( retdata );
1554				goto done;
1555			}
1556
1557			if ( ldapsync && sync_slimit != -1 &&
1558					nresponses_psearch >= sync_slimit ) {
1559				BerElement *msgidber = NULL;
1560				struct berval *msgidvalp = NULL;
1561				msgidber = ber_alloc_t(LBER_USE_DER);
1562				ber_printf(msgidber, "{i}", msgid);
1563				ber_flatten(msgidber, &msgidvalp);
1564				ldap_extended_operation(ld, LDAP_EXOP_CANCEL,
1565					msgidvalp, NULL, NULL, &cancel_msgid);
1566				nresponses_psearch = -1;
1567			}
1568		}
1569
1570		ldap_msgfree( res );
1571	}
1572
1573done:
1574	if ( tvp == NULL && rc != LDAP_RES_SEARCH_RESULT ) {
1575		ldap_get_option( ld, LDAP_OPT_RESULT_CODE, (void *)&rc2 );
1576	}
1577
1578	ldap_msgfree( res );
1579
1580	if ( pagedResults ) {
1581		npagedresponses += nresponses;
1582		npagedentries += nentries;
1583		npagedextended += nextended;
1584		npagedpartial += npartial;
1585		npagedreferences += nreferences;
1586		if ( ( pr_morePagedResults == 0 ) && ( ldif < 2 ) ) {
1587			printf( _("\n# numResponses: %d\n"), npagedresponses );
1588			if( npagedentries ) {
1589				printf( _("# numEntries: %d\n"), npagedentries );
1590			}
1591			if( npagedextended ) {
1592				printf( _("# numExtended: %d\n"), npagedextended );
1593			}
1594			if( npagedpartial ) {
1595				printf( _("# numPartial: %d\n"), npagedpartial );
1596			}
1597			if( npagedreferences ) {
1598				printf( _("# numReferences: %d\n"), npagedreferences );
1599			}
1600		}
1601	} else if ( ldif < 2 ) {
1602		printf( _("\n# numResponses: %d\n"), nresponses );
1603		if( nentries ) printf( _("# numEntries: %d\n"), nentries );
1604		if( nextended ) printf( _("# numExtended: %d\n"), nextended );
1605		if( npartial ) printf( _("# numPartial: %d\n"), npartial );
1606		if( nreferences ) printf( _("# numReferences: %d\n"), nreferences );
1607	}
1608
1609	if ( rc != LDAP_RES_SEARCH_RESULT ) {
1610		tool_perror( "ldap_result", rc2, NULL, NULL, NULL, NULL );
1611	}
1612
1613	return( rc2 );
1614}
1615
1616#ifdef __APPLE__
1617static int
1618search_results_async(LDAP *ld)
1619{
1620	int rc = ldap_pvt_thread_mutex_init(&callback_mutex);
1621	if (rc != 0) {
1622		tool_perror( "ldap_results_async: ldap_pvt_thread_mutex_init failed", rc, NULL, NULL, NULL, NULL );
1623		return rc;
1624	}
1625
1626	rc = ldap_pvt_thread_cond_init(&callback_cond);
1627	if (rc != 0) {
1628		tool_perror( "ldap_results_async: ldap_pvt_thread_cond_init failed", rc, NULL, NULL, NULL, NULL );
1629		ldap_pvt_thread_mutex_destroy(&callback_mutex);
1630		return rc;
1631	}
1632
1633	ldap_set_search_results_callback(ld, search_results_async_callback, NULL);
1634
1635	/* wait for the callback to finish */
1636	ldap_pvt_thread_mutex_lock(&callback_mutex);
1637	while (!callback_done) {
1638            ldap_pvt_thread_cond_wait(&callback_cond, &callback_mutex);
1639	}
1640
1641	ldap_pvt_thread_mutex_unlock(&callback_mutex);
1642
1643	ldap_pvt_thread_cond_destroy(&callback_cond);
1644	ldap_pvt_thread_mutex_destroy(&callback_mutex);
1645	return LDAP_SUCCESS;
1646}
1647
1648static void
1649search_results_async_callback(
1650	LDAP *ld,
1651	LDAPMessage *res,
1652	int rc,
1653	void *context)
1654{
1655	static int		nresponses = 0;
1656	static int		nentries = 0;
1657	static int		nreferences = 0;
1658	static int		nextended = 0;
1659	static int		npartial = 0;
1660	LDAPMessage		*msg;
1661	ber_int_t		msgid;
1662	char			*retoid = NULL;
1663	struct berval		*retdata = NULL;
1664	int			nresponses_psearch = -1;
1665	int			cancel_msgid = -1;
1666
1667	if ( rc <= 0 ) {
1668		goto done;
1669	}
1670
1671	rc = tool_check_abandon( ld, msgid );
1672	if ( rc ) {
1673		return;
1674	}
1675
1676	if( sortattr ) {
1677		(void) ldap_sort_entries( ld, &res,
1678			( *sortattr == '\0' ) ? NULL : sortattr, strcasecmp );
1679	}
1680
1681	for ( msg = ldap_first_message( ld, res );
1682		msg != NULL;
1683		msg = ldap_next_message( ld, msg ) )
1684	{
1685		if ( nresponses++ ) putchar('\n');
1686		if ( nresponses_psearch >= 0 )
1687			nresponses_psearch++;
1688
1689		switch( ldap_msgtype( msg ) ) {
1690		case LDAP_RES_SEARCH_ENTRY:
1691			nentries++;
1692			print_entry( ld, msg, attrsonly );
1693			break;
1694
1695		case LDAP_RES_SEARCH_REFERENCE:
1696			nreferences++;
1697			print_reference( ld, msg );
1698			break;
1699
1700		case LDAP_RES_EXTENDED:
1701			nextended++;
1702			print_extended( ld, msg );
1703
1704			if ( ldap_msgid( msg ) == 0 ) {
1705				/* unsolicited extended operation */
1706				goto done;
1707			}
1708
1709			if ( cancel_msgid != -1 &&
1710					cancel_msgid == ldap_msgid( msg ) ) {
1711				printf(_("Cancelled \n"));
1712				printf(_("cancel_msgid = %d\n"), cancel_msgid);
1713				goto done;
1714			}
1715			break;
1716
1717		case LDAP_RES_SEARCH_RESULT:
1718			/* pagedResults stuff is dealt with
1719			 * in tool_print_ctrls(), called by
1720			 * print_results(). */
1721			rc = print_result( ld, msg, 1 );
1722			if ( ldapsync == LDAP_SYNC_REFRESH_AND_PERSIST ) {
1723				break;
1724			}
1725
1726			goto done;
1727
1728		case LDAP_RES_INTERMEDIATE:
1729			npartial++;
1730			ldap_parse_intermediate( ld, msg,
1731				&retoid, &retdata, NULL, 0 );
1732
1733			nresponses_psearch = 0;
1734
1735			if ( strcmp( retoid, LDAP_SYNC_INFO ) == 0 ) {
1736				printf(_("SyncInfo Received\n"));
1737				ldap_memfree( retoid );
1738				ber_bvfree( retdata );
1739				break;
1740			}
1741
1742			print_partial( ld, msg );
1743			ldap_memfree( retoid );
1744			ber_bvfree( retdata );
1745			goto done;
1746		}
1747
1748		if ( ldapsync && sync_slimit != -1 &&
1749				nresponses_psearch >= sync_slimit ) {
1750			BerElement *msgidber = NULL;
1751			struct berval *msgidvalp = NULL;
1752			msgidber = ber_alloc_t(LBER_USE_DER);
1753			ber_printf(msgidber, "{i}", msgid);
1754			ber_flatten(msgidber, &msgidvalp);
1755			ldap_extended_operation(ld, LDAP_EXOP_CANCEL,
1756				msgidvalp, NULL, NULL, &cancel_msgid);
1757			nresponses_psearch = -1;
1758		}
1759	}
1760
1761not_done:
1762	return;
1763
1764done:
1765	if ( rc == -1 ) {
1766		tool_perror( "ldap_results_async_callback", rc, NULL, NULL, NULL, NULL );
1767	}
1768	else {
1769		if ( pagedResults ) {
1770			npagedresponses += nresponses;
1771			npagedentries += nentries;
1772			npagedextended += nextended;
1773			npagedpartial += npartial;
1774			npagedreferences += nreferences;
1775			if ( ( pr_morePagedResults == 0 ) && ( ldif < 2 ) ) {
1776				printf( _("\n# numResponses: %d\n"), npagedresponses );
1777				if( npagedentries ) {
1778					printf( _("# numEntries: %d\n"), npagedentries );
1779				}
1780				if( npagedextended ) {
1781					printf( _("# numExtended: %d\n"), npagedextended );
1782				}
1783				if( npagedpartial ) {
1784					printf( _("# numPartial: %d\n"), npagedpartial );
1785				}
1786				if( npagedreferences ) {
1787					printf( _("# numReferences: %d\n"), npagedreferences );
1788				}
1789			}
1790		} else if ( ldif < 2 ) {
1791			printf( _("\n# numResponses: %d\n"), nresponses );
1792			if( nentries ) printf( _("# numEntries: %d\n"), nentries );
1793			if( nextended ) printf( _("# numExtended: %d\n"), nextended );
1794			if( npartial ) printf( _("# numPartial: %d\n"), npartial );
1795			if( nreferences ) printf( _("# numReferences: %d\n"), nreferences );
1796		}
1797	}
1798
1799	/* Signal the waiting thread that we're done */
1800	ldap_pvt_thread_mutex_lock(&callback_mutex);
1801	callback_done = 1;
1802	ldap_pvt_thread_cond_signal(&callback_cond);
1803	ldap_pvt_thread_mutex_unlock(&callback_mutex);
1804}
1805#endif /* __APPLE__ */
1806
1807/* This is the proposed new way of doing things.
1808 * It is more efficient, but the API is non-standard.
1809 */
1810static void
1811print_entry(
1812	LDAP	*ld,
1813	LDAPMessage	*entry,
1814	int		attrsonly)
1815{
1816	char		*ufn = NULL;
1817	char	tmpfname[ 256 ];
1818	char	url[ 256 ];
1819	int			i, rc;
1820	BerElement		*ber = NULL;
1821	struct berval		bv, *bvals, **bvp = &bvals;
1822	LDAPControl **ctrls = NULL;
1823	FILE		*tmpfp;
1824
1825	rc = ldap_get_dn_ber( ld, entry, &ber, &bv );
1826
1827	if ( ldif < 2 ) {
1828		ufn = ldap_dn2ufn( bv.bv_val );
1829		tool_write_ldif( LDIF_PUT_COMMENT, NULL, ufn, ufn ? strlen( ufn ) : 0 );
1830	}
1831	tool_write_ldif( LDIF_PUT_VALUE, "dn", bv.bv_val, bv.bv_len );
1832
1833	rc = ldap_get_entry_controls( ld, entry, &ctrls );
1834	if( rc != LDAP_SUCCESS ) {
1835		fprintf(stderr, _("print_entry: %d\n"), rc );
1836		tool_perror( "ldap_get_entry_controls", rc, NULL, NULL, NULL, NULL );
1837		tool_exit( ld, EXIT_FAILURE );
1838	}
1839
1840	if( ctrls ) {
1841		tool_print_ctrls( ld, ctrls );
1842		ldap_controls_free( ctrls );
1843	}
1844
1845	if ( includeufn ) {
1846		if( ufn == NULL ) {
1847			ufn = ldap_dn2ufn( bv.bv_val );
1848		}
1849		tool_write_ldif( LDIF_PUT_VALUE, "ufn", ufn, ufn ? strlen( ufn ) : 0 );
1850	}
1851
1852	if( ufn != NULL ) ldap_memfree( ufn );
1853
1854	if ( attrsonly ) bvp = NULL;
1855
1856	for ( rc = ldap_get_attribute_ber( ld, entry, ber, &bv, bvp );
1857		rc == LDAP_SUCCESS;
1858		rc = ldap_get_attribute_ber( ld, entry, ber, &bv, bvp ) )
1859	{
1860		if (bv.bv_val == NULL) break;
1861
1862		if ( attrsonly ) {
1863			tool_write_ldif( LDIF_PUT_NOVALUE, bv.bv_val, NULL, 0 );
1864
1865		} else if ( bvals ) {
1866			for ( i = 0; bvals[i].bv_val != NULL; i++ ) {
1867				if ( vals2tmp > 1 || ( vals2tmp &&
1868					ldif_is_not_printable( bvals[i].bv_val, bvals[i].bv_len )))
1869				{
1870					int tmpfd;
1871					/* write value to file */
1872					snprintf( tmpfname, sizeof tmpfname,
1873						"%s" LDAP_DIRSEP "ldapsearch-%s-XXXXXX",
1874						tmpdir, bv.bv_val );
1875					tmpfp = NULL;
1876
1877					tmpfd = mkstemp( tmpfname );
1878
1879					if ( tmpfd < 0  ) {
1880						perror( tmpfname );
1881						continue;
1882					}
1883
1884					if (( tmpfp = fdopen( tmpfd, "w")) == NULL ) {
1885						perror( tmpfname );
1886						continue;
1887					}
1888
1889					if ( fwrite( bvals[ i ].bv_val,
1890						bvals[ i ].bv_len, 1, tmpfp ) == 0 )
1891					{
1892						perror( tmpfname );
1893						fclose( tmpfp );
1894						continue;
1895					}
1896
1897					fclose( tmpfp );
1898
1899					snprintf( url, sizeof url, "%s%s", urlpre,
1900						&tmpfname[strlen(tmpdir) + sizeof(LDAP_DIRSEP) - 1] );
1901
1902					urlize( url );
1903					tool_write_ldif( LDIF_PUT_URL, bv.bv_val, url, strlen( url ));
1904
1905				} else {
1906					tool_write_ldif( LDIF_PUT_VALUE, bv.bv_val,
1907						bvals[ i ].bv_val, bvals[ i ].bv_len );
1908				}
1909			}
1910			ber_memfree( bvals );
1911		}
1912	}
1913
1914	if( ber != NULL ) {
1915		ber_free( ber, 0 );
1916	}
1917}
1918
1919static void print_reference(
1920	LDAP *ld,
1921	LDAPMessage *reference )
1922{
1923	int rc;
1924	char **refs = NULL;
1925	LDAPControl **ctrls;
1926
1927	if( ldif < 2 ) {
1928		printf(_("# search reference\n"));
1929	}
1930
1931	rc = ldap_parse_reference( ld, reference, &refs, &ctrls, 0 );
1932
1933	if( rc != LDAP_SUCCESS ) {
1934		tool_perror( "ldap_parse_reference", rc, NULL, NULL, NULL, NULL );
1935		tool_exit( ld, EXIT_FAILURE );
1936	}
1937
1938	if( refs ) {
1939		int i;
1940		for( i=0; refs[i] != NULL; i++ ) {
1941			tool_write_ldif( ldif ? LDIF_PUT_COMMENT : LDIF_PUT_VALUE,
1942				"ref", refs[i], strlen(refs[i]) );
1943		}
1944		ber_memvfree( (void **) refs );
1945	}
1946
1947	if( ctrls ) {
1948		tool_print_ctrls( ld, ctrls );
1949		ldap_controls_free( ctrls );
1950	}
1951}
1952
1953static void print_extended(
1954	LDAP *ld,
1955	LDAPMessage *extended )
1956{
1957	int rc;
1958	char *retoid = NULL;
1959	struct berval *retdata = NULL;
1960
1961	if( ldif < 2 ) {
1962		printf(_("# extended result response\n"));
1963	}
1964
1965	rc = ldap_parse_extended_result( ld, extended,
1966		&retoid, &retdata, 0 );
1967
1968	if( rc != LDAP_SUCCESS ) {
1969		tool_perror( "ldap_parse_extended_result", rc, NULL, NULL, NULL, NULL );
1970		tool_exit( ld, EXIT_FAILURE );
1971	}
1972
1973	if ( ldif < 2 ) {
1974		tool_write_ldif( ldif ? LDIF_PUT_COMMENT : LDIF_PUT_VALUE,
1975			"extended", retoid, retoid ? strlen(retoid) : 0 );
1976	}
1977	ber_memfree( retoid );
1978
1979	if(retdata) {
1980		if ( ldif < 2 ) {
1981			tool_write_ldif( ldif ? LDIF_PUT_COMMENT : LDIF_PUT_BINARY,
1982				"data", retdata->bv_val, retdata->bv_len );
1983		}
1984		ber_bvfree( retdata );
1985	}
1986
1987	print_result( ld, extended, 0 );
1988}
1989
1990static void print_partial(
1991	LDAP *ld,
1992	LDAPMessage *partial )
1993{
1994	int rc;
1995	char *retoid = NULL;
1996	struct berval *retdata = NULL;
1997	LDAPControl **ctrls = NULL;
1998
1999	if( ldif < 2 ) {
2000		printf(_("# extended partial response\n"));
2001	}
2002
2003	rc = ldap_parse_intermediate( ld, partial,
2004		&retoid, &retdata, &ctrls, 0 );
2005
2006	if( rc != LDAP_SUCCESS ) {
2007		tool_perror( "ldap_parse_intermediate", rc, NULL, NULL, NULL, NULL );
2008		tool_exit( ld, EXIT_FAILURE );
2009	}
2010
2011	if ( ldif < 2 ) {
2012		tool_write_ldif( ldif ? LDIF_PUT_COMMENT : LDIF_PUT_VALUE,
2013			"partial", retoid, retoid ? strlen(retoid) : 0 );
2014	}
2015
2016	ber_memfree( retoid );
2017
2018	if( retdata ) {
2019		if ( ldif < 2 ) {
2020			tool_write_ldif( ldif ? LDIF_PUT_COMMENT : LDIF_PUT_BINARY,
2021				"data", retdata->bv_val, retdata->bv_len );
2022		}
2023
2024		ber_bvfree( retdata );
2025	}
2026
2027	if( ctrls ) {
2028		tool_print_ctrls( ld, ctrls );
2029		ldap_controls_free( ctrls );
2030	}
2031}
2032
2033static int print_result(
2034	LDAP *ld,
2035	LDAPMessage *result, int search )
2036{
2037	int rc;
2038	int err;
2039	char *matcheddn = NULL;
2040	char *text = NULL;
2041	char **refs = NULL;
2042	LDAPControl **ctrls = NULL;
2043
2044	if( search ) {
2045		if ( ldif < 2 ) {
2046			printf(_("# search result\n"));
2047		}
2048		if ( ldif < 1 ) {
2049			printf("%s: %d\n", _("search"), ldap_msgid(result) );
2050		}
2051	}
2052
2053	rc = ldap_parse_result( ld, result,
2054		&err, &matcheddn, &text, &refs, &ctrls, 0 );
2055
2056	if( rc != LDAP_SUCCESS ) {
2057		tool_perror( "ldap_parse_result", rc, NULL, NULL, NULL, NULL );
2058		tool_exit( ld, EXIT_FAILURE );
2059	}
2060
2061
2062	if( !ldif ) {
2063		printf( _("result: %d %s\n"), err, ldap_err2string(err) );
2064
2065	} else if ( err != LDAP_SUCCESS ) {
2066		fprintf( stderr, "%s (%d)\n", ldap_err2string(err), err );
2067	}
2068
2069	if( matcheddn ) {
2070		if( *matcheddn ) {
2071		if( !ldif ) {
2072			tool_write_ldif( LDIF_PUT_VALUE,
2073				"matchedDN", matcheddn, strlen(matcheddn) );
2074		} else {
2075			fprintf( stderr, _("Matched DN: %s\n"), matcheddn );
2076		}
2077		}
2078
2079		ber_memfree( matcheddn );
2080	}
2081
2082	if( text ) {
2083		if( *text ) {
2084			if( !ldif ) {
2085				if ( err == LDAP_PARTIAL_RESULTS ) {
2086					char	*line;
2087
2088					for ( line = text; line != NULL; ) {
2089						char	*next = strchr( line, '\n' );
2090
2091						tool_write_ldif( LDIF_PUT_TEXT,
2092							"text", line,
2093							next ? (size_t) (next - line) : strlen( line ));
2094
2095						line = next ? next + 1 : NULL;
2096					}
2097
2098				} else {
2099					tool_write_ldif( LDIF_PUT_TEXT, "text",
2100						text, strlen(text) );
2101				}
2102			} else {
2103				fprintf( stderr, _("Additional information: %s\n"), text );
2104			}
2105		}
2106
2107		ber_memfree( text );
2108	}
2109
2110	if( refs ) {
2111		int i;
2112		for( i=0; refs[i] != NULL; i++ ) {
2113			if( !ldif ) {
2114				tool_write_ldif( LDIF_PUT_VALUE, "ref", refs[i], strlen(refs[i]) );
2115			} else {
2116				fprintf( stderr, _("Referral: %s\n"), refs[i] );
2117			}
2118		}
2119
2120		ber_memvfree( (void **) refs );
2121	}
2122
2123	pr_morePagedResults = 0;
2124
2125	if( ctrls ) {
2126		tool_print_ctrls( ld, ctrls );
2127		ldap_controls_free( ctrls );
2128	}
2129
2130	return err;
2131}
2132