]> git.sur5r.net Git - openldap/blob - clients/tools/ldapsearch.c
Adjust -Z[Z] usage statements
[openldap] / clients / tools / ldapsearch.c
1 /* $OpenLDAP$ */
2 /*
3  * Copyright 1998-2000 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/signal.h>
15 #include <ac/string.h>
16 #include <ac/unistd.h>
17 #include <ac/errno.h>
18 #include <sys/stat.h>
19
20 #ifdef HAVE_FCNTL_H
21 #include <fcntl.h>
22 #endif
23 #ifdef HAVE_SYS_TYPES_H
24 #include <sys/types.h>
25 #endif
26 #ifdef HAVE_IO_H
27 #include <io.h>
28 #endif
29
30 #include <ldap.h>
31
32 #include "ldif.h"
33 #include "ldap_defaults.h"
34
35 #undef DEPSEP
36 #define DEFSEP          "="
37
38 static void
39 usage( const char *s )
40 {
41         fprintf( stderr,
42 "usage: %s [options] filter [attributes...]\nwhere:\n"
43 "       filter\tRFC-1558 compliant LDAP search filter\n"
44 "       attributes\twhitespace-separated list of attributes to retrieve\n"
45 "\t\t1.1                -- no attributes\n"
46 "\t\t*            -- all user attributes\n"
47 "\t\t+            -- all operational attributes\n"
48 "\t\tempty list -- all non-operational attributes\n"
49 "options:\n"
50 "       -a deref\tone of `never', `always', `search', or `find' (alias\n"
51 "               \tdereferencing)\n"
52 "       -A\t\tretrieve attribute names only (no values)\n"
53 "       -b basedn\tbase dn for search\n"
54 "       -d level\tset LDAP debugging level to `level'\n"
55 "       -D binddn\tbind DN\n"
56 "       -E\t\trequest SASL privacy (-EE to make it critical)\n"
57 "       -f file\t\tperform sequence of searches listed in `file'\n"
58 "       -h host\t\tLDAP server\n"
59 "       -I\t\trequest SASL integrity checking (-II to make it\n"
60 "               \tcritical)\n"
61 "       -k\t\tuse Kerberos authentication\n"
62 "       -K\t\tlike -k, but do only step 1 of the Kerberos bind\n"
63 "       -l limit\ttime limit (in seconds) for search\n"
64 "       -L\t\tprint entries in LDIF format (default)\n"
65 "       -LL\t\tprint entries in LDIF format without comments\n"
66 "       -LLL\t\tprint entries in LDIF format without comments and\n"
67 "               \tversion\n"
68 "       -M\t\tenable Manage DSA IT control (-MM to make critical)\n"
69 "       -n\t\tshow what would be done but don't actually search\n"
70 "       -p port\t\tport on LDAP server\n"
71 "       -P version\tprocotol version (2 or 3)\n"
72 "       -R\t\tdo not automatically follow referrals\n"
73 "       -s scope\tone of base, one, or sub (search scope)\n"
74 "       -S attr\t\tsort the results by attribute `attr'\n"
75 "       -t\t\twrite binary values to files in TMPDIR\n"
76 "       -tt\t\twrite all values to files in TMPDIR\n"
77 "       -T path\t\twrite files to directory specified by path (default:\n"
78 "               \t\"/tmp\")\n"
79 "       -u\t\tinclude User Friendly entry names in the output\n"
80 "       -U user\t\tSASL authentication identity (username)\n"
81 "       -v\t\trun in verbose mode (diagnostics to standard output)\n"
82 "       -V prefix\tURL prefix for files (default: \"file://tmp/\")\n"
83 "       -w passwd\tbind passwd (for simple authentication)\n"
84 "       -W\t\tprompt for bind passwd\n"
85 "       -X id\t\tSASL authorization identity (\"dn:<dn>\" or \"u:<user>\")\n"
86 "       -Y mech\t\tSASL mechanism\n"
87 "       -z limit\tsize limit (in entries) for search\n"
88 "       -Z\t\tissue Start TLS request (-ZZ to require successful response)\n"
89 ,               s );
90
91         exit( EXIT_FAILURE );
92 }
93
94 static void print_entry LDAP_P((
95         LDAP    *ld,
96         LDAPMessage     *entry,
97         int             attrsonly));
98
99 static int write_ldif LDAP_P((
100         int type,
101         char *name,
102         char *value,
103         ber_len_t vallen ));
104
105 static int dosearch LDAP_P((
106         LDAP    *ld,
107         char    *base,
108         int             scope,
109         char    **attrs,
110         int             attrsonly,
111         char    *filtpatt,
112         char    *value));
113
114 #define TMPDIR "/tmp"
115 #define URLPRE "file:/tmp/"
116
117 static char *tmpdir = NULL;
118 static char *urlpre = NULL;
119
120 static char     *binddn = NULL;
121 static struct berval passwd = { 0, NULL };
122 static char     *base = NULL;
123 static char     *ldaphost = NULL;
124 static int      ldapport = 0;
125 #ifdef HAVE_CYRUS_SASL
126 static char     *sasl_authc_id = NULL;
127 static char     *sasl_authz_id = NULL;
128 static char     *sasl_mech = NULL;
129 static int      sasl_integrity = 0;
130 static int      sasl_privacy = 0;
131 #endif
132 static int      use_tls = 0;
133 static char     *sep = DEFSEP;
134 static char     *sortattr = NULL;
135 static int      skipsortattr = 0;
136 static int      verbose, not, includeufn, binary, vals2tmp, ldif;
137
138 int
139 main( int argc, char **argv )
140 {
141         char            *infile, *filtpattern, **attrs, line[ BUFSIZ ];
142         FILE            *fp = NULL;
143         int                     rc, i, first, scope, deref, attrsonly, manageDSAit;
144         int                     referrals, timelimit, sizelimit, debug;
145         int             authmethod, version, want_bindpw;
146         LDAP            *ld;
147
148         infile = NULL;
149         debug = verbose = binary = not = vals2tmp =
150                 attrsonly = manageDSAit = ldif = want_bindpw = 0;
151
152         deref = sizelimit = timelimit = version = -1;
153
154         /* default should be off */
155         referrals = 1;
156
157         scope = LDAP_SCOPE_SUBTREE;
158         authmethod = LDAP_AUTH_SIMPLE;
159
160         while (( i = getopt( argc, argv,
161                 "Aa:Bb:D:d:EF:f:h:IKkLl:MnP:p:RS:s:T:tU:uV:vWw:X:Y:Zz:")) != EOF )
162         {
163         switch( i ) {
164         case 'n':       /* do Not do any searches */
165                 ++not;
166                 break;
167         case 'v':       /* verbose mode */
168                 ++verbose;
169                 break;
170         case 'd':
171                 debug |= atoi( optarg );
172                 break;
173         case 'k':       /* use kerberos bind */
174 #ifdef LDAP_API_FEATURE_X_OPENLDAP_V2_KBIND
175                 authmethod = LDAP_AUTH_KRBV4;
176 #else
177                 fprintf( stderr, "%s was not compiled with Kerberos support\n", argv[0] );
178                 return( EXIT_FAILURE );
179 #endif
180                 break;
181         case 'K':       /* use kerberos bind, 1st part only */
182 #ifdef LDAP_API_FEATURE_X_OPENLDAP_V2_KBIND
183                 authmethod = LDAP_AUTH_KRBV41;
184 #else
185                 fprintf( stderr, "%s was not compiled with Kerberos support\n", argv[0] );
186                 return( EXIT_FAILURE );
187 #endif
188                 break;
189                 break;
190         case 'u':       /* include UFN */
191                 ++includeufn;
192                 break;
193         case 't':       /* write attribute values to /tmp files */
194                 ++vals2tmp;
195                 break;
196         case 'M':
197                 /* enable Manage DSA IT */
198                 manageDSAit++;
199                 break;
200         case 'R':       /* don't automatically chase referrals */
201                 referrals = 0;
202                 break;
203         case 'A':       /* retrieve attribute names only -- no values */
204                 ++attrsonly;
205                 break;
206         case 'L':       /* print entries in LDIF format */
207                 ++ldif;
208                 /* fall through -- always allow binary when outputting LDIF */
209         case 'B':       /* allow binary values to be printed */
210                 ++binary;
211                 break;
212         case 's':       /* search scope */
213                 if ( strcasecmp( optarg, "base" ) == 0 ) {
214                 scope = LDAP_SCOPE_BASE;
215                 } else if ( strcasecmp( optarg, "one" ) == 0 ) {
216                 scope = LDAP_SCOPE_ONELEVEL;
217                 } else if ( strcasecmp( optarg, "sub" ) == 0 ) {
218                 scope = LDAP_SCOPE_SUBTREE;
219                 } else {
220                 fprintf( stderr, "scope should be base, one, or sub\n" );
221                 usage( argv[ 0 ] );
222                 }
223                 break;
224
225         case 'a':       /* set alias deref option */
226                 if ( strcasecmp( optarg, "never" ) == 0 ) {
227                 deref = LDAP_DEREF_NEVER;
228                 } else if ( strcasecmp( optarg, "search" ) == 0 ) {
229                 deref = LDAP_DEREF_SEARCHING;
230                 } else if ( strcasecmp( optarg, "find" ) == 0 ) {
231                 deref = LDAP_DEREF_FINDING;
232                 } else if ( strcasecmp( optarg, "always" ) == 0 ) {
233                 deref = LDAP_DEREF_ALWAYS;
234                 } else {
235                 fprintf( stderr, "alias deref should be never, search, find, or always\n" );
236                 usage( argv[ 0 ] );
237                 }
238                 break;
239                 
240         case 'T':       /* field separator */
241                 if( tmpdir ) free( tmpdir );
242                 tmpdir = strdup( optarg );
243                 break;
244         case 'V':       /* field separator */
245                 if( urlpre ) free( urlpre );
246                 urlpre = strdup( optarg );
247                 break;
248         case 'F':       /* field separator */
249                 sep = strdup( optarg );
250                 break;
251         case 'f':       /* input file */
252                 infile = strdup( optarg );
253                 break;
254         case 'h':       /* ldap host */
255                 ldaphost = strdup( optarg );
256                 break;
257         case 'b':       /* searchbase */
258                 base = strdup( optarg );
259                 break;
260         case 'D':       /* bind DN */
261                 binddn = strdup( optarg );
262                 break;
263         case 'p':       /* ldap port */
264                 ldapport = atoi( optarg );
265                 break;
266         case 'w':       /* bind password */
267                 passwd.bv_val = strdup( optarg );
268                 {
269                         char* p;
270
271                         for( p = optarg; *p == '\0'; p++ ) {
272                                 *p = '*';
273                         }
274                 }
275                 passwd.bv_len = strlen( passwd.bv_val );
276                 break;
277         case 'l':       /* time limit */
278                 timelimit = atoi( optarg );
279                 break;
280         case 'z':       /* size limit */
281                 sizelimit = atoi( optarg );
282                 break;
283         case 'S':       /* sort attribute */
284                 sortattr = strdup( optarg );
285                 break;
286         case 'W':
287                 want_bindpw++;
288                 break;
289         case 'P':
290                 switch( atoi( optarg ) )
291                 {
292                 case 2:
293                         version = LDAP_VERSION2;
294                         break;
295                 case 3:
296                         version = LDAP_VERSION3;
297                         break;
298                 default:
299                         fprintf( stderr, "protocol version should be 2 or 3\n" );
300                         usage( argv[0] );
301                 }
302                 break;
303         case 'I':
304 #ifdef HAVE_CYRUS_SASL
305                 sasl_integrity++;
306                 authmethod = LDAP_AUTH_SASL;
307 #else
308                 fprintf( stderr, "%s was not compiled with SASL support\n",
309                         argv[0] );
310                 return( EXIT_FAILURE );
311 #endif
312                 break;
313         case 'E':
314 #ifdef HAVE_CYRUS_SASL
315                 sasl_privacy++;
316                 authmethod = LDAP_AUTH_SASL;
317 #else
318                 fprintf( stderr, "%s was not compiled with SASL support\n",
319                         argv[0] );
320                 return( EXIT_FAILURE );
321 #endif
322                 break;
323         case 'Y':
324 #ifdef HAVE_CYRUS_SASL
325                 if ( strcasecmp( optarg, "any" ) && strcmp( optarg, "*" ) ) {
326                         sasl_mech = strdup( optarg );
327                 }
328                 authmethod = LDAP_AUTH_SASL;
329 #else
330                 fprintf( stderr, "%s was not compiled with SASL support\n",
331                         argv[0] );
332                 return( EXIT_FAILURE );
333 #endif
334                 break;
335         case 'U':
336 #ifdef HAVE_CYRUS_SASL
337                 sasl_authc_id = strdup( optarg );
338                 authmethod = LDAP_AUTH_SASL;
339 #else
340                 fprintf( stderr, "%s was not compiled with SASL support\n",
341                         argv[0] );
342                 return( EXIT_FAILURE );
343 #endif
344                 break;
345         case 'X':
346 #ifdef HAVE_CYRUS_SASL
347                 sasl_authz_id = strdup( optarg );
348                 authmethod = LDAP_AUTH_SASL;
349 #else
350                 fprintf( stderr, "%s was not compiled with SASL support\n",
351                         argv[0] );
352                 return( EXIT_FAILURE );
353 #endif
354                 break;
355         case 'Z':
356 #ifdef HAVE_TLS
357                 use_tls++;
358 #else
359                 fprintf( stderr, "%s was not compiled with TLS support\n",
360                         argv[0] );
361                 return( EXIT_FAILURE );
362 #endif
363                 break;
364         default:
365                 usage( argv[0] );
366         }
367         }
368
369 #define LDAP_LDIF 1
370 #ifdef LDAP_LDIF
371         /* no alternative format */
372         if( ldif == 0 ) ldif = 1;
373 #endif
374
375         if ( ( authmethod == LDAP_AUTH_KRBV4 ) || ( authmethod ==
376                         LDAP_AUTH_KRBV41 ) ) {
377                 if( version > LDAP_VERSION2 ) {
378                         fprintf( stderr, "Kerberos requires LDAPv2\n" );
379                         return( EXIT_FAILURE );
380                 }
381                 version = LDAP_VERSION2;
382         }
383         else if ( authmethod == LDAP_AUTH_SASL ) {
384                 if( version != -1 && version != LDAP_VERSION3 ) {
385                         fprintf( stderr, "SASL requires LDAPv3\n" );
386                         return( EXIT_FAILURE );
387                 }
388                 version = LDAP_VERSION3;
389         }
390
391         if( manageDSAit ) {
392                 if( version != -1 && version != LDAP_VERSION3 ) {
393                         fprintf(stderr, "manage DSA control requires LDAPv3\n");
394                         return EXIT_FAILURE;
395                 }
396                 version = LDAP_VERSION3;
397         }
398
399         if( use_tls ) {
400                 if( version != -1 && version != LDAP_VERSION3 ) {
401                         fprintf(stderr, "Start TLS requires LDAPv3\n");
402                         return EXIT_FAILURE;
403                 }
404                 version = LDAP_VERSION3;
405         }
406
407         if ( argc - optind < 1 ) {
408                 usage( argv[ 0 ] );
409         }
410
411         filtpattern = strdup( argv[ optind ] );
412
413         if ( argv[ optind + 1 ] == NULL ) {
414                 attrs = NULL;
415         } else if ( sortattr == NULL || *sortattr == '\0' ) {
416                 attrs = &argv[ optind + 1 ];
417         } else {
418                 for ( i = optind + 1; i < argc; i++ ) {
419                         if ( strcasecmp( argv[ i ], sortattr ) == 0 ) {
420                                 break;
421                         }
422                 }
423                 if ( i == argc ) {
424                         skipsortattr = 1;
425                         argv[ optind ] = sortattr;
426                 } else {
427                         optind++;
428                 }
429                 attrs = &argv[ optind ];
430         }
431
432         if ( infile != NULL ) {
433                 if ( infile[0] == '-' && infile[1] == '\0' ) {
434                         fp = stdin;
435                 } else if (( fp = fopen( infile, "r" )) == NULL ) {
436                         perror( infile );
437                         return EXIT_FAILURE;
438                 }
439         }
440
441         if( tmpdir == NULL
442                 && (tmpdir = getenv("TMPDIR")) == NULL
443                 && (tmpdir = getenv("TMP")) == NULL
444                 && (tmpdir = getenv("TEMP")) == NULL )
445         {
446                 tmpdir = "/tmp";
447         }
448
449         if( urlpre == NULL ) {
450                 urlpre = malloc( sizeof("file:////") + strlen(tmpdir) );
451
452                 if( urlpre == NULL ) {
453                         perror( "malloc" );
454                         return EXIT_FAILURE;
455                 }
456
457                 sprintf( urlpre, "file:///%s/",
458                         tmpdir[0] == '/' ? &tmpdir[1] : tmpdir );
459
460                 /* urlpre should be URLized.... */
461         }
462
463         if ( debug ) {
464                 if( ber_set_option( NULL, LBER_OPT_DEBUG_LEVEL, &debug ) != LBER_OPT_SUCCESS ) {
465                         fprintf( stderr, "Could not set LBER_OPT_DEBUG_LEVEL %d\n", debug );
466                 }
467                 if( ldap_set_option( NULL, LDAP_OPT_DEBUG_LEVEL, &debug ) != LDAP_OPT_SUCCESS ) {
468                         fprintf( stderr, "Could not set LDAP_OPT_DEBUG_LEVEL %d\n", debug );
469                 }
470                 ldif_debug = debug;
471         }
472
473 #ifdef SIGPIPE
474         (void) SIGNAL( SIGPIPE, SIG_IGN );
475 #endif
476
477         if ( verbose ) {
478                 fprintf( stderr,
479                         (ldapport ? "ldap_init( %s, %d )\n" : "ldap_init( %s, <DEFAULT> )\n"),
480                         (ldaphost != NULL) ? ldaphost : "<DEFAULT>",
481                         ldapport );
482         }
483
484         if (( ld = ldap_init( ldaphost, ldapport )) == NULL ) {
485                 perror( "ldap_init" );
486                 return( EXIT_FAILURE );
487         }
488
489         if (deref != -1 &&
490                 ldap_set_option( ld, LDAP_OPT_DEREF, (void *) &deref ) != LDAP_OPT_SUCCESS )
491         {
492                 fprintf( stderr, "Could not set LDAP_OPT_DEREF %d\n", deref );
493         }
494         if (timelimit != -1 &&
495                 ldap_set_option( ld, LDAP_OPT_TIMELIMIT, (void *) &timelimit ) != LDAP_OPT_SUCCESS )
496         {
497                 fprintf( stderr, "Could not set LDAP_OPT_TIMELIMIT %d\n", timelimit );
498         }
499         if (sizelimit != -1 &&
500                 ldap_set_option( ld, LDAP_OPT_SIZELIMIT, (void *) &sizelimit ) != LDAP_OPT_SUCCESS )
501         {
502                 fprintf( stderr, "Could not set LDAP_OPT_SIZELIMIT %d\n", sizelimit );
503         }
504         if (referrals != -1 &&
505                 ldap_set_option( ld, LDAP_OPT_REFERRALS,
506                                  (referrals ? LDAP_OPT_ON : LDAP_OPT_OFF) ) != LDAP_OPT_SUCCESS )
507         {
508                 fprintf( stderr, "Could not set LDAP_OPT_REFERRALS %s\n",
509                         referrals ? "on" : "off" );
510         }
511
512         if (version != -1 &&
513                 ldap_set_option( ld, LDAP_OPT_PROTOCOL_VERSION, &version ) != LDAP_OPT_SUCCESS )
514         {
515                 fprintf( stderr, "Could not set LDAP_OPT_PROTOCOL_VERSION %d\n", version );
516         }
517
518         if ( use_tls && ldap_start_tls_s( ld, NULL, NULL ) != LDAP_SUCCESS ) {
519                 if ( use_tls > 1 ) {
520                         ldap_perror( ld, "ldap_start_tls" );
521                         return( EXIT_FAILURE );
522                 }
523         }
524
525         if (want_bindpw) {
526                 passwd.bv_val = getpassphrase("Enter LDAP Password: ");
527                 passwd.bv_len = strlen( passwd.bv_val );
528         }
529
530         if ( authmethod == LDAP_AUTH_SASL ) {
531 #ifdef HAVE_CYRUS_SASL
532                 int     minssf = 0, maxssf = 0;
533
534                 if ( sasl_integrity > 0 )
535                         maxssf = 1;
536                 if ( sasl_integrity > 1 )
537                         minssf = 1;
538                 if ( sasl_privacy > 0 )
539                         maxssf = 100000; /* Something big value */
540                 if ( sasl_privacy > 1 )
541                         minssf = 56;
542                 
543                 if ( ldap_set_option( ld, LDAP_OPT_X_SASL_MINSSF,
544                                 (void *)&minssf ) != LDAP_OPT_SUCCESS ) {
545                         fprintf( stderr, "Could not set LDAP_OPT_X_SASL_MINSSF"
546                                 "%d\n", minssf);
547                         return( EXIT_FAILURE );
548                 }
549                 if ( ldap_set_option( ld, LDAP_OPT_X_SASL_MAXSSF,
550                                 (void *)&maxssf ) != LDAP_OPT_SUCCESS ) {
551                         fprintf( stderr, "Could not set LDAP_OPT_X_SASL_MAXSSF"
552                                 "%d\n", maxssf);
553                         return( EXIT_FAILURE );
554                 }
555                 
556                 rc = ldap_negotiated_sasl_bind_s( ld, binddn, sasl_authc_id,
557                                 sasl_authz_id, sasl_mech,
558                                 passwd.bv_len ? &passwd : NULL,
559                                 NULL, NULL );
560
561                 if( rc != LDAP_SUCCESS ) {
562                         ldap_perror( ld, "ldap_negotiated_sasl_bind_s" );
563                         return( EXIT_FAILURE );
564                 }
565 #else
566                 fprintf( stderr, "%s was not compiled with SASL support\n",
567                         argv[0] );
568                 return( EXIT_FAILURE );
569 #endif
570         }
571         else {
572                 if ( ldap_bind_s( ld, binddn, passwd.bv_val, authmethod )
573                                 != LDAP_SUCCESS ) {
574                         ldap_perror( ld, "ldap_bind" );
575                         return( EXIT_FAILURE );
576                 }
577         }
578
579         if ( manageDSAit ) {
580                 int err;
581                 LDAPControl c;
582                 LDAPControl *ctrls[2];
583                 ctrls[0] = &c;
584                 ctrls[1] = NULL;
585
586                 c.ldctl_oid = LDAP_CONTROL_MANAGEDSAIT;
587                 c.ldctl_value.bv_val = NULL;
588                 c.ldctl_value.bv_len = 0;
589                 c.ldctl_iscritical = manageDSAit > 1;
590
591                 err = ldap_set_option( ld, LDAP_OPT_SERVER_CONTROLS, &ctrls );
592
593                 if( err != LDAP_OPT_SUCCESS ) {
594                         fprintf( stderr, "Could not set Manage DSA IT Control\n" );
595                         if( c.ldctl_iscritical ) {
596                                 exit( EXIT_FAILURE );
597                         }
598                 }
599         }
600
601         if ( verbose ) {
602                 fprintf( stderr, "filter%s: %s\nreturning: ",
603                         infile != NULL ? " pattern" : "",
604                         filtpattern );
605
606                 if ( attrs == NULL ) {
607                         fprintf( stderr, "ALL" );
608                 } else {
609                         for ( i = 0; attrs[ i ] != NULL; ++i ) {
610                                 fprintf( stderr, "%s ", attrs[ i ] );
611                         }
612                 }
613                 fprintf( stderr, "\n" );
614         }
615
616         if ( ldif ) {
617                 if (ldif < 3 ) {
618                         printf( "version: 1\n\n");
619                 }
620
621                 if (ldif < 2 ) {
622                         printf( "#\n# filter%s: %s\n# returning: ",
623                                 infile != NULL ? " pattern" : "",
624                                 filtpattern );
625
626                         if ( attrs == NULL ) {
627                                 printf( "ALL" );
628                         } else {
629                                 for ( i = 0; attrs[ i ] != NULL; ++i ) {
630                                         printf( "%s ", attrs[ i ] );
631                                 }
632                         }
633                         printf( "\n#\n\n" );
634                 }
635         }
636
637         if ( infile == NULL ) {
638                 rc = dosearch( ld, base, scope, attrs, attrsonly, NULL, filtpattern );
639
640         } else {
641                 rc = 0;
642                 first = 1;
643                 while ( rc == 0 && fgets( line, sizeof( line ), fp ) != NULL ) {
644                         line[ strlen( line ) - 1 ] = '\0';
645                         if ( !first ) {
646                                 putchar( '\n' );
647                         } else {
648                                 first = 0;
649                         }
650                         rc = dosearch( ld, base, scope, attrs, attrsonly,
651                                 filtpattern, line );
652                 }
653                 if ( fp != stdin ) {
654                         fclose( fp );
655                 }
656         }
657
658         ldap_unbind( ld );
659         return( rc );
660 }
661
662
663 static int dosearch(
664         LDAP    *ld,
665         char    *base,
666         int             scope,
667         char    **attrs,
668         int             attrsonly,
669         char    *filtpatt,
670         char    *value)
671 {
672         char            filter[ BUFSIZ ];
673         int                     rc, first, matches;
674         LDAPMessage             *res, *e;
675
676         if( filtpatt != NULL ) {
677                 sprintf( filter, filtpatt, value );
678
679                 if ( verbose ) {
680                         fprintf( stderr, "filter is: (%s)\n", filter );
681                 }
682
683                 if( ldif == 1 ) {
684                         printf( "#\n# filter: %s\n#\n", filter );
685                 }
686
687         } else {
688                 sprintf( filter, "%s", value );
689         }
690
691         if ( not ) {
692                 return( LDAP_SUCCESS );
693         }
694
695         if ( ldap_search( ld, base, scope, filter, attrs, attrsonly ) == -1 ) {
696                 int ld_errno;
697                 ldap_perror( ld, "ldap_search" );
698
699                 ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, &ld_errno);
700                 return( ld_errno );
701         }
702
703         matches = 0;
704         first = 1;
705         res = NULL;
706         while ( (rc = ldap_result( ld, LDAP_RES_ANY, sortattr ? 1 : 0, NULL, &res ))
707                 == LDAP_RES_SEARCH_ENTRY ) {
708         matches++;
709         e = ldap_first_entry( ld, res );
710         if ( !first ) {
711                 putchar( '\n' );
712         } else {
713                 first = 0;
714         }
715         print_entry( ld, e, attrsonly );
716         ldap_msgfree( res );
717         res = NULL;
718         }
719         if ( rc == -1 ) {
720         ldap_perror( ld, "ldap_result" );
721         return( rc );
722         }
723         if (( rc = ldap_result2error( ld, res, 0 )) != LDAP_SUCCESS ) {
724                 ldap_perror( ld, "ldap_search" );
725         }
726         if ( sortattr != NULL ) {
727                 (void) ldap_sort_entries( ld, &res,
728                         ( *sortattr == '\0' ) ? NULL : sortattr, strcasecmp );
729                 matches = 0;
730                 first = 1;
731                 for ( e = ldap_first_entry( ld, res ); e != NULL;
732                         e = ldap_next_entry( ld, e ) ) {
733                 matches++;
734                 if ( !first ) {
735                         putchar( '\n' );
736                 } else {
737                         first = 0;
738                 }
739                 print_entry( ld, e, attrsonly );
740                 }
741         }
742
743         if ( verbose ) {
744                 printf( "%d matches\n", matches );
745         }
746
747         ldap_msgfree( res );
748         return( rc );
749 }
750
751
752 static void
753 print_entry(
754         LDAP    *ld,
755         LDAPMessage     *entry,
756         int             attrsonly)
757 {
758         char            *a, *dn, *ufn;
759         char    tmpfname[ 256 ];
760         char    url[ 256 ];
761         int                     i;
762         BerElement              *ber = NULL;
763         struct berval   **bvals;
764         FILE            *tmpfp;
765
766         dn = ldap_get_dn( ld, entry );
767         ufn = NULL;
768
769         if ( ldif == 1 ) {
770                 ufn = ldap_dn2ufn( dn );
771                 write_ldif( LDIF_PUT_COMMENT, NULL, ufn, strlen( ufn ));
772         }
773         if ( ldif ) {
774                 write_ldif( LDIF_PUT_VALUE, "dn", dn, strlen( dn ));
775         } else {
776                 printf( "%s\n", dn );
777         }
778
779         if ( includeufn ) {
780                 if( ufn == NULL ) {
781                         ufn = ldap_dn2ufn( dn );
782                 }
783                 if ( ldif ) {
784                         write_ldif( LDIF_PUT_VALUE, "ufn", ufn, strlen( ufn ));
785                 } else {
786                         printf( "%s\n", ufn );
787                 }
788         }
789
790         if( ufn != NULL ) ldap_memfree( ufn );
791         ldap_memfree( dn );
792
793         for ( a = ldap_first_attribute( ld, entry, &ber ); a != NULL;
794                 a = ldap_next_attribute( ld, entry, ber ) )
795         {
796                 if ( skipsortattr && strcasecmp( a, sortattr ) == 0 ) {
797                         continue;
798                 }
799
800                 if ( attrsonly ) {
801                         if ( ldif ) {
802                                 write_ldif( LDIF_PUT_NOVALUE, a, NULL, 0 );
803                         } else {
804                                 printf( "%s\n", a );
805                         }
806
807                 } else if (( bvals = ldap_get_values_len( ld, entry, a )) != NULL ) {
808                         for ( i = 0; bvals[i] != NULL; i++ ) {
809                                 if ( vals2tmp > 1 || ( vals2tmp
810                                         && ldif_is_not_printable( bvals[i]->bv_val, bvals[i]->bv_len ) ))
811                                 {
812                                         int tmpfd;
813                                         /* write value to file */
814                                         sprintf( tmpfname, "%s" LDAP_DIRSEP "ldapsearch-%s-XXXXXX",
815                                                 tmpdir, a );
816                                         tmpfp = NULL;
817
818                                         if ( mktemp( tmpfname ) == NULL ) {
819                                                 perror( tmpfname );
820                                                 continue;
821                                         }
822
823                                         if (( tmpfd = open( tmpfname, O_WRONLY|O_CREAT|O_EXCL, 0600 )) == -1 ) {
824                                                 perror( tmpfname );
825                                                 continue;
826                                         }
827
828                                         if (( tmpfp = fdopen( tmpfd, "w")) == NULL ) {
829                                                 perror( tmpfname );
830                                                 continue;
831                                         }
832
833                                         if ( fwrite( bvals[ i ]->bv_val,
834                                                 bvals[ i ]->bv_len, 1, tmpfp ) == 0 )
835                                         {
836                                                 perror( tmpfname );
837                                                 fclose( tmpfp );
838                                                 continue;
839                                         }
840
841                                         fclose( tmpfp );
842
843                                         sprintf( url, "%s%s", urlpre,
844                                                 &tmpfname[strlen(tmpdir) + sizeof(LDAP_DIRSEP) - 1] );
845
846                                         if ( ldif ) {
847                                                 write_ldif( LDIF_PUT_URL, a, url, strlen( url ));
848                                         } else {
849                                                 printf( "%s%s%s\n", a, sep, url );
850                                         }
851
852
853                                 } else {
854                                         if ( ldif ) {
855                                                 write_ldif( LDIF_PUT_VALUE, a,
856                                                         bvals[ i ]->bv_val, bvals[ i ]->bv_len );
857
858                                         } else {
859                                                 int notprint = !binary && !vals2tmp
860                                                         && ldif_is_not_printable( bvals[i]->bv_val,
861                                                                 bvals[i]->bv_len ); 
862                                                 printf( "%s%s", a, sep );
863                                                 puts( notprint ? "NOT PRINTABLE" : bvals[ i ]->bv_val );
864                                         }
865                                 }
866                         }
867                         ber_bvecfree( bvals );
868                 }
869         }
870
871         if( ber != NULL ) {
872                 ber_free( ber, 0 );
873         }
874 }
875
876
877 static int
878 write_ldif( int type, char *name, char *value, ber_len_t vallen )
879 {
880         char    *ldif;
881
882         if (( ldif = ldif_put( type, name, value, vallen )) == NULL ) {
883                 return( -1 );
884         }
885
886         fputs( ldif, stdout );
887         ber_memfree( ldif );
888
889         return( 0 );
890 }