]> git.sur5r.net Git - openldap/blobdiff - servers/slapd/controls.c
coverity scan, fix typo
[openldap] / servers / slapd / controls.c
index 1e768bd11bb5f806c9beb8be124fa142bc28e5cf..ea2ecba0ec2edea11f055924a6459c27ad792789 100644 (file)
@@ -1,7 +1,7 @@
 /* $OpenLDAP$ */
 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
  *
- * Copyright 1998-2006 The OpenLDAP Foundation.
+ * Copyright 1998-2007 The OpenLDAP Foundation.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
 #include "../../libraries/liblber/lber-int.h"
 
 static SLAP_CTRL_PARSE_FN parseAssert;
-static SLAP_CTRL_PARSE_FN parsePreRead;
-static SLAP_CTRL_PARSE_FN parsePostRead;
-static SLAP_CTRL_PARSE_FN parseProxyAuthz;
-#ifdef LDAP_DEVEL
+static SLAP_CTRL_PARSE_FN parseDomainScope;
 static SLAP_CTRL_PARSE_FN parseDontUseCopy;
-static SLAP_CTRL_PARSE_FN parseManageDIT;
-#endif
 static SLAP_CTRL_PARSE_FN parseManageDSAit;
 static SLAP_CTRL_PARSE_FN parseNoOp;
 static SLAP_CTRL_PARSE_FN parsePagedResults;
-#ifdef LDAP_DEVEL
+static SLAP_CTRL_PARSE_FN parsePermissiveModify;
+static SLAP_CTRL_PARSE_FN parsePreRead, parsePostRead;
+static SLAP_CTRL_PARSE_FN parseProxyAuthz;
+static SLAP_CTRL_PARSE_FN parseRelax;
+static SLAP_CTRL_PARSE_FN parseSearchOptions;
+#ifdef SLAP_SORTEDRESULTS
 static SLAP_CTRL_PARSE_FN parseSortedResults;
 #endif
-static SLAP_CTRL_PARSE_FN parseValuesReturnFilter;
-static SLAP_CTRL_PARSE_FN parsePermissiveModify;
-static SLAP_CTRL_PARSE_FN parseDomainScope;
+static SLAP_CTRL_PARSE_FN parseSubentries;
 #ifdef SLAP_CONTROL_X_TREE_DELETE
 static SLAP_CTRL_PARSE_FN parseTreeDelete;
 #endif
-static SLAP_CTRL_PARSE_FN parseSearchOptions;
-static SLAP_CTRL_PARSE_FN parseSubentries;
+static SLAP_CTRL_PARSE_FN parseValuesReturnFilter;
 
 #undef sc_mask /* avoid conflict with Irix 6.5 <sys/signal.h> */
 
@@ -96,7 +93,7 @@ static int num_known_controls = 1;
 
 static char *proxy_authz_extops[] = {
        LDAP_EXOP_MODIFY_PASSWD,
-       LDAP_EXOP_X_WHO_AM_I,
+       LDAP_EXOP_WHO_AM_I,
        LDAP_EXOP_REFRESH,
        NULL
 };
@@ -133,7 +130,7 @@ static struct slap_control control_defs[] = {
                SLAP_CTRL_SEARCH,
                NULL, NULL,
                parsePagedResults, LDAP_SLIST_ENTRY_INITIALIZER(next) },
-#ifdef LDAP_DEVEL
+#ifdef SLAP_SORTEDRESULTS
        { LDAP_CONTROL_SORTREQUEST,
                (int)offsetof(struct slap_control_ids, sc_sortedResults),
                SLAP_CTRL_GLOBAL|SLAP_CTRL_SEARCH|SLAP_CTRL_HIDE,
@@ -145,6 +142,11 @@ static struct slap_control control_defs[] = {
                SLAP_CTRL_GLOBAL|SLAP_CTRL_SEARCH|SLAP_CTRL_HIDE,
                NULL, NULL,
                parseDomainScope, LDAP_SLIST_ENTRY_INITIALIZER(next) },
+       { LDAP_CONTROL_DONTUSECOPY,
+               (int)offsetof(struct slap_control_ids, sc_dontUseCopy),
+               SLAP_CTRL_GLOBAL|SLAP_CTRL_INTROGATE|SLAP_CTRL_HIDE,
+               NULL, NULL,
+               parseDontUseCopy, LDAP_SLIST_ENTRY_INITIALIZER(next) },
        { LDAP_CONTROL_X_PERMISSIVE_MODIFY,
                (int)offsetof(struct slap_control_ids, sc_permissiveModify),
                SLAP_CTRL_MODIFY|SLAP_CTRL_HIDE,
@@ -172,17 +174,17 @@ static struct slap_control control_defs[] = {
                SLAP_CTRL_ACCESS|SLAP_CTRL_HIDE,
                NULL, NULL,
                parseNoOp, LDAP_SLIST_ENTRY_INITIALIZER(next) },
-#ifdef LDAP_DEVEL
-       { LDAP_CONTROL_DONTUSECOPY,
-               (int)offsetof(struct slap_control_ids, sc_dontUseCopy),
-               SLAP_CTRL_INTROGATE|SLAP_CTRL_HIDE,
-               NULL, NULL,
-               parseDontUseCopy, LDAP_SLIST_ENTRY_INITIALIZER(next) },
-       { LDAP_CONTROL_MANAGEDIT,
-               (int)offsetof(struct slap_control_ids, sc_manageDIT),
+       { LDAP_CONTROL_RELAX,
+               (int)offsetof(struct slap_control_ids, sc_relax),
                SLAP_CTRL_GLOBAL|SLAP_CTRL_UPDATE|SLAP_CTRL_HIDE,
                NULL, NULL,
-               parseManageDIT, LDAP_SLIST_ENTRY_INITIALIZER(next) },
+               parseRelax, LDAP_SLIST_ENTRY_INITIALIZER(next) },
+#ifdef LDAP_X_TXN
+       { LDAP_CONTROL_X_TXN_SPEC,
+               (int)offsetof(struct slap_control_ids, sc_txnSpec),
+               SLAP_CTRL_UPDATE|SLAP_CTRL_HIDE,
+               NULL, NULL,
+               txn_spec_ctrl, LDAP_SLIST_ENTRY_INITIALIZER(next) },
 #endif
        { LDAP_CONTROL_MANAGEDSAIT,
                (int)offsetof(struct slap_control_ids, sc_manageDSAit),
@@ -194,24 +196,32 @@ static struct slap_control control_defs[] = {
                SLAP_CTRL_GLOBAL|SLAP_CTRL_ACCESS,
                proxy_authz_extops, NULL,
                parseProxyAuthz, LDAP_SLIST_ENTRY_INITIALIZER(next) },
-       { NULL, 0, 0, NULL, 0, LDAP_SLIST_ENTRY_INITIALIZER(next) }
+       { NULL, 0, 0, NULL, 0, NULL, LDAP_SLIST_ENTRY_INITIALIZER(next) }
 };
 
+static struct slap_control *
+find_ctrl( const char *oid );
+
 /*
  * Register a supported control.
  *
  * This can be called by an OpenLDAP plugin or, indirectly, by a
  * SLAPI plugin calling slapi_register_supported_control().
+ *
+ * NOTE: if flags == 1 the control is replaced if already registered;
+ * otherwise registering an already registered control is not allowed.
  */
 int
-register_supported_control(const char *controloid,
+register_supported_control2(const char *controloid,
        slap_mask_t controlmask,
        char **controlexops,
        SLAP_CTRL_PARSE_FN *controlparsefn,
+       unsigned flags,
        int *controlcid)
 {
-       struct slap_control *sc;
+       struct slap_control *sc = NULL;
        int i;
+       BerVarray extendedopsbv = NULL;
 
        if ( num_known_controls >= SLAP_MAX_CIDS ) {
                Debug( LDAP_DEBUG_ANY, "Too many controls registered."
@@ -220,11 +230,23 @@ register_supported_control(const char *controloid,
                return LDAP_OTHER;
        }
 
-       if ( controloid == NULL ) return LDAP_PARAM_ERROR;
+       if ( controloid == NULL ) {
+               return LDAP_PARAM_ERROR;
+       }
 
-       /* sanity check - should never happen */
+       /* check if already registered */
        for ( i = 0; slap_known_controls[ i ]; i++ ) {
                if ( strcmp( controloid, slap_known_controls[ i ] ) == 0 ) {
+                       if ( flags == 1 ) {
+                               Debug( LDAP_DEBUG_TRACE,
+                                       "Control %s already registered; replacing.\n",
+                                       controloid, 0, 0 );
+                               /* (find and) replace existing handler */
+                               sc = find_ctrl( controloid );
+                               assert( sc != NULL );
+                               break;
+                       }
+
                        Debug( LDAP_DEBUG_ANY,
                                "Control %s already registered.\n",
                                controloid, 0, 0 );
@@ -232,41 +254,62 @@ register_supported_control(const char *controloid,
                }
        }
 
-       sc = (struct slap_control *)SLAP_MALLOC( sizeof( *sc ) );
-       if ( sc == NULL ) return LDAP_NO_MEMORY;
-
-       sc->sc_oid = ch_strdup( controloid );
-       sc->sc_mask = controlmask;
+       /* turn compatible extended operations into bervals */
        if ( controlexops != NULL ) {
                int i;
 
                for ( i = 0; controlexops[ i ]; i++ );
 
-               sc->sc_extendedopsbv = ber_memcalloc( i + 1, sizeof( struct berval ) );
-               if ( sc->sc_extendedopsbv == NULL ) {
-                       ch_free( sc );
+               extendedopsbv = ber_memcalloc( i + 1, sizeof( struct berval ) );
+               if ( extendedopsbv == NULL ) {
                        return LDAP_NO_MEMORY;
                }
 
                for ( i = 0; controlexops[ i ]; i++ ) {
-                       ber_str2bv( controlexops[ i ], 0, 1, &sc->sc_extendedopsbv[ i ] );
+                       ber_str2bv( controlexops[ i ], 0, 1, &extendedopsbv[ i ] );
+               }
+       }
+
+       if ( sc == NULL ) {
+               sc = (struct slap_control *)SLAP_MALLOC( sizeof( *sc ) );
+               if ( sc == NULL ) {
+                       return LDAP_NO_MEMORY;
                }
 
+               sc->sc_oid = ch_strdup( controloid );
+               sc->sc_cid = num_known_controls;
+
+               /* Update slap_known_controls, too. */
+               slap_known_controls[num_known_controls - 1] = sc->sc_oid;
+               slap_known_controls[num_known_controls++] = NULL;
+
+               LDAP_SLIST_NEXT( sc, sc_next ) = NULL;
+               LDAP_SLIST_INSERT_HEAD( &controls_list, sc, sc_next );
+
        } else {
-               sc->sc_extendedopsbv = NULL;
+               if ( sc->sc_extendedopsbv ) {
+                       /* FIXME: in principle, we should rather merge
+                        * existing extops with those supported by the
+                        * new control handling implementation.
+                        * In fact, whether a control is compatible with
+                        * an extop should not be a matter of implementation.
+                        * We likely also need a means for a newly
+                        * registered extop to declare that it is
+                        * comptible with an already registered control.
+                        */
+                       ber_bvarray_free( sc->sc_extendedopsbv );
+                       sc->sc_extendedopsbv = NULL;
+                       sc->sc_extendedops = NULL;
+               }
        }
-       sc->sc_extendedops = NULL;
-       sc->sc_parse = controlparsefn;
-
-       if ( controlcid ) *controlcid = num_known_controls;
-       sc->sc_cid = num_known_controls;
 
-       /* Update slap_known_controls, too. */
-       slap_known_controls[num_known_controls-1] = sc->sc_oid;
-       slap_known_controls[num_known_controls++] = NULL;
+       sc->sc_extendedopsbv = extendedopsbv;
+       sc->sc_mask = controlmask;
+       sc->sc_parse = controlparsefn;
+       if ( controlcid ) {
+               *controlcid = sc->sc_cid;
+       }
 
-       LDAP_SLIST_NEXT( sc, sc_next ) = NULL;
-       LDAP_SLIST_INSERT_HEAD( &controls_list, sc, sc_next );
        return LDAP_SUCCESS;
 }
 
@@ -372,7 +415,7 @@ get_supported_controls(char ***ctrloidsp,
        }
        masks = (slap_mask_t *)SLAP_MALLOC( (n + 1) * sizeof(slap_mask_t) );
        if  ( masks == NULL ) {
-               ch_free( oids );
+               SLAP_FREE( oids );
                return LDAP_NO_MEMORY;
        }
 
@@ -444,9 +487,11 @@ slap_global_control( Operation *op, const char *oid, int *cid )
                return LDAP_COMPARE_TRUE;
        }
 
+#if 0
        Debug( LDAP_DEBUG_TRACE,
                "slap_global_control: unavailable control: %s\n",      
                oid, 0, 0 );
+#endif
 
        return LDAP_COMPARE_FALSE;
 }
@@ -794,7 +839,6 @@ slap_remove_control(
        return rs->sr_err;
 }
 
-#ifdef LDAP_DEVEL
 static int parseDontUseCopy (
        Operation *op,
        SlapReply *rs,
@@ -805,12 +849,12 @@ static int parseDontUseCopy (
                return LDAP_PROTOCOL_ERROR;
        }
 
-       if ( ctrl->ldctl_value.bv_len ) {
-               rs->sr_text = "dontUseCopy control value not empty";
+       if ( !BER_BVISNULL( &ctrl->ldctl_value )) {
+               rs->sr_text = "dontUseCopy control value not absent";
                return LDAP_PROTOCOL_ERROR;
        }
 
-       if ( ctrl->ldctl_iscritical != SLAP_CONTROL_CRITICAL ) {
+       if ( !ctrl->ldctl_iscritical ) {
                rs->sr_text = "dontUseCopy criticality of FALSE not allowed";
                return LDAP_PROTOCOL_ERROR;
        }
@@ -819,28 +863,27 @@ static int parseDontUseCopy (
        return LDAP_SUCCESS;
 }
 
-static int parseManageDIT (
+static int parseRelax (
        Operation *op,
        SlapReply *rs,
        LDAPControl *ctrl )
 {
-       if ( op->o_managedit != SLAP_CONTROL_NONE ) {
-               rs->sr_text = "manageDIT control specified multiple times";
+       if ( op->o_relax != SLAP_CONTROL_NONE ) {
+               rs->sr_text = "relax control specified multiple times";
                return LDAP_PROTOCOL_ERROR;
        }
 
-       if ( ctrl->ldctl_value.bv_len ) {
-               rs->sr_text = "manageDIT control value not empty";
+       if ( !BER_BVISNULL( &ctrl->ldctl_value )) {
+               rs->sr_text = "relax control value not absent";
                return LDAP_PROTOCOL_ERROR;
        }
 
-       op->o_managedit = ctrl->ldctl_iscritical
+       op->o_relax = ctrl->ldctl_iscritical
                ? SLAP_CONTROL_CRITICAL
                : SLAP_CONTROL_NONCRITICAL;
 
        return LDAP_SUCCESS;
 }
-#endif
 
 static int parseManageDSAit (
        Operation *op,
@@ -852,8 +895,8 @@ static int parseManageDSAit (
                return LDAP_PROTOCOL_ERROR;
        }
 
-       if ( ctrl->ldctl_value.bv_len ) {
-               rs->sr_text = "manageDSAit control value not empty";
+       if ( !BER_BVISNULL( &ctrl->ldctl_value )) {
+               rs->sr_text = "manageDSAit control value not absent";
                return LDAP_PROTOCOL_ERROR;
        }
 
@@ -877,11 +920,16 @@ static int parseProxyAuthz (
                return LDAP_PROTOCOL_ERROR;
        }
 
+       if ( BER_BVISNULL( &ctrl->ldctl_value )) {
+               rs->sr_text = "proxy authorization control value absent";
+               return LDAP_PROTOCOL_ERROR;
+       }
+
        if ( !( global_allows & SLAP_ALLOW_PROXY_AUTHZ_ANON )
                && BER_BVISEMPTY( &op->o_ndn ) )
        {
-               rs->sr_text = "anonymous proxyAuthz not allowed";
-               return LDAP_PROXY_AUTHZ_FAILURE;
+               rs->sr_text = "anonymous proxied authorization not allowed";
+               return LDAP_PROXIED_AUTHORIZATION_DENIED;
        }
 
        op->o_proxy_authz = ctrl->ldctl_iscritical
@@ -894,7 +942,7 @@ static int parseProxyAuthz (
                ctrl->ldctl_value.bv_len ?  ctrl->ldctl_value.bv_val : "anonymous",
                0 );
 
-       if ( ctrl->ldctl_value.bv_len == 0 ) {
+       if ( BER_BVISEMPTY( &ctrl->ldctl_value )) {
                Debug( LDAP_DEBUG_TRACE,
                        "parseProxyAuthz: conn=%lu anonymous\n", 
                        op->o_connid, 0, 0 );
@@ -922,7 +970,7 @@ static int parseProxyAuthz (
                        ch_free( dn.bv_val );
                }
                rs->sr_text = "authzId mapping failed";
-               return LDAP_PROXY_AUTHZ_FAILURE;
+               return LDAP_PROXIED_AUTHORIZATION_DENIED;
        }
 
        Debug( LDAP_DEBUG_TRACE,
@@ -935,7 +983,7 @@ static int parseProxyAuthz (
        if ( rc ) {
                ch_free( dn.bv_val );
                rs->sr_text = "not authorized to assume identity";
-               return LDAP_PROXY_AUTHZ_FAILURE;
+               return LDAP_PROXIED_AUTHORIZATION_DENIED;
        }
 
        ch_free( op->o_ndn.bv_val );
@@ -948,7 +996,6 @@ static int parseProxyAuthz (
        op->o_ndn = dn;
        ber_dupbv( &op->o_dn, &dn );
 
-
        Statslog( LDAP_DEBUG_STATS, "%s PROXYAUTHZ dn=\"%s\"\n",
            op->o_log_prefix, dn.bv_val, 0, 0, 0 );
 
@@ -994,8 +1041,13 @@ static int parsePagedResults (
                return LDAP_PROTOCOL_ERROR;
        }
 
+       if ( BER_BVISNULL( &ctrl->ldctl_value ) ) {
+               rs->sr_text = "paged results control value is absent";
+               return LDAP_PROTOCOL_ERROR;
+       }
+
        if ( BER_BVISEMPTY( &ctrl->ldctl_value ) ) {
-               rs->sr_text = "paged results control value is empty (or absent)";
+               rs->sr_text = "paged results control value is empty";
                return LDAP_PROTOCOL_ERROR;
        }
 
@@ -1057,7 +1109,7 @@ done:;
        return rc;
 }
 
-#ifdef LDAP_DEVEL
+#ifdef SLAP_SORTEDRESULTS
 static int parseSortedResults (
        Operation *op,
        SlapReply *rs,
@@ -1070,8 +1122,13 @@ static int parseSortedResults (
                return LDAP_PROTOCOL_ERROR;
        }
 
+       if ( BER_BVISNULL( &ctrl->ldctl_value ) ) {
+               rs->sr_text = "sorted results control value is absent";
+               return LDAP_PROTOCOL_ERROR;
+       }
+
        if ( BER_BVISEMPTY( &ctrl->ldctl_value ) ) {
-               rs->sr_text = "sorted results control value is empty (or absent)";
+               rs->sr_text = "sorted results control value is empty";
                return LDAP_PROTOCOL_ERROR;
        }
 
@@ -1098,8 +1155,13 @@ static int parseAssert (
                return LDAP_PROTOCOL_ERROR;
        }
 
-       if ( ctrl->ldctl_value.bv_len == 0 ) {
-               rs->sr_text = "assert control value is empty (or absent)";
+       if ( BER_BVISNULL( &ctrl->ldctl_value )) {
+               rs->sr_text = "assert control value is absent";
+               return LDAP_PROTOCOL_ERROR;
+       }
+
+       if ( BER_BVISEMPTY( &ctrl->ldctl_value )) {
+               rs->sr_text = "assert control value is empty";
                return LDAP_PROTOCOL_ERROR;
        }
 
@@ -1111,6 +1173,7 @@ static int parseAssert (
        
        rs->sr_err = get_filter( op, ber, (Filter **)&(op->o_assertion),
                &rs->sr_text);
+       (void) ber_free( ber, 1 );
        if( rs->sr_err != LDAP_SUCCESS ) {
                if( rs->sr_err == SLAPD_DISCONNECT ) {
                        rs->sr_err = LDAP_PROTOCOL_ERROR;
@@ -1155,37 +1218,51 @@ static int parsePreRead (
                return LDAP_PROTOCOL_ERROR;
        }
 
-       if ( ctrl->ldctl_value.bv_len == 0 ) {
-               rs->sr_text = "preread control value is empty (or absent)";
+       if ( BER_BVISNULL( &ctrl->ldctl_value )) {
+               rs->sr_text = "preread control value is absent";
+               return LDAP_PROTOCOL_ERROR;
+       }
+
+       if ( BER_BVISEMPTY( &ctrl->ldctl_value )) {
+               rs->sr_text = "preread control value is empty";
                return LDAP_PROTOCOL_ERROR;
        }
 
+#ifdef LDAP_X_TXN
+       if ( op->o_txnSpec ) { /* temporary limitation */
+               rs->sr_text = "cannot perform pre-read in transaction";
+               return LDAP_UNWILLING_TO_PERFORM;
+       }
+#endif
+
        ber = ber_init( &(ctrl->ldctl_value) );
        if (ber == NULL) {
                rs->sr_text = "preread control: internal error";
                return LDAP_OTHER;
        }
 
+       rs->sr_err = LDAP_SUCCESS;
+
        siz = sizeof( AttributeName );
        off = offsetof( AttributeName, an_name );
        if ( ber_scanf( ber, "{M}", &an, &siz, off ) == LBER_ERROR ) {
                rs->sr_text = "preread control: decoding error";
-               return LDAP_PROTOCOL_ERROR;
+               rs->sr_err = LDAP_PROTOCOL_ERROR;
+               goto done;
        }
 
        for( i=0; i<siz; i++ ) {
-               int             rc = LDAP_SUCCESS;
                const char      *dummy = NULL;
 
                an[i].an_desc = NULL;
                an[i].an_oc = NULL;
                an[i].an_oc_exclude = 0;
-               rc = slap_bv2ad( &an[i].an_name, &an[i].an_desc, &dummy );
-               if ( rc != LDAP_SUCCESS && ctrl->ldctl_iscritical ) {
+               rs->sr_err = slap_bv2ad( &an[i].an_name, &an[i].an_desc, &dummy );
+               if ( rs->sr_err != LDAP_SUCCESS && ctrl->ldctl_iscritical ) {
                        rs->sr_text = dummy
                                ? dummy
                                : "postread control: unknown attributeType";
-                       return rc;
+                       goto done;
                }
        }
 
@@ -1195,8 +1272,9 @@ static int parsePreRead (
 
        op->o_preread_attrs = an;
 
-       rs->sr_err = LDAP_SUCCESS;
-       return LDAP_SUCCESS;
+done:
+       (void) ber_free( ber, 1 );
+       return rs->sr_err;
 }
 
 static int parsePostRead (
@@ -1213,37 +1291,69 @@ static int parsePostRead (
                return LDAP_PROTOCOL_ERROR;
        }
 
-       if ( ctrl->ldctl_value.bv_len == 0 ) {
-               rs->sr_text = "postread control value is empty (or absent)";
+       if ( BER_BVISNULL( &ctrl->ldctl_value )) {
+               rs->sr_text = "postread control value is absent";
                return LDAP_PROTOCOL_ERROR;
        }
 
+       if ( BER_BVISEMPTY( &ctrl->ldctl_value )) {
+               rs->sr_text = "postread control value is empty";
+               return LDAP_PROTOCOL_ERROR;
+       }
+
+#ifdef LDAP_X_TXN
+       if ( op->o_txnSpec ) { /* temporary limitation */
+               rs->sr_text = "cannot perform post-read in transaction";
+               return LDAP_UNWILLING_TO_PERFORM;
+       }
+#endif
+
        ber = ber_init( &(ctrl->ldctl_value) );
        if (ber == NULL) {
                rs->sr_text = "postread control: internal error";
                return LDAP_OTHER;
        }
 
+       rs->sr_err = LDAP_SUCCESS;
        siz = sizeof( AttributeName );
        off = offsetof( AttributeName, an_name );
        if ( ber_scanf( ber, "{M}", &an, &siz, off ) == LBER_ERROR ) {
                rs->sr_text = "postread control: decoding error";
-               return LDAP_PROTOCOL_ERROR;
+               rs->sr_err = LDAP_PROTOCOL_ERROR;
+               goto done;
        }
 
-       for( i=0; i<siz; i++ ) {
-               int             rc = LDAP_SUCCESS;
+       for ( i = 0; i < siz; i++ ) {
                const char      *dummy = NULL;
+               int             rc;
 
                an[i].an_desc = NULL;
                an[i].an_oc = NULL;
                an[i].an_oc_exclude = 0;
                rc = slap_bv2ad( &an[i].an_name, &an[i].an_desc, &dummy );
-               if ( rc != LDAP_SUCCESS && ctrl->ldctl_iscritical ) {
-                       rs->sr_text = dummy
-                               ? dummy
-                               : "postread control: unknown attributeType";
-                       return rc;
+               if ( rc != LDAP_SUCCESS ) {
+                       int                     i;
+                       static struct berval    special_attrs[] = {
+                               BER_BVC( LDAP_NO_ATTRS ),
+                               BER_BVC( LDAP_ALL_USER_ATTRIBUTES ),
+                               BER_BVC( LDAP_ALL_OPERATIONAL_ATTRIBUTES ),
+                               BER_BVNULL
+                       };
+
+                       /* deal with special attribute types */
+                       for ( i = 0; !BER_BVISNULL( &special_attrs[ i ] ); i++ ) {
+                               if ( bvmatch( &an[i].an_name, &special_attrs[ i ] ) ) {
+                                       break;
+                               }
+                       }
+
+                       if ( BER_BVISNULL( &special_attrs[ i ] ) && ctrl->ldctl_iscritical ) {
+                               rs->sr_err = rc;
+                               rs->sr_text = dummy
+                                       ? dummy
+                                       : "postread control: unknown attributeType";
+                               goto done;
+                       }
                }
        }
 
@@ -1253,8 +1363,9 @@ static int parsePostRead (
 
        op->o_postread_attrs = an;
 
-       rs->sr_err = LDAP_SUCCESS;
-       return LDAP_SUCCESS;
+done:
+       (void) ber_free( ber, 1 );
+       return rs->sr_err;
 }
 
 static int parseValuesReturnFilter (
@@ -1270,8 +1381,13 @@ static int parseValuesReturnFilter (
                return LDAP_PROTOCOL_ERROR;
        }
 
-       if ( ctrl->ldctl_value.bv_len == 0 ) {
-               rs->sr_text = "valuesReturnFilter control value is empty (or absent)";
+       if ( BER_BVISNULL( &ctrl->ldctl_value )) {
+               rs->sr_text = "valuesReturnFilter control value is absent";
+               return LDAP_PROTOCOL_ERROR;
+       }
+
+       if ( BER_BVISEMPTY( &ctrl->ldctl_value )) {
+               rs->sr_text = "valuesReturnFilter control value is empty";
                return LDAP_PROTOCOL_ERROR;
        }
 
@@ -1284,6 +1400,8 @@ static int parseValuesReturnFilter (
        rs->sr_err = get_vrFilter( op, ber,
                (ValuesReturnFilter **)&(op->o_vrFilter), &rs->sr_text);
 
+       (void) ber_free( ber, 1 );
+
        if( rs->sr_err != LDAP_SUCCESS ) {
                if( rs->sr_err == SLAPD_DISCONNECT ) {
                        rs->sr_err = LDAP_PROTOCOL_ERROR;
@@ -1352,8 +1470,8 @@ static int parsePermissiveModify (
                return LDAP_PROTOCOL_ERROR;
        }
 
-       if ( ctrl->ldctl_value.bv_len ) {
-               rs->sr_text = "permissiveModify control value not empty";
+       if ( BER_BVISNULL( &ctrl->ldctl_value )) {
+               rs->sr_text = "permissiveModify control value not absent";
                return LDAP_PROTOCOL_ERROR;
        }
 
@@ -1374,7 +1492,7 @@ static int parseDomainScope (
                return LDAP_PROTOCOL_ERROR;
        }
 
-       if ( ctrl->ldctl_value.bv_len ) {
+       if ( BER_BVISNULL( &ctrl->ldctl_value )) {
                rs->sr_text = "domainScope control value not empty";
                return LDAP_PROTOCOL_ERROR;
        }
@@ -1397,8 +1515,8 @@ static int parseTreeDelete (
                return LDAP_PROTOCOL_ERROR;
        }
 
-       if ( ctrl->ldctl_value.bv_len ) {
-               rs->sr_text = "treeDelete control value not empty";
+       if ( BER_BVISNULL( &ctrl->ldctl_value )) {
+               rs->sr_text = "treeDelete control value not absent";
                return LDAP_PROTOCOL_ERROR;
        }
 
@@ -1419,8 +1537,13 @@ static int parseSearchOptions (
        ber_int_t search_flags;
        ber_tag_t tag;
 
-       if ( ctrl->ldctl_value.bv_len == 0 ) {
-               rs->sr_text = "searchOptions control value is empty (or absent)";
+       if ( BER_BVISNULL( &ctrl->ldctl_value )) {
+               rs->sr_text = "searchOptions control value is absent";
+               return LDAP_PROTOCOL_ERROR;
+       }
+
+       if ( BER_BVISEMPTY( &ctrl->ldctl_value )) {
+               rs->sr_text = "searchOptions control value is empty";
                return LDAP_PROTOCOL_ERROR;
        }
 
@@ -1430,13 +1553,14 @@ static int parseSearchOptions (
                return LDAP_OTHER;
        }
 
-       if ( (tag = ber_scanf( ber, "{i}", &search_flags )) == LBER_ERROR ) {
+       tag = ber_scanf( ber, "{i}", &search_flags );
+       (void) ber_free( ber, 1 );
+
+       if ( tag == 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_CONTROL_NONE ) {
                        rs->sr_text = "searchOptions control specified multiple times "