]> git.sur5r.net Git - openldap/blobdiff - servers/slapd/controls.c
added slapi_operation_set_pb
[openldap] / servers / slapd / controls.c
index b8a2011112a7da97830faf069fd0e35f19862207..88bfc9427986f2983d96c61f2390dbba7fc04dad 100644 (file)
@@ -1,6 +1,6 @@
 /* $OpenLDAP$ */
 /* 
- * Copyright 1999-2002 The OpenLDAP Foundation.
+ * Copyright 1999-2003 The OpenLDAP Foundation.
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms are permitted only
@@ -44,18 +44,27 @@ typedef int (SLAP_CTRL_PARSE_FN) LDAP_P((
        LDAPControl *ctrl,
        const char **text ));
 
+static SLAP_CTRL_PARSE_FN parseProxyAuthz;
 static SLAP_CTRL_PARSE_FN parseManageDSAit;
-static SLAP_CTRL_PARSE_FN parseSubentries;
 static SLAP_CTRL_PARSE_FN parseNoOp;
 static SLAP_CTRL_PARSE_FN parsePagedResults;
 static SLAP_CTRL_PARSE_FN parseValuesReturnFilter;
 
+#ifdef LDAP_CONTROL_SUBENTRIES
+static SLAP_CTRL_PARSE_FN parseSubentries;
+#endif
 #ifdef LDAP_CLIENT_UPDATE
 static SLAP_CTRL_PARSE_FN parseClientUpdate;
-#endif /* LDAP_CLIENT_UPDATE */
+#endif
 
 #undef sc_mask /* avoid conflict with Irix 6.5 <sys/signal.h> */
 
+static char *proxy_authz_extops[] = {
+       LDAP_EXOP_MODIFY_PASSWD,
+       LDAP_EXOP_X_WHO_AM_I,
+       NULL
+};
+
 static struct slap_control {
        char *sc_oid;
        slap_mask_t sc_mask;
@@ -63,35 +72,32 @@ static struct slap_control {
        SLAP_CTRL_PARSE_FN *sc_parse;
 
 } supportedControls[] = {
+       { LDAP_CONTROL_PROXY_AUTHZ,
+               SLAP_CTRL_FRONTEND|SLAP_CTRL_ACCESS, proxy_authz_extops,
+               parseProxyAuthz },
        { LDAP_CONTROL_MANAGEDSAIT,
                SLAP_CTRL_ACCESS, NULL,
                parseManageDSAit },
-#ifdef LDAP_CONTROL_SUBENTRIES
-       { LDAP_CONTROL_SUBENTRIES,
-               SLAP_CTRL_SEARCH, NULL,
-               parseSubentries },
-#endif
-#ifdef LDAP_CONTROL_NOOP
        { LDAP_CONTROL_NOOP,
                SLAP_CTRL_ACCESS, NULL,
                parseNoOp },
-#endif
-#ifdef LDAP_CONTROL_PAGEDRESULTS
        { LDAP_CONTROL_PAGEDRESULTS,
                SLAP_CTRL_SEARCH, NULL,
                parsePagedResults },
-#endif /* LDAP_CONTROL_PAGEDRESULTS */
-#ifdef LDAP_CONTROL_VALUESRETURNFILTER
        { LDAP_CONTROL_VALUESRETURNFILTER,
                SLAP_CTRL_SEARCH, NULL,
-               parseValuesReturnFilter },
+               parseValuesReturnFilter },
+#ifdef LDAP_CONTROL_SUBENTRIES
+       { LDAP_CONTROL_SUBENTRIES,
+               SLAP_CTRL_SEARCH, NULL,
+               parseSubentries },
 #endif
 #ifdef LDAP_CLIENT_UPDATE
        { LDAP_CONTROL_CLIENT_UPDATE,
                SLAP_CTRL_SEARCH, NULL,
                parseClientUpdate },
 #endif /* LDAP_CLIENT_UPDATE */
-       { NULL }
+       { NULL, 0, NULL, 0 }
 };
 
 char *
@@ -100,6 +106,12 @@ get_supported_ctrl(int index)
        return supportedControls[index].sc_oid;
 }
 
+slap_mask_t
+get_supported_ctrl_mask(int index)
+{
+       return supportedControls[index].sc_mask;
+}
+
 static struct slap_control *
 find_ctrl( const char *oid )
 {
@@ -144,10 +156,13 @@ int get_ctrls(
        }
 
 #ifdef NEW_LOGGING
-       LDAP_LOG( OPERATION, ENTRY, "get_ctrls: conn %lu\n", conn->c_connid, 0, 0 );
+       LDAP_LOG( OPERATION, ENTRY,
+               "get_ctrls: conn %lu\n", conn->c_connid, 0, 0 );
 #else
-       Debug( LDAP_DEBUG_TRACE, "=> get_ctrls\n", 0, 0, 0 );
+       Debug( LDAP_DEBUG_TRACE,
+               "=> get_ctrls\n", 0, 0, 0 );
 #endif
+
        if( op->o_protocol < LDAP_VERSION3 ) {
                rc = SLAPD_DISCONNECT;
                errmsg = "controls require LDAPv3";
@@ -155,12 +170,7 @@ int get_ctrls(
        }
 
        /* one for first control, one for termination */
-#ifndef LDAP_CONTROL_PAGEDRESULTS
        op->o_ctrls = ch_malloc( 2 * sizeof(LDAPControl *) );
-#else /* LDAP_CONTROL_PAGEDRESULTS */
-       /* FIXME: are we sure we need this? */
-       op->o_ctrls = ch_malloc( 3 * sizeof(LDAPControl *) );
-#endif /* LDAP_CONTROL_PAGEDRESULTS */
 
 #if 0
        if( op->ctrls == NULL ) {
@@ -225,11 +235,29 @@ int get_ctrls(
                        Debug( LDAP_DEBUG_TRACE, "=> get_ctrls: get oid failed.\n",
                                0, 0, 0 );
 #endif
+
                        ldap_controls_free( op->o_ctrls );
                        op->o_ctrls = NULL;
                        rc = SLAPD_DISCONNECT;
                        errmsg = "decoding controls error";
                        goto return_results;
+
+               } else if( c->ldctl_oid == NULL ) {
+#ifdef NEW_LOGGING
+                       LDAP_LOG( OPERATION, INFO,
+                               "get_ctrls: conn %lu got emtpy OID.\n",
+                               conn->c_connid, 0, 0 );
+#else
+                       Debug( LDAP_DEBUG_TRACE,
+                               "get_ctrls: conn %lu got emtpy OID.\n",
+                               conn->c_connid, 0, 0 );
+#endif
+
+                       ldap_controls_free( op->o_ctrls );
+                       op->o_ctrls = NULL;
+                       rc = LDAP_PROTOCOL_ERROR;
+                       errmsg = "OID field is empty";
+                       goto return_results;
                }
 
                tag = ber_peek_tag( ber, &len );
@@ -265,13 +293,12 @@ int get_ctrls(
 #ifdef NEW_LOGGING
                                LDAP_LOG( OPERATION, INFO, "get_ctrls: conn %lu: "
                                        "%s (%scritical): get value failed.\n",
-                                       conn->c_connid, c->ldctl_oid ? c->ldctl_oid : "(NULL)",
+                                       conn->c_connid, c->ldctl_oid,
                                        c->ldctl_iscritical ? "" : "non" );
 #else
                                Debug( LDAP_DEBUG_TRACE, "=> get_ctrls: conn %lu: "
                                        "%s (%scritical): get value failed.\n",
-                                       conn->c_connid,
-                                       c->ldctl_oid ? c->ldctl_oid : "(NULL)",
+                                       conn->c_connid, c->ldctl_oid,
                                        c->ldctl_iscritical ? "" : "non" );
 #endif
                                ldap_controls_free( op->o_ctrls );
@@ -285,13 +312,11 @@ int get_ctrls(
 #ifdef NEW_LOGGING
                LDAP_LOG( OPERATION, INFO, 
                        "get_ctrls: conn %lu oid=\"%s\" (%scritical)\n",
-                       conn->c_connid, c->ldctl_oid ? c->ldctl_oid : "(NULL)",
-                       c->ldctl_iscritical ? "" : "non" );
+                       conn->c_connid, c->ldctl_oid, c->ldctl_iscritical ? "" : "non" );
 #else
-               Debug( LDAP_DEBUG_TRACE, "=> get_ctrls: oid=\"%s\" (%scritical)\n",
-                       c->ldctl_oid ? c->ldctl_oid : "(NULL)",
-                       c->ldctl_iscritical ? "" : "non",
-                       0 );
+               Debug( LDAP_DEBUG_TRACE,
+                       "=> get_ctrls: oid=\"%s\" (%scritical)\n",
+                       c->ldctl_oid, c->ldctl_iscritical ? "" : "non", 0 );
 #endif
 
                sc = find_ctrl( c->ldctl_oid );
@@ -327,8 +352,19 @@ int get_ctrls(
                                tagmask = SLAP_CTRL_ABANDON;
                                break;
                        case LDAP_REQ_EXTENDED:
-                               /* FIXME: check list of extended operations */
-                               tagmask = ~0U;
+                               tagmask=~0L;
+                               assert( op->o_extendedop != NULL );
+                               if( sc->sc_extendedops != NULL ) {
+                                       int i;
+                                       for( i=0; sc->sc_extendedops[i] != NULL; i++ ) {
+                                               if( strcmp( op->o_extendedop, sc->sc_extendedops[i] )
+                                                       == 0 )
+                                               {
+                                                       tagmask=0L;
+                                                       break;
+                                               }
+                                       }
+                               }
                                break;
                        default:
                                rc = LDAP_OTHER;
@@ -378,9 +414,11 @@ int get_ctrls(
 return_results:
 #ifdef NEW_LOGGING
        LDAP_LOG( OPERATION, RESULTS, 
-               "get_ctrls: n=%d rc=%d err=%s\n", nctrls, rc, errmsg ? errmsg : "" );
+               "get_ctrls: n=%d rc=%d err=\"%s\"\n",
+               nctrls, rc, errmsg ? errmsg : "" );
 #else
-       Debug( LDAP_DEBUG_TRACE, "<= get_ctrls: n=%d rc=%d err=%s\n",
+       Debug( LDAP_DEBUG_TRACE,
+               "<= get_ctrls: n=%d rc=%d err=\"%s\"\n",
                nctrls, rc, errmsg ? errmsg : "");
 #endif
 
@@ -419,38 +457,100 @@ static int parseManageDSAit (
        return LDAP_SUCCESS;
 }
 
-#ifdef LDAP_CONTROL_SUBENTRIES
-static int parseSubentries (
+static int parseProxyAuthz (
        Connection *conn,
        Operation *op,
        LDAPControl *ctrl,
        const char **text )
 {
-       if ( op->o_subentries != SLAP_NO_CONTROL ) {
-               *text = "subentries control specified multiple times";
-               return LDAP_PROTOCOL_ERROR;
-       }
+       int rc;
+       struct berval dn;
 
-       /* 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 ))
-       {
-               *text = "subentries control value encoding is bogus";
+       if ( op->o_proxy_authz != SLAP_NO_CONTROL ) {
+               *text = "proxy authorization control specified multiple times";
                return LDAP_PROTOCOL_ERROR;
        }
 
-       op->o_subentries = ctrl->ldctl_iscritical
+       op->o_proxy_authz = ctrl->ldctl_iscritical
                ? SLAP_CRITICAL_CONTROL
                : SLAP_NONCRITICAL_CONTROL;
 
-       op->o_subentries_visibility = (ctrl->ldctl_value.bv_val[2] != 0x00);
+#ifdef NEW_LOGGING
+       LDAP_LOG( OPERATION, ARGS, 
+               "parseProxyAuthz: conn %lu authzid=\"%s\"\n", 
+               conn->c_connid,
+               ctrl->ldctl_value.bv_len ?  ctrl->ldctl_value.bv_val : "anonymous",
+               0 );
+#else
+       Debug( LDAP_DEBUG_ARGS,
+               "parseProxyAuthz: conn %lu authzid=\"%s\"\n", 
+               conn->c_connid,
+               ctrl->ldctl_value.bv_len ?  ctrl->ldctl_value.bv_val : "anonymous",
+               0 );
+#endif
+
+       if( ctrl->ldctl_value.bv_len == 0 ) {
+#ifdef NEW_LOGGING
+               LDAP_LOG( OPERATION, RESULTS, 
+                       "parseProxyAuthz: conn=%lu anonymous\n", 
+                       conn->c_connid, 0, 0 );
+#else
+               Debug( LDAP_DEBUG_TRACE,
+                       "parseProxyAuthz: conn=%lu anonymous\n", 
+                       conn->c_connid, 0, 0 );
+#endif
+
+               /* anonymous */
+               free( op->o_dn.bv_val );
+               op->o_dn.bv_len = 0;
+               op->o_dn.bv_val = ch_strdup( "" );
+
+               free( op->o_ndn.bv_val );
+               op->o_ndn.bv_len = 0;
+               op->o_ndn.bv_val = ch_strdup( "" );
+
+               return LDAP_SUCCESS;
+       }
+
+       rc = slap_sasl_getdn( conn,
+               ctrl->ldctl_value.bv_val, ctrl->ldctl_value.bv_len,
+               NULL, &dn, SLAP_GETDN_AUTHZID );
+
+       if( rc != LDAP_SUCCESS || !dn.bv_len ) {
+               *text = "authzId mapping failed";
+               return LDAP_PROXY_AUTHZ_FAILURE;
+       }
+
+#ifdef NEW_LOGGING
+       LDAP_LOG( OPERATION, RESULTS, 
+               "parseProxyAuthz: conn=%lu \"%s\"\n", 
+               conn->c_connid,
+               dn.bv_len ? dn.bv_val : "(NULL)", 0 );
+#else
+       Debug( LDAP_DEBUG_TRACE,
+               "parseProxyAuthz: conn=%lu \"%s\"\n", 
+               conn->c_connid,
+               dn.bv_len ? dn.bv_val : "(NULL)", 0 );
+#endif
+
+       rc = slap_sasl_authorized( conn, &op->o_ndn, &dn );
+
+       if( rc ) {
+               ch_free( dn.bv_val );
+               *text = "not authorized to assume identity";
+               return LDAP_PROXY_AUTHZ_FAILURE;
+       }
+
+       ch_free( op->o_dn.bv_val );
+       ch_free( op->o_ndn.bv_val );
+
+       op->o_dn.bv_val = NULL;
+       op->o_ndn = dn;
+       ber_dupbv( &op->o_dn, &dn );
 
        return LDAP_SUCCESS;
 }
-#endif
 
-#ifdef LDAP_CONTROL_NOOP
 static int parseNoOp (
        Connection *conn,
        Operation *op,
@@ -473,9 +573,7 @@ static int parseNoOp (
 
        return LDAP_SUCCESS;
 }
-#endif
 
-#ifdef LDAP_CONTROL_PAGEDRESULTS
 static int parsePagedResults (
        Connection *conn,
        Operation *op,
@@ -493,7 +591,7 @@ static int parsePagedResults (
        }
 
        if ( ctrl->ldctl_value.bv_len == 0 ) {
-               *text = "paged results control value is empty";
+               *text = "paged results control value is empty (or absent)";
                return LDAP_PROTOCOL_ERROR;
        }
 
@@ -518,7 +616,7 @@ static int parsePagedResults (
                return LDAP_PROTOCOL_ERROR;
        }
 
-       if( size <= 0 ) {
+       if( size < 0 ) {
                *text = "paged results control size invalid";
                return LDAP_PROTOCOL_ERROR;
        }
@@ -556,9 +654,7 @@ static int parsePagedResults (
 
        return LDAP_SUCCESS;
 }
-#endif /* LDAP_CONTROL_PAGEDRESULTS */
 
-#ifdef LDAP_CONTROL_VALUESRETURNFILTER
 int parseValuesReturnFilter (
        Connection *conn,
        Operation *op,
@@ -571,7 +667,12 @@ int parseValuesReturnFilter (
        const char *err_msg = "";
 
        if ( op->o_valuesreturnfilter != SLAP_NO_CONTROL ) {
-               *text = "valuesreturnfilter control specified multiple times";
+               *text = "valuesReturnFilter control specified multiple times";
+               return LDAP_PROTOCOL_ERROR;
+       }
+
+       if ( ctrl->ldctl_value.bv_len == 0 ) {
+               *text = "valuesReturnFilter control value is empty (or absent)";
                return LDAP_PROTOCOL_ERROR;
        }
 
@@ -614,6 +715,36 @@ int parseValuesReturnFilter (
 
        return LDAP_SUCCESS;
 }
+
+#ifdef LDAP_CONTROL_SUBENTRIES
+static int parseSubentries (
+       Connection *conn,
+       Operation *op,
+       LDAPControl *ctrl,
+       const char **text )
+{
+       if ( op->o_subentries != SLAP_NO_CONTROL ) {
+               *text = "subentries control specified multiple times";
+               return LDAP_PROTOCOL_ERROR;
+       }
+
+       /* 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 ))
+       {
+               *text = "subentries control value encoding is bogus";
+               return LDAP_PROTOCOL_ERROR;
+       }
+
+       op->o_subentries = ctrl->ldctl_iscritical
+               ? SLAP_CRITICAL_CONTROL
+               : SLAP_NONCRITICAL_CONTROL;
+
+       op->o_subentries_visibility = (ctrl->ldctl_value.bv_val[2] != 0x00);
+
+       return LDAP_SUCCESS;
+}
 #endif
 
 #ifdef LDAP_CLIENT_UPDATE
@@ -637,7 +768,7 @@ static int parseClientUpdate (
        }
 
        if ( ctrl->ldctl_value.bv_len == 0 ) {
-               *text = "LCUP client update control value is empty";
+               *text = "LCUP client update control value is empty (or absent)";
                return LDAP_PROTOCOL_ERROR;
        }