Home | History | Annotate | Download | only in common
      1 /*
      2  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
      3  * Use is subject to license terms.
      4  */
      5 
      6 /*
      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/
     11  *
     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.
     16  *
     17  * The Original Code is Mozilla Communicator client code, released
     18  * March 31, 1998.
     19  *
     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
     23  * Rights Reserved.
     24  *
     25  * Contributor(s):
     26  */
     27 
     28 /* ldapsearch.c - generic program to search LDAP */
     29 
     30 #include "ldaptool.h"
     31 #include "fileurl.h"
     32 #ifdef SOLARIS_LDAP_CMD
     33 #include <locale.h>
     34 #include "solaris-int.h"
     35 #endif	/* SOLARIS_LDAP_CMD */
     36 
     37 #define VLV_PARAM_SEP ':'
     38 
     39 #ifndef SOLARIS_LDAP_CMD
     40 #define gettext(s) s
     41 #endif
     42 
     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,
     47 	unsigned long opts );
     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);
     58 
     59 #ifdef SOLARIS_LDAP_CMD
     60 static void fill_ldapsearch_msgtypes( void );
     61 #endif	/* SOLARIS_LDAP_CMD */
     62 
     63 /*
     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).
     67  */
     68 #define LDAPTOOL_PSEARCH_ATTR_PREFIX	"persistentSearch-"
     69 
     70 
     71 static void
     72 usage( void )
     73 {
     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") );
     87 #else
     88     fprintf( stderr, gettext("    -t\t\twrite values to files in /tmp\n") );
     89 #endif
     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") );
     95 #endif
     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 */
    128 
    129     exit( LDAP_PARAM_ERROR );
    130 }
    131 
    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 */
    149 
    150 /* Persistent search variables */
    151 static int	chgtype=0, changesonly=1, return_echg_ctls=1;
    152 
    153 
    154 int
    155 main( int argc, char **argv )
    156 {
    157     char		*filtpattern, **attrs;
    158     int			rc, optind, i, first, free_filtpattern;
    159     LDAP		*ld;
    160 
    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 */
    166 
    167     free_filtpattern = 0;
    168     deref = LDAP_DEREF_NEVER;
    169     allow_binary = vals2tmp = attrsonly = 0;
    170     minimize_base64 = produce_file_urls = 0;
    171     ldif = 1;
    172     fold = 1;
    173     sizelimit = timelimit = 0;
    174     scope = LDAP_SCOPE_SUBTREE;
    175 	server_sort = 0;
    176 
    177 
    178 #ifdef notdef
    179 #ifdef HPUX11
    180 #ifndef __LP64__
    181 	_main( argc, argv);
    182 #endif /* __LP64_ */
    183 #endif /* HPUX11 */
    184 #endif
    185 
    186 
    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 );
    192 #else
    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 */
    196 #else
    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 */
    200 
    201     if ( optind == -1 ) {
    202 	usage();
    203     }
    204 
    205     if ( base == NULL ) {
    206 	if (( base = getenv( "LDAP_BASEDN" )) == NULL ) {
    207 	    usage();
    208 	}
    209     }
    210     if ( sortattr ) {
    211 	for ( sortsize = 0; sortattr[sortsize] != NULL; sortsize++ ) {
    212 	    ;       /* NULL */
    213 	}
    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 );
    219 	}
    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 */
    223     }
    224 
    225     if ( argc - optind < 1 ) {
    226 	if ( ldaptool_fp == NULL ) {
    227 	    usage();
    228 	}
    229 	attrs = NULL;
    230 	filtpattern = "%s";
    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;
    236 	    ++optind;
    237 	} else {
    238 	    filtpattern = "%s";
    239 	}
    240 
    241 	if ( argv[ optind ] == NULL ) {
    242 	    attrs = NULL;
    243 	} else if ( sortattr == NULL || *sortattr == '\0' || server_sort) {
    244 	    attrs = &argv[ optind ];
    245 	} else {
    246 	    attrs = ldap_charray_dup( &argv[ optind ] );
    247 	    if ( attrs == NULL ) {
    248 		fprintf( stderr, gettext("Out of memory\n") );
    249 		exit( LDAP_NO_MEMORY );
    250 	    }
    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 );
    256 		    }
    257                     /*
    258                      * attribute in the search list only for the purpose of
    259                      * sorting
    260                      */
    261                     skipsortattr[i] = 1;
    262                 }
    263 	    }
    264         }
    265     }
    266 
    267     ld = ldaptool_ldap_init( 0 );
    268 
    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 );
    273     }
    274 
    275     ldaptool_bind( ld );
    276 
    277     if ( ldaptool_verbose ) {
    278 	printf( gettext("filter pattern: %s\nreturning: "), filtpattern );
    279 	if ( attrs == NULL ) {
    280 	    printf( gettext("ALL") );
    281 	} else {
    282 	    for ( i = 0; attrs[ i ] != NULL; ++i ) {
    283 		printf( "%s ", attrs[ i ] );
    284 	    }
    285 	}
    286 	putchar( '\n' );
    287     }
    288 
    289     if ( ldaptool_fp == NULL ) {
    290 	char *conv;
    291 
    292 	conv = ldaptool_local2UTF8( base );
    293 	rc = dosearch( ld, conv, scope, attrs, attrsonly, filtpattern, "" );
    294 	if( conv != NULL )
    295             free( conv );
    296     } else {
    297 	int done = 0;
    298 
    299 	rc = LDAP_SUCCESS;
    300 	first = 1;
    301 	while ( rc == LDAP_SUCCESS && !done ) {
    302 	    char *linep = NULL;
    303 	    int   increment = 0;
    304 	    int	  c, index;
    305 
    306 	    /* allocate initial block of memory */
    307 	    if ((linep = (char *)malloc(BUFSIZ)) == NULL) {
    308 	        fprintf( stderr, gettext("Out of memory\n") );
    309 		exit( LDAP_NO_MEMORY );
    310 	    }
    311 	    increment++;
    312 	    index = 0;
    313 	    while ((c = fgetc( ldaptool_fp )) != '\n' && c != EOF) {
    314 
    315 	        /* check if we will overflow the buffer */
    316 	        if ((c != EOF) && (index == ((increment * BUFSIZ) -1))) {
    317 
    318 		    /* if we did, add another BUFSIZ worth of bytes */
    319 	   	    if ((linep = (char *)
    320 			realloc(linep, (increment + 1) * BUFSIZ)) == NULL) {
    321 			fprintf( stderr, gettext("Out of memory\n") );
    322 			exit( LDAP_NO_MEMORY );
    323 		    }
    324 		    increment++;
    325 		}
    326 		linep[index++] = c;
    327 	    }
    328 
    329 	    if (c == EOF) {
    330 		done = 1;
    331 		break;
    332 	    }
    333 
    334 	    linep[index] = '\0';
    335 
    336 	    if ( !first ) {
    337 		putchar( '\n' );
    338 	    } else {
    339 		first = 0;
    340 	    }
    341 	    rc = dosearch( ld, base, scope, attrs, attrsonly, filtpattern,
    342 		    linep );
    343 	    free (linep);
    344 	}
    345     }
    346 
    347     ldaptool_cleanup( ld );
    348     if (free_filtpattern != 0 && filtpattern != NULL) {
    349 	free (filtpattern);
    350     }
    351 
    352     /* check for and report output error */
    353     fflush( stdout );
    354     rc = ldaptool_check_ferror( stdout, rc,
    355 		gettext("output error (output might be incomplete)") );
    356     return( rc );
    357 }
    358 
    359 
    360 static void
    361 options_callback( int option, char *optarg )
    362 {
    363     char *s, *temp_arg, *ps_ptr, *ps_arg;
    364 
    365     switch( option ) {
    366     case 'u':	/* include UFN */
    367 	++includeufn;
    368 	break;
    369     case 't':	/* write attribute values to /tmp files */
    370 	++vals2tmp;
    371 	break;
    372     case 'U':	/* produce file URLs in conjunction with -t */
    373 	++produce_file_urls;
    374 	break;
    375     case 'e':	/* minimize base-64 encoding of values */
    376 	++minimize_base64;
    377 	break;
    378     case 'A':	/* retrieve attribute names only -- no values */
    379 	++attrsonly;
    380 	break;
    381     case 'L':       /* print entries in LDIF format -- now the default */
    382 	break;
    383 #ifdef SOLARIS_LDAP_CMD
    384     case 'r':	/* print entries in the old format */
    385 	ldif = 0;
    386 	break;
    387 #endif	/* SOLARIS_LDAP_CMD */
    388 #ifdef HAVE_SASL_OPTIONS
    389 #ifdef HAVE_SASL_OPTIONS_2
    390     case 'o':	/* print entries using old ldapsearch format */
    391 	ldif = 0;
    392 	break;
    393 #endif
    394 #else
    395     case 'o':	/* print entries using old ldapsearch format */
    396 	ldif = 0;
    397 	break;
    398 #endif
    399     case 'B':	/* allow binary values to be printed, use old format */
    400 	++allow_binary;
    401 	ldif = 0;
    402 	break;
    403     case '1':	/* omit leading "version: #" line from LDIF output */
    404 	write_ldif_version = 0;
    405 	break;
    406     case 's':	/* search scope */
    407 	if ( strncasecmp( optarg, "base", 4 ) == 0 ) {
    408 	    scope = LDAP_SCOPE_BASE;
    409 	} else if ( strncasecmp( optarg, "one", 3 ) == 0 ) {
    410 	    scope = LDAP_SCOPE_ONELEVEL;
    411 	} else if ( strncasecmp( optarg, "sub", 3 ) == 0 ) {
    412 	    scope = LDAP_SCOPE_SUBTREE;
    413 	} else {
    414 	    fprintf( stderr, gettext("scope should be base, one, or sub\n") );
    415 	    usage();
    416 	}
    417 	break;
    418 
    419     case 'a':	/* set alias deref option */
    420 	if ( strncasecmp( optarg, "never", 5 ) == 0 ) {
    421 	    deref = LDAP_DEREF_NEVER;
    422 	} else if ( strncasecmp( optarg, "search", 5 ) == 0 ) {
    423 	    deref = LDAP_DEREF_SEARCHING;
    424 	} else if ( strncasecmp( optarg, "find", 4 ) == 0 ) {
    425 	    deref = LDAP_DEREF_FINDING;
    426 	} else if ( strncasecmp( optarg, "always", 6 ) == 0 ) {
    427 	    deref = LDAP_DEREF_ALWAYS;
    428 	} else {
    429 	    fprintf( stderr, gettext("alias deref should be never, search, find, or always\n") );
    430 	    usage();
    431 	}
    432 	break;
    433 
    434     case 'F':	/* field separator */
    435 	sep = strdup( optarg );
    436 	ldif = 0;
    437 	break;
    438 #ifndef SOLARIS_LDAP_CMD
    439 	case 'c':
    440 		if ( optarg && optarg[0] == '\0' ) {
    441 			/* -c ""
    442 				means "This user"
    443 			*/
    444 			get_effectiverights_control_target_dn = NULL;
    445 			do_effective_rights_control = 1;
    446 		}else if ( strlen(optarg) < 3 || (strncasecmp(optarg, "dn:", 3) != 0) ) {
    447 			fprintf(stderr, gettext("-c wrong format--should be \"\" or \"dn:...\".\n"
    448 				"\"dn:\" means anonymous user."));
    449 			usage();
    450 		} else {
    451 			get_effectiverights_control_target_dn = strdup(optarg);
    452 			do_effective_rights_control = 1;
    453 		}
    454 	break;
    455 	case 'X':
    456 		get_effectiverights_control_attrlist = get_effectiverights_attrlist(optarg);
    457 		do_effective_rights_control = 1;
    458 	break;
    459 #endif	/* SOLARIS_LDAP_CMD */
    460     case 'b':	/* searchbase */
    461 	base = strdup( optarg );
    462 	break;
    463     case 'l':	/* time limit */
    464 	timelimit = atoi( optarg );
    465 	break;
    466     case 'x':	/* server sorting requested */
    467 	server_sort = 1;
    468 	break;
    469     case 'z':	/* size limit */
    470 	sizelimit = atoi( optarg );
    471 	break;
    472     case 'S':	/* sort attribute */
    473 	ldap_charray_add( &sortattr, strdup( optarg ) );
    474 	break;
    475     case 'T':	/* don't fold lines */
    476 	fold = 0;
    477 	break;
    478     case 'G':  /* do the virtual list setup */
    479 	use_vlv++;
    480 	s = strchr(optarg, VLV_PARAM_SEP );
    481 
    482 	if (s != NULL)
    483 	{
    484 	    vlv_before = atoi(optarg);
    485 	    s++;
    486 	    vlv_after = atoi( s );
    487 	    s = strchr(s, VLV_PARAM_SEP );
    488 	    if (s != NULL)
    489 	    {
    490 		s++;
    491 		/* below is a small set of logic to implement the following cases
    492 		 * -G23:23:wilber
    493 		 * -G23:23:"wilber:wright"
    494 		 * -G23:23:'wilber'
    495 		 * -G23:23:wilber wright
    496 		 * all of the above are before, after, value -  NOTE: a colon not in a quoted
    497 		 * string will break the parser!!!!
    498 		 * -G23:23:45:600
    499 		 * above is index, count encoding
    500 		 */
    501 
    502 		if (*s == '\'' || *s == '"')
    503 		{
    504 		    vlv_value = strdup( s );
    505 		}
    506 		else
    507 		{
    508 		    if (strchr( s, VLV_PARAM_SEP ))
    509 		    {
    510 			/* we have an index + count option */
    511 			vlv_index = atoi( s );
    512 			vlv_count = atoi( strchr( s, VLV_PARAM_SEP) + 1);
    513 		    }
    514 		    else
    515 		    {
    516 			/* we don't have a quote surrounding the assertion value
    517 			 * do we need to???
    518 			 */
    519 			vlv_value = strdup( s );
    520 		    }
    521 		}
    522 	    }
    523 	    else
    524 	    {
    525 		fprintf( stderr,gettext("Illegal 'after' paramater for virtual list\n") );
    526 		exit( LDAP_PARAM_ERROR );
    527 	    }
    528 
    529 	}
    530 	else
    531 	{
    532 	    fprintf( stderr,gettext("Illegal 'before' paramater for virtual list\n") );
    533 	    exit( LDAP_PARAM_ERROR );
    534 	}
    535 	break;
    536     case 'C':
    537 	use_psearch++;
    538 	if ( (ps_arg = strdup( optarg)) == NULL ) {
    539 	    perror ("strdup");
    540 	    exit (LDAP_NO_MEMORY);
    541 	}
    542 
    543 	ps_ptr=strtok(ps_arg, ":");
    544 	if (ps_ptr == NULL || (strcasecmp(ps_ptr, "ps")) ) {
    545 	    fprintf (stderr, gettext("Invalid argument for -C\n"));
    546 	    usage();
    547 	}
    548 	if (NULL != (ps_ptr=strtok(NULL, ":"))) {
    549 	    if ( (temp_arg = strdup( ps_ptr )) == NULL ) {
    550 	        perror ("strdup");
    551 	    	exit (LDAP_NO_MEMORY);
    552 	    }
    553 	} else {
    554 	    fprintf (stderr, gettext("Invalid argument for -C\n"));
    555 	    usage();
    556 	}
    557 	if (NULL != (ps_ptr=strtok(NULL, ":"))) {
    558 	    if ( (changesonly = ldaptool_boolean_str2value(ps_ptr, 0)) == -1) {
    559 		fprintf(stderr, gettext("Invalid option value: %s\n"), ps_ptr);
    560 		usage();
    561 	    }
    562 	}
    563 	if (NULL != (ps_ptr=strtok(NULL, ":"))) {
    564 	    if ( (return_echg_ctls = ldaptool_boolean_str2value(ps_ptr, 0)) == -1) {
    565 		fprintf(stderr, gettext("Invalid option value: %s\n"), ps_ptr);
    566 		usage();
    567 	    }
    568 	}
    569 
    570 	/* Now parse the temp_arg and build chgtype as
    571 	 * the changetypes are encountered */
    572 
    573 	if ((ps_ptr = strtok( temp_arg, "," )) == NULL) {
    574 		usage();
    575 	} else {
    576 	    while ( ps_ptr ) {
    577 		if ((strcasecmp(ps_ptr, "add"))==0)
    578 		    chgtype |= LDAP_CHANGETYPE_ADD;
    579 		else if ((strcasecmp(ps_ptr, "delete"))==0)
    580 		    chgtype |= LDAP_CHANGETYPE_DELETE;
    581 		else if ((strcasecmp(ps_ptr, "modify"))==0)
    582 		    chgtype |= LDAP_CHANGETYPE_MODIFY;
    583 		else if ((strcasecmp(ps_ptr, "moddn"))==0)
    584 		    chgtype |= LDAP_CHANGETYPE_MODDN;
    585 		else if ((strcasecmp(ps_ptr, "any"))==0)
    586 		    chgtype = LDAP_CHANGETYPE_ANY;
    587 		else {
    588 			fprintf(stderr, gettext("Unknown changetype: %s\n"), ps_ptr);
    589 			usage();
    590 		}
    591 		ps_ptr = strtok( NULL, "," );
    592 	    }
    593 	  }
    594 	break;
    595     default:
    596 	usage();
    597 	break;
    598     }
    599 }
    600 
    601 
    602 static int
    603 dosearch( ld, base, scope, attrs, attrsonly, filtpatt, value )
    604     LDAP	*ld;
    605     char	*base;
    606     int		scope;
    607     char	**attrs;
    608     int		attrsonly;
    609     char	*filtpatt;
    610     char	*value;
    611 {
    612     char		**refs = NULL, filter[ BUFSIZ ], *filterp = NULL;
    613     int			rc, first, matches;
    614     LDAPMessage		*res, *e;
    615     LDAPControl		*ldctrl;
    616     LDAPControl		**ctrl_response_array = NULL;
    617     LDAPVirtualList	vlv_data;
    618     int			msgid = 0;
    619     int			length = 0;
    620     int			mallocd_filter = 0;
    621 
    622     if ( strstr( filtpatt, "%s" ) == NULL ) {	/* no need to sprintf() */
    623 	    filterp = filtpatt;
    624     } else {
    625 	length = strlen( filtpatt ) + strlen ( value ) +1;
    626 	if ( length > BUFSIZ ) {
    627 	    if ((filterp = (char *)
    628 		 malloc ( length )) == NULL) {
    629 		perror( gettext("filter and/or pattern too long?") );
    630 		exit (LDAP_PARAM_ERROR);
    631 	    }
    632 	    mallocd_filter = 1;
    633 	} else {
    634 	    filterp = filter;
    635 	}
    636 
    637 #ifdef HAVE_SNPRINTF
    638 	if ( snprintf( filterp, length, filtpatt, value ) < 0 ) {
    639 	    perror( gettext("snprintf filter (filter and/or pattern too long?)") );
    640 	    exit( LDAP_PARAM_ERROR );
    641 	}
    642 #else
    643 	sprintf( filterp, filtpatt, value );
    644 #endif
    645     }
    646 
    647     if ( *filterp == '\0' ) {	/* treat empty filter is a shortcut for oc=* */
    648 	if (mallocd_filter) {
    649 	    free(filterp);
    650 	    mallocd_filter = 0;
    651 	}
    652 	filterp = "(objectclass=*)";
    653     }
    654 
    655     if ( ldaptool_verbose ) {
    656 	/*
    657 	 * Display the filter that will be used.  Add surrounding parens.
    658 	 * if they are missing.
    659 	 */
    660 	if ( '(' == *filterp ) {
    661 	    printf( "filter is: %s\n", filterp );
    662 	} else {
    663 	    printf( "filter is: (%s)\n", filterp );
    664 	}
    665     }
    666 
    667     if ( ldaptool_not ) {
    668 	if (mallocd_filter) free(filterp);
    669 	return( LDAP_SUCCESS );
    670     }
    671 
    672     if (( ldctrl = ldaptool_create_manage_dsait_control()) != NULL ) {
    673 	ldaptool_add_control_to_array(ldctrl, ldaptool_request_ctrls);
    674     }
    675 
    676     if ((ldctrl = ldaptool_create_proxyauth_control(ld)) !=NULL) {
    677 	ldaptool_add_control_to_array(ldctrl, ldaptool_request_ctrls);
    678     }
    679 
    680 #ifndef SOLARIS_LDAP_CMD
    681     if ( do_effective_rights_control ) {
    682         if ((ldctrl = ldaptool_create_geteffectiveRights_control(ld,
    683 							       get_effectiverights_control_target_dn,
    684 							       (const char**)	get_effectiverights_control_attrlist)) !=NULL) {
    685 	    ldaptool_add_control_to_array(ldctrl, ldaptool_request_ctrls);
    686         }
    687     }
    688 #endif	/* SOLARIS_LDAP_CMD */
    689 
    690     if (use_psearch) {
    691 	if ( ldap_create_persistentsearch_control( ld, chgtype,
    692                 changesonly, return_echg_ctls,
    693 		1, &ldctrl ) != LDAP_SUCCESS )
    694 	{
    695 		ldap_perror( ld, "ldap_create_persistentsearch_control" );
    696 		return (1);
    697 	}
    698 	ldaptool_add_control_to_array(ldctrl, ldaptool_request_ctrls);
    699     }
    700 
    701 
    702     if (server_sort) {
    703 	/* First make a sort key list from the attribute list we have */
    704 	LDAPsortkey **keylist = NULL;
    705 	int i = 0;
    706 	char *sortattrs = NULL;
    707 	char *s = NULL;
    708 	int string_length = 0;
    709 
    710 	/* Count the sort strings */
    711 	for (i = 0; i < sortsize - 1 ; i++) {
    712 	    string_length += strlen(sortattr[i]) + 1;
    713 	}
    714 
    715 	sortattrs = (char *) malloc(string_length + 1);
    716 	if (NULL == sortattrs) {
    717 	    fprintf( stderr, gettext("Out of memory\n") );
    718 	    exit( LDAP_NO_MEMORY );
    719 	}
    720 
    721 	s = sortattrs;
    722 	for (i = 0; i < sortsize - 1 ; i++) {
    723 	    memcpy(s, sortattr[i], strlen(sortattr[i]));
    724 	    s += strlen(sortattr[i]);
    725 	    *s++ = ' ';
    726 	}
    727 
    728 	sortattrs[string_length] = '\0';
    729 
    730 	ldap_create_sort_keylist(&keylist,sortattrs);
    731 	free(sortattrs);
    732 	sortattrs = NULL;
    733 
    734 	/* Then make a control for the sort attributes we have */
    735 	rc = ldap_create_sort_control(ld,keylist,0,&ldctrl);
    736 	ldap_free_sort_keylist(keylist);
    737 	if ( rc != LDAP_SUCCESS ) {
    738 	    if (mallocd_filter) free(filterp);
    739 	    return( ldaptool_print_lderror( ld, "ldap_create_sort_control",
    740 		LDAPTOOL_CHECK4SSL_IF_APPROP ));
    741 	}
    742 
    743 	ldaptool_add_control_to_array(ldctrl, ldaptool_request_ctrls);
    744 
    745     }
    746     /* remember server side sorting must be available for vlv!!!! */
    747 
    748     if (use_vlv)
    749     {
    750 	vlv_data.ldvlist_before_count = vlv_before;
    751 	vlv_data.ldvlist_after_count = vlv_after;
    752 	if ( ldaptool_verbose ) {
    753 	    printf( gettext("vlv data %lu, %lu, "),
    754 		    vlv_data.ldvlist_before_count,
    755 		    vlv_data.ldvlist_after_count
    756 		);
    757 	}
    758 	if (vlv_value)
    759 	{
    760 	    vlv_data.ldvlist_attrvalue = vlv_value;
    761 	    vlv_data.ldvlist_size = 0;
    762 	    vlv_data.ldvlist_index = 0;
    763 	    if ( ldaptool_verbose ) {
    764 		printf( "%s, 0, 0\n", vlv_data.ldvlist_attrvalue);
    765 	    }
    766 	}
    767 	else
    768 	{
    769 	    vlv_data.ldvlist_attrvalue = NULL;
    770 	    vlv_data.ldvlist_size = vlv_count;
    771 	    vlv_data.ldvlist_index = vlv_index;
    772 	    if ( ldaptool_verbose ) {
    773 		printf( "(null), %lu, %lu\n", vlv_data.ldvlist_size, vlv_data.ldvlist_index );
    774 	    }
    775 	}
    776 
    777 	if ( rc != LDAP_SUCCESS ) {
    778 	    if (mallocd_filter) free(filterp);
    779 	    return( ldaptool_print_lderror( ld, "ldap_create_sort_control",
    780 		LDAPTOOL_CHECK4SSL_IF_APPROP ));
    781 	}
    782 	if (LDAP_SUCCESS != (rc = ldap_create_virtuallist_control(ld,
    783 		&vlv_data, &ldctrl)))
    784 	{
    785 	    if (mallocd_filter) free(filterp);
    786 	    return( ldaptool_print_lderror( ld,
    787 		"ldap_create_virtuallist_control",
    788 		LDAPTOOL_CHECK4SSL_IF_APPROP ));
    789 	}
    790 
    791 	ldaptool_add_control_to_array(ldctrl, ldaptool_request_ctrls);
    792 
    793     }
    794 
    795     if ( ldap_search_ext( ld, base, scope, filterp, attrs, attrsonly,
    796 	    ldaptool_request_ctrls, NULL, NULL, -1, &msgid )
    797 	    != LDAP_SUCCESS ) {
    798 	if (mallocd_filter) free(filterp);
    799 	return( ldaptool_print_lderror( ld, "ldap_search",
    800 		LDAPTOOL_CHECK4SSL_IF_APPROP ));
    801     }
    802 
    803 
    804     matches = 0;
    805     first = 1;
    806     if ( sortattr && !server_sort ) {
    807         rc = ldap_result( ld, LDAP_RES_ANY, 1, NULL, &res );
    808     } else {
    809         while ( (rc = ldap_result( ld, LDAP_RES_ANY, 0, NULL, &res )) !=
    810 		LDAP_RES_SEARCH_RESULT && rc != -1 ) {
    811 	    if ( rc != LDAP_RES_SEARCH_ENTRY ) {
    812 		if ( rc == LDAP_RES_SEARCH_REFERENCE ) {
    813 		    parse_and_display_reference( ld, res );
    814 		} else if ( rc == LDAP_RES_EXTENDED
    815 			&& ldap_msgid( res ) == LDAP_RES_UNSOLICITED ) {
    816 		    ldaptool_print_extended_response( ld, res,
    817 			    gettext("Unsolicited response") );
    818 		} else {
    819 		    fprintf( stderr, gettext("%s: ignoring LDAP response message"
    820 			    " type 0x%x (%s)\n"),
    821 			    ldaptool_progname, rc, msgtype2str( rc ));
    822 		}
    823 		ldap_msgfree( res );
    824 		continue;
    825 	    }
    826 	    matches++;
    827 	    e = ldap_first_entry( ld, res );
    828 	    if ( !first ) {
    829 	        putchar( '\n' );
    830 	    } else {
    831 	        first = 0;
    832 	    }
    833 	    print_entry( ld, e, attrsonly );
    834 	    ldap_msgfree( res );
    835         }
    836     }
    837     if ( rc == -1 ) {
    838 	if (mallocd_filter) free(filterp);
    839 	return( ldaptool_print_lderror( ld, "ldap_result",
    840 		LDAPTOOL_CHECK4SSL_IF_APPROP ));
    841     }
    842 
    843     if ( ldap_parse_result( ld, res, &rc, NULL, NULL, &refs,
    844 	    &ctrl_response_array, 0 ) != LDAP_SUCCESS ) {
    845 	ldaptool_print_lderror( ld, "ldap_parse_result",
    846 		LDAPTOOL_CHECK4SSL_IF_APPROP );
    847     } else if ( rc != LDAP_SUCCESS ) {
    848 	ldaptool_print_lderror( ld, "ldap_search",
    849 		LDAPTOOL_CHECK4SSL_IF_APPROP );
    850     }
    851     /* Parse the returned sort control */
    852     if (server_sort) {
    853 	unsigned long result = 0;
    854 	char *attribute;
    855 
    856 	if ( LDAP_SUCCESS != ldap_parse_sort_control(ld,ctrl_response_array,&result,&attribute) ) {
    857 	    ldaptool_print_lderror(ld, "ldap_parse_sort_control",
    858 		    LDAPTOOL_CHECK4SSL_IF_APPROP );
    859 	    ldap_controls_free(ctrl_response_array);
    860 	    ldap_msgfree(res);
    861 	    if (mallocd_filter) free(filterp);
    862 	    return ( ldap_get_lderrno( ld, NULL, NULL ) );
    863 	}
    864 
    865 	if (0 == result) {
    866 	    if ( ldaptool_verbose ) {
    867 		printf( gettext("Server indicated results sorted OK\n"));
    868 	    }
    869 	} else {
    870 	    if (NULL != attribute) {
    871 		printf(gettext("Server reported sorting error %ld: %s, attribute in error\"%s\"\n"),result,sortresult2string(result),attribute);
    872 	    } else {
    873 		printf(gettext("Server reported sorting error %ld: %s\n"),result,sortresult2string(result));
    874 	    }
    875 	}
    876 
    877     }
    878 
    879     if (use_vlv)
    880     {
    881 	unsigned long vpos, vcount;
    882 	int vresult;
    883 	if ( LDAP_SUCCESS != ldap_parse_virtuallist_control(ld,ctrl_response_array,&vpos, &vcount,&vresult) ) {
    884 	    ldaptool_print_lderror( ld, "ldap_parse_virtuallist_control",
    885 		    LDAPTOOL_CHECK4SSL_IF_APPROP );
    886 	    ldap_controls_free(ctrl_response_array);
    887 	    ldap_msgfree(res);
    888 	    if (mallocd_filter) free(filterp);
    889 	    return ( ldap_get_lderrno( ld, NULL, NULL ) );
    890 	}
    891 
    892 	if (0 == vresult) {
    893 	    if ( ldaptool_verbose ) {
    894 		printf( gettext("Server indicated virtual list positioning OK\n"));
    895 	    }
    896 	    printf(gettext("index %lu content count %lu\n"), vpos, vcount);
    897 
    898 	} else {
    899 	    printf(gettext("Server reported sorting error %d: %s\n"),vresult,sortresult2string(vresult));
    900 
    901 	}
    902 
    903     }
    904 
    905     ldap_controls_free(ctrl_response_array);
    906 
    907     if ( sortattr != NULL && !server_sort) {
    908 
    909 	(void) ldap_multisort_entries( ld, &res,
    910 				       ( *sortattr == NULL ) ? NULL : sortattr,
    911 				       (LDAP_CMP_CALLBACK *)strcasecmp );
    912 	matches = 0;
    913 	first = 1;
    914 	for ( e = ldap_first_entry( ld, res ); e != NULLMSG;
    915 	      e = ldap_next_entry( ld, e ) ) {
    916 	    matches++;
    917 	    if ( !first ) {
    918 		putchar( '\n' );
    919 	    } else {
    920 		first = 0;
    921 	    }
    922 	    print_entry( ld, e, attrsonly );
    923 	}
    924     }
    925 
    926     if ( ldaptool_verbose ) {
    927 	printf( gettext("%d matches\n"), matches );
    928     }
    929 
    930     if ( refs != NULL ) {
    931 	ldaptool_print_referrals( refs );
    932 	ldap_value_free( refs );
    933     }
    934 
    935     if (mallocd_filter) free(filterp);
    936 
    937     ldap_msgfree( res );
    938     return( rc );
    939 }
    940 
    941 
    942 static void
    943 print_entry( ld, entry, attrsonly )
    944     LDAP	*ld;
    945     LDAPMessage	*entry;
    946     int		attrsonly;
    947 {
    948     char		*a, *dn, *ufn, tmpfname[ BUFSIZ ];
    949     int			i, notascii;
    950     BerElement		*ber;
    951     struct berval	**bvals;
    952     FILE		*tmpfp;
    953 #if defined( XP_WIN32 )
    954 	char	mode[20] = "w+b";
    955 #else
    956 	char	mode[20] = "w";
    957 #endif
    958 
    959     dn = ldap_get_dn( ld, entry );
    960     write_string_attr_value( "dn", dn, LDAPTOOL_WRITEVALOPT_SUPPRESS_NAME );
    961     if ( includeufn ) {
    962 	ufn = ldap_dn2ufn( dn );
    963 	write_string_attr_value( "ufn", ufn,
    964 			LDAPTOOL_WRITEVALOPT_SUPPRESS_NAME );
    965 	free( ufn );
    966     }
    967     ldap_memfree( dn );
    968 
    969     if ( use_psearch ) {
    970 	LDAPControl	**ectrls;
    971 	int		chgtype, chgnumpresent;
    972 #ifdef SOLARIS_LDAP_CMD
    973 	ber_int_t	chgnum;
    974 #else
    975 	long		chgnum;
    976 #endif	/* SOLARIS_LDAP_CMD */
    977 	char		*prevdn, longbuf[ 128 ];
    978 
    979 	if ( ldap_get_entry_controls( ld, entry, &ectrls ) == LDAP_SUCCESS ) {
    980 	    if ( ldap_parse_entrychange_control( ld, ectrls, &chgtype,
    981 			&prevdn, &chgnumpresent, &chgnum ) == LDAP_SUCCESS ) {
    982 		write_string_attr_value(
    983 			LDAPTOOL_PSEARCH_ATTR_PREFIX "changeType",
    984 			changetype_num2string( chgtype ), 0 );
    985 		if ( chgnumpresent ) {
    986 		    sprintf( longbuf, "%d", chgnum );
    987 		    write_string_attr_value(
    988 			    LDAPTOOL_PSEARCH_ATTR_PREFIX "changeNumber",
    989 			    longbuf, 0 );
    990 		}
    991 		if ( NULL != prevdn ) {
    992 		    write_string_attr_value(
    993 			    LDAPTOOL_PSEARCH_ATTR_PREFIX "previousDN",
    994 			    prevdn, 0 );
    995 		    ldap_memfree( prevdn );
    996 		}
    997 	    }
    998 	    ldap_controls_free (ectrls);
    999 	}
   1000     }
   1001 
   1002     for ( a = ldap_first_attribute( ld, entry, &ber ); a != NULL;
   1003 	    a = ldap_next_attribute( ld, entry, ber ) ) {
   1004 	if ( ldap_charray_inlist(sortattr, a) &&            /* in the list*/
   1005 	    skipsortattr[ldap_charray_position(sortattr, a)] ) {/* and skip it*/
   1006 	    continue;                                       /* so skip it! */
   1007 	}
   1008 	if ( attrsonly ) {
   1009 	    if ( ldif ) {
   1010 		write_ldif_value( a, "", 0, 0 );
   1011 	    } else {
   1012 		printf( "%s\n", a );
   1013 	    }
   1014 	} else if (( bvals = ldap_get_values_len( ld, entry, a )) != NULL ) {
   1015 	    for ( i = 0; bvals[i] != NULL; i++ ) {
   1016 		if ( vals2tmp ) {
   1017 #ifdef HAVE_SNPRINTF
   1018 		    if ( snprintf( tmpfname, sizeof(tmpfname),
   1019 			    "%s/ldapsearch-%s-XXXXXX",
   1020 			    ldaptool_get_tmp_dir(), a ) < 0 ) {
   1021 			perror( gettext("snprintf tmpfname (attribute name too long?)") );
   1022 			exit( LDAP_PARAM_ERROR );
   1023 		    }
   1024 #else
   1025 		    sprintf( tmpfname, "%s/ldapsearch-%s-XXXXXX",
   1026 			    ldaptool_get_tmp_dir(), a );
   1027 #endif
   1028 		    tmpfp = NULL;
   1029 
   1030 		    if ( LDAPTOOL_MKTEMP( tmpfname ) == NULL ) {
   1031 			perror( tmpfname );
   1032 		    } else if (( tmpfp = ldaptool_open_file( tmpfname, mode)) == NULL ) {
   1033 			perror( tmpfname );
   1034 		    } else if ( bvals[ i ]->bv_len > 0 &&
   1035 			    fwrite( bvals[ i ]->bv_val,
   1036 			    bvals[ i ]->bv_len, 1, tmpfp ) == 0 ) {
   1037 			perror( tmpfname );
   1038 		    } else if ( ldif ) {
   1039 			if ( produce_file_urls ) {
   1040 			    char	*url;
   1041 
   1042 			    if ( ldaptool_path2fileurl( tmpfname, &url ) !=
   1043 				LDAPTOOL_FILEURL_SUCCESS ) {
   1044 				    perror( "ldaptool_path2fileurl" );
   1045 				} else {
   1046 				    write_ldif_value( a, url, strlen( url ),
   1047 					    LDIF_OPT_VALUE_IS_URL );
   1048 				    free( url );
   1049 				}
   1050 			} else {
   1051 			    write_ldif_value( a, tmpfname, strlen( tmpfname ),
   1052 				    0 );
   1053 			}
   1054 		    } else {
   1055 			printf( "%s%s%s\n", a, sep, tmpfname );
   1056 		    }
   1057 
   1058 		    if ( tmpfp != NULL ) {
   1059 			fclose( tmpfp );
   1060 		    }
   1061 		} else {
   1062 		    notascii = 0;
   1063 		    if ( !ldif && !allow_binary ) {
   1064 			notascii = !ldaptool_berval_is_ascii( bvals[i] );
   1065 		    }
   1066 
   1067 		    if ( ldif ) {
   1068 			write_ldif_value( a, bvals[ i ]->bv_val,
   1069 				bvals[ i ]->bv_len, 0 );
   1070 		    } else {
   1071 			printf( "%s%s%s\n", a, sep,
   1072 				notascii ? gettext("NOT ASCII") : bvals[ i ]->bv_val );
   1073 		    }
   1074 		}
   1075 	    }
   1076 	    ber_bvecfree( bvals );
   1077 	}
   1078 	ldap_memfree( a );
   1079     }
   1080 
   1081     if ( ldap_get_lderrno( ld, NULL, NULL ) != LDAP_SUCCESS ) {
   1082 	ldaptool_print_lderror( ld, "ldap_first_attribute/ldap_next_attribute",
   1083 		LDAPTOOL_CHECK4SSL_IF_APPROP );
   1084     }
   1085 
   1086     if ( ber != NULL ) {
   1087 	ber_free( ber, 0 );
   1088     }
   1089 }
   1090 
   1091 
   1092 static void
   1093 write_string_attr_value( char *attrname, char *strval, unsigned long opts )
   1094 {
   1095     if ( strval == NULL ) {
   1096 	strval = "";
   1097     }
   1098     if ( ldif ) {
   1099 	write_ldif_value( attrname, strval, strlen( strval ), 0 );
   1100     } else if ( 0 != ( opts & LDAPTOOL_WRITEVALOPT_SUPPRESS_NAME )) {
   1101 	printf( "%s\n", strval );
   1102     } else {
   1103 	printf( "%s%s%s\n", attrname, sep, strval );
   1104     }
   1105 }
   1106 
   1107 
   1108 static int
   1109 write_ldif_value( char *type, char *value, unsigned long vallen,
   1110 	unsigned long ldifoptions )
   1111 {
   1112     char	*ldif;
   1113     static int	wrote_version = 0;
   1114 
   1115     if ( write_ldif_version && !wrote_version ) {
   1116 	char	versionbuf[ 64 ];
   1117 
   1118 	wrote_version = 1;
   1119 	sprintf( versionbuf, "%d", LDIF_VERSION_ONE );
   1120 	write_ldif_value( "version", versionbuf, strlen( versionbuf ), 0 );
   1121     }
   1122 
   1123     if ( !fold ) {
   1124 	ldifoptions |= LDIF_OPT_NOWRAP;
   1125     }
   1126     if ( minimize_base64 ) {
   1127 	ldifoptions |= LDIF_OPT_MINIMAL_ENCODING;
   1128     }
   1129 
   1130     if (( ldif = ldif_type_and_value_with_options( type, value, (int)vallen,
   1131 	    ldifoptions )) == NULL ) {
   1132 	return( -1 );
   1133     }
   1134 
   1135     fputs( ldif, stdout );
   1136     free( ldif );
   1137 
   1138     return( 0 );
   1139 }
   1140 
   1141 
   1142 static char *
   1143 sortresult2string(unsigned long result)
   1144 {
   1145 	/*
   1146             success                   (0), -- results are sorted
   1147             operationsError           (1), -- server internal failure
   1148             timeLimitExceeded         (3), -- timelimit reached before
   1149                                            -- sorting was completed
   1150             strongAuthRequired        (8), -- refused to return sorted
   1151                                            -- results via insecure
   1152                                            -- protocol
   1153             adminLimitExceeded       (11), -- too many matching entries
   1154                                            -- for the server to sort
   1155             noSuchAttribute          (16), -- unrecognized attribute
   1156                                            -- type in sort key
   1157             inappropriateMatching    (18), -- unrecognized or inappro-
   1158                                            -- priate matching rule in
   1159                                            -- sort key
   1160             insufficientAccessRights (50), -- refused to return sorted
   1161                                            -- results to this client
   1162             busy                     (51), -- too busy to process
   1163             unwillingToPerform       (53), -- unable to sort
   1164             other                    (80)
   1165 	*/
   1166 
   1167 	switch (result) {
   1168 	case 0: return (gettext("success"));
   1169 	case 1: return (gettext("operations error"));
   1170 	case 3: return (gettext("time limit exceeded"));
   1171 	case 8: return (gettext("strong auth required"));
   1172 	case 11: return (gettext("admin limit exceeded"));
   1173 	case 16: return (gettext("no such attribute"));
   1174 	case 18: return (gettext("unrecognized or inappropriate matching rule"));
   1175 	case 50: return (gettext("insufficient access rights"));
   1176 	case 51: return (gettext("too busy"));
   1177 	case 53: return (gettext("unable to sort"));
   1178 	case 80:
   1179         default: return (gettext("Er...Other ?"));
   1180 	}
   1181 }
   1182 
   1183 
   1184 static void
   1185 parse_and_display_reference( LDAP *ld, LDAPMessage *ref )
   1186 {
   1187     int		i;
   1188     char	**refs;
   1189 
   1190     if ( ldap_parse_reference( ld, ref, &refs, NULL, 0 ) != LDAP_SUCCESS ) {
   1191 	ldaptool_print_lderror( ld, "ldap_parse_reference",
   1192 		LDAPTOOL_CHECK4SSL_IF_APPROP );
   1193     } else if ( refs != NULL && refs[ 0 ] != NULL ) {
   1194 	fputs( gettext("Unfollowed continuation reference(s):\n"), stderr );
   1195 	for ( i = 0; refs[ i ] != NULL; ++i ) {
   1196 	    fprintf( stderr, "    %s\n", refs[ i ] );
   1197 	}
   1198 	ldap_value_free( refs );
   1199     }
   1200 }
   1201 
   1202 
   1203 /*possible operations a client can invoke -- copied from ldaprot.h */
   1204 
   1205 #ifndef LDAP_REQ_BIND
   1206 #define LDAP_REQ_BIND                   0x60L   /* application + constructed */
   1207 #define LDAP_REQ_UNBIND                 0x42L   /* application + primitive   */
   1208 #define LDAP_REQ_SEARCH                 0x63L   /* application + constructed */
   1209 #define LDAP_REQ_MODIFY                 0x66L   /* application + constructed */
   1210 #define LDAP_REQ_ADD                    0x68L   /* application + constructed */
   1211 #define LDAP_REQ_DELETE                 0x4aL   /* application + primitive   */
   1212 #define LDAP_REQ_RENAME                 0x6cL   /* application + constructed */
   1213 #define LDAP_REQ_COMPARE                0x6eL   /* application + constructed */
   1214 #define LDAP_REQ_ABANDON                0x50L   /* application + primitive   */
   1215 #define LDAP_REQ_EXTENDED               0x77L   /* application + constructed */
   1216 #endif /* LDAP_REQ_BIND */
   1217 
   1218 
   1219 
   1220 struct ldapsearch_type2str {
   1221 
   1222     int         ldst2s_type;    /* message type */
   1223     char        *ldst2s_string; /* descriptive string */
   1224 };
   1225 
   1226 #ifdef SOLARIS_LDAP_CMD
   1227 static struct ldapsearch_type2str ldapsearch_msgtypes[] = {
   1228 
   1229     /* results: */
   1230     { LDAP_RES_BIND,                    NULL },
   1231     { LDAP_RES_SEARCH_REFERENCE,        NULL },
   1232     { LDAP_RES_SEARCH_ENTRY,            NULL },
   1233     { LDAP_RES_SEARCH_RESULT,           NULL },
   1234     { LDAP_RES_MODIFY,                  NULL },
   1235     { LDAP_RES_ADD,                     NULL },
   1236     { LDAP_RES_DELETE,                  NULL },
   1237     { LDAP_RES_MODDN,                   NULL },
   1238     { LDAP_RES_COMPARE,                 NULL },
   1239     { LDAP_RES_EXTENDED,                NULL },
   1240     /* requests: */
   1241     { LDAP_REQ_BIND,                    NULL },
   1242     { LDAP_REQ_UNBIND,                  NULL },
   1243     { LDAP_REQ_SEARCH,                  NULL },
   1244     { LDAP_REQ_MODIFY,                  NULL },
   1245     { LDAP_REQ_ADD,                     NULL },
   1246     { LDAP_REQ_DELETE,                  NULL },
   1247     { LDAP_REQ_RENAME,                  NULL },
   1248     { LDAP_REQ_COMPARE,                 NULL },
   1249     { LDAP_REQ_ABANDON,                 NULL },
   1250     { LDAP_REQ_EXTENDED,                NULL },
   1251 
   1252 };
   1253 #else
   1254 static struct ldapsearch_type2str ldapsearch_msgtypes[] = {
   1255 
   1256     /* results: */
   1257     { LDAP_RES_BIND,                    "bind result" },
   1258     { LDAP_RES_SEARCH_REFERENCE,        "continuation reference" },
   1259     { LDAP_RES_SEARCH_ENTRY,            "entry" },
   1260     { LDAP_RES_SEARCH_RESULT,           "search result" },
   1261     { LDAP_RES_MODIFY,                  "modify result" },
   1262     { LDAP_RES_ADD,                     "add result" },
   1263     { LDAP_RES_DELETE,                  "delete result" },
   1264     { LDAP_RES_MODDN,                   "rename result" },
   1265     { LDAP_RES_COMPARE,                 "compare result" },
   1266     { LDAP_RES_EXTENDED,                "extended operation result" },
   1267     /* requests: */
   1268     { LDAP_REQ_BIND,                    "bind request" },
   1269     { LDAP_REQ_UNBIND,                  "unbind request" },
   1270     { LDAP_REQ_SEARCH,                  "search request" },
   1271     { LDAP_REQ_MODIFY,                  "modify request" },
   1272     { LDAP_REQ_ADD,                     "add request" },
   1273     { LDAP_REQ_DELETE,                  "delete request" },
   1274     { LDAP_REQ_RENAME,                  "rename request" },
   1275     { LDAP_REQ_COMPARE,                 "compare request" },
   1276     { LDAP_REQ_ABANDON,                 "abandon request" },
   1277     { LDAP_REQ_EXTENDED,                "extended request" },
   1278 
   1279 };
   1280 #endif	/* SOLARIS_LDAP_CMD */
   1281 
   1282 
   1283 #define LDAPSEARCHTOOL_NUMTYPES (sizeof(ldapsearch_msgtypes) \
   1284 				 / sizeof(struct ldapsearch_type2str))
   1285 
   1286 #ifdef SOLARIS_LDAP_CMD
   1287 static void
   1288 fill_ldapsearch_msgtypes( void )
   1289 {
   1290     int		i = 0;
   1291     if (ldapsearch_msgtypes[LDAPSEARCHTOOL_NUMTYPES - 1].ldst2s_string
   1292 	!= NULL)
   1293 		return;
   1294 
   1295     /* results: */
   1296     ldapsearch_msgtypes[i++].ldst2s_string = gettext(
   1297 			"bind result");
   1298     ldapsearch_msgtypes[i++].ldst2s_string = gettext(
   1299 			"continuation reference");
   1300     ldapsearch_msgtypes[i++].ldst2s_string = gettext(
   1301 			"entry");
   1302     ldapsearch_msgtypes[i++].ldst2s_string = gettext(
   1303     			"search result");
   1304     ldapsearch_msgtypes[i++].ldst2s_string = gettext(
   1305     			"modify result");
   1306     ldapsearch_msgtypes[i++].ldst2s_string = gettext(
   1307     			"add result");
   1308     ldapsearch_msgtypes[i++].ldst2s_string = gettext(
   1309     			"delete result");
   1310     ldapsearch_msgtypes[i++].ldst2s_string = gettext(
   1311     			"rename result");
   1312     ldapsearch_msgtypes[i++].ldst2s_string = gettext(
   1313     			"compare result");
   1314     ldapsearch_msgtypes[i++].ldst2s_string = gettext(
   1315     			"extended operation result");
   1316     /* requests: */
   1317     ldapsearch_msgtypes[i++].ldst2s_string = gettext(
   1318     			"bind request");
   1319     ldapsearch_msgtypes[i++].ldst2s_string = gettext(
   1320     			"unbind request");
   1321     ldapsearch_msgtypes[i++].ldst2s_string = gettext(
   1322     			"search request");
   1323     ldapsearch_msgtypes[i++].ldst2s_string = gettext(
   1324     			"modify request");
   1325     ldapsearch_msgtypes[i++].ldst2s_string = gettext(
   1326     			"add request");
   1327     ldapsearch_msgtypes[i++].ldst2s_string = gettext(
   1328     			"delete request");
   1329     ldapsearch_msgtypes[i++].ldst2s_string = gettext(
   1330     			"rename request");
   1331     ldapsearch_msgtypes[i++].ldst2s_string = gettext(
   1332     			"compare request");
   1333     ldapsearch_msgtypes[i++].ldst2s_string = gettext(
   1334     			"abandon request");
   1335     ldapsearch_msgtypes[i++].ldst2s_string = gettext(
   1336 			"extended request");
   1337 }
   1338 #endif	/* SOLARIS_LDAP_CMD */
   1339 
   1340 /*
   1341  * Return a descriptive string given an LDAP result message type (tag).
   1342  */
   1343 static char *
   1344 msgtype2str( int msgtype )
   1345 {
   1346     char        *s = gettext("unknown");
   1347     int         i;
   1348 
   1349 #ifdef SOLARIS_LDAP_CMD
   1350     /* Make sure ldapsearch_msgtypes is initialized */
   1351     if (ldapsearch_msgtypes[LDAPSEARCHTOOL_NUMTYPES - 1].ldst2s_string
   1352 	== NULL)
   1353 		(void) fill_ldapsearch_msgtypes();
   1354 #endif	/* SOLARIS_LDAP_CMD */
   1355 
   1356     for ( i = 0; i < LDAPSEARCHTOOL_NUMTYPES; ++i ) {
   1357 	if ( msgtype == ldapsearch_msgtypes[ i ].ldst2s_type ) {
   1358 	    s = ldapsearch_msgtypes[ i ].ldst2s_string;
   1359 	}
   1360     }
   1361     return( s );
   1362 }
   1363 
   1364 
   1365 /*
   1366  * Return a descriptive string given a Persistent Search change type
   1367  */
   1368 static char *
   1369 changetype_num2string( int chgtype )
   1370 {
   1371     char	*s = gettext("unknown");
   1372 
   1373     switch( chgtype ) {
   1374     case LDAP_CHANGETYPE_ADD:
   1375 	s = gettext("add");
   1376 	break;
   1377     case LDAP_CHANGETYPE_DELETE:
   1378 	s = gettext("delete");
   1379 	break;
   1380     case LDAP_CHANGETYPE_MODIFY:
   1381 	s = gettext("modify");
   1382 	break;
   1383     case LDAP_CHANGETYPE_MODDN:
   1384 	s = gettext("moddn");
   1385 	break;
   1386     }
   1387 
   1388     return( s );
   1389 }
   1390 
   1391 /* returns a null teminated charrary */
   1392 static char  **get_effectiverights_attrlist(char * optarg) {
   1393 
   1394 	char * tmp_str = strdup(optarg);
   1395 	char ** retArray = NULL;
   1396 	int i = 0;
   1397 
   1398 	retArray = ldap_str2charray( tmp_str, " "); /* takes copies */
   1399 
   1400 	free(tmp_str);
   1401 
   1402 	/* Oops - somebody left this debug message in for the
   1403 	   getEffectiveRights control
   1404 	   fprintf(stderr, "attrlist: "); */
   1405 	i = 0;
   1406 	while( retArray[i] != NULL ) {
   1407 
   1408 		fprintf(stderr,"%s ", retArray[i]);
   1409 		i++;
   1410 	}
   1411 	fprintf(stderr, "\n");
   1412 
   1413 	return(retArray);
   1414 
   1415 }
   1416