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