Back to index

lightning-sunbird  0.9+nobinonly
ldapsearch.c
Go to the documentation of this file.
00001 /* ***** BEGIN LICENSE BLOCK *****
00002  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00003  *
00004  * The contents of this file are subject to the Mozilla Public License Version
00005  * 1.1 (the "License"); you may not use this file except in compliance with
00006  * the License. You may obtain a copy of the License at
00007  * http://www.mozilla.org/MPL/
00008  *
00009  * Software distributed under the License is distributed on an "AS IS" basis,
00010  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00011  * for the specific language governing rights and limitations under the
00012  * License.
00013  *
00014  * The Original Code is Mozilla Communicator client code, released
00015  * March 31, 1998.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1998-1999
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *
00024  * Alternatively, the contents of this file may be used under the terms of
00025  * either the GNU General Public License Version 2 or later (the "GPL"), or
00026  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00027  * in which case the provisions of the GPL or the LGPL are applicable instead
00028  * of those above. If you wish to allow use of your version of this file only
00029  * under the terms of either the GPL or the LGPL, and not to allow others to
00030  * use your version of this file under the terms of the MPL, indicate your
00031  * decision by deleting the provisions above and replace them with the notice
00032  * and other provisions required by the GPL or the LGPL. If you do not delete
00033  * the provisions above, a recipient may use your version of this file under
00034  * the terms of any one of the MPL, the GPL or the LGPL.
00035  *
00036  * ***** END LICENSE BLOCK ***** */
00037 
00038 /* ldapsearch.c - generic program to search LDAP */
00039 
00040 #include "ldaptool.h"
00041 #include "fileurl.h"
00042 
00043 #define VLV_PARAM_SEP ':'
00044 
00045 static void usage( void );
00046 static int dosearch( LDAP *ld, char *base, int scope, char **attrs, 
00047                       int attrsonly, char *filtpatt, char *value);
00048 static void write_string_attr_value( char *attrname, char *strval,
00049        unsigned long opts );
00050 #define LDAPTOOL_WRITEVALOPT_SUPPRESS_NAME       0x01
00051 static int write_ldif_value( char *type, char *value, unsigned long vallen,
00052        unsigned long ldifoptions );
00053 static void print_entry( LDAP *ld, LDAPMessage *entry, int attrsonly );
00054 static void options_callback( int option, char *optarg );
00055 static void parse_and_display_reference( LDAP *ld, LDAPMessage *ref );
00056 static char *sortresult2string(unsigned long result);
00057 static char *changetype_num2string( int chgtype );
00058 static char *msgtype2str( int msgtype );
00059 
00060 /*
00061  * Prefix used in names of pseudo attributes added to the entry LDIF
00062  * output if we receive an entryChangeNotification control with an entry
00063  * (requested using persistent search).
00064  */
00065 #define LDAPTOOL_PSEARCH_ATTR_PREFIX      "persistentSearch-"
00066 
00067 
00068 static void
00069 usage( void )
00070 {
00071     fprintf( stderr, "usage: %s -b basedn [options] filter [attributes...]\n", ldaptool_progname );
00072     fprintf( stderr, "       %s -b basedn [options] -f file [attributes...]\nwhere:\n", ldaptool_progname );
00073     fprintf( stderr, "    basedn\tbase dn for search\n" );
00074     fprintf( stderr, "\t\t(if the environment variable LDAP_BASEDN is set,\n" );
00075     fprintf( stderr, "\t\tthen the -b flag is not required)\n" );
00076     fprintf( stderr, "    filter\tRFC-2254 compliant LDAP search filter\n" );
00077     fprintf( stderr, "    file\tfile containing a sequence of LDAP search filters to use\n" );
00078     fprintf( stderr, "    attributes\twhitespace-separated list of attributes to retrieve\n" );
00079     fprintf( stderr, "\t\t(if no attribute list is given, all are retrieved)\n" );
00080     fprintf( stderr, "options:\n" );
00081     ldaptool_common_usage( 0 );
00082 #if defined( XP_WIN32 )
00083     fprintf( stderr, "    -t\t\twrite values to files in temp directory.\n" );
00084 #else
00085     fprintf( stderr, "    -t\t\twrite values to files in /tmp\n" );
00086 #endif
00087     fprintf( stderr, "    -U\t\tproduce file URLs in conjunction with -t\n" );
00088     fprintf( stderr, "    -e\t\tminimize base-64 encoding of values\n" );
00089     fprintf( stderr, "    -u\t\tinclude User Friendly entry names in the output\n" );
00090     fprintf( stderr, "    -o\t\tprint entries using old format (default is LDIF)\n" );
00091     fprintf( stderr, "    -T\t\tdon't fold (wrap) long lines (default is to fold)\n" );
00092     fprintf( stderr, "    -1\t\tomit leading \"version: %d\" line in LDIF output\n", LDIF_VERSION_ONE );
00093     fprintf( stderr, "    -A\t\tretrieve attribute names only (no values)\n" );
00094     fprintf( stderr, "    -B\t\tprint non-ASCII values when old format (-o) is used\n" );
00095     fprintf( stderr, "    -x\t\tperforming sorting on server\n" );
00096     fprintf( stderr, "    -F sep\tprint `sep' instead of `%s' between attribute names\n", LDAPTOOL_DEFSEP );
00097     fprintf( stderr, "          \tand values\n" );
00098     fprintf( stderr, "    -S attr\tsort the results by attribute `attr'\n" );
00099     fprintf( stderr, "    -s scope\tone of base, one, or sub (default is sub)\n" );
00100     fprintf( stderr, "    -a deref\tone of never, always, search, or find (default: never)\n" );
00101     fprintf( stderr, "            \t(alias dereferencing)\n" );
00102     fprintf( stderr, "    -l time lim\ttime limit (in seconds) for search\n" );
00103     fprintf( stderr, "    -z size lim\tsize limit (in entries) for search\n" );
00104     fprintf( stderr, "    -C ps:changetype[:changesonly[:entrychgcontrols]]\n" );
00105     fprintf( stderr, "\t\tchangetypes are add,delete,modify,moddn,any\n" );
00106     fprintf( stderr, "\t\tchangesonly and  entrychgcontrols are boolean values\n" );
00107     fprintf( stderr, "\t\t(default is 1)\n" );
00108     fprintf( stderr, "    -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 );
00109     fprintf( stderr, "\t\t'after' are the number of entries surrounding 'index.'\n");
00110     fprintf( stderr, "\t\t'count' is the content count, 'value' is the search value.\n");
00111 
00112     exit( LDAP_PARAM_ERROR );
00113 }
00114 
00115 static char   *base = NULL;
00116 static char   *sep = LDAPTOOL_DEFSEP;
00117 static char   **sortattr = NULL;
00118 static char     *vlv_value = NULL;
00119 static int    sortsize = 0;
00120 static int    *skipsortattr = NULL;
00121 static int    includeufn, allow_binary, vals2tmp, ldif, scope, deref;
00122 static int    attrsonly, timelimit, sizelimit, server_sort, fold;
00123 static int    minimize_base64, produce_file_urls;
00124 static int    use_vlv = 0, vlv_before, vlv_after, vlv_index, vlv_count;
00125 static int    use_psearch=0;
00126 static int    write_ldif_version = 1;
00127 
00128 /* Persistent search variables */
00129 static int    chgtype=0, changesonly=1, return_echg_ctls=1;
00130 
00131 
00132 int
00133 main( int argc, char **argv )
00134 {
00135     char             *filtpattern, **attrs;
00136     int                     rc, optind, i, first;
00137     LDAP             *ld;
00138 
00139     deref = LDAP_DEREF_NEVER;
00140     allow_binary = vals2tmp = attrsonly = 0;
00141     minimize_base64 = produce_file_urls = 0;
00142     ldif = 1;
00143     fold = 1;
00144     sizelimit = timelimit = 0;
00145     scope = LDAP_SCOPE_SUBTREE;
00146        server_sort = 0;
00147 
00148 #ifdef notdef
00149 #ifdef HPUX11
00150 #ifndef __LP64__
00151        _main( argc, argv);
00152 #endif /* __LP64_ */
00153 #endif /* HPUX11 */
00154 #endif
00155 
00156 
00157     ldaptool_reset_control_array( ldaptool_request_ctrls );
00158     optind = ldaptool_process_args( argc, argv, "ABLTU1eotuxa:b:F:G:l:S:s:z:C:",
00159         0, options_callback );
00160 
00161     if ( optind == -1 ) {
00162        usage();
00163     }
00164 
00165     if ( base == NULL ) {
00166        if (( base = getenv( "LDAP_BASEDN" )) == NULL ) {
00167            usage();
00168        }
00169     }    
00170     if ( sortattr ) {
00171        for ( sortsize = 0; sortattr[sortsize] != NULL; sortsize++ ) {
00172            ;       /* NULL */
00173        }
00174        sortsize++;             /* add in the final NULL field */
00175        skipsortattr = (int *) malloc( sortsize * sizeof(int *) );
00176        if ( skipsortattr == NULL ) {
00177               fprintf( stderr, "Out of memory\n" );
00178               exit( LDAP_NO_MEMORY );
00179        }
00180        memset( (char *) skipsortattr, 0, sortsize * sizeof(int *) );
00181     } else if ( server_sort ) {
00182        server_sort = 0;   /* ignore this option if no sortattrs were given */
00183     }
00184 
00185     if ( argc - optind < 1 ) {
00186        if ( ldaptool_fp == NULL ) {
00187            usage();
00188        }
00189        attrs = NULL;
00190        filtpattern = "%s";
00191     } else {  /* there are additional args (filter + attrs) */
00192        if ( ldaptool_fp == NULL || strstr( argv[ optind ], "%s" ) != NULL ) {
00193            filtpattern = ldaptool_local2UTF8( argv[ optind ] );
00194            ++optind;
00195        } else {
00196            filtpattern = "%s";
00197        }
00198 
00199        if ( argv[ optind ] == NULL ) {
00200            attrs = NULL;
00201        } else if ( sortattr == NULL || *sortattr == '\0' || server_sort) {
00202            attrs = &argv[ optind ];
00203        } else {
00204            attrs = ldap_charray_dup( &argv[ optind ] );
00205            if ( attrs == NULL ) {
00206               fprintf( stderr, "Out of memory\n" );
00207               exit( LDAP_NO_MEMORY );
00208            }
00209            for ( i = 0; i < (sortsize - 1); i++ ) {
00210                 if ( !ldap_charray_inlist( attrs, sortattr[i] ) ) {
00211                     if ( ldap_charray_add( &attrs, sortattr[i] ) != 0 ) {
00212                      fprintf( stderr, "Out of memory\n" );
00213                      exit( LDAP_NO_MEMORY );
00214                   }
00215                     /*
00216                      * attribute in the search list only for the purpose of
00217                      * sorting
00218                      */
00219                     skipsortattr[i] = 1;
00220                 }
00221            }
00222         }
00223     }
00224 
00225     ld = ldaptool_ldap_init( 0 );
00226 
00227     if ( !ldaptool_not ) {
00228        ldap_set_option( ld, LDAP_OPT_DEREF, &deref );
00229        ldap_set_option( ld, LDAP_OPT_TIMELIMIT, &timelimit );
00230        ldap_set_option( ld, LDAP_OPT_SIZELIMIT, &sizelimit );
00231     }
00232 
00233     ldaptool_bind( ld );
00234 
00235     if ( ldaptool_verbose ) {
00236        printf( "filter pattern: %s\nreturning: ", filtpattern );
00237        if ( attrs == NULL ) {
00238            printf( "ALL" );
00239        } else {
00240            for ( i = 0; attrs[ i ] != NULL; ++i ) {
00241               printf( "%s ", attrs[ i ] );
00242            }
00243        }
00244        putchar( '\n' );
00245     }
00246 
00247     if ( ldaptool_fp == NULL ) {
00248        char *conv;
00249 
00250        conv = ldaptool_local2UTF8( base );
00251        rc = dosearch( ld, conv, scope, attrs, attrsonly, filtpattern, "" );
00252        if( conv != NULL )
00253             free( conv );
00254     } else {
00255        int done = 0;
00256 
00257        rc = LDAP_SUCCESS;
00258        first = 1;
00259        while ( rc == LDAP_SUCCESS && !done ) {
00260            char *linep = NULL;
00261            int   increment = 0;
00262            int         c, index;
00263         
00264            /* allocate initial block of memory */ 
00265            if ((linep = (char *)malloc(BUFSIZ)) == NULL) {
00266                fprintf( stderr, "Out of memory\n" );
00267               exit( LDAP_NO_MEMORY );
00268            }
00269            increment++;
00270            index = 0;
00271            while ((c = fgetc( ldaptool_fp )) != '\n' && c != EOF) {
00272 
00273                /* check if we will overflow the buffer */
00274                if ((c != EOF) && (index == ((increment * BUFSIZ) -1))) {
00275 
00276                   /* if we did, add another BUFSIZ worth of bytes */
00277                   if ((linep = (char *)
00278                      realloc(linep, (increment + 1) * BUFSIZ)) == NULL) {
00279                      fprintf( stderr, "Out of memory\n" );
00280                      exit( LDAP_NO_MEMORY );
00281                   }
00282                   increment++;
00283               }
00284               linep[index++] = c;
00285            }
00286 
00287            if (c == EOF) {
00288               done = 1;
00289               break;
00290            }
00291            
00292            linep[index] = '\0';
00293 
00294            if ( !first ) {
00295               putchar( '\n' );
00296            } else {
00297               first = 0;
00298            }
00299            rc = dosearch( ld, base, scope, attrs, attrsonly, filtpattern,
00300                   linep );
00301            free (linep);
00302        }
00303     }
00304 
00305     ldaptool_cleanup( ld );
00306     return( rc );
00307 }
00308 
00309 
00310 static void
00311 options_callback( int option, char *optarg )
00312 {
00313     char *s, *p, *temp_arg, *ps_ptr, *ps_arg;
00314     int i=0;
00315     
00316     switch( option ) {
00317     case 'u': /* include UFN */
00318        ++includeufn;
00319        break;
00320     case 't': /* write attribute values to /tmp files */
00321        ++vals2tmp;
00322        break;
00323     case 'U': /* produce file URLs in conjunction with -t */
00324        ++produce_file_urls;
00325        break;
00326     case 'e': /* minimize base-64 encoding of values */
00327        ++minimize_base64;
00328        break;
00329     case 'A': /* retrieve attribute names only -- no values */
00330        ++attrsonly;
00331        break;
00332     case 'L':       /* print entries in LDIF format -- now the default */
00333        break;
00334     case 'o': /* print entries using old ldapsearch format */
00335        ldif = 0;
00336        break;
00337     case 'B': /* allow binary values to be printed, even if -o used */
00338        ++allow_binary;
00339        break;
00340     case '1': /* omit leading "version: #" line from LDIF output */
00341        write_ldif_version = 0;
00342        break;
00343     case 's': /* search scope */
00344        if ( strncasecmp( optarg, "base", 4 ) == 0 ) {
00345            scope = LDAP_SCOPE_BASE;
00346        } else if ( strncasecmp( optarg, "one", 3 ) == 0 ) {
00347            scope = LDAP_SCOPE_ONELEVEL;
00348        } else if ( strncasecmp( optarg, "sub", 3 ) == 0 ) {
00349            scope = LDAP_SCOPE_SUBTREE;
00350        } else {
00351            fprintf( stderr, "scope should be base, one, or sub\n" );
00352            usage();
00353        }
00354        break;
00355 
00356     case 'a': /* set alias deref option */
00357        if ( strncasecmp( optarg, "never", 5 ) == 0 ) {
00358            deref = LDAP_DEREF_NEVER;
00359        } else if ( strncasecmp( optarg, "search", 5 ) == 0 ) {
00360            deref = LDAP_DEREF_SEARCHING;
00361        } else if ( strncasecmp( optarg, "find", 4 ) == 0 ) {
00362            deref = LDAP_DEREF_FINDING;
00363        } else if ( strncasecmp( optarg, "always", 6 ) == 0 ) {
00364            deref = LDAP_DEREF_ALWAYS;
00365        } else {
00366            fprintf( stderr, "alias deref should be never, search, find, or always\n" );
00367            usage();
00368        }
00369        break;
00370 
00371     case 'F': /* field separator */
00372        sep = strdup( optarg );
00373        break;
00374     case 'b': /* searchbase */
00375        base = strdup( optarg );
00376        break;
00377     case 'l': /* time limit */
00378        timelimit = atoi( optarg );
00379        break;
00380     case 'x': /* server sorting requested */
00381        server_sort = 1;
00382        break;
00383     case 'z': /* size limit */
00384        sizelimit = atoi( optarg );
00385        break;
00386     case 'S': /* sort attribute */
00387        ldap_charray_add( &sortattr, strdup( optarg ) );
00388        break;
00389     case 'T': /* don't fold lines */
00390        fold = 0;
00391        break;
00392     case 'G':  /* do the virtual list setup */
00393        use_vlv++;
00394        s = strchr(optarg, VLV_PARAM_SEP );
00395        
00396        if (s != NULL)
00397        {
00398            vlv_before = atoi(optarg);
00399            s++;
00400            vlv_after = atoi( s );
00401            s = strchr(s, VLV_PARAM_SEP );
00402            if (s != NULL)
00403            {
00404               s++;
00405               /* below is a small set of logic to implement the following cases
00406                * -G23:23:wilber
00407                * -G23:23:"wilber:wright"
00408                * -G23:23:'wilber'
00409                * -G23:23:wilber wright
00410                * all of the above are before, after, value -  NOTE: a colon not in a quoted 
00411                * string will break the parser!!!!
00412                * -G23:23:45:600
00413                * above is index, count encoding
00414                */
00415 
00416               if (*s == '\'' || *s == '"')
00417               {
00418                   vlv_value = strdup( s );
00419               }
00420               else
00421               {
00422                   if (strchr( s, VLV_PARAM_SEP ))
00423                   {
00424                      /* we have an index + count option */
00425                      vlv_index = atoi( s );
00426                      vlv_count = atoi( strchr( s, VLV_PARAM_SEP) + 1);
00427                   }
00428                   else
00429                   {
00430                      /* we don't have a quote surrounding the assertion value 
00431                       * do we need to??? 
00432                       */
00433                      vlv_value = strdup( s );
00434                   }
00435               }
00436            }
00437            else
00438            {
00439               fprintf( stderr,"Illegal 'after' paramater for virtual list\n" );
00440               exit( LDAP_PARAM_ERROR );
00441            }
00442            
00443        }
00444        else
00445        {
00446            fprintf( stderr,"Illegal 'before' paramater for virtual list\n" );
00447            exit( LDAP_PARAM_ERROR );
00448        }
00449        break;
00450     case 'C':
00451        use_psearch++;
00452        if ( (ps_arg = strdup( optarg)) == NULL ) {
00453            perror ("strdup");
00454            exit (LDAP_NO_MEMORY);
00455        }
00456        
00457        ps_ptr=strtok(ps_arg, ":");
00458        if (ps_ptr == NULL || (strcasecmp(ps_ptr, "ps")) ) {
00459            fprintf (stderr, "Invalid argument for -C\n");
00460            usage();
00461        }
00462        if (ps_ptr=strtok(NULL, ":")) {
00463            if ( (temp_arg = strdup( ps_ptr )) == NULL ) {
00464                perror ("strdup");
00465               exit (LDAP_NO_MEMORY);
00466            } 
00467        } else {
00468            fprintf (stderr, "Invalid argument for -C\n");
00469            usage();
00470        }
00471        if (ps_ptr=strtok(NULL, ":")) {
00472            if ( (changesonly = ldaptool_boolean_str2value(ps_ptr, 0)) == -1) {
00473               fprintf(stderr, "Invalid option value: %s\n", ps_ptr);
00474               usage();
00475            }
00476        }    
00477        if (ps_ptr=strtok(NULL, ":")) {
00478            if ( (return_echg_ctls = ldaptool_boolean_str2value(ps_ptr, 0)) == -1) {
00479               fprintf(stderr, "Invalid option value: %s\n", ps_ptr);
00480               usage();
00481            }
00482        }    
00483 
00484        /* Now parse the temp_arg and build chgtype as
00485         * the changetypes are encountered */
00486 
00487        if ((ps_ptr = strtok( temp_arg, "," )) == NULL) {
00488               usage();
00489        } else {
00490            while ( ps_ptr ) {
00491               if ((strcasecmp(ps_ptr, "add"))==0) 
00492                   chgtype |= LDAP_CHANGETYPE_ADD;
00493               else if ((strcasecmp(ps_ptr, "delete"))==0) 
00494                   chgtype |= LDAP_CHANGETYPE_DELETE;
00495               else if ((strcasecmp(ps_ptr, "modify"))==0) 
00496                   chgtype |= LDAP_CHANGETYPE_MODIFY;
00497               else if ((strcasecmp(ps_ptr, "moddn"))==0) 
00498                   chgtype |= LDAP_CHANGETYPE_MODDN;
00499               else if ((strcasecmp(ps_ptr, "any"))==0) 
00500                   chgtype = LDAP_CHANGETYPE_ANY;
00501               else {
00502                      fprintf(stderr, "Unknown changetype: %s\n", ps_ptr);
00503                      usage();
00504               }
00505               ps_ptr = strtok( NULL, "," );
00506            }
00507          }
00508        break;
00509     default:
00510        usage();
00511        break;
00512     }
00513 }
00514 
00515 
00516 static int
00517 dosearch( ld, base, scope, attrs, attrsonly, filtpatt, value )
00518     LDAP      *ld;
00519     char      *base;
00520     int              scope;
00521     char      **attrs;
00522     int              attrsonly;
00523     char      *filtpatt;
00524     char      *value;
00525 {
00526     char             **refs = NULL, filter[ BUFSIZ ], *filterp = NULL;
00527     int                     rc, first, matches;
00528     LDAPMessage             *res, *e;
00529     LDAPControl             *ldctrl;
00530     LDAPControl             **ctrl_response_array = NULL;
00531     LDAPVirtualList  vlv_data;
00532     int                     msgid = 0;
00533     int                     length = 0;
00534 
00535     length = strlen( filtpatt ) + strlen ( value ) +1;
00536     if ( length > BUFSIZ ) {
00537        if ((filterp = (char *)
00538               malloc ( length )) == NULL) {
00539               perror( "filter and/or pattern too long?" );
00540               exit (LDAP_PARAM_ERROR);
00541        }
00542     } else {
00543        filterp = filter;
00544     }
00545  
00546 #ifdef HAVE_SNPRINTF
00547     if ( snprintf( filterp, length, filtpatt, value ) < 0 ) {
00548        perror( "snprintf filter (filter and/or pattern too long?)" );
00549        exit( LDAP_PARAM_ERROR );
00550     }
00551 #else
00552     sprintf( filterp, filtpatt, value );
00553 #endif
00554 
00555     if ( *filterp == '\0' ) {      /* treat empty filter is a shortcut for oc=* */
00556        strcpy( filterp, "(objectclass=*)" );
00557     }
00558 
00559     if ( ldaptool_verbose ) {
00560        /*
00561         * Display the filter that will be used.  Add surrounding parens.
00562         * if they are missing.
00563         */
00564        if ( '(' == *filterp ) {
00565            printf( "filter is: %s\n", filterp );
00566        } else {
00567            printf( "filter is: (%s)\n", filterp );
00568        }
00569     }
00570 
00571     if ( ldaptool_not ) {
00572        if (filterp != filter)
00573               free (filterp);
00574        return( LDAP_SUCCESS );
00575     }
00576 
00577     if (( ldctrl = ldaptool_create_manage_dsait_control()) != NULL ) {
00578        ldaptool_add_control_to_array(ldctrl, ldaptool_request_ctrls);
00579     }
00580 
00581     if ((ldctrl = ldaptool_create_proxyauth_control(ld)) !=NULL) {
00582        ldaptool_add_control_to_array(ldctrl, ldaptool_request_ctrls);
00583     }
00584     
00585     if (use_psearch) {
00586        if ( ldap_create_persistentsearch_control( ld, chgtype,
00587                 changesonly, return_echg_ctls, 
00588               1, &ldctrl ) != LDAP_SUCCESS )
00589        {
00590               ldap_perror( ld, "ldap_create_persistentsearch_control" );
00591               return (1);
00592        }
00593        ldaptool_add_control_to_array(ldctrl, ldaptool_request_ctrls);
00594     }
00595 
00596 
00597     if (server_sort) {
00598        /* First make a sort key list from the attribute list we have */
00599        LDAPsortkey **keylist = NULL;
00600        int i = 0;
00601        char *sortattrs = NULL;
00602        char *s = NULL;
00603        int string_length = 0;
00604 
00605        /* Count the sort strings */
00606        for (i = 0; i < sortsize - 1 ; i++) {
00607            string_length += strlen(sortattr[i]) + 1;
00608        }
00609 
00610        sortattrs = (char *) malloc(string_length + 1);
00611        if (NULL == sortattrs) {
00612            fprintf( stderr, "Out of memory\n" );
00613            exit( LDAP_NO_MEMORY );
00614        }
00615        
00616        s = sortattrs;
00617        for (i = 0; i < sortsize - 1 ; i++) {
00618            memcpy(s, sortattr[i], strlen(sortattr[i]));
00619            s += strlen(sortattr[i]);
00620            *s++ = ' ';
00621        }
00622 
00623        sortattrs[string_length] = '\0';
00624 
00625        ldap_create_sort_keylist(&keylist,sortattrs);
00626        free(sortattrs);
00627        sortattrs = NULL;
00628 
00629        /* Then make a control for the sort attributes we have */
00630        rc = ldap_create_sort_control(ld,keylist,0,&ldctrl);
00631        ldap_free_sort_keylist(keylist);
00632        if ( rc != LDAP_SUCCESS ) {
00633            if (filterp != filter)
00634               free (filterp);
00635            return( ldaptool_print_lderror( ld, "ldap_create_sort_control",
00636               LDAPTOOL_CHECK4SSL_IF_APPROP ));
00637        }
00638 
00639        ldaptool_add_control_to_array(ldctrl, ldaptool_request_ctrls);
00640 
00641     }
00642     /* remember server side sorting must be available for vlv!!!! */
00643 
00644     if (use_vlv)
00645     {
00646        vlv_data.ldvlist_before_count = vlv_before;
00647        vlv_data.ldvlist_after_count = vlv_after;
00648        if ( ldaptool_verbose ) {
00649            printf( "vlv data %lu, %lu, ", 
00650                   vlv_data.ldvlist_before_count,
00651                   vlv_data.ldvlist_after_count 
00652               );
00653        }
00654        if (vlv_value)
00655        {
00656            vlv_data.ldvlist_attrvalue = vlv_value;
00657            vlv_data.ldvlist_size = 0;
00658            vlv_data.ldvlist_index = 0;
00659            if ( ldaptool_verbose ) {
00660               printf( "%s, 0, 0\n", vlv_data.ldvlist_attrvalue);
00661            }
00662        }
00663        else
00664        {
00665            vlv_data.ldvlist_attrvalue = NULL;
00666            vlv_data.ldvlist_size = vlv_count;
00667            vlv_data.ldvlist_index = vlv_index;
00668            if ( ldaptool_verbose ) {
00669               printf( "(null), %lu, %lu\n", vlv_data.ldvlist_size, vlv_data.ldvlist_index );
00670            }
00671        }
00672        
00673        if ( rc != LDAP_SUCCESS ) {
00674            if (filterp != filter)
00675               free (filterp);
00676            return( ldaptool_print_lderror( ld, "ldap_create_sort_control",
00677               LDAPTOOL_CHECK4SSL_IF_APPROP ));
00678        }
00679        if (LDAP_SUCCESS != (rc = ldap_create_virtuallist_control(ld,
00680               &vlv_data, &ldctrl)))
00681        {
00682            if (filterp != filter)
00683               free (filterp);
00684            return( ldaptool_print_lderror( ld,
00685               "ldap_create_virtuallist_control",
00686               LDAPTOOL_CHECK4SSL_IF_APPROP ));
00687        }
00688 
00689        ldaptool_add_control_to_array(ldctrl, ldaptool_request_ctrls);
00690        
00691     }
00692 
00693     if ( ldap_search_ext( ld, base, scope, filterp, attrs, attrsonly, 
00694            ldaptool_request_ctrls, NULL, NULL, -1, &msgid )
00695            != LDAP_SUCCESS ) {
00696        if (filterp != filter)
00697               free (filterp);
00698        return( ldaptool_print_lderror( ld, "ldap_search",
00699               LDAPTOOL_CHECK4SSL_IF_APPROP ));
00700     }
00701 
00702 
00703     matches = 0;
00704     first = 1;
00705     if ( sortattr && !server_sort ) {
00706         rc = ldap_result( ld, LDAP_RES_ANY, 1, NULL, &res );
00707     } else {
00708         while ( (rc = ldap_result( ld, LDAP_RES_ANY, 0, NULL, &res )) != 
00709               LDAP_RES_SEARCH_RESULT && rc != -1 ) {
00710            if ( rc != LDAP_RES_SEARCH_ENTRY ) {
00711               if ( rc == LDAP_RES_SEARCH_REFERENCE ) {
00712                   parse_and_display_reference( ld, res );
00713               } else if ( rc == LDAP_RES_EXTENDED
00714                      && ldap_msgid( res ) == LDAP_RES_UNSOLICITED ) {
00715                   ldaptool_print_extended_response( ld, res,
00716                          "Unsolicited response" );
00717               } else {
00718                   fprintf( stderr, "%s: ignoring LDAP response message"
00719                          " type 0x%x (%s)\n",
00720                          ldaptool_progname, rc, msgtype2str( rc ));
00721               }
00722               ldap_msgfree( res );
00723               continue;
00724            }
00725            matches++;
00726            e = ldap_first_entry( ld, res );
00727            if ( !first ) {
00728                putchar( '\n' );
00729            } else {
00730                first = 0;
00731            }
00732            print_entry( ld, e, attrsonly );
00733            ldap_msgfree( res );
00734         }
00735     }
00736     if ( rc == -1 ) {
00737        if (filterp != filter)
00738               free (filterp);
00739        return( ldaptool_print_lderror( ld, "ldap_result",
00740               LDAPTOOL_CHECK4SSL_IF_APPROP ));
00741     }
00742 
00743     if ( ldap_parse_result( ld, res, &rc, NULL, NULL, &refs,
00744            &ctrl_response_array, 0 ) != LDAP_SUCCESS ) {
00745        ldaptool_print_lderror( ld, "ldap_parse_result",
00746               LDAPTOOL_CHECK4SSL_IF_APPROP );
00747     } else if ( rc != LDAP_SUCCESS ) {                                          
00748        ldaptool_print_lderror( ld, "ldap_search",
00749               LDAPTOOL_CHECK4SSL_IF_APPROP );
00750     } 
00751     /* Parse the returned sort control */
00752     if (server_sort) {
00753        unsigned long result = 0;
00754        char *attribute;
00755        
00756        if ( LDAP_SUCCESS != ldap_parse_sort_control(ld,ctrl_response_array,&result,&attribute) ) {
00757            ldaptool_print_lderror(ld, "ldap_parse_sort_control",
00758                   LDAPTOOL_CHECK4SSL_IF_APPROP );
00759            ldap_controls_free(ctrl_response_array);
00760            ldap_msgfree(res);
00761            if (filterp != filter)
00762               free (filterp);
00763            return ( ldap_get_lderrno( ld, NULL, NULL ) );
00764        }
00765        
00766        if (0 == result) {
00767            if ( ldaptool_verbose ) {
00768               printf( "Server indicated results sorted OK\n");
00769            }
00770        } else {
00771            if (NULL != attribute) {
00772               printf("Server reported sorting error %ld: %s, attribute in error\"%s\"\n",result,sortresult2string(result),attribute);
00773            } else {
00774               printf("Server reported sorting error %ld: %s\n",result,sortresult2string(result));
00775            }
00776        }
00777 
00778     }
00779 
00780     if (use_vlv)
00781     {
00782        unsigned long vpos, vcount;
00783        int vresult;
00784        if ( LDAP_SUCCESS != ldap_parse_virtuallist_control(ld,ctrl_response_array,&vpos, &vcount,&vresult) ) {
00785            ldaptool_print_lderror( ld, "ldap_parse_virtuallist_control",
00786                   LDAPTOOL_CHECK4SSL_IF_APPROP );
00787            ldap_controls_free(ctrl_response_array);
00788            ldap_msgfree(res);
00789            if (filterp != filter)
00790               free (filterp);
00791            return ( ldap_get_lderrno( ld, NULL, NULL ) );
00792        }
00793        
00794        if (0 == vresult) {
00795            if ( ldaptool_verbose ) {
00796               printf( "Server indicated virtual list positioning OK\n");
00797            }
00798            printf("index %lu content count %lu\n", vpos, vcount);
00799            
00800        } else {
00801            printf("Server reported sorting error %d: %s\n",vresult,sortresult2string(vresult));
00802 
00803        }
00804 
00805     }
00806     
00807     ldap_controls_free(ctrl_response_array);   
00808     
00809     if ( sortattr != NULL && !server_sort) {
00810        
00811        (void) ldap_multisort_entries( ld, &res,
00812                                    ( *sortattr == NULL ) ? NULL : sortattr, 
00813                                    (LDAP_CMP_CALLBACK *)strcasecmp );
00814        matches = 0;
00815        first = 1;
00816        for ( e = ldap_first_entry( ld, res ); e != NULLMSG;
00817              e = ldap_next_entry( ld, e ) ) {
00818            matches++;
00819            if ( !first ) {
00820               putchar( '\n' );
00821            } else {
00822               first = 0;
00823            }
00824            print_entry( ld, e, attrsonly );
00825        }
00826     }
00827     
00828     if ( ldaptool_verbose ) {
00829        printf( "%d matches\n", matches );
00830     }
00831 
00832     if ( refs != NULL ) {
00833        ldaptool_print_referrals( refs );
00834        ldap_value_free( refs );
00835     }
00836 
00837     if (filterp != filter)
00838        free (filterp);
00839 
00840     ldap_msgfree( res );
00841     return( rc );
00842 }
00843 
00844 
00845 static void
00846 print_entry( ld, entry, attrsonly )
00847     LDAP      *ld;
00848     LDAPMessage      *entry;
00849     int              attrsonly;
00850 {
00851     char             *a, *dn, *ufn, tmpfname[ BUFSIZ ];
00852     int                     i, notascii;
00853     BerElement              *ber;
00854     struct berval    **bvals;
00855     FILE             *tmpfp;
00856 #if defined( XP_WIN32 )
00857        char   mode[20] = "w+b";
00858 #else
00859        char   mode[20] = "w";
00860 #endif
00861 
00862     dn = ldap_get_dn( ld, entry );
00863     write_string_attr_value( "dn", dn, LDAPTOOL_WRITEVALOPT_SUPPRESS_NAME );
00864     if ( includeufn ) {
00865        ufn = ldap_dn2ufn( dn );
00866        write_string_attr_value( "ufn", ufn,
00867                      LDAPTOOL_WRITEVALOPT_SUPPRESS_NAME );
00868        free( ufn );
00869     }
00870     ldap_memfree( dn );
00871 
00872     if ( use_psearch ) {
00873        LDAPControl   **ectrls;
00874        int           chgtype, chgnumpresent;
00875        long          chgnum;
00876        char          *prevdn, intbuf[ 128 ];
00877 
00878        if ( ldap_get_entry_controls( ld, entry, &ectrls ) == LDAP_SUCCESS ) {
00879            if ( ldap_parse_entrychange_control( ld, ectrls, &chgtype,
00880                      &prevdn, &chgnumpresent, &chgnum ) == LDAP_SUCCESS ) {
00881               write_string_attr_value(
00882                      LDAPTOOL_PSEARCH_ATTR_PREFIX "changeType",
00883                      changetype_num2string( chgtype ), 0 );
00884               if ( chgnumpresent ) {
00885                   sprintf( intbuf, "%d", chgnum );
00886                   write_string_attr_value(
00887                          LDAPTOOL_PSEARCH_ATTR_PREFIX "changeNumber",
00888                          intbuf, 0 );
00889               }
00890               if ( NULL != prevdn ) {
00891                   write_string_attr_value(
00892                          LDAPTOOL_PSEARCH_ATTR_PREFIX "previousDN",
00893                          prevdn, 0 );
00894                   ldap_memfree( prevdn );
00895               }
00896            }
00897        }
00898     }
00899 
00900     for ( a = ldap_first_attribute( ld, entry, &ber ); a != NULL;
00901            a = ldap_next_attribute( ld, entry, ber ) ) {
00902        if ( ldap_charray_inlist(sortattr, a) &&            /* in the list*/
00903            skipsortattr[ldap_charray_position(sortattr, a)] ) {/* and skip it*/
00904            continue;                                       /* so skip it! */
00905        }
00906        if ( attrsonly ) {
00907            if ( ldif ) {
00908               write_ldif_value( a, "", 0, 0 );
00909            } else {
00910               printf( "%s\n", a );
00911            }
00912        } else if (( bvals = ldap_get_values_len( ld, entry, a )) != NULL ) {
00913            for ( i = 0; bvals[i] != NULL; i++ ) {
00914               if ( vals2tmp ) {
00915 #ifdef HAVE_SNPRINTF
00916                   if ( snprintf( tmpfname, sizeof(tmpfname),
00917                          "%s/ldapsearch-%s-XXXXXX",
00918                          ldaptool_get_tmp_dir(), a ) < 0 ) {
00919                      perror( "snprintf tmpfname (attribute name too long?)" );
00920                      exit( LDAP_PARAM_ERROR );
00921                   }
00922 #else
00923                   sprintf( tmpfname, "%s/ldapsearch-%s-XXXXXX",
00924                          ldaptool_get_tmp_dir(), a );
00925 #endif
00926                   tmpfp = NULL;
00927 
00928                   if ( mktemp( tmpfname ) == NULL ) {
00929                      perror( tmpfname );
00930                   } else if (( tmpfp = fopen( tmpfname, mode)) == NULL ) {
00931                      perror( tmpfname );
00932                   } else if ( bvals[ i ]->bv_len > 0 &&
00933                          fwrite( bvals[ i ]->bv_val,
00934                          bvals[ i ]->bv_len, 1, tmpfp ) == 0 ) {
00935                      perror( tmpfname );
00936                   } else if ( ldif ) {
00937                      if ( produce_file_urls ) {
00938                          char      *url;
00939 
00940                          if ( ldaptool_path2fileurl( tmpfname, &url ) !=
00941                             LDAPTOOL_FILEURL_SUCCESS ) {
00942                                 perror( "ldaptool_path2fileurl" );
00943                             } else {
00944                                 write_ldif_value( a, url, strlen( url ),
00945                                        LDIF_OPT_VALUE_IS_URL );
00946                                 free( url );
00947                             }
00948                      } else {
00949                          write_ldif_value( a, tmpfname, strlen( tmpfname ),
00950                                 0 );
00951                      }
00952                   } else {
00953                      printf( "%s%s%s\n", a, sep, tmpfname );
00954                   }
00955 
00956                   if ( tmpfp != NULL ) {
00957                      fclose( tmpfp );
00958                   }
00959               } else {
00960                   notascii = 0;
00961                   if ( !ldif && !allow_binary ) {
00962                      notascii = !ldaptool_berval_is_ascii( bvals[i] );
00963                   }
00964 
00965                   if ( ldif ) {
00966                      write_ldif_value( a, bvals[ i ]->bv_val,
00967                             bvals[ i ]->bv_len, 0 );
00968                   } else {
00969                      printf( "%s%s%s\n", a, sep,
00970                             notascii ? "NOT ASCII" : bvals[ i ]->bv_val );
00971                   }
00972               }
00973            }
00974            ber_bvecfree( bvals );
00975        }
00976        ldap_memfree( a );
00977     }
00978 
00979     if ( ldap_get_lderrno( ld, NULL, NULL ) != LDAP_SUCCESS ) {
00980        ldaptool_print_lderror( ld, "ldap_first_attribute/ldap_next_attribute",
00981               LDAPTOOL_CHECK4SSL_IF_APPROP );
00982     }
00983 
00984     if ( ber != NULL ) {
00985        ber_free( ber, 0 );
00986     }
00987 }
00988 
00989 
00990 static void
00991 write_string_attr_value( char *attrname, char *strval, unsigned long opts )
00992 {
00993     if ( strval == NULL ) {
00994        strval = "";
00995     }
00996     if ( ldif ) {
00997        write_ldif_value( attrname, strval, strlen( strval ), 0 );
00998     } else if ( 0 != ( opts & LDAPTOOL_WRITEVALOPT_SUPPRESS_NAME )) {
00999        printf( "%s\n", strval );
01000     } else {
01001        printf( "%s%s%s\n", attrname, sep, strval );
01002     }
01003 }
01004 
01005 
01006 static int
01007 write_ldif_value( char *type, char *value, unsigned long vallen,
01008        unsigned long ldifoptions )
01009 {
01010     char      *ldif;
01011     static int       wrote_version = 0;
01012 
01013     if ( write_ldif_version && !wrote_version ) {
01014        char   versionbuf[ 64 ];
01015 
01016        wrote_version = 1;
01017        sprintf( versionbuf, "%d", LDIF_VERSION_ONE );
01018        write_ldif_value( "version", versionbuf, strlen( versionbuf ), 0 );
01019     }
01020 
01021     if ( !fold ) {
01022        ldifoptions |= LDIF_OPT_NOWRAP;
01023     }
01024     if ( minimize_base64 ) {
01025        ldifoptions |= LDIF_OPT_MINIMAL_ENCODING;
01026     }
01027 
01028     if (( ldif = ldif_type_and_value_with_options( type, value, (int)vallen,
01029            ldifoptions )) == NULL ) {
01030        return( -1 );
01031     }
01032 
01033     fputs( ldif, stdout );
01034     free( ldif );
01035 
01036     return( 0 );
01037 }
01038 
01039 
01040 static char *
01041 sortresult2string(unsigned long result)
01042 {
01043        /*
01044             success                   (0), -- results are sorted
01045             operationsError           (1), -- server internal failure
01046             timeLimitExceeded         (3), -- timelimit reached before
01047                                            -- sorting was completed
01048             strongAuthRequired        (8), -- refused to return sorted
01049                                            -- results via insecure
01050                                            -- protocol
01051             adminLimitExceeded       (11), -- too many matching entries
01052                                            -- for the server to sort
01053             noSuchAttribute          (16), -- unrecognized attribute
01054                                            -- type in sort key
01055             inappropriateMatching    (18), -- unrecognized or inappro-
01056                                            -- priate matching rule in
01057                                            -- sort key
01058             insufficientAccessRights (50), -- refused to return sorted
01059                                            -- results to this client
01060             busy                     (51), -- too busy to process
01061             unwillingToPerform       (53), -- unable to sort
01062             other                    (80)
01063        */
01064 
01065        switch (result) {
01066        case 0: return ("success");
01067        case 1: return ("operations error");
01068        case 3: return ("time limit exceeded");
01069        case 8: return ("strong auth required");
01070        case 11: return ("admin limit exceeded");
01071        case 16: return ("no such attribute");
01072        case 18: return ("unrecognized or inappropriate matching rule");
01073        case 50: return ("insufficient access rights");
01074        case 51: return ("too busy");
01075        case 53: return ("unable to sort");
01076        case 80:
01077         default: return ("Er...Other ?");
01078        }
01079 }
01080 
01081 
01082 static void
01083 parse_and_display_reference( LDAP *ld, LDAPMessage *ref )
01084 {
01085     int              i;
01086     char      **refs;
01087 
01088     if ( ldap_parse_reference( ld, ref, &refs, NULL, 0 ) != LDAP_SUCCESS ) {
01089        ldaptool_print_lderror( ld, "ldap_parse_reference",
01090               LDAPTOOL_CHECK4SSL_IF_APPROP );
01091     } else if ( refs != NULL && refs[ 0 ] != NULL ) {
01092        fputs( "Unfollowed continuation reference(s):\n", stderr );
01093        for ( i = 0; refs[ i ] != NULL; ++i ) {
01094            fprintf( stderr, "    %s\n", refs[ i ] );
01095        }
01096        ldap_value_free( refs );
01097     }
01098 }
01099 
01100 
01101 /*possible operations a client can invoke -- copied from ldaprot.h */          
01102 
01103 #ifndef LDAP_REQ_BIND                                                           
01104 #define LDAP_REQ_BIND                   0x60L   /* application + constructed */ 
01105 #define LDAP_REQ_UNBIND                 0x42L   /* application + primitive   */ 
01106 #define LDAP_REQ_SEARCH                 0x63L   /* application + constructed */ 
01107 #define LDAP_REQ_MODIFY                 0x66L   /* application + constructed */ 
01108 #define LDAP_REQ_ADD                    0x68L   /* application + constructed */ 
01109 #define LDAP_REQ_DELETE                 0x4aL   /* application + primitive   */ 
01110 #define LDAP_REQ_RENAME                 0x6cL   /* application + constructed */ 
01111 #define LDAP_REQ_COMPARE                0x6eL   /* application + constructed */ 
01112 #define LDAP_REQ_ABANDON                0x50L   /* application + primitive   */ 
01113 #define LDAP_REQ_EXTENDED               0x77L   /* application + constructed */ 
01114 #endif /* LDAP_REQ_BIND */                                                      
01115 
01116 
01117 
01118 struct ldapsearch_type2str {
01119     
01120     int         ldst2s_type;    /* message type */ 
01121     char        *ldst2s_string; /* descriptive string */     
01122 };  
01123 
01124 
01125 static struct ldapsearch_type2str ldapsearch_msgtypes[] = {
01126     
01127     /* results: */    
01128     { LDAP_RES_BIND,                    "bind result" },
01129     { LDAP_RES_SEARCH_REFERENCE,        "continuation reference" },
01130     { LDAP_RES_SEARCH_ENTRY,            "entry" },
01131     { LDAP_RES_SEARCH_RESULT,           "search result" },
01132     { LDAP_RES_MODIFY,                  "modify result" },
01133     { LDAP_RES_ADD,                     "add result" }, 
01134     { LDAP_RES_DELETE,                  "delete result" },
01135     { LDAP_RES_MODDN,                   "rename result" },
01136     { LDAP_RES_COMPARE,                 "compare result" },
01137     { LDAP_RES_EXTENDED,                "extended operation result" },
01138     /* requests: */ 
01139     { LDAP_REQ_BIND,                    "bind request" }, 
01140     { LDAP_REQ_UNBIND,                  "unbind request" }, 
01141     { LDAP_REQ_SEARCH,                  "search request" }, 
01142     { LDAP_REQ_MODIFY,                  "modify request" }, 
01143     { LDAP_REQ_ADD,                     "add request" },
01144     { LDAP_REQ_DELETE,                  "delete request" }, 
01145     { LDAP_REQ_RENAME,                  "rename request" }, 
01146     { LDAP_REQ_COMPARE,                 "compare request" }, 
01147     { LDAP_REQ_ABANDON,                 "abandon request" }, 
01148     { LDAP_REQ_EXTENDED,                "extended request" },
01149     
01150 };
01151 
01152 
01153 #define LDAPSEARCHTOOL_NUMTYPES (sizeof(ldapsearch_msgtypes) \
01154                              / sizeof(struct ldapsearch_type2str))
01155 
01156 
01157 /*
01158 * Return a descriptive string given an LDAP result message type (tag). 
01159 */     
01160 static char * 
01161 msgtype2str( int msgtype )
01162 {    
01163     char        *s = "unknown"; 
01164     int         i;
01165     
01166     s = "unknown";
01167     for ( i = 0; i < LDAPSEARCHTOOL_NUMTYPES; ++i ) {
01168        if ( msgtype == ldapsearch_msgtypes[ i ].ldst2s_type ) {
01169            s = ldapsearch_msgtypes[ i ].ldst2s_string;  
01170        }      
01171     }    
01172     return( s );
01173 }
01174 
01175 
01176 /*
01177  * Return a descriptive string given a Persistent Search change type
01178  */
01179 static char *
01180 changetype_num2string( int chgtype )
01181 {
01182     char      *s = "unknown";
01183 
01184     switch( chgtype ) {
01185     case LDAP_CHANGETYPE_ADD:
01186        s = "add";
01187        break;
01188     case LDAP_CHANGETYPE_DELETE:
01189        s = "delete";
01190        break;
01191     case LDAP_CHANGETYPE_MODIFY:
01192        s = "modify";
01193        break;
01194     case LDAP_CHANGETYPE_MODDN:
01195        s = "moddn";
01196        break;
01197     }
01198 
01199     return( s );
01200 }