]> git.sur5r.net Git - openldap/blobdiff - servers/slapd/controls.c
Add ability to cache negative results and specify negative TTL on templates
[openldap] / servers / slapd / controls.c
index 08003bee1c53c246853a6fc8787653250881ae15..33d71d1f01471c177f83b5b6c49784a0b7b260df 100644 (file)
@@ -97,10 +97,12 @@ static int num_known_controls = 1;
 static char *proxy_authz_extops[] = {
        LDAP_EXOP_MODIFY_PASSWD,
        LDAP_EXOP_X_WHO_AM_I,
+       LDAP_EXOP_REFRESH,
        NULL
 };
 
 static char *manageDSAit_extops[] = {
+       LDAP_EXOP_REFRESH,
        NULL
 };
 
@@ -192,24 +194,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."
@@ -218,11 +228,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 );
@@ -230,41 +252,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;
 }
 
@@ -875,6 +918,13 @@ static int parseProxyAuthz (
                return LDAP_PROTOCOL_ERROR;
        }
 
+       if ( !( global_allows & SLAP_ALLOW_PROXY_AUTHZ_ANON )
+               && BER_BVISEMPTY( &op->o_ndn ) )
+       {
+               rs->sr_text = "anonymous proxied authorization not allowed";
+               return LDAP_PROXIED_AUTHORIZATION_DENIED;
+       }
+
        op->o_proxy_authz = ctrl->ldctl_iscritical
                ? SLAP_CONTROL_CRITICAL
                : SLAP_CONTROL_NONCRITICAL;
@@ -891,10 +941,14 @@ static int parseProxyAuthz (
                        op->o_connid, 0, 0 );
 
                /* anonymous */
-               op->o_ndn.bv_val[ 0 ] = '\0';
+               if ( !BER_BVISNULL( &op->o_ndn ) ) {
+                       op->o_ndn.bv_val[ 0 ] = '\0';
+               }
                op->o_ndn.bv_len = 0;
 
-               op->o_dn.bv_val[ 0 ] = '\0';
+               if ( !BER_BVISNULL( &op->o_dn ) ) {
+                       op->o_dn.bv_val[ 0 ] = '\0';
+               }
                op->o_dn.bv_len = 0;
 
                return LDAP_SUCCESS;
@@ -909,7 +963,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,
@@ -922,7 +976,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 );