]> git.sur5r.net Git - openldap/blobdiff - servers/slapd/controls.c
ITS#3563 fix parseSubentries bug
[openldap] / servers / slapd / controls.c
index a5bdde13fc57f7b80cc017830495ce887cc318de..b8b18974fc8a9acaabcf24c2367509878e37be31 100644 (file)
@@ -1,7 +1,7 @@
 /* $OpenLDAP$ */
 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
  *
- * Copyright 1998-2003 The OpenLDAP Foundation.
+ * Copyright 1998-2005 The OpenLDAP Foundation.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -35,6 +35,8 @@ static SLAP_CTRL_PARSE_FN parsePagedResults;
 static SLAP_CTRL_PARSE_FN parseValuesReturnFilter;
 static SLAP_CTRL_PARSE_FN parsePermissiveModify;
 static SLAP_CTRL_PARSE_FN parseDomainScope;
+static SLAP_CTRL_PARSE_FN parseTreeDelete;
+static SLAP_CTRL_PARSE_FN parseSearchOptions;
 
 #ifdef LDAP_CONTROL_SUBENTRIES
 static SLAP_CTRL_PARSE_FN parseSubentries;
@@ -102,13 +104,23 @@ static struct slap_control control_defs[] = {
                SLAP_CTRL_MODIFY, NULL,
                parsePermissiveModify, LDAP_SLIST_ENTRY_INITIALIZER(next) },
 #endif
+#ifdef LDAP_CONTROL_X_TREE_DELETE
+       { LDAP_CONTROL_X_TREE_DELETE,
+               SLAP_CTRL_DELETE, NULL,
+               parseTreeDelete, LDAP_SLIST_ENTRY_INITIALIZER(next) },
+#endif
+#ifdef LDAP_CONTORL_X_SEARCH_OPTIONS
+       { LDAP_CONTORL_X_SEARCH_OPTIONS,
+               SLAP_CTRL_FRONTEND|SLAP_CTRL_SEARCH, NULL,
+               parseSearchOptions, LDAP_SLIST_ENTRY_INITIALIZER(next) },
+#endif
 #ifdef LDAP_CONTROL_SUBENTRIES
        { LDAP_CONTROL_SUBENTRIES,
                SLAP_CTRL_SEARCH, NULL,
                parseSubentries, LDAP_SLIST_ENTRY_INITIALIZER(next) },
 #endif
        { LDAP_CONTROL_NOOP,
-               SLAP_CTRL_ACCESS, NULL,
+               SLAP_CTRL_HIDE|SLAP_CTRL_ACCESS, NULL,
                parseNoOp, LDAP_SLIST_ENTRY_INITIALIZER(next) },
        { LDAP_CONTROL_SYNC,
                SLAP_CTRL_HIDE|SLAP_CTRL_SEARCH, NULL,
@@ -336,8 +348,7 @@ find_ctrl( const char *oid )
 
 void slap_free_ctrls(
        Operation *op,
-       LDAPControl **ctrls
-)
+       LDAPControl **ctrls )
 {
        int i;
 
@@ -570,8 +581,8 @@ int get_ctrls(
                                if( sc->sc_extendedops != NULL ) {
                                        int i;
                                        for( i=0; sc->sc_extendedops[i] != NULL; i++ ) {
-                                               if( strcmp( op->ore_reqoid.bv_val, sc->sc_extendedops[i] )
-                                                       == 0 )
+                                               if( strcmp( op->ore_reqoid.bv_val,
+                                                       sc->sc_extendedops[i] ) == 0 )
                                                {
                                                        tagmask=0L;
                                                        break;
@@ -587,6 +598,7 @@ int get_ctrls(
 
                        if (( sc->sc_mask & tagmask ) == tagmask ) {
                                /* available extension */
+                               int     rc;
 
                                if( !sc->sc_parse ) {
                                        rs->sr_err = LDAP_OTHER;
@@ -594,9 +606,12 @@ int get_ctrls(
                                        goto return_results;
                                }
 
-                               rs->sr_err = sc->sc_parse( op, rs, c );
-
-                               if( rs->sr_err != LDAP_SUCCESS ) goto return_results;
+                               rc = sc->sc_parse( op, rs, c );
+                               assert( rc != LDAP_UNAVAILABLE_CRITICAL_EXTENSION );
+                               if ( rc ) {
+                                       rs->sr_err = rc;
+                                       goto return_results;
+                               }
 
                                if ( sc->sc_mask & SLAP_CTRL_FRONTEND ) {
                                        /* kludge to disable backend_control() check */
@@ -622,6 +637,7 @@ int get_ctrls(
                        rs->sr_text = "critical extension is not recognized";
                        goto return_results;
                }
+next_ctrl:;
        }
 
 return_results:
@@ -654,7 +670,7 @@ static int parseModifyIncrement (
        LDAPControl *ctrl )
 {
 #if 0
-       if ( op->o_parseModifyIncrement != SLAP_NO_CONTROL ) {
+       if ( op->o_modifyIncrement != SLAP_NO_CONTROL ) {
                rs->sr_text = "modifyIncrement control specified multiple times";
                return LDAP_PROTOCOL_ERROR;
        }
@@ -666,7 +682,7 @@ static int parseModifyIncrement (
        }
 
 #if 0
-       op->o_parseModifyIncrement = ctrl->ldctl_iscritical
+       op->o_modifyIncrement = ctrl->ldctl_iscritical
                ? SLAP_CRITICAL_CONTROL
                : SLAP_NONCRITICAL_CONTROL;
 #endif
@@ -702,7 +718,7 @@ static int parseProxyAuthz (
        LDAPControl *ctrl )
 {
        int             rc;
-       struct berval   dn = { 0, NULL };
+       struct berval   dn = BER_BVNULL;
 
        if ( op->o_proxy_authz != SLAP_NO_CONTROL ) {
                rs->sr_text = "proxy authorization control specified multiple times";
@@ -754,13 +770,13 @@ static int parseProxyAuthz (
                        ctrl->ldctl_value.bv_val, ctrl->ldctl_value.bv_len,
                        NULL, &dn, SLAP_GETDN_AUTHZID );
 
-       if( rc != LDAP_SUCCESS || !dn.bv_len ) {
+       /* FIXME: empty DN in proxyAuthz control should be legal... */
+       if( rc != LDAP_SUCCESS /* || !dn.bv_len */ ) {
                if ( dn.bv_val ) {
                        ch_free( dn.bv_val );
                }
                rs->sr_text = "authzId mapping failed";
                return LDAP_PROXY_AUTHZ_FAILURE;
-
        }
 
 #ifdef NEW_LOGGING
@@ -789,6 +805,9 @@ static int parseProxyAuthz (
        op->o_dn.bv_val = NULL;
        op->o_ndn = dn;
 
+       Statslog( LDAP_DEBUG_STATS, "conn=%lu op=%lu PROXYAUTHZ dn=\"%s\"\n",
+           op->o_connid, op->o_opid, dn.bv_val, 0, 0 );
+
        /*
         * NOTE: since slap_sasl_getdn() returns a normalized dn,
         * from now on op->o_dn is normalized
@@ -825,16 +844,22 @@ static int parsePagedResults (
        SlapReply *rs,
        LDAPControl *ctrl )
 {
-       ber_tag_t tag;
-       ber_int_t size;
-       BerElement *ber;
-       struct berval cookie = { 0, NULL };
+       int             rc = LDAP_SUCCESS;
+       ber_tag_t       tag;
+       ber_int_t       size;
+       BerElement      *ber;
+       struct berval   cookie = BER_BVNULL;
 
        if ( op->o_pagedresults != SLAP_NO_CONTROL ) {
                rs->sr_text = "paged results control specified multiple times";
                return LDAP_PROTOCOL_ERROR;
        }
 
+       if ( op->o_sync != SLAP_NO_CONTROL ) {
+               rs->sr_text = "paged results control specified with sync control";
+               return LDAP_PROTOCOL_ERROR;
+       }
+
        if ( ctrl->ldctl_value.bv_len == 0 ) {
                rs->sr_text = "paged results control value is empty (or absent)";
                return LDAP_PROTOCOL_ERROR;
@@ -855,16 +880,17 @@ static int parsePagedResults (
        }
 
        tag = ber_scanf( ber, "{im}", &size, &cookie );
-       (void) ber_free( ber, 1 );
 
        if( tag == LBER_ERROR ) {
                rs->sr_text = "paged results control could not be decoded";
-               return LDAP_PROTOCOL_ERROR;
+               rc = LDAP_PROTOCOL_ERROR;
+               goto done;
        }
 
        if( size < 0 ) {
                rs->sr_text = "paged results control size invalid";
-               return LDAP_PROTOCOL_ERROR;
+               rc = LDAP_PROTOCOL_ERROR;
+               goto done;
        }
 
        if( cookie.bv_len ) {
@@ -872,33 +898,64 @@ static int parsePagedResults (
                if( cookie.bv_len != sizeof( reqcookie ) ) {
                        /* bad cookie */
                        rs->sr_text = "paged results cookie is invalid";
-                       return LDAP_PROTOCOL_ERROR;
+                       rc = LDAP_PROTOCOL_ERROR;
+                       goto done;
                }
 
                AC_MEMCPY( &reqcookie, cookie.bv_val, sizeof( reqcookie ));
 
-               if( reqcookie > op->o_pagedresults_state.ps_cookie ) {
+               if ( reqcookie > op->o_pagedresults_state.ps_cookie ) {
                        /* bad cookie */
                        rs->sr_text = "paged results cookie is invalid";
-                       return LDAP_PROTOCOL_ERROR;
+                       rc = LDAP_PROTOCOL_ERROR;
+                       goto done;
 
-               } else if( reqcookie < op->o_pagedresults_state.ps_cookie ) {
+               } else if ( reqcookie < op->o_pagedresults_state.ps_cookie ) {
                        rs->sr_text = "paged results cookie is invalid or old";
-                       return LDAP_UNWILLING_TO_PERFORM;
+                       rc = LDAP_UNWILLING_TO_PERFORM;
+                       goto done;
                }
+
        } else {
                /* Initial request.  Initialize state. */
+#if 0
+               if ( op->o_conn->c_pagedresults_state.ps_cookie != 0 ) {
+                       /* There's another pagedResults control on the
+                        * same connection; reject new pagedResults controls 
+                        * (allowed by RFC2696) */
+                       rs->sr_text = "paged results cookie unavailable; try later";
+                       rc = LDAP_UNWILLING_TO_PERFORM;
+                       goto done;
+               }
+#endif
                op->o_pagedresults_state.ps_cookie = 0;
-               op->o_pagedresults_state.ps_id = NOID;
+               op->o_pagedresults_state.ps_count = 0;
        }
 
        op->o_pagedresults_size = size;
 
-       op->o_pagedresults = ctrl->ldctl_iscritical
-               ? SLAP_CRITICAL_CONTROL
-               : SLAP_NONCRITICAL_CONTROL;
+       /* NOTE: according to RFC 2696 3.:
 
-       return LDAP_SUCCESS;
+    If the page size is greater than or equal to the sizeLimit value, the
+    server should ignore the control as the request can be satisfied in a
+    single page.
+        
+        * NOTE: this assumes that the op->ors_slimit be set
+        * before the controls are parsed.     
+        */
+       if ( op->ors_slimit > 0 && size >= op->ors_slimit ) {
+               op->o_pagedresults = SLAP_IGNORED_CONTROL;
+
+       } else if ( ctrl->ldctl_iscritical ) {
+               op->o_pagedresults = SLAP_CRITICAL_CONTROL;
+
+       } else {
+               op->o_pagedresults = SLAP_NONCRITICAL_CONTROL;
+       }
+
+done:;
+       (void)ber_free( ber, 1 );
+       return rc;
 }
 
 static int parseAssert (
@@ -907,7 +964,7 @@ static int parseAssert (
        LDAPControl *ctrl )
 {
        BerElement      *ber;
-       struct berval   fstr = { 0, NULL };
+       struct berval   fstr = BER_BVNULL;
        const char *err_msg = "";
 
        if ( op->o_assert != SLAP_NO_CONTROL ) {
@@ -1082,7 +1139,7 @@ int parseValuesReturnFilter (
        LDAPControl *ctrl )
 {
        BerElement      *ber;
-       struct berval   fstr = { 0, NULL };
+       struct berval   fstr = BER_BVNULL;
        const char *err_msg = "";
 
        if ( op->o_valuesreturnfilter != SLAP_NO_CONTROL ) {
@@ -1150,8 +1207,8 @@ static int parseSubentries (
 
        /* FIXME: should use BER library */
        if( ( ctrl->ldctl_value.bv_len != 3 )
-               && ( ctrl->ldctl_value.bv_val[0] != 0x01 )
-               && ( ctrl->ldctl_value.bv_val[1] != 0x01 ))
+               || ( ctrl->ldctl_value.bv_val[0] != 0x01 )
+               || ( ctrl->ldctl_value.bv_val[1] != 0x01 ))
        {
                rs->sr_text = "subentries control value encoding is bogus";
                return LDAP_PROTOCOL_ERROR;
@@ -1215,6 +1272,79 @@ static int parseDomainScope (
 }
 #endif
 
+#ifdef LDAP_CONTROL_X_TREE_DELETE
+static int parseTreeDelete (
+       Operation *op,
+       SlapReply *rs,
+       LDAPControl *ctrl )
+{
+       if ( op->o_tree_delete != SLAP_NO_CONTROL ) {
+               rs->sr_text = "treeDelete control specified multiple times";
+               return LDAP_PROTOCOL_ERROR;
+       }
+
+       if ( ctrl->ldctl_value.bv_len ) {
+               rs->sr_text = "treeDelete control value not empty";
+               return LDAP_PROTOCOL_ERROR;
+       }
+
+       op->o_tree_delete = ctrl->ldctl_iscritical
+               ? SLAP_CRITICAL_CONTROL
+               : SLAP_NONCRITICAL_CONTROL;
+
+       return LDAP_SUCCESS;
+}
+#endif
+
+#ifdef LDAP_CONTORL_X_SEARCH_OPTIONS
+static int parseSearchOptions (
+       Operation *op,
+       SlapReply *rs,
+       LDAPControl *ctrl )
+{
+       BerElement *ber;
+       ber_int_t search_flags;
+
+       if ( ctrl->ldctl_value.bv_len == 0 ) {
+               rs->sr_text = "searchOptions control value not empty";
+               return LDAP_PROTOCOL_ERROR;
+       }
+
+       ber = ber_init( &ctrl->ldctl_value );
+       if( ber == NULL ) {
+               rs->sr_text = "internal error";
+               return LDAP_OTHER;
+       }
+
+       if ( (tag = ber_scanf( ber, "{i}", &search_flags )) == LBER_ERROR ) {
+               rs->sr_text = "searchOptions control decoding error";
+               return LDAP_PROTOCOL_ERROR;
+       }
+
+       (void) ber_free( ber, 1 );
+
+       if ( search_flags & LDAP_SEARCH_FLAG_DOMAIN_SCOPE ) {
+               if ( op->o_domain_scope != SLAP_NO_CONTROL ) {
+                       rs->sr_text = "searchOptions control specified multiple times "
+                               "or with domainScope control";
+                       return LDAP_PROTOCOL_ERROR;
+               }
+
+               op->o_domain_scope = ctrl->ldctl_iscritical
+                       ? SLAP_CRITICAL_CONTROL
+                       : SLAP_NONCRITICAL_CONTROL;
+       }
+
+       if ( search_flags & ~(LDAP_SEARCH_FLAG_DOMAIN_SCOPE) ) {
+               /* Other search flags not recognised so far */
+               rs->sr_text = "searchOptions contained unrecongized flag";
+               return LDAP_UNWILLING_TO_PERFORM;
+       }
+
+       return LDAP_SUCCESS;
+}
+#endif
+
 static int parseLDAPsync (
        Operation *op,
        SlapReply *rs,
@@ -1227,12 +1357,18 @@ static int parseLDAPsync (
        struct slap_session_entry *se;
 
        if ( op->o_sync != SLAP_NO_CONTROL ) {
-               rs->sr_text = "LDAP Sync control specified multiple times";
+               rs->sr_text = "Sync control specified multiple times";
                return LDAP_PROTOCOL_ERROR;
        }
 
+       if ( op->o_pagedresults != SLAP_NO_CONTROL ) {
+               rs->sr_text = "Sync control specified with pagedResults control";
+               return LDAP_PROTOCOL_ERROR;
+       }
+
+
        if ( ctrl->ldctl_value.bv_len == 0 ) {
-               rs->sr_text = "LDAP Sync control value is empty (or absent)";
+               rs->sr_text = "Sync control value is empty (or absent)";
                return LDAP_PROTOCOL_ERROR;
        }
 
@@ -1255,7 +1391,7 @@ static int parseLDAPsync (
        }
 
        if ( (tag = ber_scanf( ber, "{i" /*}*/, &mode )) == LBER_ERROR ) {
-               rs->sr_text = "LDAP Sync control : mode decoding error";
+               rs->sr_text = "Sync control : mode decoding error";
                return LDAP_PROTOCOL_ERROR;
        }
 
@@ -1267,7 +1403,7 @@ static int parseLDAPsync (
                mode = SLAP_SYNC_REFRESH_AND_PERSIST;
                break;
        default:
-               rs->sr_text = "LDAP Sync control : unknown update mode";
+               rs->sr_text = "Sync control : unknown update mode";
                return LDAP_PROTOCOL_ERROR;
        }
 
@@ -1276,7 +1412,7 @@ static int parseLDAPsync (
        if ( tag == LDAP_TAG_SYNC_COOKIE ) {
                struct berval tmp_bv;   
                if (( ber_scanf( ber, /*{*/ "o", &tmp_bv )) == LBER_ERROR ) {
-                       rs->sr_text = "LDAP Sync control : cookie decoding error";
+                       rs->sr_text = "Sync control : cookie decoding error";
                        return LDAP_PROTOCOL_ERROR;
                }
                ber_bvarray_add( &op->o_sync_state.octet_str, &tmp_bv );
@@ -1284,12 +1420,12 @@ static int parseLDAPsync (
        }
        if ( tag == LDAP_TAG_RELOAD_HINT ) {
                if (( ber_scanf( ber, /*{*/ "b", &op->o_sync_rhint )) == LBER_ERROR ) {
-                       rs->sr_text = "LDAP Sync control : rhint decoding error";
+                       rs->sr_text = "Sync control : rhint decoding error";
                        return LDAP_PROTOCOL_ERROR;
                }
        }
        if (( ber_scanf( ber, /*{*/ "}")) == LBER_ERROR ) {
-                       rs->sr_text = "LDAP Sync control : decoding error";
+                       rs->sr_text = "Sync control : decoding error";
                        return LDAP_PROTOCOL_ERROR;
        }