Back to index

openldap  2.4.31
search.c
Go to the documentation of this file.
00001 /* $OpenLDAP$ */
00002 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
00003  *
00004  * Copyright 1998-2012 The OpenLDAP Foundation.
00005  * All rights reserved.
00006  *
00007  * Redistribution and use in source and binary forms, with or without
00008  * modification, are permitted only as authorized by the OpenLDAP
00009  * Public License.
00010  *
00011  * A copy of this license is available in the file LICENSE in the
00012  * top-level directory of the distribution or, alternatively, at
00013  * <http://www.OpenLDAP.org/license.html>.
00014  */
00015 /* Portions Copyright (c) 1990 Regents of the University of Michigan.
00016  * All rights reserved.
00017  */
00018 
00019 #include "portable.h"
00020 
00021 #include <stdio.h>
00022 
00023 #include <ac/stdlib.h>
00024 
00025 #include <ac/socket.h>
00026 #include <ac/string.h>
00027 #include <ac/time.h>
00028 
00029 #include "ldap-int.h"
00030 #include "ldap_log.h"
00031 
00032 /*
00033  * ldap_search_ext - initiate an ldap search operation.
00034  *
00035  * Parameters:
00036  *
00037  *     ld            LDAP descriptor
00038  *     base          DN of the base object
00039  *     scope         the search scope - one of
00040  *                          LDAP_SCOPE_BASE (baseObject),
00041  *                       LDAP_SCOPE_ONELEVEL (oneLevel),
00042  *                          LDAP_SCOPE_SUBTREE (subtree), or
00043  *                          LDAP_SCOPE_SUBORDINATE (children) -- OpenLDAP extension
00044  *     filter        a string containing the search filter
00045  *                   (e.g., "(|(cn=bob)(sn=bob))")
00046  *     attrs         list of attribute types to return for matches
00047  *     attrsonly     1 => attributes only 0 => attributes and values
00048  *
00049  * Example:
00050  *     char   *attrs[] = { "mail", "title", 0 };
00051  *     ldap_search_ext( ld, "dc=example,dc=com", LDAP_SCOPE_SUBTREE, "cn~=bob",
00052  *         attrs, attrsonly, sctrls, ctrls, timeout, sizelimit,
00053  *            &msgid );
00054  */
00055 int
00056 ldap_search_ext(
00057        LDAP *ld,
00058        LDAP_CONST char *base,
00059        int scope,
00060        LDAP_CONST char *filter,
00061        char **attrs,
00062        int attrsonly,
00063        LDAPControl **sctrls,
00064        LDAPControl **cctrls,
00065        struct timeval *timeout,
00066        int sizelimit,
00067        int *msgidp )
00068 {
00069        return ldap_pvt_search( ld, base, scope, filter, attrs,
00070               attrsonly, sctrls, cctrls, timeout, sizelimit, -1, msgidp );
00071 }
00072 
00073 int
00074 ldap_pvt_search(
00075        LDAP *ld,
00076        LDAP_CONST char *base,
00077        int scope,
00078        LDAP_CONST char *filter,
00079        char **attrs,
00080        int attrsonly,
00081        LDAPControl **sctrls,
00082        LDAPControl **cctrls,
00083        struct timeval *timeout,
00084        int sizelimit,
00085        int deref,
00086        int *msgidp )
00087 {
00088        int rc;
00089        BerElement    *ber;
00090        int timelimit;
00091        ber_int_t id;
00092 
00093        Debug( LDAP_DEBUG_TRACE, "ldap_search_ext\n", 0, 0, 0 );
00094 
00095        assert( ld != NULL );
00096        assert( LDAP_VALID( ld ) );
00097 
00098        /* check client controls */
00099        rc = ldap_int_client_controls( ld, cctrls );
00100        if( rc != LDAP_SUCCESS ) return rc;
00101 
00102        /*
00103         * if timeout is provided, both tv_sec and tv_usec must
00104         * not be zero
00105         */
00106        if( timeout != NULL ) {
00107               if( timeout->tv_sec == 0 && timeout->tv_usec == 0 ) {
00108                      return LDAP_PARAM_ERROR;
00109               }
00110 
00111               /* timelimit must be non-zero if timeout is provided */
00112               timelimit = timeout->tv_sec != 0 ? timeout->tv_sec : 1;
00113 
00114        } else {
00115               /* no timeout, no timelimit */
00116               timelimit = -1;
00117        }
00118 
00119        ber = ldap_build_search_req( ld, base, scope, filter, attrs,
00120            attrsonly, sctrls, cctrls, timelimit, sizelimit, deref, &id ); 
00121 
00122        if ( ber == NULL ) {
00123               return ld->ld_errno;
00124        }
00125 
00126 
00127        /* send the message */
00128        *msgidp = ldap_send_initial_request( ld, LDAP_REQ_SEARCH, base, ber, id );
00129 
00130        if( *msgidp < 0 )
00131               return ld->ld_errno;
00132 
00133        return LDAP_SUCCESS;
00134 }
00135 
00136 int
00137 ldap_search_ext_s(
00138        LDAP *ld,
00139        LDAP_CONST char *base,
00140        int scope,
00141        LDAP_CONST char *filter,
00142        char **attrs,
00143        int attrsonly,
00144        LDAPControl **sctrls,
00145        LDAPControl **cctrls,
00146        struct timeval *timeout,
00147        int sizelimit,
00148        LDAPMessage **res )
00149 {
00150        return ldap_pvt_search_s( ld, base, scope, filter, attrs,
00151               attrsonly, sctrls, cctrls, timeout, sizelimit, -1, res );
00152 }
00153 
00154 int
00155 ldap_pvt_search_s(
00156        LDAP *ld,
00157        LDAP_CONST char *base,
00158        int scope,
00159        LDAP_CONST char *filter,
00160        char **attrs,
00161        int attrsonly,
00162        LDAPControl **sctrls,
00163        LDAPControl **cctrls,
00164        struct timeval *timeout,
00165        int sizelimit,
00166        int deref,
00167        LDAPMessage **res )
00168 {
00169        int rc;
00170        int    msgid;
00171 
00172     *res = NULL;
00173 
00174        rc = ldap_pvt_search( ld, base, scope, filter, attrs, attrsonly,
00175               sctrls, cctrls, timeout, sizelimit, deref, &msgid );
00176 
00177        if ( rc != LDAP_SUCCESS ) {
00178               return( rc );
00179        }
00180 
00181        rc = ldap_result( ld, msgid, LDAP_MSG_ALL, timeout, res );
00182 
00183        if( rc <= 0 ) {
00184               /* error(-1) or timeout(0) */
00185               if ( ld->ld_errno == LDAP_TIMEOUT ) {
00186                      /* cleanup request */
00187                      (void) ldap_abandon( ld, msgid );
00188                      ld->ld_errno = LDAP_TIMEOUT;
00189               }
00190               return( ld->ld_errno );
00191        }
00192 
00193        if( rc == LDAP_RES_SEARCH_REFERENCE || rc == LDAP_RES_INTERMEDIATE ) {
00194               return( ld->ld_errno );
00195        }
00196 
00197        return( ldap_result2error( ld, *res, 0 ) );
00198 }
00199 
00200 /*
00201  * ldap_search - initiate an ldap search operation.
00202  *
00203  * Parameters:
00204  *
00205  *     ld            LDAP descriptor
00206  *     base          DN of the base object
00207  *     scope         the search scope - one of
00208  *                          LDAP_SCOPE_BASE (baseObject),
00209  *                       LDAP_SCOPE_ONELEVEL (oneLevel),
00210  *                          LDAP_SCOPE_SUBTREE (subtree), or
00211  *                          LDAP_SCOPE_SUBORDINATE (children) -- OpenLDAP extension
00212  *     filter        a string containing the search filter
00213  *                   (e.g., "(|(cn=bob)(sn=bob))")
00214  *     attrs         list of attribute types to return for matches
00215  *     attrsonly     1 => attributes only 0 => attributes and values
00216  *
00217  * Example:
00218  *     char   *attrs[] = { "mail", "title", 0 };
00219  *     msgid = ldap_search( ld, "dc=example,dc=com", LDAP_SCOPE_SUBTREE, "cn~=bob",
00220  *         attrs, attrsonly );
00221  */
00222 int
00223 ldap_search(
00224        LDAP *ld, LDAP_CONST char *base, int scope, LDAP_CONST char *filter,
00225        char **attrs, int attrsonly )
00226 {
00227        BerElement    *ber;
00228        ber_int_t     id;
00229 
00230        Debug( LDAP_DEBUG_TRACE, "ldap_search\n", 0, 0, 0 );
00231 
00232        assert( ld != NULL );
00233        assert( LDAP_VALID( ld ) );
00234 
00235        ber = ldap_build_search_req( ld, base, scope, filter, attrs,
00236            attrsonly, NULL, NULL, -1, -1, -1, &id ); 
00237 
00238        if ( ber == NULL ) {
00239               return( -1 );
00240        }
00241 
00242 
00243        /* send the message */
00244        return ( ldap_send_initial_request( ld, LDAP_REQ_SEARCH, base, ber, id ));
00245 }
00246 
00247 
00248 BerElement *
00249 ldap_build_search_req(
00250        LDAP *ld,
00251        LDAP_CONST char *base,
00252        ber_int_t scope,
00253        LDAP_CONST char *filter,
00254        char **attrs,
00255        ber_int_t attrsonly,
00256        LDAPControl **sctrls,
00257        LDAPControl **cctrls,
00258        ber_int_t timelimit,
00259        ber_int_t sizelimit,
00260        ber_int_t deref,
00261        ber_int_t *idp)
00262 {
00263        BerElement    *ber;
00264        int           err;
00265 
00266        /*
00267         * Create the search request.  It looks like this:
00268         *     SearchRequest := [APPLICATION 3] SEQUENCE {
00269         *            baseObject    DistinguishedName,
00270         *            scope         ENUMERATED {
00271         *                   baseObject    (0),
00272         *                   singleLevel   (1),
00273         *                   wholeSubtree  (2)
00274         *            },
00275         *            derefAliases  ENUMERATED {
00276         *                   neverDerefaliases    (0),
00277         *                   derefInSearching     (1),
00278         *                   derefFindingBaseObj  (2),
00279         *                   alwaysDerefAliases   (3)
00280         *            },
00281         *            sizelimit     INTEGER (0 .. 65535),
00282         *            timelimit     INTEGER (0 .. 65535),
00283         *            attrsOnly     BOOLEAN,
00284         *            filter        Filter,
00285         *            attributes    SEQUENCE OF AttributeType
00286         *     }
00287         * wrapped in an ldap message.
00288         */
00289 
00290        /* create a message to send */
00291        if ( (ber = ldap_alloc_ber_with_options( ld )) == NULL ) {
00292               return( NULL );
00293        }
00294 
00295        if ( base == NULL ) {
00296               /* no base provided, use session default base */
00297               base = ld->ld_options.ldo_defbase;
00298 
00299               if ( base == NULL ) {
00300                      /* no session default base, use top */
00301                      base = "";
00302               }
00303        }
00304 
00305        LDAP_NEXT_MSGID( ld, *idp );
00306 #ifdef LDAP_CONNECTIONLESS
00307        if ( LDAP_IS_UDP(ld) ) {
00308               struct sockaddr sa = {0};
00309               /* dummy, filled with ldo_peer in request.c */
00310            err = ber_write( ber, (char *) &sa, sizeof( sa ), 0 );
00311        }
00312        if ( LDAP_IS_UDP(ld) && ld->ld_options.ldo_version == LDAP_VERSION2) {
00313            char *dn = ld->ld_options.ldo_cldapdn;
00314            if (!dn) dn = "";
00315            err = ber_printf( ber, "{ist{seeiib", *idp, dn,
00316               LDAP_REQ_SEARCH, base, (ber_int_t) scope,
00317               (deref < 0) ? ld->ld_deref : deref,
00318               (sizelimit < 0) ? ld->ld_sizelimit : sizelimit,
00319               (timelimit < 0) ? ld->ld_timelimit : timelimit,
00320               attrsonly );
00321        } else
00322 #endif
00323        {
00324            err = ber_printf( ber, "{it{seeiib", *idp,
00325               LDAP_REQ_SEARCH, base, (ber_int_t) scope,
00326               (deref < 0) ? ld->ld_deref : deref,
00327               (sizelimit < 0) ? ld->ld_sizelimit : sizelimit,
00328               (timelimit < 0) ? ld->ld_timelimit : timelimit,
00329               attrsonly );
00330        }
00331 
00332        if ( err == -1 ) {
00333               ld->ld_errno = LDAP_ENCODING_ERROR;
00334               ber_free( ber, 1 );
00335               return( NULL );
00336        }
00337 
00338        if( filter == NULL ) {
00339               filter = "(objectclass=*)";
00340        }
00341 
00342        err = ldap_pvt_put_filter( ber, filter );
00343 
00344        if ( err  == -1 ) {
00345               ld->ld_errno = LDAP_FILTER_ERROR;
00346               ber_free( ber, 1 );
00347               return( NULL );
00348        }
00349 
00350 #ifdef LDAP_DEBUG
00351        if ( ldap_debug & LDAP_DEBUG_ARGS ) {
00352               char   buf[ BUFSIZ ], *ptr = " *";
00353 
00354               if ( attrs != NULL ) {
00355                      int    i, len, rest = sizeof( buf );
00356 
00357                      for ( i = 0; attrs[ i ] != NULL && rest > 0; i++ ) {
00358                             ptr = &buf[ sizeof( buf ) - rest ];
00359                             len = snprintf( ptr, rest, " %s", attrs[ i ] );
00360                             rest -= (len >= 0 ? len : (int) sizeof( buf ));
00361                      }
00362 
00363                      if ( rest <= 0 ) {
00364                             AC_MEMCPY( &buf[ sizeof( buf ) - STRLENOF( "...(truncated)" ) - 1 ],
00365                                    "...(truncated)", STRLENOF( "...(truncated)" ) + 1 );
00366                      } 
00367                      ptr = buf;
00368               }
00369 
00370               Debug( LDAP_DEBUG_ARGS, "ldap_build_search_req ATTRS:%s\n", ptr, 0,0 );
00371        }
00372 #endif /* LDAP_DEBUG */
00373 
00374        if ( ber_printf( ber, /*{*/ "{v}N}", attrs ) == -1 ) {
00375               ld->ld_errno = LDAP_ENCODING_ERROR;
00376               ber_free( ber, 1 );
00377               return( NULL );
00378        }
00379 
00380        /* Put Server Controls */
00381        if( ldap_int_put_controls( ld, sctrls, ber ) != LDAP_SUCCESS ) {
00382               ber_free( ber, 1 );
00383               return( NULL );
00384        }
00385 
00386        if ( ber_printf( ber, /*{*/ "N}" ) == -1 ) {
00387               ld->ld_errno = LDAP_ENCODING_ERROR;
00388               ber_free( ber, 1 );
00389               return( NULL );
00390        }
00391 
00392        return( ber );
00393 }
00394 
00395 int
00396 ldap_search_st(
00397        LDAP *ld, LDAP_CONST char *base, int scope,
00398        LDAP_CONST char *filter, char **attrs,
00399        int attrsonly, struct timeval *timeout, LDAPMessage **res )
00400 {
00401        int    msgid;
00402 
00403     *res = NULL;
00404 
00405        if ( (msgid = ldap_search( ld, base, scope, filter, attrs, attrsonly ))
00406            == -1 )
00407               return( ld->ld_errno );
00408 
00409        if ( ldap_result( ld, msgid, LDAP_MSG_ALL, timeout, res ) == -1 || !*res )
00410               return( ld->ld_errno );
00411 
00412        if ( ld->ld_errno == LDAP_TIMEOUT ) {
00413               (void) ldap_abandon( ld, msgid );
00414               ld->ld_errno = LDAP_TIMEOUT;
00415               return( ld->ld_errno );
00416        }
00417 
00418        return( ldap_result2error( ld, *res, 0 ) );
00419 }
00420 
00421 int
00422 ldap_search_s(
00423        LDAP *ld,
00424        LDAP_CONST char *base,
00425        int scope,
00426        LDAP_CONST char *filter,
00427        char **attrs,
00428        int attrsonly,
00429        LDAPMessage **res )
00430 {
00431        int    msgid;
00432 
00433     *res = NULL;
00434 
00435        if ( (msgid = ldap_search( ld, base, scope, filter, attrs, attrsonly ))
00436            == -1 )
00437               return( ld->ld_errno );
00438 
00439        if ( ldap_result( ld, msgid, LDAP_MSG_ALL, (struct timeval *) NULL, res ) == -1 || !*res )
00440               return( ld->ld_errno );
00441 
00442        return( ldap_result2error( ld, *res, 0 ) );
00443 }
00444 
00445 static char escape[128] = {
00446        1, 1, 1, 1, 1, 1, 1, 1,
00447        1, 1, 1, 1, 1, 1, 1, 1,
00448        1, 1, 1, 1, 1, 1, 1, 1,
00449        1, 1, 1, 1, 1, 1, 1, 1,
00450 
00451        0, 0, 0, 0, 0, 0, 0, 0,
00452        1, 1, 1, 0, 0, 0, 0, 0,
00453        0, 0, 0, 0, 0, 0, 0, 0,
00454        0, 0, 0, 0, 0, 0, 0, 0,
00455 
00456        0, 0, 0, 0, 0, 0, 0, 0,
00457        0, 0, 0, 0, 0, 0, 0, 0,
00458        0, 0, 0, 0, 0, 0, 0, 0,
00459        0, 0, 0, 0, 1, 0, 0, 0,
00460 
00461        0, 0, 0, 0, 0, 0, 0, 0,
00462        0, 0, 0, 0, 0, 0, 0, 0,
00463        0, 0, 0, 0, 0, 0, 0, 0,
00464        0, 0, 0, 0, 0, 0, 0, 1
00465 };
00466 #define       NEEDFLTESCAPE(c)     ((c) & 0x80 || escape[ (unsigned)(c) ])
00467 
00468 /*
00469  * compute the length of the escaped value
00470  */
00471 ber_len_t
00472 ldap_bv2escaped_filter_value_len( struct berval *in )
00473 {
00474        ber_len_t     i, l;
00475 
00476        assert( in != NULL );
00477 
00478        if ( in->bv_len == 0 ) {
00479               return 0;
00480        }
00481 
00482        for( l = 0, i = 0; i < in->bv_len; l++, i++ ) {
00483               char c = in->bv_val[ i ];
00484               if ( NEEDFLTESCAPE( c ) ) {
00485                      l += 2;
00486               }
00487        }
00488 
00489        return l;
00490 }
00491 
00492 int
00493 ldap_bv2escaped_filter_value( struct berval *in, struct berval *out )
00494 {
00495        return ldap_bv2escaped_filter_value_x( in, out, 0, NULL );
00496 }
00497 
00498 int
00499 ldap_bv2escaped_filter_value_x( struct berval *in, struct berval *out, int inplace, void *ctx )
00500 {
00501        ber_len_t     i, l;
00502 
00503        assert( in != NULL );
00504        assert( out != NULL );
00505 
00506        BER_BVZERO( out );
00507 
00508        if ( in->bv_len == 0 ) {
00509               return 0;
00510        }
00511 
00512        /* assume we'll escape everything */
00513        l = ldap_bv2escaped_filter_value_len( in );
00514        if ( l == in->bv_len ) {
00515               if ( inplace ) {
00516                      *out = *in;
00517               } else {
00518                      ber_dupbv( out, in );
00519               }
00520               return 0;
00521        }
00522        out->bv_val = LDAP_MALLOCX( l + 1, ctx );
00523        if ( out->bv_val == NULL ) {
00524               return -1;
00525        }
00526 
00527        for ( i = 0; i < in->bv_len; i++ ) {
00528               char c = in->bv_val[ i ];
00529               if ( NEEDFLTESCAPE( c ) ) {
00530                      assert( out->bv_len < l - 2 );
00531                      out->bv_val[out->bv_len++] = '\\';
00532                      out->bv_val[out->bv_len++] = "0123456789ABCDEF"[0x0f & (c>>4)];
00533                      out->bv_val[out->bv_len++] = "0123456789ABCDEF"[0x0f & c];
00534 
00535               } else {
00536                      assert( out->bv_len < l );
00537                      out->bv_val[out->bv_len++] = c;
00538               }
00539        }
00540 
00541        out->bv_val[out->bv_len] = '\0';
00542 
00543        return 0;
00544 }
00545