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