ldapsearch.c file

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