xref: /netbsd-src/external/bsd/openldap/dist/clients/tools/ldapsearch.c (revision b62fc9e20372b08e1785ff6d769312d209fa2005)
1 /*	$NetBSD: ldapsearch.c,v 1.1.1.2 2010/03/08 02:14:20 lukem Exp $	*/
2 
3 /* ldapsearch -- a tool for searching LDAP directories */
4 /* OpenLDAP: pkg/ldap/clients/tools/ldapsearch.c,v 1.234.2.23 2009/08/25 22:58:08 quanah Exp */
5 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
6  *
7  * Copyright 1998-2009 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 	if ( pw_file || want_bindpw ) {
905 		if ( pw_file ) {
906 			rc = lutil_get_filed_password( pw_file, &passwd );
907 			if( rc ) return EXIT_FAILURE;
908 		} else {
909 			passwd.bv_val = getpassphrase( _("Enter LDAP Password: ") );
910 			passwd.bv_len = passwd.bv_val ? strlen( passwd.bv_val ) : 0;
911 		}
912 	}
913 
914 	tool_bind( ld );
915 
916 getNextPage:
917 	save_nctrls = nctrls;
918 	i = nctrls;
919 	if ( nctrls > 0
920 #ifdef LDAP_CONTROL_DONTUSECOPY
921 		|| dontUseCopy
922 #endif
923 #ifdef LDAP_CONTROL_X_DEREF
924 		|| derefcrit
925 #endif
926 		|| domainScope
927 		|| pagedResults
928 		|| ldapsync
929 		|| sss
930 		|| subentries
931 		|| valuesReturnFilter
932 		|| vlv )
933 	{
934 
935 #ifdef LDAP_CONTROL_DONTUSECOPY
936 		if ( dontUseCopy ) {
937 			if ( ctrl_add() ) {
938 				return EXIT_FAILURE;
939 			}
940 
941 			c[i].ldctl_oid = LDAP_CONTROL_DONTUSECOPY;
942 			c[i].ldctl_value.bv_val = NULL;
943 			c[i].ldctl_value.bv_len = 0;
944 			c[i].ldctl_iscritical = dontUseCopy > 1;
945 			i++;
946 		}
947 #endif
948 
949 		if ( domainScope ) {
950 			if ( ctrl_add() ) {
951 				return EXIT_FAILURE;
952 			}
953 
954 			c[i].ldctl_oid = LDAP_CONTROL_X_DOMAIN_SCOPE;
955 			c[i].ldctl_value.bv_val = NULL;
956 			c[i].ldctl_value.bv_len = 0;
957 			c[i].ldctl_iscritical = domainScope > 1;
958 			i++;
959 		}
960 
961 		if ( subentries ) {
962 			if ( ctrl_add() ) {
963 				return EXIT_FAILURE;
964 			}
965 
966 			if (( seber = ber_alloc_t(LBER_USE_DER)) == NULL ) {
967 				return EXIT_FAILURE;
968 			}
969 
970 			err = ber_printf( seber, "b", abs(subentries) == 1 ? 0 : 1 );
971 			if ( err == -1 ) {
972 				ber_free( seber, 1 );
973 				fprintf( stderr, _("Subentries control encoding error!\n") );
974 				return EXIT_FAILURE;
975 			}
976 
977 			if ( ber_flatten2( seber, &c[i].ldctl_value, 0 ) == -1 ) {
978 				return EXIT_FAILURE;
979 			}
980 
981 			c[i].ldctl_oid = LDAP_CONTROL_SUBENTRIES;
982 			c[i].ldctl_iscritical = subentries < 1;
983 			i++;
984 		}
985 
986 		if ( ldapsync ) {
987 			if ( ctrl_add() ) {
988 				return EXIT_FAILURE;
989 			}
990 
991 			if (( syncber = ber_alloc_t(LBER_USE_DER)) == NULL ) {
992 				return EXIT_FAILURE;
993 			}
994 
995 			if ( sync_cookie.bv_len == 0 ) {
996 				err = ber_printf( syncber, "{e}", abs(ldapsync) );
997 			} else {
998 				err = ber_printf( syncber, "{eO}", abs(ldapsync),
999 							&sync_cookie );
1000 			}
1001 
1002 			if ( err == -1 ) {
1003 				ber_free( syncber, 1 );
1004 				fprintf( stderr, _("ldap sync control encoding error!\n") );
1005 				return EXIT_FAILURE;
1006 			}
1007 
1008 			if ( ber_flatten( syncber, &syncbvalp ) == -1 ) {
1009 				return EXIT_FAILURE;
1010 			}
1011 
1012 			c[i].ldctl_oid = LDAP_CONTROL_SYNC;
1013 			c[i].ldctl_value = (*syncbvalp);
1014 			c[i].ldctl_iscritical = ldapsync < 0;
1015 			i++;
1016 		}
1017 
1018 		if ( valuesReturnFilter ) {
1019 			if ( ctrl_add() ) {
1020 				return EXIT_FAILURE;
1021 			}
1022 
1023 			if (( vrber = ber_alloc_t(LBER_USE_DER)) == NULL ) {
1024 				return EXIT_FAILURE;
1025 			}
1026 
1027 			if ( ( err = ldap_put_vrFilter( vrber, vrFilter ) ) == -1 ) {
1028 				ber_free( vrber, 1 );
1029 				fprintf( stderr, _("Bad ValuesReturnFilter: %s\n"), vrFilter );
1030 				return EXIT_FAILURE;
1031 			}
1032 
1033 			if ( ber_flatten2( vrber, &c[i].ldctl_value, 0 ) == -1 ) {
1034 				return EXIT_FAILURE;
1035 			}
1036 
1037 			c[i].ldctl_oid = LDAP_CONTROL_VALUESRETURNFILTER;
1038 			c[i].ldctl_iscritical = valuesReturnFilter > 1;
1039 			i++;
1040 		}
1041 
1042 		if ( pagedResults ) {
1043 			if ( ctrl_add() ) {
1044 				return EXIT_FAILURE;
1045 			}
1046 
1047 			if ( ldap_create_page_control_value( ld,
1048 				pageSize, &pr_cookie, &c[i].ldctl_value ) )
1049 			{
1050 				return EXIT_FAILURE;
1051 			}
1052 
1053 			if ( pr_cookie.bv_val != NULL ) {
1054 				ber_memfree( pr_cookie.bv_val );
1055 				pr_cookie.bv_val = NULL;
1056 				pr_cookie.bv_len = 0;
1057 			}
1058 
1059 			c[i].ldctl_oid = LDAP_CONTROL_PAGEDRESULTS;
1060 			c[i].ldctl_iscritical = pagedResults > 1;
1061 			i++;
1062 		}
1063 
1064 		if ( sss ) {
1065 			if ( ctrl_add() ) {
1066 				return EXIT_FAILURE;
1067 			}
1068 
1069 			if ( ldap_create_sort_control_value( ld,
1070 				sss_keys, &c[i].ldctl_value ) )
1071 			{
1072 				return EXIT_FAILURE;
1073 			}
1074 
1075 			c[i].ldctl_oid = LDAP_CONTROL_SORTREQUEST;
1076 			c[i].ldctl_iscritical = sss > 1;
1077 			i++;
1078 		}
1079 
1080 		if ( vlv ) {
1081 			if ( ctrl_add() ) {
1082 				return EXIT_FAILURE;
1083 			}
1084 
1085 			if ( ldap_create_vlv_control_value( ld,
1086 				&vlvInfo, &c[i].ldctl_value ) )
1087 			{
1088 				return EXIT_FAILURE;
1089 			}
1090 
1091 			c[i].ldctl_oid = LDAP_CONTROL_VLVREQUEST;
1092 			c[i].ldctl_iscritical = sss > 1;
1093 			i++;
1094 		}
1095 #ifdef LDAP_CONTROL_X_DEREF
1096 		if ( derefcrit ) {
1097 			if ( derefval.bv_val == NULL ) {
1098 				int i;
1099 
1100 				assert( ds != NULL );
1101 
1102 				if ( ldap_create_deref_control_value( ld, ds, &derefval ) != LDAP_SUCCESS ) {
1103 					return EXIT_FAILURE;
1104 				}
1105 
1106 				for ( i = 0; ds[ i ].derefAttr != NULL; i++ ) {
1107 					ldap_memfree( ds[ i ].derefAttr );
1108 					ldap_charray_free( ds[ i ].attributes );
1109 				}
1110 				ldap_memfree( ds );
1111 				ds = NULL;
1112 			}
1113 
1114 			if ( ctrl_add() ) {
1115 				exit( EXIT_FAILURE );
1116 			}
1117 
1118 			c[ i ].ldctl_iscritical = derefcrit > 1;
1119 			c[ i ].ldctl_oid = LDAP_CONTROL_X_DEREF;
1120 			c[ i ].ldctl_value = derefval;
1121 			i++;
1122 		}
1123 #endif /* LDAP_CONTROL_X_DEREF */
1124 	}
1125 
1126 	tool_server_controls( ld, c, i );
1127 
1128 	if ( seber ) ber_free( seber, 1 );
1129 	if ( vrber ) ber_free( vrber, 1 );
1130 
1131 	/* step back to the original number of controls, so that
1132 	 * those set while parsing args are preserved */
1133 	nctrls = save_nctrls;
1134 
1135 	if ( verbose ) {
1136 		fprintf( stderr, _("filter%s: %s\nrequesting: "),
1137 			infile != NULL ? _(" pattern") : "",
1138 			filtpattern );
1139 
1140 		if ( attrs == NULL ) {
1141 			fprintf( stderr, _("All userApplication attributes") );
1142 		} else {
1143 			for ( i = 0; attrs[ i ] != NULL; ++i ) {
1144 				fprintf( stderr, "%s ", attrs[ i ] );
1145 			}
1146 		}
1147 		fprintf( stderr, "\n" );
1148 	}
1149 
1150 	if ( ldif == 0 ) {
1151 		printf( _("# extended LDIF\n") );
1152 	} else if ( ldif < 3 ) {
1153 		printf( _("version: %d\n\n"), 1 );
1154 	}
1155 
1156 	if (ldif < 2 ) {
1157 		char	*realbase = base;
1158 
1159 		if ( realbase == NULL ) {
1160 			ldap_get_option( ld, LDAP_OPT_DEFBASE, (void **)(char *)&realbase );
1161 		}
1162 
1163 		printf( "#\n" );
1164 		printf(_("# LDAPv%d\n"), protocol);
1165 		printf(_("# base <%s>%s with scope %s\n"),
1166 			realbase ? realbase : "",
1167 			( realbase == NULL || realbase != base ) ? " (default)" : "",
1168 			((scope == LDAP_SCOPE_BASE) ? "baseObject"
1169 				: ((scope == LDAP_SCOPE_ONELEVEL) ? "oneLevel"
1170 				: ((scope == LDAP_SCOPE_SUBORDINATE) ? "children"
1171 				: "subtree" ))));
1172 		printf(_("# filter%s: %s\n"), infile != NULL ? _(" pattern") : "",
1173 		       filtpattern);
1174 		printf(_("# requesting: "));
1175 
1176 		if ( attrs == NULL ) {
1177 			printf( _("ALL") );
1178 		} else {
1179 			for ( i = 0; attrs[ i ] != NULL; ++i ) {
1180 				printf( "%s ", attrs[ i ] );
1181 			}
1182 		}
1183 
1184 		if ( manageDSAit ) {
1185 			printf(_("\n# with manageDSAit %scontrol"),
1186 				manageDSAit > 1 ? _("critical ") : "" );
1187 		}
1188 		if ( noop ) {
1189 			printf(_("\n# with noop %scontrol"),
1190 				noop > 1 ? _("critical ") : "" );
1191 		}
1192 		if ( subentries ) {
1193 			printf(_("\n# with subentries %scontrol: %s"),
1194 				subentries < 0 ? _("critical ") : "",
1195 				abs(subentries) == 1 ? "false" : "true" );
1196 		}
1197 		if ( valuesReturnFilter ) {
1198 			printf(_("\n# with valuesReturnFilter %scontrol: %s"),
1199 				valuesReturnFilter > 1 ? _("critical ") : "", vrFilter );
1200 		}
1201 		if ( pagedResults ) {
1202 			printf(_("\n# with pagedResults %scontrol: size=%d"),
1203 				(pagedResults > 1) ? _("critical ") : "",
1204 				pageSize );
1205 		}
1206 		if ( sss ) {
1207 			printf(_("\n# with server side sorting %scontrol"),
1208 				sss > 1 ? _("critical ") : "" );
1209 		}
1210 		if ( vlv ) {
1211 			printf(_("\n# with virtual list view %scontrol: %d/%d"),
1212 				vlv > 1 ? _("critical ") : "",
1213 				vlvInfo.ldvlv_before_count, vlvInfo.ldvlv_after_count);
1214 			if ( vlvInfo.ldvlv_attrvalue )
1215 				printf(":%s", vlvInfo.ldvlv_attrvalue->bv_val );
1216 			else
1217 				printf("/%d/%d", vlvInfo.ldvlv_offset, vlvInfo.ldvlv_count );
1218 		}
1219 #ifdef LDAP_CONTROL_X_DEREF
1220 		if ( derefcrit ) {
1221 			printf(_("\n# with dereference %scontrol"),
1222 				derefcrit > 1 ? _("critical ") : "" );
1223 		}
1224 #endif
1225 
1226 		printf( _("\n#\n\n") );
1227 
1228 		if ( realbase && realbase != base ) {
1229 			ldap_memfree( realbase );
1230 		}
1231 	}
1232 
1233 	if ( infile == NULL ) {
1234 		rc = dosearch( ld, base, scope, NULL, filtpattern,
1235 			attrs, attrsonly, NULL, NULL, NULL, -1 );
1236 
1237 	} else {
1238 		rc = 0;
1239 		first = 1;
1240 		while ( fgets( line, sizeof( line ), fp ) != NULL ) {
1241 			line[ strlen( line ) - 1 ] = '\0';
1242 			if ( !first ) {
1243 				putchar( '\n' );
1244 			} else {
1245 				first = 0;
1246 			}
1247 			rc1 = dosearch( ld, base, scope, filtpattern, line,
1248 				attrs, attrsonly, NULL, NULL, NULL, -1 );
1249 
1250 			if ( rc1 != 0 ) {
1251 				rc = rc1;
1252 				if ( !contoper )
1253 					break;
1254 			}
1255 		}
1256 		if ( fp != stdin ) {
1257 			fclose( fp );
1258 		}
1259 	}
1260 
1261 	if (( rc == LDAP_SUCCESS ) && pageSize && pr_morePagedResults ) {
1262 		char	buf[12];
1263 		int	i, moreEntries, tmpSize;
1264 
1265 		/* Loop to get the next pages when
1266 		 * enter is pressed on the terminal.
1267 		 */
1268 		if ( pagePrompt != 0 ) {
1269 			if ( entriesLeft > 0 ) {
1270 				printf( _("Estimate entries: %d\n"), entriesLeft );
1271 			}
1272 			printf( _("Press [size] Enter for the next {%d|size} entries.\n"),
1273 				(int)pageSize );
1274 			i = 0;
1275 			moreEntries = getchar();
1276 			while ( moreEntries != EOF && moreEntries != '\n' ) {
1277 				if ( i < (int)sizeof(buf) - 1 ) {
1278 					buf[i] = moreEntries;
1279 					i++;
1280 				}
1281 				moreEntries = getchar();
1282 			}
1283 			buf[i] = '\0';
1284 
1285 			if ( i > 0 && isdigit( (unsigned char)buf[0] ) ) {
1286 				int num = sscanf( buf, "%d", &tmpSize );
1287 				if ( num != 1 ) {
1288 					fprintf( stderr,
1289 						_("Invalid value for PagedResultsControl, %s.\n"), buf);
1290 					return EXIT_FAILURE;
1291 
1292 				}
1293 				pageSize = (ber_int_t)tmpSize;
1294 			}
1295 		}
1296 
1297 		goto getNextPage;
1298 	}
1299 
1300 	if (( rc == LDAP_SUCCESS ) && vlv ) {
1301 		char	buf[BUFSIZ];
1302 		int	i, moreEntries;
1303 
1304 		/* Loop to get the next window when
1305 		 * enter is pressed on the terminal.
1306 		 */
1307 		printf( _("Press [before/after(/offset/count|:value)] Enter for the next window.\n"));
1308 		i = 0;
1309 		moreEntries = getchar();
1310 		while ( moreEntries != EOF && moreEntries != '\n' ) {
1311 			if ( i < (int)sizeof(buf) - 1 ) {
1312 				buf[i] = moreEntries;
1313 				i++;
1314 			}
1315 			moreEntries = getchar();
1316 		}
1317 		buf[i] = '\0';
1318 		if ( buf[0] ) {
1319 			i = parse_vlv( strdup( buf ));
1320 			if ( i )
1321 				return EXIT_FAILURE;
1322 		} else {
1323 			vlvInfo.ldvlv_attrvalue = NULL;
1324 			vlvInfo.ldvlv_count = vlvCount;
1325 			vlvInfo.ldvlv_offset += vlvInfo.ldvlv_after_count;
1326 		}
1327 
1328 		if ( vlvInfo.ldvlv_context )
1329 			ber_bvfree( vlvInfo.ldvlv_context );
1330 		vlvInfo.ldvlv_context = vlvContext;
1331 
1332 		goto getNextPage;
1333 	}
1334 
1335 	tool_unbind( ld );
1336 	tool_destroy();
1337 	if ( base != NULL ) {
1338 		ber_memfree( base );
1339 	}
1340 	if ( control != NULL ) {
1341 		ber_memfree( control );
1342 	}
1343 	if ( sss_keys != NULL ) {
1344 		ldap_free_sort_keylist( sss_keys );
1345 	}
1346 	if ( derefval.bv_val != NULL ) {
1347 		ldap_memfree( derefval.bv_val );
1348 	}
1349 
1350 	if ( c ) {
1351 		for ( ; save_nctrls-- > 0; ) {
1352 			ber_memfree( c[ save_nctrls ].ldctl_value.bv_val );
1353 		}
1354 		free( c );
1355 		c = NULL;
1356 	}
1357 
1358 	return( rc );
1359 }
1360 
1361 
1362 static int dosearch(
1363 	LDAP	*ld,
1364 	char	*base,
1365 	int		scope,
1366 	char	*filtpatt,
1367 	char	*value,
1368 	char	**attrs,
1369 	int		attrsonly,
1370 	LDAPControl **sctrls,
1371 	LDAPControl **cctrls,
1372 	struct timeval *timeout,
1373 	int sizelimit )
1374 {
1375 	char			*filter;
1376 	int			rc;
1377 	int			nresponses;
1378 	int			nentries;
1379 	int			nreferences;
1380 	int			nextended;
1381 	int			npartial;
1382 	LDAPMessage		*res, *msg;
1383 	ber_int_t		msgid;
1384 	char			*retoid = NULL;
1385 	struct berval		*retdata = NULL;
1386 	int			nresponses_psearch = -1;
1387 	int			cancel_msgid = -1;
1388 
1389 	if( filtpatt != NULL ) {
1390 		size_t max_fsize = strlen( filtpatt ) + strlen( value ) + 1, outlen;
1391 		filter = malloc( max_fsize );
1392 		if( filter == NULL ) {
1393 			perror( "malloc" );
1394 			return EXIT_FAILURE;
1395 		}
1396 
1397 		outlen = snprintf( filter, max_fsize, filtpatt, value );
1398 		if( outlen >= max_fsize ) {
1399 			fprintf( stderr, "Bad filter pattern: \"%s\"\n", filtpatt );
1400 			free( filter );
1401 			return EXIT_FAILURE;
1402 		}
1403 
1404 		if ( verbose ) {
1405 			fprintf( stderr, _("filter: %s\n"), filter );
1406 		}
1407 
1408 		if( ldif < 2 ) {
1409 			printf( _("#\n# filter: %s\n#\n"), filter );
1410 		}
1411 
1412 	} else {
1413 		filter = value;
1414 	}
1415 
1416 	if ( dont ) {
1417 		if ( filtpatt != NULL ) {
1418 			free( filter );
1419 		}
1420 		return LDAP_SUCCESS;
1421 	}
1422 
1423 	rc = ldap_search_ext( ld, base, scope, filter, attrs, attrsonly,
1424 		sctrls, cctrls, timeout, sizelimit, &msgid );
1425 
1426 	if ( filtpatt != NULL ) {
1427 		free( filter );
1428 	}
1429 
1430 	if( rc != LDAP_SUCCESS ) {
1431 		fprintf( stderr, _("%s: ldap_search_ext: %s (%d)\n"),
1432 			prog, ldap_err2string( rc ), rc );
1433 		return( rc );
1434 	}
1435 
1436 	nresponses = nentries = nreferences = nextended = npartial = 0;
1437 
1438 	res = NULL;
1439 
1440 	while ((rc = ldap_result( ld, LDAP_RES_ANY,
1441 		sortattr ? LDAP_MSG_ALL : LDAP_MSG_ONE,
1442 		NULL, &res )) > 0 )
1443 	{
1444 		rc = tool_check_abandon( ld, msgid );
1445 		if ( rc ) {
1446 			return rc;
1447 		}
1448 
1449 		if( sortattr ) {
1450 			(void) ldap_sort_entries( ld, &res,
1451 				( *sortattr == '\0' ) ? NULL : sortattr, strcasecmp );
1452 		}
1453 
1454 		for ( msg = ldap_first_message( ld, res );
1455 			msg != NULL;
1456 			msg = ldap_next_message( ld, msg ) )
1457 		{
1458 			if ( nresponses++ ) putchar('\n');
1459 			if ( nresponses_psearch >= 0 )
1460 				nresponses_psearch++;
1461 
1462 			switch( ldap_msgtype( msg ) ) {
1463 			case LDAP_RES_SEARCH_ENTRY:
1464 				nentries++;
1465 				print_entry( ld, msg, attrsonly );
1466 				break;
1467 
1468 			case LDAP_RES_SEARCH_REFERENCE:
1469 				nreferences++;
1470 				print_reference( ld, msg );
1471 				break;
1472 
1473 			case LDAP_RES_EXTENDED:
1474 				nextended++;
1475 				print_extended( ld, msg );
1476 
1477 				if ( ldap_msgid( msg ) == 0 ) {
1478 					/* unsolicited extended operation */
1479 					goto done;
1480 				}
1481 
1482 				if ( cancel_msgid != -1 &&
1483 						cancel_msgid == ldap_msgid( msg ) ) {
1484 					printf(_("Cancelled \n"));
1485 					printf(_("cancel_msgid = %d\n"), cancel_msgid);
1486 					goto done;
1487 				}
1488 				break;
1489 
1490 			case LDAP_RES_SEARCH_RESULT:
1491 				/* pagedResults stuff is dealt with
1492 				 * in tool_print_ctrls(), called by
1493 				 * print_results(). */
1494 				rc = print_result( ld, msg, 1 );
1495 				if ( ldapsync == LDAP_SYNC_REFRESH_AND_PERSIST ) {
1496 					break;
1497 				}
1498 
1499 				goto done;
1500 
1501 			case LDAP_RES_INTERMEDIATE:
1502 				npartial++;
1503 				ldap_parse_intermediate( ld, msg,
1504 					&retoid, &retdata, NULL, 0 );
1505 
1506 				nresponses_psearch = 0;
1507 
1508 				if ( strcmp( retoid, LDAP_SYNC_INFO ) == 0 ) {
1509 					printf(_("SyncInfo Received\n"));
1510 					ldap_memfree( retoid );
1511 					ber_bvfree( retdata );
1512 					break;
1513 				}
1514 
1515 				print_partial( ld, msg );
1516 				ldap_memfree( retoid );
1517 				ber_bvfree( retdata );
1518 				goto done;
1519 			}
1520 
1521 			if ( ldapsync && sync_slimit != -1 &&
1522 					nresponses_psearch >= sync_slimit ) {
1523 				BerElement *msgidber = NULL;
1524 				struct berval *msgidvalp = NULL;
1525 				msgidber = ber_alloc_t(LBER_USE_DER);
1526 				ber_printf(msgidber, "{i}", msgid);
1527 				ber_flatten(msgidber, &msgidvalp);
1528 				ldap_extended_operation(ld, LDAP_EXOP_CANCEL,
1529 					msgidvalp, NULL, NULL, &cancel_msgid);
1530 				nresponses_psearch = -1;
1531 			}
1532 		}
1533 
1534 		ldap_msgfree( res );
1535 	}
1536 
1537 done:
1538 	if ( rc == -1 ) {
1539 		tool_perror( "ldap_result", rc, NULL, NULL, NULL, NULL );
1540 		return( rc );
1541 	}
1542 
1543 	ldap_msgfree( res );
1544 
1545 	if ( pagedResults ) {
1546 		npagedresponses += nresponses;
1547 		npagedentries += nentries;
1548 		npagedextended += nextended;
1549 		npagedpartial += npartial;
1550 		npagedreferences += nreferences;
1551 		if ( ( pr_morePagedResults == 0 ) && ( ldif < 2 ) ) {
1552 			printf( _("\n# numResponses: %d\n"), npagedresponses );
1553 			if( npagedentries ) {
1554 				printf( _("# numEntries: %d\n"), npagedentries );
1555 			}
1556 			if( npagedextended ) {
1557 				printf( _("# numExtended: %d\n"), npagedextended );
1558 			}
1559 			if( npagedpartial ) {
1560 				printf( _("# numPartial: %d\n"), npagedpartial );
1561 			}
1562 			if( npagedreferences ) {
1563 				printf( _("# numReferences: %d\n"), npagedreferences );
1564 			}
1565 		}
1566 	} else if ( ldif < 2 ) {
1567 		printf( _("\n# numResponses: %d\n"), nresponses );
1568 		if( nentries ) printf( _("# numEntries: %d\n"), nentries );
1569 		if( nextended ) printf( _("# numExtended: %d\n"), nextended );
1570 		if( npartial ) printf( _("# numPartial: %d\n"), npartial );
1571 		if( nreferences ) printf( _("# numReferences: %d\n"), nreferences );
1572 	}
1573 
1574 	return( rc );
1575 }
1576 
1577 /* This is the proposed new way of doing things.
1578  * It is more efficient, but the API is non-standard.
1579  */
1580 static void
1581 print_entry(
1582 	LDAP	*ld,
1583 	LDAPMessage	*entry,
1584 	int		attrsonly)
1585 {
1586 	char		*ufn = NULL;
1587 	char	tmpfname[ 256 ];
1588 	char	url[ 256 ];
1589 	int			i, rc;
1590 	BerElement		*ber = NULL;
1591 	struct berval		bv, *bvals, **bvp = &bvals;
1592 	LDAPControl **ctrls = NULL;
1593 	FILE		*tmpfp;
1594 
1595 	rc = ldap_get_dn_ber( ld, entry, &ber, &bv );
1596 
1597 	if ( ldif < 2 ) {
1598 		ufn = ldap_dn2ufn( bv.bv_val );
1599 		tool_write_ldif( LDIF_PUT_COMMENT, NULL, ufn, ufn ? strlen( ufn ) : 0 );
1600 	}
1601 	tool_write_ldif( LDIF_PUT_VALUE, "dn", bv.bv_val, bv.bv_len );
1602 
1603 	rc = ldap_get_entry_controls( ld, entry, &ctrls );
1604 	if( rc != LDAP_SUCCESS ) {
1605 		fprintf(stderr, _("print_entry: %d\n"), rc );
1606 		tool_perror( "ldap_get_entry_controls", rc, NULL, NULL, NULL, NULL );
1607 		exit( EXIT_FAILURE );
1608 	}
1609 
1610 	if( ctrls ) {
1611 		tool_print_ctrls( ld, ctrls );
1612 		ldap_controls_free( ctrls );
1613 	}
1614 
1615 	if ( includeufn ) {
1616 		if( ufn == NULL ) {
1617 			ufn = ldap_dn2ufn( bv.bv_val );
1618 		}
1619 		tool_write_ldif( LDIF_PUT_VALUE, "ufn", ufn, ufn ? strlen( ufn ) : 0 );
1620 	}
1621 
1622 	if( ufn != NULL ) ldap_memfree( ufn );
1623 
1624 	if ( attrsonly ) bvp = NULL;
1625 
1626 	for ( rc = ldap_get_attribute_ber( ld, entry, ber, &bv, bvp );
1627 		rc == LDAP_SUCCESS;
1628 		rc = ldap_get_attribute_ber( ld, entry, ber, &bv, bvp ) )
1629 	{
1630 		if (bv.bv_val == NULL) break;
1631 
1632 		if ( attrsonly ) {
1633 			tool_write_ldif( LDIF_PUT_NOVALUE, bv.bv_val, NULL, 0 );
1634 
1635 		} else if ( bvals ) {
1636 			for ( i = 0; bvals[i].bv_val != NULL; i++ ) {
1637 				if ( vals2tmp > 1 || ( vals2tmp &&
1638 					ldif_is_not_printable( bvals[i].bv_val, bvals[i].bv_len )))
1639 				{
1640 					int tmpfd;
1641 					/* write value to file */
1642 					snprintf( tmpfname, sizeof tmpfname,
1643 						"%s" LDAP_DIRSEP "ldapsearch-%s-XXXXXX",
1644 						tmpdir, bv.bv_val );
1645 					tmpfp = NULL;
1646 
1647 					tmpfd = mkstemp( tmpfname );
1648 
1649 					if ( tmpfd < 0  ) {
1650 						perror( tmpfname );
1651 						continue;
1652 					}
1653 
1654 					if (( tmpfp = fdopen( tmpfd, "w")) == NULL ) {
1655 						perror( tmpfname );
1656 						continue;
1657 					}
1658 
1659 					if ( fwrite( bvals[ i ].bv_val,
1660 						bvals[ i ].bv_len, 1, tmpfp ) == 0 )
1661 					{
1662 						perror( tmpfname );
1663 						fclose( tmpfp );
1664 						continue;
1665 					}
1666 
1667 					fclose( tmpfp );
1668 
1669 					snprintf( url, sizeof url, "%s%s", urlpre,
1670 						&tmpfname[strlen(tmpdir) + sizeof(LDAP_DIRSEP) - 1] );
1671 
1672 					urlize( url );
1673 					tool_write_ldif( LDIF_PUT_URL, bv.bv_val, url, strlen( url ));
1674 
1675 				} else {
1676 					tool_write_ldif( LDIF_PUT_VALUE, bv.bv_val,
1677 						bvals[ i ].bv_val, bvals[ i ].bv_len );
1678 				}
1679 			}
1680 			ber_memfree( bvals );
1681 		}
1682 	}
1683 
1684 	if( ber != NULL ) {
1685 		ber_free( ber, 0 );
1686 	}
1687 }
1688 
1689 static void print_reference(
1690 	LDAP *ld,
1691 	LDAPMessage *reference )
1692 {
1693 	int rc;
1694 	char **refs = NULL;
1695 	LDAPControl **ctrls;
1696 
1697 	if( ldif < 2 ) {
1698 		printf(_("# search reference\n"));
1699 	}
1700 
1701 	rc = ldap_parse_reference( ld, reference, &refs, &ctrls, 0 );
1702 
1703 	if( rc != LDAP_SUCCESS ) {
1704 		tool_perror( "ldap_parse_reference", rc, NULL, NULL, NULL, NULL );
1705 		exit( EXIT_FAILURE );
1706 	}
1707 
1708 	if( refs ) {
1709 		int i;
1710 		for( i=0; refs[i] != NULL; i++ ) {
1711 			tool_write_ldif( ldif ? LDIF_PUT_COMMENT : LDIF_PUT_VALUE,
1712 				"ref", refs[i], strlen(refs[i]) );
1713 		}
1714 		ber_memvfree( (void **) refs );
1715 	}
1716 
1717 	if( ctrls ) {
1718 		tool_print_ctrls( ld, ctrls );
1719 		ldap_controls_free( ctrls );
1720 	}
1721 }
1722 
1723 static void print_extended(
1724 	LDAP *ld,
1725 	LDAPMessage *extended )
1726 {
1727 	int rc;
1728 	char *retoid = NULL;
1729 	struct berval *retdata = NULL;
1730 
1731 	if( ldif < 2 ) {
1732 		printf(_("# extended result response\n"));
1733 	}
1734 
1735 	rc = ldap_parse_extended_result( ld, extended,
1736 		&retoid, &retdata, 0 );
1737 
1738 	if( rc != LDAP_SUCCESS ) {
1739 		tool_perror( "ldap_parse_extended_result", rc, NULL, NULL, NULL, NULL );
1740 		exit( EXIT_FAILURE );
1741 	}
1742 
1743 	if ( ldif < 2 ) {
1744 		tool_write_ldif( ldif ? LDIF_PUT_COMMENT : LDIF_PUT_VALUE,
1745 			"extended", retoid, retoid ? strlen(retoid) : 0 );
1746 	}
1747 	ber_memfree( retoid );
1748 
1749 	if(retdata) {
1750 		if ( ldif < 2 ) {
1751 			tool_write_ldif( ldif ? LDIF_PUT_COMMENT : LDIF_PUT_BINARY,
1752 				"data", retdata->bv_val, retdata->bv_len );
1753 		}
1754 		ber_bvfree( retdata );
1755 	}
1756 
1757 	print_result( ld, extended, 0 );
1758 }
1759 
1760 static void print_partial(
1761 	LDAP *ld,
1762 	LDAPMessage *partial )
1763 {
1764 	int rc;
1765 	char *retoid = NULL;
1766 	struct berval *retdata = NULL;
1767 	LDAPControl **ctrls = NULL;
1768 
1769 	if( ldif < 2 ) {
1770 		printf(_("# extended partial response\n"));
1771 	}
1772 
1773 	rc = ldap_parse_intermediate( ld, partial,
1774 		&retoid, &retdata, &ctrls, 0 );
1775 
1776 	if( rc != LDAP_SUCCESS ) {
1777 		tool_perror( "ldap_parse_intermediate", rc, NULL, NULL, NULL, NULL );
1778 		exit( EXIT_FAILURE );
1779 	}
1780 
1781 	if ( ldif < 2 ) {
1782 		tool_write_ldif( ldif ? LDIF_PUT_COMMENT : LDIF_PUT_VALUE,
1783 			"partial", retoid, retoid ? strlen(retoid) : 0 );
1784 	}
1785 
1786 	ber_memfree( retoid );
1787 
1788 	if( retdata ) {
1789 		if ( ldif < 2 ) {
1790 			tool_write_ldif( ldif ? LDIF_PUT_COMMENT : LDIF_PUT_BINARY,
1791 				"data", retdata->bv_val, retdata->bv_len );
1792 		}
1793 
1794 		ber_bvfree( retdata );
1795 	}
1796 
1797 	if( ctrls ) {
1798 		tool_print_ctrls( ld, ctrls );
1799 		ldap_controls_free( ctrls );
1800 	}
1801 }
1802 
1803 static int print_result(
1804 	LDAP *ld,
1805 	LDAPMessage *result, int search )
1806 {
1807 	int rc;
1808 	int err;
1809 	char *matcheddn = NULL;
1810 	char *text = NULL;
1811 	char **refs = NULL;
1812 	LDAPControl **ctrls = NULL;
1813 
1814 	if( search ) {
1815 		if ( ldif < 2 ) {
1816 			printf(_("# search result\n"));
1817 		}
1818 		if ( ldif < 1 ) {
1819 			printf("%s: %d\n", _("search"), ldap_msgid(result) );
1820 		}
1821 	}
1822 
1823 	rc = ldap_parse_result( ld, result,
1824 		&err, &matcheddn, &text, &refs, &ctrls, 0 );
1825 
1826 	if( rc != LDAP_SUCCESS ) {
1827 		tool_perror( "ldap_parse_result", rc, NULL, NULL, NULL, NULL );
1828 		exit( EXIT_FAILURE );
1829 	}
1830 
1831 
1832 	if( !ldif ) {
1833 		printf( _("result: %d %s\n"), err, ldap_err2string(err) );
1834 
1835 	} else if ( err != LDAP_SUCCESS ) {
1836 		fprintf( stderr, "%s (%d)\n", ldap_err2string(err), err );
1837 	}
1838 
1839 	if( matcheddn ) {
1840 		if( *matcheddn ) {
1841 		if( !ldif ) {
1842 			tool_write_ldif( LDIF_PUT_VALUE,
1843 				"matchedDN", matcheddn, strlen(matcheddn) );
1844 		} else {
1845 			fprintf( stderr, _("Matched DN: %s\n"), matcheddn );
1846 		}
1847 		}
1848 
1849 		ber_memfree( matcheddn );
1850 	}
1851 
1852 	if( text ) {
1853 		if( *text ) {
1854 			if( !ldif ) {
1855 				if ( err == LDAP_PARTIAL_RESULTS ) {
1856 					char	*line;
1857 
1858 					for ( line = text; line != NULL; ) {
1859 						char	*next = strchr( line, '\n' );
1860 
1861 						tool_write_ldif( LDIF_PUT_TEXT,
1862 							"text", line,
1863 							next ? (size_t) (next - line) : strlen( line ));
1864 
1865 						line = next ? next + 1 : NULL;
1866 					}
1867 
1868 				} else {
1869 					tool_write_ldif( LDIF_PUT_TEXT, "text",
1870 						text, strlen(text) );
1871 				}
1872 			} else {
1873 				fprintf( stderr, _("Additional information: %s\n"), text );
1874 			}
1875 		}
1876 
1877 		ber_memfree( text );
1878 	}
1879 
1880 	if( refs ) {
1881 		int i;
1882 		for( i=0; refs[i] != NULL; i++ ) {
1883 			if( !ldif ) {
1884 				tool_write_ldif( LDIF_PUT_VALUE, "ref", refs[i], strlen(refs[i]) );
1885 			} else {
1886 				fprintf( stderr, _("Referral: %s\n"), refs[i] );
1887 			}
1888 		}
1889 
1890 		ber_memvfree( (void **) refs );
1891 	}
1892 
1893 	pr_morePagedResults = 0;
1894 
1895 	if( ctrls ) {
1896 		tool_print_ctrls( ld, ctrls );
1897 		ldap_controls_free( ctrls );
1898 	}
1899 
1900 	return err;
1901 }
1902 
1903