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