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