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