2 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
3 * Use is subject to license terms.
7 * The contents of this file are subject to the Netscape Public
8 * License Version 1.1 (the "License"); you may not use this file
9 * except in compliance with the License. You may obtain a copy of
10 * the License at http://www.mozilla.org/NPL/
12 * Software distributed under the License is distributed on an "AS
13 * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
14 * implied. See the License for the specific language governing
15 * rights and limitations under the License.
17 * The Original Code is Mozilla Communicator client code, released
20 * The Initial Developer of the Original Code is Netscape
21 * Communications Corporation. Portions created by Netscape are
22 * Copyright (C) 1998-1999 Netscape Communications Corporation. All
28 /* ldapsearch.c - generic program to search LDAP */
32 #ifdef SOLARIS_LDAP_CMD
34 #include "solaris-int.h"
35 #endif /* SOLARIS_LDAP_CMD */
37 #define VLV_PARAM_SEP ':'
39 #ifndef SOLARIS_LDAP_CMD
43 static void usage( void );
44 static int dosearch( LDAP
*ld
, char *base
, int scope
, char **attrs
,
45 int attrsonly
, char *filtpatt
, char *value
);
46 static void write_string_attr_value( char *attrname
, char *strval
,
48 #define LDAPTOOL_WRITEVALOPT_SUPPRESS_NAME 0x01
49 static int write_ldif_value( char *type
, char *value
, unsigned long vallen
,
50 unsigned long ldifoptions
);
51 static void print_entry( LDAP
*ld
, LDAPMessage
*entry
, int attrsonly
);
52 static void options_callback( int option
, char *optarg
);
53 static void parse_and_display_reference( LDAP
*ld
, LDAPMessage
*ref
);
54 static char *sortresult2string(unsigned long result
);
55 static char *changetype_num2string( int chgtype
);
56 static char *msgtype2str( int msgtype
);
57 static char **get_effectiverights_attrlist(char * optarg
);
59 #ifdef SOLARIS_LDAP_CMD
60 static void fill_ldapsearch_msgtypes( void );
61 #endif /* SOLARIS_LDAP_CMD */
64 * Prefix used in names of pseudo attributes added to the entry LDIF
65 * output if we receive an entryChangeNotification control with an entry
66 * (requested using persistent search).
68 #define LDAPTOOL_PSEARCH_ATTR_PREFIX "persistentSearch-"
74 fprintf( stderr
, gettext("usage: %s -b basedn [options] filter [attributes...]\n"), ldaptool_progname
);
75 fprintf( stderr
, gettext(" %s -b basedn [options] -f file [attributes...]\nwhere:\n"), ldaptool_progname
);
76 fprintf( stderr
, gettext(" basedn\tbase dn for search\n") );
77 fprintf( stderr
, gettext("\t\t(if the environment variable LDAP_BASEDN is set,\n") );
78 fprintf( stderr
, gettext("\t\tthen the -b flag is not required)\n") );
79 fprintf( stderr
, gettext(" filter\tRFC-2254 compliant LDAP search filter\n") );
80 fprintf( stderr
, gettext(" file\tfile containing a sequence of LDAP search filters to use\n") );
81 fprintf( stderr
, gettext(" attributes\twhitespace-separated list of attributes to retrieve\n") );
82 fprintf( stderr
, gettext("\t\t(if no attribute list is given, all are retrieved)\n") );
83 fprintf( stderr
, gettext("options:\n") );
84 ldaptool_common_usage( 0 );
85 #if defined( XP_WIN32 )
86 fprintf( stderr
, gettext(" -t\t\twrite values to files in temp directory.\n") );
88 fprintf( stderr
, gettext(" -t\t\twrite values to files in /tmp\n") );
90 fprintf( stderr
, gettext(" -U\t\tproduce file URLs in conjunction with -t\n") );
91 fprintf( stderr
, gettext(" -e\t\tminimize base-64 encoding of values\n") );
92 fprintf( stderr
, gettext(" -u\t\tinclude User Friendly entry names in the output\n") );
93 #ifndef HAVE_SASL_OPTIONS
94 fprintf( stderr
, gettext(" -o\t\tprint entries using old format (default is LDIF)\n") );
96 fprintf( stderr
, gettext(" -T\t\tdon't fold (wrap) long lines (default is to fold)\n") );
97 fprintf( stderr
, gettext(" -1\t\tomit leading \"version: %d\" line in LDIF output\n"), LDIF_VERSION_ONE
);
98 fprintf( stderr
, gettext(" -A\t\tretrieve attribute names only (no values)\n") );
99 fprintf( stderr
, gettext(" -B\t\tprint non-ASCII values and use old output format (attr=value)\n") );
100 fprintf( stderr
, gettext(" -x\t\tperforming sorting on server\n") );
101 #ifdef SOLARIS_LDAP_CMD
102 fprintf( stderr
, gettext(" -r\t\tprint entries using old format (default is LDIF)\n") );
103 #endif /* SOLARIS_LDAP_CMD */
104 fprintf( stderr
, gettext(" -F sep\tprint `sep' instead of `%s' between attribute names\n"), LDAPTOOL_DEFSEP
);
105 fprintf( stderr
, gettext(" \tand values\n") );
106 fprintf( stderr
, gettext(" -S attr\tsort the results by attribute `attr'\n") );
107 fprintf( stderr
, gettext(" -s scope\tone of base, one, or sub (default is sub)\n") );
108 fprintf( stderr
, gettext(" -a deref\tone of never, always, search, or find (default: never)\n") );
109 fprintf( stderr
, gettext(" \t(alias dereferencing)\n") );
110 fprintf( stderr
, gettext(" -l timelim\ttime limit (in seconds) for search (default is no limit)\n") );
111 fprintf( stderr
, gettext(" -z sizelim\tsize limit (in entries) for search (default is no limit)\n") );
112 fprintf( stderr
, gettext(" -C ps:changetype[:changesonly[:entrychgcontrols]]\n") );
113 fprintf( stderr
, gettext("\t\tchangetypes are add,delete,modify,moddn,any\n") );
114 fprintf( stderr
, gettext("\t\tchangesonly and entrychgcontrols are boolean values\n") );
115 fprintf( stderr
, gettext("\t\t(default is 1)\n") );
116 fprintf( stderr
, gettext(" -G before%cafter%cindex%ccount | before%cafter%cvalue where 'before' and\n"), VLV_PARAM_SEP
, VLV_PARAM_SEP
, VLV_PARAM_SEP
, VLV_PARAM_SEP
, VLV_PARAM_SEP
);
117 fprintf( stderr
, gettext("\t\t'after' are the number of entries surrounding 'index.'\n"));
118 fprintf( stderr
, gettext("\t\t'count' is the content count, 'value' is the search value.\n"));
119 #ifndef SOLARIS_LDAP_CMD
120 fprintf( stderr
, gettext(" -c authzid\tspecifies the getEffectiveRights control authzid\n"));
121 fprintf( stderr
, gettext("\t\t eg. dn:uid=bjensen,dc=example,dc=com\n"));
122 fprintf( stderr
, gettext("\t\t A value of \"\" means \"the authorization id for the operation\".\n"));
123 fprintf( stderr
, gettext("\t\t A value of \"dn:\" means \"anonymous\"\n"));
124 fprintf( stderr
, gettext("\t\t (The aclRights operational attribute must be requested)\n"));
125 fprintf( stderr
, gettext(" -X attrlist\tspecifies the getEffectiveRights control specific attribute list.\n"));
126 fprintf( stderr
, gettext("\t\t eg. \"nsroledn userPassword\"\n"));
127 #endif /* SOLARIS_LDAP_CMD */
129 exit( LDAP_PARAM_ERROR
);
132 static char *base
= NULL
;
133 static char *sep
= LDAPTOOL_DEFSEP
;
134 static char **sortattr
= NULL
;
135 static char *vlv_value
= NULL
;
136 static int sortsize
= 0;
137 static int *skipsortattr
= NULL
;
138 static int includeufn
, allow_binary
, vals2tmp
, ldif
, scope
, deref
;
139 static int attrsonly
, timelimit
, sizelimit
, server_sort
, fold
;
140 static int minimize_base64
, produce_file_urls
;
141 static int use_vlv
= 0, vlv_before
, vlv_after
, vlv_index
, vlv_count
;
142 static int use_psearch
=0;
143 static int write_ldif_version
= 1;
144 #ifndef SOLARIS_LDAP_CMD
145 static char *get_effectiverights_control_target_dn
= NULL
; /* -c */
146 static char **get_effectiverights_control_attrlist
= NULL
; /* -X */
147 static int do_effective_rights_control
= 0;
148 #endif /* SOLARIS_LDAP_CMD */
150 /* Persistent search variables */
151 static int chgtype
=0, changesonly
=1, return_echg_ctls
=1;
155 main( int argc
, char **argv
)
157 char *filtpattern
, **attrs
;
158 int rc
, optind
, i
, first
, free_filtpattern
;
161 #ifdef SOLARIS_LDAP_CMD
162 char *locale
= setlocale(LC_ALL
, "");
163 textdomain(TEXT_DOMAIN
);
164 ldaptool_require_binddn
= 0;
165 #endif /* SOLARIS_LDAP_CMD */
167 free_filtpattern
= 0;
168 deref
= LDAP_DEREF_NEVER
;
169 allow_binary
= vals2tmp
= attrsonly
= 0;
170 minimize_base64
= produce_file_urls
= 0;
173 sizelimit
= timelimit
= 0;
174 scope
= LDAP_SCOPE_SUBTREE
;
187 ldaptool_reset_control_array( ldaptool_request_ctrls
);
188 #ifdef HAVE_SASL_OPTIONS
189 #ifdef SOLARIS_LDAP_CMD
190 optind
= ldaptool_process_args( argc
, argv
, "ABLTU1etuxra:b:F:G:l:S:s:z:C:",
191 0, options_callback
);
193 optind
= ldaptool_process_args( argc
, argv
, "ABLTU1etuxa:b:F:G:l:S:s:z:C:c:",
194 0, options_callback
);
195 #endif /* SOLARIS_LDAP_CMD */
197 optind
= ldaptool_process_args( argc
, argv
, "ABLTU1eotuxa:b:F:G:l:S:s:z:C:c:",
198 0, options_callback
);
199 #endif /* HAVE_SASL_OPTIONS */
201 if ( optind
== -1 ) {
205 if ( base
== NULL
) {
206 if (( base
= getenv( "LDAP_BASEDN" )) == NULL
) {
211 for ( sortsize
= 0; sortattr
[sortsize
] != NULL
; sortsize
++ ) {
214 sortsize
++; /* add in the final NULL field */
215 skipsortattr
= (int *) malloc( sortsize
* sizeof(int *) );
216 if ( skipsortattr
== NULL
) {
217 fprintf( stderr
, gettext("Out of memory\n") );
218 exit( LDAP_NO_MEMORY
);
220 memset( (char *) skipsortattr
, 0, sortsize
* sizeof(int *) );
221 } else if ( server_sort
) {
222 server_sort
= 0; /* ignore this option if no sortattrs were given */
225 if ( argc
- optind
< 1 ) {
226 if ( ldaptool_fp
== NULL
) {
231 } else { /* there are additional args (filter + attrs) */
232 if ( ldaptool_fp
== NULL
|| strstr( argv
[ optind
], "%s" ) != NULL
) {
233 filtpattern
= ldaptool_local2UTF8( argv
[ optind
] );
234 /* since local2UTF8 always allocates something, we should free it */
235 free_filtpattern
= 1;
241 if ( argv
[ optind
] == NULL
) {
243 } else if ( sortattr
== NULL
|| *sortattr
== '\0' || server_sort
) {
244 attrs
= &argv
[ optind
];
246 attrs
= ldap_charray_dup( &argv
[ optind
] );
247 if ( attrs
== NULL
) {
248 fprintf( stderr
, gettext("Out of memory\n") );
249 exit( LDAP_NO_MEMORY
);
251 for ( i
= 0; i
< (sortsize
- 1); i
++ ) {
252 if ( !ldap_charray_inlist( attrs
, sortattr
[i
] ) ) {
253 if ( ldap_charray_add( &attrs
, sortattr
[i
] ) != 0 ) {
254 fprintf( stderr
, gettext("Out of memory\n") );
255 exit( LDAP_NO_MEMORY
);
258 * attribute in the search list only for the purpose of
267 ld
= ldaptool_ldap_init( 0 );
269 if ( !ldaptool_not
) {
270 ldap_set_option( ld
, LDAP_OPT_DEREF
, &deref
);
271 ldap_set_option( ld
, LDAP_OPT_TIMELIMIT
, &timelimit
);
272 ldap_set_option( ld
, LDAP_OPT_SIZELIMIT
, &sizelimit
);
277 if ( ldaptool_verbose
) {
278 printf( gettext("filter pattern: %s\nreturning: "), filtpattern
);
279 if ( attrs
== NULL
) {
280 printf( gettext("ALL") );
282 for ( i
= 0; attrs
[ i
] != NULL
; ++i
) {
283 printf( "%s ", attrs
[ i
] );
289 if ( ldaptool_fp
== NULL
) {
292 conv
= ldaptool_local2UTF8( base
);
293 rc
= dosearch( ld
, conv
, scope
, attrs
, attrsonly
, filtpattern
, "" );
300 while ( rc
== LDAP_SUCCESS
&& !done
) {
305 /* allocate initial block of memory */
306 if ((linep
= (char *)malloc(BUFSIZ
)) == NULL
) {
307 fprintf( stderr
, gettext("Out of memory\n") );
308 exit( LDAP_NO_MEMORY
);
312 while ((c
= fgetc( ldaptool_fp
)) != '\n' && c
!= EOF
) {
314 /* check if we will overflow the buffer */
315 if ((c
!= EOF
) && (index
== ((increment
* BUFSIZ
) -1))) {
317 /* if we did, add another BUFSIZ worth of bytes */
318 if ((linep
= (char *)
319 reallocarray(linep
, increment
+ 1, BUFSIZ
)) == NULL
) {
320 fprintf( stderr
, gettext("Out of memory\n") );
321 exit( LDAP_NO_MEMORY
);
340 rc
= dosearch( ld
, base
, scope
, attrs
, attrsonly
, filtpattern
,
346 ldaptool_cleanup( ld
);
347 if (free_filtpattern
!= 0 && filtpattern
!= NULL
) {
351 /* check for and report output error */
353 rc
= ldaptool_check_ferror( stdout
, rc
,
354 gettext("output error (output might be incomplete)") );
360 options_callback( int option
, char *optarg
)
362 char *s
, *temp_arg
, *ps_ptr
, *ps_arg
;
365 case 'u': /* include UFN */
368 case 't': /* write attribute values to /tmp files */
371 case 'U': /* produce file URLs in conjunction with -t */
374 case 'e': /* minimize base-64 encoding of values */
377 case 'A': /* retrieve attribute names only -- no values */
380 case 'L': /* print entries in LDIF format -- now the default */
382 #ifdef SOLARIS_LDAP_CMD
383 case 'r': /* print entries in the old format */
386 #endif /* SOLARIS_LDAP_CMD */
387 #ifdef HAVE_SASL_OPTIONS
388 #ifdef HAVE_SASL_OPTIONS_2
389 case 'o': /* print entries using old ldapsearch format */
394 case 'o': /* print entries using old ldapsearch format */
398 case 'B': /* allow binary values to be printed, use old format */
402 case '1': /* omit leading "version: #" line from LDIF output */
403 write_ldif_version
= 0;
405 case 's': /* search scope */
406 if ( strncasecmp( optarg
, "base", 4 ) == 0 ) {
407 scope
= LDAP_SCOPE_BASE
;
408 } else if ( strncasecmp( optarg
, "one", 3 ) == 0 ) {
409 scope
= LDAP_SCOPE_ONELEVEL
;
410 } else if ( strncasecmp( optarg
, "sub", 3 ) == 0 ) {
411 scope
= LDAP_SCOPE_SUBTREE
;
413 fprintf( stderr
, gettext("scope should be base, one, or sub\n") );
418 case 'a': /* set alias deref option */
419 if ( strncasecmp( optarg
, "never", 5 ) == 0 ) {
420 deref
= LDAP_DEREF_NEVER
;
421 } else if ( strncasecmp( optarg
, "search", 5 ) == 0 ) {
422 deref
= LDAP_DEREF_SEARCHING
;
423 } else if ( strncasecmp( optarg
, "find", 4 ) == 0 ) {
424 deref
= LDAP_DEREF_FINDING
;
425 } else if ( strncasecmp( optarg
, "always", 6 ) == 0 ) {
426 deref
= LDAP_DEREF_ALWAYS
;
428 fprintf( stderr
, gettext("alias deref should be never, search, find, or always\n") );
433 case 'F': /* field separator */
434 sep
= strdup( optarg
);
437 #ifndef SOLARIS_LDAP_CMD
439 if ( optarg
&& optarg
[0] == '\0' ) {
443 get_effectiverights_control_target_dn
= NULL
;
444 do_effective_rights_control
= 1;
445 }else if ( strlen(optarg
) < 3 || (strncasecmp(optarg
, "dn:", 3) != 0) ) {
446 fprintf(stderr
, gettext("-c wrong format--should be \"\" or \"dn:...\".\n"
447 "\"dn:\" means anonymous user."));
450 get_effectiverights_control_target_dn
= strdup(optarg
);
451 do_effective_rights_control
= 1;
455 get_effectiverights_control_attrlist
= get_effectiverights_attrlist(optarg
);
456 do_effective_rights_control
= 1;
458 #endif /* SOLARIS_LDAP_CMD */
459 case 'b': /* searchbase */
460 base
= strdup( optarg
);
462 case 'l': /* time limit */
463 timelimit
= atoi( optarg
);
465 case 'x': /* server sorting requested */
468 case 'z': /* size limit */
469 sizelimit
= atoi( optarg
);
471 case 'S': /* sort attribute */
472 ldap_charray_add( &sortattr
, strdup( optarg
) );
474 case 'T': /* don't fold lines */
477 case 'G': /* do the virtual list setup */
479 s
= strchr(optarg
, VLV_PARAM_SEP
);
483 vlv_before
= atoi(optarg
);
485 vlv_after
= atoi( s
);
486 s
= strchr(s
, VLV_PARAM_SEP
);
490 /* below is a small set of logic to implement the following cases
492 * -G23:23:"wilber:wright"
494 * -G23:23:wilber wright
495 * all of the above are before, after, value - NOTE: a colon not in a quoted
496 * string will break the parser!!!!
498 * above is index, count encoding
501 if (*s
== '\'' || *s
== '"')
503 vlv_value
= strdup( s
);
507 if (strchr( s
, VLV_PARAM_SEP
))
509 /* we have an index + count option */
510 vlv_index
= atoi( s
);
511 vlv_count
= atoi( strchr( s
, VLV_PARAM_SEP
) + 1);
515 /* we don't have a quote surrounding the assertion value
518 vlv_value
= strdup( s
);
524 fprintf( stderr
,gettext("Illegal 'after' paramater for virtual list\n") );
525 exit( LDAP_PARAM_ERROR
);
531 fprintf( stderr
,gettext("Illegal 'before' paramater for virtual list\n") );
532 exit( LDAP_PARAM_ERROR
);
537 if ( (ps_arg
= strdup( optarg
)) == NULL
) {
539 exit (LDAP_NO_MEMORY
);
542 ps_ptr
=strtok(ps_arg
, ":");
543 if (ps_ptr
== NULL
|| (strcasecmp(ps_ptr
, "ps")) ) {
544 fprintf (stderr
, gettext("Invalid argument for -C\n"));
547 if (NULL
!= (ps_ptr
=strtok(NULL
, ":"))) {
548 if ( (temp_arg
= strdup( ps_ptr
)) == NULL
) {
550 exit (LDAP_NO_MEMORY
);
553 fprintf (stderr
, gettext("Invalid argument for -C\n"));
556 if (NULL
!= (ps_ptr
=strtok(NULL
, ":"))) {
557 if ( (changesonly
= ldaptool_boolean_str2value(ps_ptr
, 0)) == -1) {
558 fprintf(stderr
, gettext("Invalid option value: %s\n"), ps_ptr
);
562 if (NULL
!= (ps_ptr
=strtok(NULL
, ":"))) {
563 if ( (return_echg_ctls
= ldaptool_boolean_str2value(ps_ptr
, 0)) == -1) {
564 fprintf(stderr
, gettext("Invalid option value: %s\n"), ps_ptr
);
569 /* Now parse the temp_arg and build chgtype as
570 * the changetypes are encountered */
572 if ((ps_ptr
= strtok( temp_arg
, "," )) == NULL
) {
576 if ((strcasecmp(ps_ptr
, "add"))==0)
577 chgtype
|= LDAP_CHANGETYPE_ADD
;
578 else if ((strcasecmp(ps_ptr
, "delete"))==0)
579 chgtype
|= LDAP_CHANGETYPE_DELETE
;
580 else if ((strcasecmp(ps_ptr
, "modify"))==0)
581 chgtype
|= LDAP_CHANGETYPE_MODIFY
;
582 else if ((strcasecmp(ps_ptr
, "moddn"))==0)
583 chgtype
|= LDAP_CHANGETYPE_MODDN
;
584 else if ((strcasecmp(ps_ptr
, "any"))==0)
585 chgtype
= LDAP_CHANGETYPE_ANY
;
587 fprintf(stderr
, gettext("Unknown changetype: %s\n"), ps_ptr
);
590 ps_ptr
= strtok( NULL
, "," );
602 dosearch( ld
, base
, scope
, attrs
, attrsonly
, filtpatt
, value
)
611 char **refs
= NULL
, filter
[ BUFSIZ
], *filterp
= NULL
;
612 int rc
, first
, matches
;
613 LDAPMessage
*res
, *e
;
615 LDAPControl
**ctrl_response_array
= NULL
;
616 LDAPVirtualList vlv_data
;
619 int mallocd_filter
= 0;
621 if ( strstr( filtpatt
, "%s" ) == NULL
) { /* no need to sprintf() */
624 length
= strlen( filtpatt
) + strlen ( value
) +1;
625 if ( length
> BUFSIZ
) {
626 if ((filterp
= (char *)
627 malloc ( length
)) == NULL
) {
628 perror( gettext("filter and/or pattern too long?") );
629 exit (LDAP_PARAM_ERROR
);
637 if ( snprintf( filterp
, length
, filtpatt
, value
) < 0 ) {
638 perror( gettext("snprintf filter (filter and/or pattern too long?)") );
639 exit( LDAP_PARAM_ERROR
);
642 sprintf( filterp
, filtpatt
, value
);
646 if ( *filterp
== '\0' ) { /* treat empty filter is a shortcut for oc=* */
647 if (mallocd_filter
) {
651 filterp
= "(objectclass=*)";
654 if ( ldaptool_verbose
) {
656 * Display the filter that will be used. Add surrounding parens.
657 * if they are missing.
659 if ( '(' == *filterp
) {
660 printf( "filter is: %s\n", filterp
);
662 printf( "filter is: (%s)\n", filterp
);
666 if ( ldaptool_not
) {
667 if (mallocd_filter
) free(filterp
);
668 return( LDAP_SUCCESS
);
671 if (( ldctrl
= ldaptool_create_manage_dsait_control()) != NULL
) {
672 ldaptool_add_control_to_array(ldctrl
, ldaptool_request_ctrls
);
675 if ((ldctrl
= ldaptool_create_proxyauth_control(ld
)) !=NULL
) {
676 ldaptool_add_control_to_array(ldctrl
, ldaptool_request_ctrls
);
679 #ifndef SOLARIS_LDAP_CMD
680 if ( do_effective_rights_control
) {
681 if ((ldctrl
= ldaptool_create_geteffectiveRights_control(ld
,
682 get_effectiverights_control_target_dn
,
683 (const char**) get_effectiverights_control_attrlist
)) !=NULL
) {
684 ldaptool_add_control_to_array(ldctrl
, ldaptool_request_ctrls
);
687 #endif /* SOLARIS_LDAP_CMD */
690 if ( ldap_create_persistentsearch_control( ld
, chgtype
,
691 changesonly
, return_echg_ctls
,
692 1, &ldctrl
) != LDAP_SUCCESS
)
694 ldap_perror( ld
, "ldap_create_persistentsearch_control" );
697 ldaptool_add_control_to_array(ldctrl
, ldaptool_request_ctrls
);
702 /* First make a sort key list from the attribute list we have */
703 LDAPsortkey
**keylist
= NULL
;
705 char *sortattrs
= NULL
;
707 int string_length
= 0;
709 /* Count the sort strings */
710 for (i
= 0; i
< sortsize
- 1 ; i
++) {
711 string_length
+= strlen(sortattr
[i
]) + 1;
714 sortattrs
= (char *) malloc(string_length
+ 1);
715 if (NULL
== sortattrs
) {
716 fprintf( stderr
, gettext("Out of memory\n") );
717 exit( LDAP_NO_MEMORY
);
721 for (i
= 0; i
< sortsize
- 1 ; i
++) {
722 memcpy(s
, sortattr
[i
], strlen(sortattr
[i
]));
723 s
+= strlen(sortattr
[i
]);
727 sortattrs
[string_length
] = '\0';
729 ldap_create_sort_keylist(&keylist
,sortattrs
);
733 /* Then make a control for the sort attributes we have */
734 rc
= ldap_create_sort_control(ld
,keylist
,0,&ldctrl
);
735 ldap_free_sort_keylist(keylist
);
736 if ( rc
!= LDAP_SUCCESS
) {
737 if (mallocd_filter
) free(filterp
);
738 return( ldaptool_print_lderror( ld
, "ldap_create_sort_control",
739 LDAPTOOL_CHECK4SSL_IF_APPROP
));
742 ldaptool_add_control_to_array(ldctrl
, ldaptool_request_ctrls
);
745 /* remember server side sorting must be available for vlv!!!! */
749 vlv_data
.ldvlist_before_count
= vlv_before
;
750 vlv_data
.ldvlist_after_count
= vlv_after
;
751 if ( ldaptool_verbose
) {
752 printf( gettext("vlv data %lu, %lu, "),
753 vlv_data
.ldvlist_before_count
,
754 vlv_data
.ldvlist_after_count
759 vlv_data
.ldvlist_attrvalue
= vlv_value
;
760 vlv_data
.ldvlist_size
= 0;
761 vlv_data
.ldvlist_index
= 0;
762 if ( ldaptool_verbose
) {
763 printf( "%s, 0, 0\n", vlv_data
.ldvlist_attrvalue
);
768 vlv_data
.ldvlist_attrvalue
= NULL
;
769 vlv_data
.ldvlist_size
= vlv_count
;
770 vlv_data
.ldvlist_index
= vlv_index
;
771 if ( ldaptool_verbose
) {
772 printf( "(null), %lu, %lu\n", vlv_data
.ldvlist_size
, vlv_data
.ldvlist_index
);
776 if ( rc
!= LDAP_SUCCESS
) {
777 if (mallocd_filter
) free(filterp
);
778 return( ldaptool_print_lderror( ld
, "ldap_create_sort_control",
779 LDAPTOOL_CHECK4SSL_IF_APPROP
));
781 if (LDAP_SUCCESS
!= (rc
= ldap_create_virtuallist_control(ld
,
782 &vlv_data
, &ldctrl
)))
784 if (mallocd_filter
) free(filterp
);
785 return( ldaptool_print_lderror( ld
,
786 "ldap_create_virtuallist_control",
787 LDAPTOOL_CHECK4SSL_IF_APPROP
));
790 ldaptool_add_control_to_array(ldctrl
, ldaptool_request_ctrls
);
794 if ( ldap_search_ext( ld
, base
, scope
, filterp
, attrs
, attrsonly
,
795 ldaptool_request_ctrls
, NULL
, NULL
, -1, &msgid
)
797 if (mallocd_filter
) free(filterp
);
798 return( ldaptool_print_lderror( ld
, "ldap_search",
799 LDAPTOOL_CHECK4SSL_IF_APPROP
));
805 if ( sortattr
&& !server_sort
) {
806 rc
= ldap_result( ld
, LDAP_RES_ANY
, 1, NULL
, &res
);
808 while ( (rc
= ldap_result( ld
, LDAP_RES_ANY
, 0, NULL
, &res
)) !=
809 LDAP_RES_SEARCH_RESULT
&& rc
!= -1 ) {
810 if ( rc
!= LDAP_RES_SEARCH_ENTRY
) {
811 if ( rc
== LDAP_RES_SEARCH_REFERENCE
) {
812 parse_and_display_reference( ld
, res
);
813 } else if ( rc
== LDAP_RES_EXTENDED
814 && ldap_msgid( res
) == LDAP_RES_UNSOLICITED
) {
815 ldaptool_print_extended_response( ld
, res
,
816 gettext("Unsolicited response") );
818 fprintf( stderr
, gettext("%s: ignoring LDAP response message"
819 " type 0x%x (%s)\n"),
820 ldaptool_progname
, rc
, msgtype2str( rc
));
826 e
= ldap_first_entry( ld
, res
);
832 print_entry( ld
, e
, attrsonly
);
837 if (mallocd_filter
) free(filterp
);
838 return( ldaptool_print_lderror( ld
, "ldap_result",
839 LDAPTOOL_CHECK4SSL_IF_APPROP
));
842 if ( ldap_parse_result( ld
, res
, &rc
, NULL
, NULL
, &refs
,
843 &ctrl_response_array
, 0 ) != LDAP_SUCCESS
) {
844 ldaptool_print_lderror( ld
, "ldap_parse_result",
845 LDAPTOOL_CHECK4SSL_IF_APPROP
);
846 } else if ( rc
!= LDAP_SUCCESS
) {
847 ldaptool_print_lderror( ld
, "ldap_search",
848 LDAPTOOL_CHECK4SSL_IF_APPROP
);
850 /* Parse the returned sort control */
852 unsigned long result
= 0;
855 if ( LDAP_SUCCESS
!= ldap_parse_sort_control(ld
,ctrl_response_array
,&result
,&attribute
) ) {
856 ldaptool_print_lderror(ld
, "ldap_parse_sort_control",
857 LDAPTOOL_CHECK4SSL_IF_APPROP
);
858 ldap_controls_free(ctrl_response_array
);
860 if (mallocd_filter
) free(filterp
);
861 return ( ldap_get_lderrno( ld
, NULL
, NULL
) );
865 if ( ldaptool_verbose
) {
866 printf( gettext("Server indicated results sorted OK\n"));
869 if (NULL
!= attribute
) {
870 printf(gettext("Server reported sorting error %ld: %s, attribute in error\"%s\"\n"),result
,sortresult2string(result
),attribute
);
872 printf(gettext("Server reported sorting error %ld: %s\n"),result
,sortresult2string(result
));
880 unsigned long vpos
, vcount
;
882 if ( LDAP_SUCCESS
!= ldap_parse_virtuallist_control(ld
,ctrl_response_array
,&vpos
, &vcount
,&vresult
) ) {
883 ldaptool_print_lderror( ld
, "ldap_parse_virtuallist_control",
884 LDAPTOOL_CHECK4SSL_IF_APPROP
);
885 ldap_controls_free(ctrl_response_array
);
887 if (mallocd_filter
) free(filterp
);
888 return ( ldap_get_lderrno( ld
, NULL
, NULL
) );
892 if ( ldaptool_verbose
) {
893 printf( gettext("Server indicated virtual list positioning OK\n"));
895 printf(gettext("index %lu content count %lu\n"), vpos
, vcount
);
898 printf(gettext("Server reported sorting error %d: %s\n"),vresult
,sortresult2string(vresult
));
904 ldap_controls_free(ctrl_response_array
);
906 if ( sortattr
!= NULL
&& !server_sort
) {
908 (void) ldap_multisort_entries( ld
, &res
,
909 ( *sortattr
== NULL
) ? NULL
: sortattr
,
910 (LDAP_CMP_CALLBACK
*)strcasecmp
);
913 for ( e
= ldap_first_entry( ld
, res
); e
!= NULLMSG
;
914 e
= ldap_next_entry( ld
, e
) ) {
921 print_entry( ld
, e
, attrsonly
);
925 if ( ldaptool_verbose
) {
926 printf( gettext("%d matches\n"), matches
);
929 if ( refs
!= NULL
) {
930 ldaptool_print_referrals( refs
);
931 ldap_value_free( refs
);
934 if (mallocd_filter
) free(filterp
);
942 print_entry( ld
, entry
, attrsonly
)
947 char *a
, *dn
, *ufn
, tmpfname
[ BUFSIZ
];
950 struct berval
**bvals
;
952 #if defined( XP_WIN32 )
953 char mode
[20] = "w+b";
958 dn
= ldap_get_dn( ld
, entry
);
959 write_string_attr_value( "dn", dn
, LDAPTOOL_WRITEVALOPT_SUPPRESS_NAME
);
961 ufn
= ldap_dn2ufn( dn
);
962 write_string_attr_value( "ufn", ufn
,
963 LDAPTOOL_WRITEVALOPT_SUPPRESS_NAME
);
969 LDAPControl
**ectrls
;
970 int chgtype
, chgnumpresent
;
971 #ifdef SOLARIS_LDAP_CMD
975 #endif /* SOLARIS_LDAP_CMD */
976 char *prevdn
, longbuf
[ 128 ];
978 if ( ldap_get_entry_controls( ld
, entry
, &ectrls
) == LDAP_SUCCESS
) {
979 if ( ldap_parse_entrychange_control( ld
, ectrls
, &chgtype
,
980 &prevdn
, &chgnumpresent
, &chgnum
) == LDAP_SUCCESS
) {
981 write_string_attr_value(
982 LDAPTOOL_PSEARCH_ATTR_PREFIX
"changeType",
983 changetype_num2string( chgtype
), 0 );
984 if ( chgnumpresent
) {
985 sprintf( longbuf
, "%d", chgnum
);
986 write_string_attr_value(
987 LDAPTOOL_PSEARCH_ATTR_PREFIX
"changeNumber",
990 if ( NULL
!= prevdn
) {
991 write_string_attr_value(
992 LDAPTOOL_PSEARCH_ATTR_PREFIX
"previousDN",
994 ldap_memfree( prevdn
);
997 ldap_controls_free (ectrls
);
1001 for ( a
= ldap_first_attribute( ld
, entry
, &ber
); a
!= NULL
;
1002 a
= ldap_next_attribute( ld
, entry
, ber
) ) {
1003 if ( ldap_charray_inlist(sortattr
, a
) && /* in the list*/
1004 skipsortattr
[ldap_charray_position(sortattr
, a
)] ) {/* and skip it*/
1005 continue; /* so skip it! */
1009 write_ldif_value( a
, "", 0, 0 );
1011 printf( "%s\n", a
);
1013 } else if (( bvals
= ldap_get_values_len( ld
, entry
, a
)) != NULL
) {
1014 for ( i
= 0; bvals
[i
] != NULL
; i
++ ) {
1016 #ifdef HAVE_SNPRINTF
1017 if ( snprintf( tmpfname
, sizeof(tmpfname
),
1018 "%s/ldapsearch-%s-XXXXXX",
1019 ldaptool_get_tmp_dir(), a
) < 0 ) {
1020 perror( gettext("snprintf tmpfname (attribute name too long?)") );
1021 exit( LDAP_PARAM_ERROR
);
1024 sprintf( tmpfname
, "%s/ldapsearch-%s-XXXXXX",
1025 ldaptool_get_tmp_dir(), a
);
1029 if ( LDAPTOOL_MKTEMP( tmpfname
) == NULL
) {
1031 } else if (( tmpfp
= ldaptool_open_file( tmpfname
, mode
)) == NULL
) {
1033 } else if ( bvals
[ i
]->bv_len
> 0 &&
1034 fwrite( bvals
[ i
]->bv_val
,
1035 bvals
[ i
]->bv_len
, 1, tmpfp
) == 0 ) {
1037 } else if ( ldif
) {
1038 if ( produce_file_urls
) {
1041 if ( ldaptool_path2fileurl( tmpfname
, &url
) !=
1042 LDAPTOOL_FILEURL_SUCCESS
) {
1043 perror( "ldaptool_path2fileurl" );
1045 write_ldif_value( a
, url
, strlen( url
),
1046 LDIF_OPT_VALUE_IS_URL
);
1050 write_ldif_value( a
, tmpfname
, strlen( tmpfname
),
1054 printf( "%s%s%s\n", a
, sep
, tmpfname
);
1057 if ( tmpfp
!= NULL
) {
1062 if ( !ldif
&& !allow_binary
) {
1063 notascii
= !ldaptool_berval_is_ascii( bvals
[i
] );
1067 write_ldif_value( a
, bvals
[ i
]->bv_val
,
1068 bvals
[ i
]->bv_len
, 0 );
1070 printf( "%s%s%s\n", a
, sep
,
1071 notascii
? gettext("NOT ASCII") : bvals
[ i
]->bv_val
);
1075 ber_bvecfree( bvals
);
1080 if ( ldap_get_lderrno( ld
, NULL
, NULL
) != LDAP_SUCCESS
) {
1081 ldaptool_print_lderror( ld
, "ldap_first_attribute/ldap_next_attribute",
1082 LDAPTOOL_CHECK4SSL_IF_APPROP
);
1085 if ( ber
!= NULL
) {
1092 write_string_attr_value( char *attrname
, char *strval
, unsigned long opts
)
1094 if ( strval
== NULL
) {
1098 write_ldif_value( attrname
, strval
, strlen( strval
), 0 );
1099 } else if ( 0 != ( opts
& LDAPTOOL_WRITEVALOPT_SUPPRESS_NAME
)) {
1100 printf( "%s\n", strval
);
1102 printf( "%s%s%s\n", attrname
, sep
, strval
);
1108 write_ldif_value( char *type
, char *value
, unsigned long vallen
,
1109 unsigned long ldifoptions
)
1112 static int wrote_version
= 0;
1114 if ( write_ldif_version
&& !wrote_version
) {
1115 char versionbuf
[ 64 ];
1118 sprintf( versionbuf
, "%d", LDIF_VERSION_ONE
);
1119 write_ldif_value( "version", versionbuf
, strlen( versionbuf
), 0 );
1123 ldifoptions
|= LDIF_OPT_NOWRAP
;
1125 if ( minimize_base64
) {
1126 ldifoptions
|= LDIF_OPT_MINIMAL_ENCODING
;
1129 if (( ldif
= ldif_type_and_value_with_options( type
, value
, (int)vallen
,
1130 ldifoptions
)) == NULL
) {
1134 fputs( ldif
, stdout
);
1142 sortresult2string(unsigned long result
)
1145 success (0), -- results are sorted
1146 operationsError (1), -- server internal failure
1147 timeLimitExceeded (3), -- timelimit reached before
1148 -- sorting was completed
1149 strongAuthRequired (8), -- refused to return sorted
1150 -- results via insecure
1152 adminLimitExceeded (11), -- too many matching entries
1153 -- for the server to sort
1154 noSuchAttribute (16), -- unrecognized attribute
1156 inappropriateMatching (18), -- unrecognized or inappro-
1157 -- priate matching rule in
1159 insufficientAccessRights (50), -- refused to return sorted
1160 -- results to this client
1161 busy (51), -- too busy to process
1162 unwillingToPerform (53), -- unable to sort
1167 case 0: return (gettext("success"));
1168 case 1: return (gettext("operations error"));
1169 case 3: return (gettext("time limit exceeded"));
1170 case 8: return (gettext("strong auth required"));
1171 case 11: return (gettext("admin limit exceeded"));
1172 case 16: return (gettext("no such attribute"));
1173 case 18: return (gettext("unrecognized or inappropriate matching rule"));
1174 case 50: return (gettext("insufficient access rights"));
1175 case 51: return (gettext("too busy"));
1176 case 53: return (gettext("unable to sort"));
1178 default: return (gettext("Er...Other ?"));
1184 parse_and_display_reference( LDAP
*ld
, LDAPMessage
*ref
)
1189 if ( ldap_parse_reference( ld
, ref
, &refs
, NULL
, 0 ) != LDAP_SUCCESS
) {
1190 ldaptool_print_lderror( ld
, "ldap_parse_reference",
1191 LDAPTOOL_CHECK4SSL_IF_APPROP
);
1192 } else if ( refs
!= NULL
&& refs
[ 0 ] != NULL
) {
1193 fputs( gettext("Unfollowed continuation reference(s):\n"), stderr
);
1194 for ( i
= 0; refs
[ i
] != NULL
; ++i
) {
1195 fprintf( stderr
, " %s\n", refs
[ i
] );
1197 ldap_value_free( refs
);
1202 /*possible operations a client can invoke -- copied from ldaprot.h */
1204 #ifndef LDAP_REQ_BIND
1205 #define LDAP_REQ_BIND 0x60L /* application + constructed */
1206 #define LDAP_REQ_UNBIND 0x42L /* application + primitive */
1207 #define LDAP_REQ_SEARCH 0x63L /* application + constructed */
1208 #define LDAP_REQ_MODIFY 0x66L /* application + constructed */
1209 #define LDAP_REQ_ADD 0x68L /* application + constructed */
1210 #define LDAP_REQ_DELETE 0x4aL /* application + primitive */
1211 #define LDAP_REQ_RENAME 0x6cL /* application + constructed */
1212 #define LDAP_REQ_COMPARE 0x6eL /* application + constructed */
1213 #define LDAP_REQ_ABANDON 0x50L /* application + primitive */
1214 #define LDAP_REQ_EXTENDED 0x77L /* application + constructed */
1215 #endif /* LDAP_REQ_BIND */
1219 struct ldapsearch_type2str
{
1221 int ldst2s_type
; /* message type */
1222 char *ldst2s_string
; /* descriptive string */
1225 #ifdef SOLARIS_LDAP_CMD
1226 static struct ldapsearch_type2str ldapsearch_msgtypes
[] = {
1229 { LDAP_RES_BIND
, NULL
},
1230 { LDAP_RES_SEARCH_REFERENCE
, NULL
},
1231 { LDAP_RES_SEARCH_ENTRY
, NULL
},
1232 { LDAP_RES_SEARCH_RESULT
, NULL
},
1233 { LDAP_RES_MODIFY
, NULL
},
1234 { LDAP_RES_ADD
, NULL
},
1235 { LDAP_RES_DELETE
, NULL
},
1236 { LDAP_RES_MODDN
, NULL
},
1237 { LDAP_RES_COMPARE
, NULL
},
1238 { LDAP_RES_EXTENDED
, NULL
},
1240 { LDAP_REQ_BIND
, NULL
},
1241 { LDAP_REQ_UNBIND
, NULL
},
1242 { LDAP_REQ_SEARCH
, NULL
},
1243 { LDAP_REQ_MODIFY
, NULL
},
1244 { LDAP_REQ_ADD
, NULL
},
1245 { LDAP_REQ_DELETE
, NULL
},
1246 { LDAP_REQ_RENAME
, NULL
},
1247 { LDAP_REQ_COMPARE
, NULL
},
1248 { LDAP_REQ_ABANDON
, NULL
},
1249 { LDAP_REQ_EXTENDED
, NULL
},
1253 static struct ldapsearch_type2str ldapsearch_msgtypes
[] = {
1256 { LDAP_RES_BIND
, "bind result" },
1257 { LDAP_RES_SEARCH_REFERENCE
, "continuation reference" },
1258 { LDAP_RES_SEARCH_ENTRY
, "entry" },
1259 { LDAP_RES_SEARCH_RESULT
, "search result" },
1260 { LDAP_RES_MODIFY
, "modify result" },
1261 { LDAP_RES_ADD
, "add result" },
1262 { LDAP_RES_DELETE
, "delete result" },
1263 { LDAP_RES_MODDN
, "rename result" },
1264 { LDAP_RES_COMPARE
, "compare result" },
1265 { LDAP_RES_EXTENDED
, "extended operation result" },
1267 { LDAP_REQ_BIND
, "bind request" },
1268 { LDAP_REQ_UNBIND
, "unbind request" },
1269 { LDAP_REQ_SEARCH
, "search request" },
1270 { LDAP_REQ_MODIFY
, "modify request" },
1271 { LDAP_REQ_ADD
, "add request" },
1272 { LDAP_REQ_DELETE
, "delete request" },
1273 { LDAP_REQ_RENAME
, "rename request" },
1274 { LDAP_REQ_COMPARE
, "compare request" },
1275 { LDAP_REQ_ABANDON
, "abandon request" },
1276 { LDAP_REQ_EXTENDED
, "extended request" },
1279 #endif /* SOLARIS_LDAP_CMD */
1282 #define LDAPSEARCHTOOL_NUMTYPES (sizeof(ldapsearch_msgtypes) \
1283 / sizeof(struct ldapsearch_type2str))
1285 #ifdef SOLARIS_LDAP_CMD
1287 fill_ldapsearch_msgtypes( void )
1290 if (ldapsearch_msgtypes
[LDAPSEARCHTOOL_NUMTYPES
- 1].ldst2s_string
1295 ldapsearch_msgtypes
[i
++].ldst2s_string
= gettext(
1297 ldapsearch_msgtypes
[i
++].ldst2s_string
= gettext(
1298 "continuation reference");
1299 ldapsearch_msgtypes
[i
++].ldst2s_string
= gettext(
1301 ldapsearch_msgtypes
[i
++].ldst2s_string
= gettext(
1303 ldapsearch_msgtypes
[i
++].ldst2s_string
= gettext(
1305 ldapsearch_msgtypes
[i
++].ldst2s_string
= gettext(
1307 ldapsearch_msgtypes
[i
++].ldst2s_string
= gettext(
1309 ldapsearch_msgtypes
[i
++].ldst2s_string
= gettext(
1311 ldapsearch_msgtypes
[i
++].ldst2s_string
= gettext(
1313 ldapsearch_msgtypes
[i
++].ldst2s_string
= gettext(
1314 "extended operation result");
1316 ldapsearch_msgtypes
[i
++].ldst2s_string
= gettext(
1318 ldapsearch_msgtypes
[i
++].ldst2s_string
= gettext(
1320 ldapsearch_msgtypes
[i
++].ldst2s_string
= gettext(
1322 ldapsearch_msgtypes
[i
++].ldst2s_string
= gettext(
1324 ldapsearch_msgtypes
[i
++].ldst2s_string
= gettext(
1326 ldapsearch_msgtypes
[i
++].ldst2s_string
= gettext(
1328 ldapsearch_msgtypes
[i
++].ldst2s_string
= gettext(
1330 ldapsearch_msgtypes
[i
++].ldst2s_string
= gettext(
1332 ldapsearch_msgtypes
[i
++].ldst2s_string
= gettext(
1334 ldapsearch_msgtypes
[i
++].ldst2s_string
= gettext(
1335 "extended request");
1337 #endif /* SOLARIS_LDAP_CMD */
1340 * Return a descriptive string given an LDAP result message type (tag).
1343 msgtype2str( int msgtype
)
1345 char *s
= gettext("unknown");
1348 #ifdef SOLARIS_LDAP_CMD
1349 /* Make sure ldapsearch_msgtypes is initialized */
1350 if (ldapsearch_msgtypes
[LDAPSEARCHTOOL_NUMTYPES
- 1].ldst2s_string
1352 (void) fill_ldapsearch_msgtypes();
1353 #endif /* SOLARIS_LDAP_CMD */
1355 for ( i
= 0; i
< LDAPSEARCHTOOL_NUMTYPES
; ++i
) {
1356 if ( msgtype
== ldapsearch_msgtypes
[ i
].ldst2s_type
) {
1357 s
= ldapsearch_msgtypes
[ i
].ldst2s_string
;
1365 * Return a descriptive string given a Persistent Search change type
1368 changetype_num2string( int chgtype
)
1370 char *s
= gettext("unknown");
1373 case LDAP_CHANGETYPE_ADD
:
1376 case LDAP_CHANGETYPE_DELETE
:
1377 s
= gettext("delete");
1379 case LDAP_CHANGETYPE_MODIFY
:
1380 s
= gettext("modify");
1382 case LDAP_CHANGETYPE_MODDN
:
1383 s
= gettext("moddn");
1390 /* returns a null teminated charrary */
1391 static char **get_effectiverights_attrlist(char * optarg
) {
1393 char * tmp_str
= strdup(optarg
);
1394 char ** retArray
= NULL
;
1397 retArray
= ldap_str2charray( tmp_str
, " "); /* takes copies */
1401 /* Oops - somebody left this debug message in for the
1402 getEffectiveRights control
1403 fprintf(stderr, "attrlist: "); */
1405 while( retArray
[i
] != NULL
) {
1407 fprintf(stderr
,"%s ", retArray
[i
]);
1410 fprintf(stderr
, "\n");