home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / ldapsdk.zip / libraries / libldap / search.c < prev    next >
C/C++ Source or Header  |  2001-07-22  |  19KB  |  957 lines

  1. /* $OpenLDAP: pkg/ldap/libraries/libldap/search.c,v 1.22.2.8 2001/07/21 19:01:40 kurt Exp $ */
  2. /*
  3.  * Copyright 1998-2000 The OpenLDAP Foundation, All Rights Reserved.
  4.  * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
  5.  */
  6. /*  Portions
  7.  *  Copyright (c) 1990 Regents of the University of Michigan.
  8.  *  All rights reserved.
  9.  *
  10.  *  search.c
  11.  */
  12.  
  13. #include "portable.h"
  14.  
  15. #include <stdio.h>
  16.  
  17. #include <ac/stdlib.h>
  18.  
  19. #include <ac/socket.h>
  20. #include <ac/string.h>
  21. #include <ac/time.h>
  22.  
  23. #include "ldap-int.h"
  24.  
  25. static int ldap_is_attr_oid LDAP_P((
  26.     const char *attr ));
  27.  
  28. static int ldap_is_attr_desc LDAP_P((
  29.     const char *attr ));
  30.  
  31. static int hex2value LDAP_P((
  32.     int c ));
  33.  
  34. static char *find_right_paren LDAP_P((
  35.     char *s ));
  36.  
  37. static char *put_complex_filter LDAP_P((
  38.     BerElement *ber,
  39.     char *str,
  40.     ber_tag_t tag,
  41.     int not ));
  42.  
  43. static int put_filter LDAP_P((
  44.     BerElement *ber,
  45.     char *str ));
  46.  
  47. static int put_simple_filter LDAP_P((
  48.     BerElement *ber,
  49.     char *str ));
  50.  
  51. static int put_substring_filter LDAP_P((
  52.     BerElement *ber,
  53.     char *type,
  54.     char *str ));
  55.  
  56. static int put_filter_list LDAP_P((
  57.     BerElement *ber,
  58.     char *str ));
  59.  
  60. /*
  61.  * ldap_search_ext - initiate an ldap search operation.
  62.  *
  63.  * Parameters:
  64.  *
  65.  *    ld        LDAP descriptor
  66.  *    base        DN of the base object
  67.  *    scope        the search scope - one of LDAP_SCOPE_BASE,
  68.  *                LDAP_SCOPE_ONELEVEL, LDAP_SCOPE_SUBTREE
  69.  *    filter        a string containing the search filter
  70.  *            (e.g., "(|(cn=bob)(sn=bob))")
  71.  *    attrs        list of attribute types to return for matches
  72.  *    attrsonly    1 => attributes only 0 => attributes and values
  73.  *
  74.  * Example:
  75.  *    char    *attrs[] = { "mail", "title", 0 };
  76.  *    ldap_search_ext( ld, "c=us,o=UM", LDAP_SCOPE_SUBTREE, "cn~=bob",
  77.  *        attrs, attrsonly, sctrls, ctrls, timeout, sizelimit,
  78.  *        &msgid );
  79.  */
  80. int
  81. ldap_search_ext(
  82.     LDAP *ld,
  83.     LDAP_CONST char *base,
  84.     int scope,
  85.     LDAP_CONST char *filter,
  86.     char **attrs,
  87.     int attrsonly,
  88.     LDAPControl **sctrls,
  89.     LDAPControl **cctrls,
  90.     struct timeval *timeout,
  91.     int sizelimit,
  92.     int *msgidp )
  93. {
  94.     int rc;
  95.     BerElement    *ber;
  96.     int timelimit;
  97.  
  98.     Debug( LDAP_DEBUG_TRACE, "ldap_search_ext\n", 0, 0, 0 );
  99.  
  100.     assert( ld != NULL );
  101.     assert( LDAP_VALID( ld ) );
  102.  
  103.     /* check client controls */
  104.     rc = ldap_int_client_controls( ld, cctrls );
  105.     if( rc != LDAP_SUCCESS ) return rc;
  106.  
  107.     /*
  108.      * if timeout is provided, both tv_sec and tv_usec must
  109.      * be non-zero
  110.      */
  111.     if( timeout != NULL ) {
  112.         if( timeout->tv_sec == 0 && timeout->tv_usec == 0 ) {
  113.             return LDAP_PARAM_ERROR;
  114.         }
  115.  
  116.         /* timelimit must be non-zero if timeout is provided */
  117.         timelimit = timeout->tv_sec != 0 ? timeout->tv_sec : 1;
  118.  
  119.     } else {
  120.         /* no timeout, no timelimit */
  121.         timelimit = -1;
  122.     }
  123.  
  124.     ber = ldap_build_search_req( ld, base, scope, filter, attrs,
  125.         attrsonly, sctrls, cctrls, timelimit, sizelimit ); 
  126.  
  127.     if ( ber == NULL ) {
  128.         return ld->ld_errno;
  129.     }
  130.  
  131. #ifndef LDAP_NOCACHE
  132.     if ( ld->ld_cache != NULL ) {
  133.         if ( ldap_check_cache( ld, LDAP_REQ_SEARCH, ber ) == 0 ) {
  134.             ber_free( ber, 1 );
  135.             ld->ld_errno = LDAP_SUCCESS;
  136.             *msgidp = ld->ld_msgid;
  137.             return ld->ld_errno;
  138.         }
  139.         ldap_add_request_to_cache( ld, LDAP_REQ_SEARCH, ber );
  140.     }
  141. #endif /* LDAP_NOCACHE */
  142.  
  143.     /* send the message */
  144.     *msgidp = ldap_send_initial_request( ld, LDAP_REQ_SEARCH, base, ber );
  145.  
  146.     if( *msgidp < 0 )
  147.         return ld->ld_errno;
  148.  
  149.     return LDAP_SUCCESS;
  150. }
  151.  
  152. int
  153. ldap_search_ext_s(
  154.     LDAP *ld,
  155.     LDAP_CONST char *base,
  156.     int scope,
  157.     LDAP_CONST char *filter,
  158.     char **attrs,
  159.     int attrsonly,
  160.     LDAPControl **sctrls,
  161.     LDAPControl **cctrls,
  162.     struct timeval *timeout,
  163.     int sizelimit,
  164.     LDAPMessage **res )
  165. {
  166.     int rc;
  167.     int    msgid;
  168.  
  169.     rc = ldap_search_ext( ld, base, scope, filter, attrs, attrsonly,
  170.         sctrls, cctrls, timeout, sizelimit, &msgid );
  171.  
  172.     if ( rc != LDAP_SUCCESS ) {
  173.         return( rc );
  174.     }
  175.  
  176.     rc = ldap_result( ld, msgid, 1, timeout, res );
  177.  
  178.     if( rc <= 0 ) {
  179.         /* error(-1) or timeout(0) */
  180.         return( ld->ld_errno );
  181.     }
  182.  
  183.     if( rc == LDAP_RES_SEARCH_REFERENCE || rc == LDAP_RES_EXTENDED_PARTIAL ) {
  184.         return( ld->ld_errno );
  185.     }
  186.  
  187.     return( ldap_result2error( ld, *res, 0 ) );
  188. }
  189.  
  190. /*
  191.  * ldap_search - initiate an ldap search operation.
  192.  *
  193.  * Parameters:
  194.  *
  195.  *    ld        LDAP descriptor
  196.  *    base        DN of the base object
  197.  *    scope        the search scope - one of LDAP_SCOPE_BASE,
  198.  *                LDAP_SCOPE_ONELEVEL, LDAP_SCOPE_SUBTREE
  199.  *    filter        a string containing the search filter
  200.  *            (e.g., "(|(cn=bob)(sn=bob))")
  201.  *    attrs        list of attribute types to return for matches
  202.  *    attrsonly    1 => attributes only 0 => attributes and values
  203.  *
  204.  * Example:
  205.  *    char    *attrs[] = { "mail", "title", 0 };
  206.  *    msgid = ldap_search( ld, "c=us@o=UM", LDAP_SCOPE_SUBTREE, "cn~=bob",
  207.  *        attrs, attrsonly );
  208.  */
  209. int
  210. ldap_search(
  211.     LDAP *ld, LDAP_CONST char *base, int scope, LDAP_CONST char *filter,
  212.     char **attrs, int attrsonly )
  213. {
  214.     BerElement    *ber;
  215.  
  216.     Debug( LDAP_DEBUG_TRACE, "ldap_search\n", 0, 0, 0 );
  217.  
  218.     assert( ld != NULL );
  219.     assert( LDAP_VALID( ld ) );
  220.  
  221.     ber = ldap_build_search_req( ld, base, scope, filter, attrs,
  222.         attrsonly, NULL, NULL, -1, -1 ); 
  223.  
  224.     if ( ber == NULL ) {
  225.         return( -1 );
  226.     }
  227.  
  228. #ifndef LDAP_NOCACHE
  229.     if ( ld->ld_cache != NULL ) {
  230.         if ( ldap_check_cache( ld, LDAP_REQ_SEARCH, ber ) == 0 ) {
  231.             ber_free( ber, 1 );
  232.             ld->ld_errno = LDAP_SUCCESS;
  233.             return( ld->ld_msgid );
  234.         }
  235.         ldap_add_request_to_cache( ld, LDAP_REQ_SEARCH, ber );
  236.     }
  237. #endif /* LDAP_NOCACHE */
  238.  
  239.     /* send the message */
  240.     return ( ldap_send_initial_request( ld, LDAP_REQ_SEARCH, base, ber ));
  241. }
  242.  
  243.  
  244. BerElement *
  245. ldap_build_search_req(
  246.     LDAP *ld,
  247.     LDAP_CONST char *base,
  248.     ber_int_t scope,
  249.     LDAP_CONST char *filter_in,
  250.     char **attrs,
  251.     ber_int_t attrsonly,
  252.     LDAPControl **sctrls,
  253.     LDAPControl **cctrls,
  254.     ber_int_t timelimit,
  255.     ber_int_t sizelimit )
  256. {
  257.     BerElement    *ber;
  258.     int        err;
  259.     char    *filter;
  260.  
  261.     /*
  262.      * Create the search request.  It looks like this:
  263.      *    SearchRequest := [APPLICATION 3] SEQUENCE {
  264.      *        baseObject    DistinguishedName,
  265.      *        scope        ENUMERATED {
  266.      *            baseObject    (0),
  267.      *            singleLevel    (1),
  268.      *            wholeSubtree    (2)
  269.      *        },
  270.      *        derefAliases    ENUMERATED {
  271.      *            neverDerefaliases    (0),
  272.      *            derefInSearching    (1),
  273.      *            derefFindingBaseObj    (2),
  274.      *            alwaysDerefAliases    (3)
  275.      *        },
  276.      *        sizelimit    INTEGER (0 .. 65535),
  277.      *        timelimit    INTEGER (0 .. 65535),
  278.      *        attrsOnly    BOOLEAN,
  279.      *        filter        Filter,
  280.      *        attributes    SEQUENCE OF AttributeType
  281.      *    }
  282.      * wrapped in an ldap message.
  283.      */
  284.  
  285.     /* create a message to send */
  286.     if ( (ber = ldap_alloc_ber_with_options( ld )) == NULL ) {
  287.         return( NULL );
  288.     }
  289.  
  290.     if ( base == NULL ) {
  291.         /* no base provided, use session default base */
  292.         base = ld->ld_options.ldo_defbase;
  293.  
  294.         if ( base == NULL ) {
  295.             /* no session default base, use top */
  296.             base = "";
  297.         }
  298.     }
  299.  
  300.     err = ber_printf( ber, "{it{seeiib", ++ld->ld_msgid,
  301.         LDAP_REQ_SEARCH, base, (ber_int_t) scope, ld->ld_deref,
  302.         (sizelimit < 0) ? ld->ld_sizelimit : sizelimit,
  303.         (timelimit < 0) ? ld->ld_timelimit : timelimit,
  304.         attrsonly );
  305.  
  306.     if ( err == -1 ) {
  307.         ld->ld_errno = LDAP_ENCODING_ERROR;
  308.         ber_free( ber, 1 );
  309.         return( NULL );
  310.     }
  311.  
  312.     if( filter_in != NULL ) {
  313.         filter = LDAP_STRDUP( filter_in );
  314.     } else {
  315.         filter = LDAP_STRDUP( "(objectclass=*)" );
  316.     }
  317.     err = put_filter( ber, filter );
  318.     LDAP_FREE( filter );
  319.  
  320.     if ( err  == -1 ) {
  321.         ld->ld_errno = LDAP_FILTER_ERROR;
  322.         ber_free( ber, 1 );
  323.         return( NULL );
  324.     }
  325.  
  326.     if ( ber_printf( ber, /*{*/ "{v}N}", attrs ) == -1 ) {
  327.         ld->ld_errno = LDAP_ENCODING_ERROR;
  328.         ber_free( ber, 1 );
  329.         return( NULL );
  330.     }
  331.  
  332.     /* Put Server Controls */
  333.     if( ldap_int_put_controls( ld, sctrls, ber ) != LDAP_SUCCESS ) {
  334.         ber_free( ber, 1 );
  335.         return( NULL );
  336.     }
  337.  
  338.     if ( ber_printf( ber, /*{*/ "N}" ) == -1 ) {
  339.         ld->ld_errno = LDAP_ENCODING_ERROR;
  340.         ber_free( ber, 1 );
  341.         return( NULL );
  342.     }
  343.  
  344.     return( ber );
  345. }
  346.  
  347. static int ldap_is_attr_oid ( const char *attr )
  348. {
  349.     int i, c, digit=0;
  350.  
  351.     for( i = 0; (c = attr[i]) != 0; i++ ) {
  352.         if( c >= '0' && c <= '9' ) {
  353.             digit=1;
  354.  
  355.         } else if ( c != '.' ) {
  356.             /* not digit nor '.' */
  357.             return 0;
  358.  
  359.         } else if ( !digit ) {
  360.             /* '.' but prev not digit */
  361.             return 0;
  362.  
  363.         } else {
  364.             /* '.' */
  365.             digit = 0;
  366.         }
  367.     }
  368.  
  369.     return digit;
  370. }
  371.  
  372. static int ldap_is_attr_desc ( const char *attr )
  373. {
  374.     /* cheap attribute description check */
  375.     int i, c;
  376.  
  377.     for( i = 0; (c = attr[i]) != 0; i++ ) {
  378.         if (( c >= '0' && c <= '9' )
  379.             || ( c >= 'A' && c <= 'Z' )
  380.             || ( c >= 'a' && c <= 'z' )
  381.             || ( c == '.' || c == '-' )
  382.             || ( c == ';' )) continue;
  383.  
  384.         return 0;
  385.     }
  386.  
  387.     return i > 0;
  388. }
  389.  
  390. static char *
  391. find_right_paren( char *s )
  392. {
  393.     int    balance, escape;
  394.  
  395.     balance = 1;
  396.     escape = 0;
  397.     while ( *s && balance ) {
  398.         if ( escape == 0 ) {
  399.             if ( *s == '(' )
  400.                 balance++;
  401.             else if ( *s == ')' )
  402.                 balance--;
  403.         }
  404.         if ( *s == '\\' && ! escape )
  405.             escape = 1;
  406.         else
  407.             escape = 0;
  408.         if ( balance )
  409.             s++;
  410.     }
  411.  
  412.     return( *s ? s : NULL );
  413. }
  414.  
  415. static int hex2value( int c )
  416. {
  417.     if( c >= '0' && c <= '9' ) {
  418.         return c - '0';
  419.     }
  420.  
  421.     if( c >= 'A' && c <= 'F' ) {
  422.         return c + (10 - (int) 'A');
  423.     }
  424.  
  425.     if( c >= 'a' && c <= 'f' ) {
  426.         return c + (10 - (int) 'a');
  427.     }
  428.  
  429.     return -1;
  430. }
  431.  
  432. char *
  433. ldap_pvt_find_wildcard( const char *s )
  434. {
  435.     for( ; *s != '\0' ; s++ ) {
  436.         switch( *s ) {
  437.         case '*':    /* found wildcard */
  438.             return (char *) s;
  439.  
  440.         case '\\':
  441.             s++; /* skip over escape */
  442.             if ( *s == '\0' )
  443.                 return NULL;    /* escape at end of string */
  444.         }
  445.     }
  446.  
  447.     return NULL;
  448. }
  449.  
  450. /* unescape filter value */
  451. /* support both LDAP v2 and v3 escapes */
  452. /* output can include nul characters */
  453. ber_slen_t
  454. ldap_pvt_filter_value_unescape( char *fval )
  455. {
  456.     ber_slen_t r, v;
  457.     int v1, v2;
  458.  
  459.     for( r=v=0; fval[v] != '\0'; v++ ) {
  460.         switch( fval[v] ) {
  461.         case '\\':
  462.             /* escape */
  463.             v++;
  464.  
  465.             if ( fval[v] == '\0' ) {
  466.                 /* escape at end of string */
  467.                 return -1;
  468.  
  469.             }
  470.  
  471.             if (( v1 = hex2value( fval[v] )) >= 0 ) {
  472.                 /* LDAPv3 escape */
  473.  
  474.                 if (( v2 = hex2value( fval[v+1] )) < 0 ) {
  475.                     /* must be two digit code */
  476.                     return -1;
  477.                 }
  478.  
  479.                 fval[r++] = v1 * 16 + v2;
  480.                 v++;
  481.  
  482.             } else {
  483.                 /* LDAPv2 escape */
  484.                 fval[r++] = fval[v];
  485.             }
  486.  
  487.             break;
  488.  
  489.         default:
  490.             fval[r++] = fval[v];
  491.         }
  492.     }
  493.  
  494.     fval[r] = '\0';
  495.     return r;
  496. }
  497.  
  498. static char *
  499. put_complex_filter( BerElement *ber, char *str, ber_tag_t tag, int not )
  500. {
  501.     char    *next;
  502.  
  503.     /*
  504.      * We have (x(filter)...) with str sitting on
  505.      * the x.  We have to find the paren matching
  506.      * the one before the x and put the intervening
  507.      * filters by calling put_filter_list().
  508.      */
  509.  
  510.     /* put explicit tag */
  511.     if ( ber_printf( ber, "t{" /*}*/, tag ) == -1 )
  512.         return( NULL );
  513.  
  514.     str++;
  515.     if ( (next = find_right_paren( str )) == NULL )
  516.         return( NULL );
  517.  
  518.     *next = '\0';
  519.     if ( put_filter_list( ber, str ) == -1 )
  520.         return( NULL );
  521.     *next++ = ')';
  522.  
  523.     /* flush explicit tagged thang */
  524.     if ( ber_printf( ber, /*{*/ "N}" ) == -1 )
  525.         return( NULL );
  526.  
  527.     return( next );
  528. }
  529.  
  530. static int
  531. put_filter( BerElement *ber, char *str )
  532. {
  533.     char    *next;
  534.     int    parens, balance, escape;
  535.  
  536.     /*
  537.      * A Filter looks like this:
  538.      *      Filter ::= CHOICE {
  539.      *              and             [0]     SET OF Filter,
  540.      *              or              [1]     SET OF Filter,
  541.      *              not             [2]     Filter,
  542.      *              equalityMatch   [3]     AttributeValueAssertion,
  543.      *              substrings      [4]     SubstringFilter,
  544.      *              greaterOrEqual  [5]     AttributeValueAssertion,
  545.      *              lessOrEqual     [6]     AttributeValueAssertion,
  546.      *              present         [7]     AttributeType,
  547.      *              approxMatch     [8]     AttributeValueAssertion,
  548.      *                extensibleMatch [9]        MatchingRuleAssertion -- LDAPv3
  549.      *      }
  550.      *
  551.      *      SubstringFilter ::= SEQUENCE {
  552.      *              type               AttributeType,
  553.      *              SEQUENCE OF CHOICE {
  554.      *                      initial          [0] IA5String,
  555.      *                      any              [1] IA5String,
  556.      *                      final            [2] IA5String
  557.      *              }
  558.      *      }
  559.      *
  560.      *        MatchingRuleAssertion ::= SEQUENCE {    -- LDAPv3
  561.      *            matchingRule    [1] MatchingRuleId OPTIONAL,
  562.      *            type            [2] AttributeDescription OPTIONAL,
  563.      *            matchValue      [3] AssertionValue,
  564.      *            dnAttributes    [4] BOOLEAN DEFAULT FALSE }
  565.      *
  566.      * Note: tags in a choice are always explicit
  567.      */
  568.  
  569.     Debug( LDAP_DEBUG_TRACE, "put_filter \"%s\"\n", str, 0, 0 );
  570.  
  571.     parens = 0;
  572.     while ( *str ) {
  573.         switch ( *str ) {
  574.         case '(':
  575.             str++;
  576.             parens++;
  577.  
  578.             /* skip spaces */
  579.             while( LDAP_SPACE( *str ) ) str++;
  580.  
  581.             switch ( *str ) {
  582.             case '&':
  583.                 Debug( LDAP_DEBUG_TRACE, "put_filter: AND\n",
  584.                     0, 0, 0 );
  585.  
  586.                 if ( (str = put_complex_filter( ber, str,
  587.                     LDAP_FILTER_AND, 0 )) == NULL )
  588.                     return( -1 );
  589.  
  590.                 parens--;
  591.                 break;
  592.  
  593.             case '|':
  594.                 Debug( LDAP_DEBUG_TRACE, "put_filter: OR\n",
  595.                     0, 0, 0 );
  596.  
  597.                 if ( (str = put_complex_filter( ber, str,
  598.                     LDAP_FILTER_OR, 0 )) == NULL )
  599.                     return( -1 );
  600.  
  601.                 parens--;
  602.                 break;
  603.  
  604.             case '!':
  605.                 Debug( LDAP_DEBUG_TRACE, "put_filter: NOT\n",
  606.                     0, 0, 0 );
  607.  
  608.                 if ( (str = put_complex_filter( ber, str,
  609.                     LDAP_FILTER_NOT, 1 )) == NULL )
  610.                     return( -1 );
  611.  
  612.                 parens--;
  613.                 break;
  614.  
  615.             default:
  616.                 Debug( LDAP_DEBUG_TRACE, "put_filter: simple\n",
  617.                     0, 0, 0 );
  618.  
  619.                 balance = 1;
  620.                 escape = 0;
  621.                 next = str;
  622.                 while ( *next && balance ) {
  623.                     if ( escape == 0 ) {
  624.                         if ( *next == '(' )
  625.                             balance++;
  626.                         else if ( *next == ')' )
  627.                             balance--;
  628.                     }
  629.                     if ( *next == '\\' && ! escape )
  630.                         escape = 1;
  631.                     else
  632.                         escape = 0;
  633.                     if ( balance )
  634.                         next++;
  635.                 }
  636.                 if ( balance != 0 )
  637.                     return( -1 );
  638.  
  639.                 *next = '\0';
  640.                 if ( put_simple_filter( ber, str ) == -1 ) {
  641.                     return( -1 );
  642.                 }
  643.                 *next++ = ')';
  644.                 str = next;
  645.                 parens--;
  646.                 break;
  647.             }
  648.             break;
  649.  
  650.         case ')':
  651.             Debug( LDAP_DEBUG_TRACE, "put_filter: end\n", 0, 0,
  652.                 0 );
  653.             if ( ber_printf( ber, /*[*/ "]" ) == -1 )
  654.                 return( -1 );
  655.             str++;
  656.             parens--;
  657.             break;
  658.  
  659.         case ' ':
  660.             str++;
  661.             break;
  662.  
  663.         default:    /* assume it's a simple type=value filter */
  664.             Debug( LDAP_DEBUG_TRACE, "put_filter: default\n", 0, 0,
  665.                 0 );
  666.             next = strchr( str, '\0' );
  667.             if ( put_simple_filter( ber, str ) == -1 ) {
  668.                 return( -1 );
  669.             }
  670.             str = next;
  671.             break;
  672.         }
  673.     }
  674.  
  675.     return( parens ? -1 : 0 );
  676. }
  677.  
  678. /*
  679.  * Put a list of filters like this "(filter1)(filter2)..."
  680.  */
  681.  
  682. static int
  683. put_filter_list( BerElement *ber, char *str )
  684. {
  685.     char    *next;
  686.     char    save;
  687.  
  688.     Debug( LDAP_DEBUG_TRACE, "put_filter_list \"%s\"\n", str, 0, 0 );
  689.  
  690.     while ( *str ) {
  691.         while ( *str && LDAP_SPACE( (unsigned char) *str ) )
  692.             str++;
  693.         if ( *str == '\0' )
  694.             break;
  695.  
  696.         if ( (next = find_right_paren( str + 1 )) == NULL )
  697.             return( -1 );
  698.         save = *++next;
  699.  
  700.         /* now we have "(filter)" with str pointing to it */
  701.         *next = '\0';
  702.         if ( put_filter( ber, str ) == -1 )
  703.             return( -1 );
  704.         *next = save;
  705.  
  706.         str = next;
  707.     }
  708.  
  709.     return( 0 );
  710. }
  711.  
  712. static int
  713. put_simple_filter(
  714.     BerElement *ber,
  715.     char *str )
  716. {
  717.     char        *s;
  718.     char        *value;
  719.     ber_tag_t    ftype;
  720.     int        rc = -1;
  721.  
  722.     Debug( LDAP_DEBUG_TRACE, "put_simple_filter \"%s\"\n", str, 0, 0 );
  723.  
  724.     str = LDAP_STRDUP( str );
  725.     if( str == NULL ) return -1;
  726.  
  727.     if ( (s = strchr( str, '=' )) == NULL ) {
  728.         goto done;
  729.     }
  730.  
  731.     value = s + 1;
  732.     *s-- = '\0';
  733.  
  734.     switch ( *s ) {
  735.     case '<':
  736.         ftype = LDAP_FILTER_LE;
  737.         *s = '\0';
  738.         if(! ldap_is_attr_desc( str ) ) goto done;
  739.         break;
  740.  
  741.     case '>':
  742.         ftype = LDAP_FILTER_GE;
  743.         *s = '\0';
  744.         if(! ldap_is_attr_desc( str ) ) goto done;
  745.         break;
  746.  
  747.     case '~':
  748.         ftype = LDAP_FILTER_APPROX;
  749.         *s = '\0';
  750.         if(! ldap_is_attr_desc( str ) ) goto done;
  751.         break;
  752.  
  753.     case ':':
  754.         /* RFC2254 extensible filters are off the form:
  755.          *        type [:dn] [:rule] := value
  756.          * or    [:dn]:rule := value        
  757.          */
  758.         ftype = LDAP_FILTER_EXT;
  759.         *s = '\0';
  760.  
  761.         {
  762.             char *dn = strchr( str, ':' );
  763.             char *rule = NULL;
  764.  
  765.             if( dn == NULL ) {
  766.                 if(! ldap_is_attr_desc( str ) ) goto done;
  767.             } else {
  768.  
  769.                 *dn++ = '\0';
  770.                 rule = strchr( dn, ':' );
  771.  
  772.                 if( rule == NULL ) {
  773.                     /* one colon */
  774.                     if ( strcmp(dn, "dn") == 0 ) {
  775.                         /* must have attribute */
  776.                         if( !ldap_is_attr_desc( str ) ) {
  777.                             goto done;
  778.                         }
  779.  
  780.                         rule = "";
  781.  
  782.                     } else {
  783.                       rule = dn;
  784.                       dn = NULL;
  785.                     }
  786.                 
  787.                 } else {
  788.                     /* two colons */
  789.                     *rule++ = '\0';
  790.  
  791.                     if ( strcmp(dn, "dn") != 0 ) {
  792.                         /* must have "dn" */
  793.                         goto done;
  794.                     }
  795.                 }
  796.  
  797.             }
  798.  
  799.             if ( *str == '\0' && ( !rule || *rule == '\0' ) ) {
  800.                 /* must have either type or rule */
  801.                 goto done;
  802.             }
  803.  
  804.             if ( *str != '\0' && !ldap_is_attr_desc( str ) ) {
  805.                 goto done;
  806.             }
  807.  
  808.             if ( rule && *rule != '\0' && !ldap_is_attr_oid( rule ) ) {
  809.                 goto done;
  810.             }
  811.  
  812.             rc = ber_printf( ber, "t{" /*}*/, ftype );
  813.  
  814.             if( rc != -1 && rule && *rule != '\0' ) {
  815.                 rc = ber_printf( ber, "ts", LDAP_FILTER_EXT_OID, rule );
  816.             }
  817.             if( rc != -1 && *str != '\0' ) {
  818.                 rc = ber_printf( ber, "ts", LDAP_FILTER_EXT_TYPE, str );
  819.             }
  820.  
  821.             if( rc != -1 ) {
  822.                 ber_slen_t len = ldap_pvt_filter_value_unescape( value );
  823.  
  824.                 if( len >= 0 ) {
  825.                     rc = ber_printf( ber, "totbN}",
  826.                         LDAP_FILTER_EXT_VALUE, value, len,
  827.                         LDAP_FILTER_EXT_DNATTRS, dn != NULL);
  828.                 } else {
  829.                     rc = -1;
  830.                 }
  831.             }
  832.         }
  833.         goto done;
  834.  
  835.     default:
  836.         if ( ldap_pvt_find_wildcard( value ) == NULL ) {
  837.             ftype = LDAP_FILTER_EQUALITY;
  838.         } else if ( strcmp( value, "*" ) == 0 ) {
  839.             ftype = LDAP_FILTER_PRESENT;
  840.         } else {
  841.             rc = put_substring_filter( ber, str, value );
  842.             goto done;
  843.         }
  844.         break;
  845.     }
  846.  
  847.     if ( ftype == LDAP_FILTER_PRESENT ) {
  848.         rc = ber_printf( ber, "ts", ftype, str );
  849.  
  850.     } else {
  851.         ber_slen_t len = ldap_pvt_filter_value_unescape( value );
  852.  
  853.         if( len >= 0 ) {
  854.             rc = ber_printf( ber, "t{soN}",
  855.                 ftype, str, value, len );
  856.         }
  857.     }
  858.  
  859.     if( rc != -1 ) rc = 0;
  860.  
  861. done:
  862.     LDAP_FREE( str );
  863.     return rc;
  864. }
  865.  
  866. static int
  867. put_substring_filter( BerElement *ber, char *type, char *val )
  868. {
  869.     char        *nextstar, gotstar = 0;
  870.     ber_tag_t    ftype = LDAP_FILTER_SUBSTRINGS;
  871.  
  872.     Debug( LDAP_DEBUG_TRACE, "put_substring_filter \"%s=%s\"\n", type,
  873.         val, 0 );
  874.  
  875.     if ( ber_printf( ber, "t{s{", ftype, type ) == -1 )
  876.         return( -1 );
  877.  
  878.     for( ; val != NULL; val=nextstar ) {
  879.         if ( (nextstar = ldap_pvt_find_wildcard( val )) != NULL )
  880.             *nextstar++ = '\0';
  881.  
  882.         if ( gotstar == 0 ) {
  883.             ftype = LDAP_SUBSTRING_INITIAL;
  884.         } else if ( nextstar == NULL ) {
  885.             ftype = LDAP_SUBSTRING_FINAL;
  886.         } else {
  887.             ftype = LDAP_SUBSTRING_ANY;
  888.         }
  889.  
  890.         if ( *val != '\0' ) {
  891.             ber_slen_t len = ldap_pvt_filter_value_unescape( val );
  892.  
  893.             if ( len < 0  ) {
  894.                 return -1;
  895.             }
  896.  
  897.             if ( ber_printf( ber, "to", ftype, val, len ) == -1 ) {
  898.                 return( -1 );
  899.             }
  900.         }
  901.  
  902.         gotstar = 1;
  903.     }
  904.  
  905.     if ( ber_printf( ber, /* {{ */ "N}N}" ) == -1 )
  906.         return( -1 );
  907.  
  908.     return( 0 );
  909. }
  910.  
  911. int
  912. ldap_search_st(
  913.     LDAP *ld, LDAP_CONST char *base, int scope,
  914.     LDAP_CONST char *filter, char **attrs,
  915.     int attrsonly, struct timeval *timeout, LDAPMessage **res )
  916. {
  917.     int    msgid;
  918.  
  919.     if ( (msgid = ldap_search( ld, base, scope, filter, attrs, attrsonly ))
  920.         == -1 )
  921.         return( ld->ld_errno );
  922.  
  923.     if ( ldap_result( ld, msgid, 1, timeout, res ) == -1 )
  924.         return( ld->ld_errno );
  925.  
  926.     if ( ld->ld_errno == LDAP_TIMEOUT ) {
  927.         (void) ldap_abandon( ld, msgid );
  928.         ld->ld_errno = LDAP_TIMEOUT;
  929.         return( ld->ld_errno );
  930.     }
  931.  
  932.     return( ldap_result2error( ld, *res, 0 ) );
  933. }
  934.  
  935. int
  936. ldap_search_s(
  937.     LDAP *ld,
  938.     LDAP_CONST char *base,
  939.     int scope,
  940.     LDAP_CONST char *filter,
  941.     char **attrs,
  942.     int attrsonly,
  943.     LDAPMessage **res )
  944. {
  945.     int    msgid;
  946.  
  947.     if ( (msgid = ldap_search( ld, base, scope, filter, attrs, attrsonly ))
  948.         == -1 )
  949.         return( ld->ld_errno );
  950.  
  951.     if ( ldap_result( ld, msgid, 1, (struct timeval *) NULL, res ) == -1 )
  952.         return( ld->ld_errno );
  953.  
  954.     return( ldap_result2error( ld, *res, 0 ) );
  955. }
  956.  
  957.