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