]> git.sur5r.net Git - openldap/commitdiff
add "What Failed?" LDAP control (ITS#5784)
authorPierangelo Masarati <ando@openldap.org>
Sat, 1 Nov 2008 15:15:57 +0000 (15:15 +0000)
committerPierangelo Masarati <ando@openldap.org>
Sat, 1 Nov 2008 15:15:57 +0000 (15:15 +0000)
clients/tools/common.c
include/ldap.h
servers/slapd/backend.c
servers/slapd/controls.c
servers/slapd/proto-slap.h
servers/slapd/slap.h

index 58d5e6bf4962be59b326a6d18e08053864ed9a00..cda39c9f8caa3706e1630ea6f7540d87cc9afa20 100644 (file)
@@ -138,6 +138,9 @@ static int print_sss( LDAP *ld, LDAPControl *ctrl );
 #ifdef LDAP_CONTROL_X_DEREF
 static int print_deref( LDAP *ld, LDAPControl *ctrl );
 #endif
+#ifdef LDAP_CONTROL_X_WHATFAILED
+static int print_whatfailed( LDAP *ld, LDAPControl *ctrl );
+#endif
 
 static struct tool_ctrls_t {
        const char      *oid;
@@ -153,6 +156,9 @@ static struct tool_ctrls_t {
        { LDAP_CONTROL_SORTRESPONSE,    TOOL_SEARCH,    print_sss },
 #ifdef LDAP_CONTROL_X_DEREF
        { LDAP_CONTROL_X_DEREF,                         TOOL_SEARCH,    print_deref },
+#endif
+#ifdef LDAP_CONTROL_X_WHATFAILED
+       { LDAP_CONTROL_X_WHATFAILED,                    TOOL_ALL,       print_whatfailed },
 #endif
        { NULL,                                         0,              NULL }
 };
@@ -1966,6 +1972,43 @@ done:;
 }
 #endif
 
+#ifdef LDAP_CONTROL_X_WHATFAILED
+static int
+print_whatfailed( LDAP *ld, LDAPControl *ctrl )
+{
+       BerElement *ber;
+       ber_tag_t tag;
+       ber_len_t siz;
+       BerVarray bva = NULL;
+
+       /* Create a BerElement from the berval returned in the control. */
+       ber = ber_init( &ctrl->ldctl_value );
+
+       if ( ber == NULL ) {
+               return LDAP_NO_MEMORY;
+       }
+
+       siz = sizeof(struct berval);
+       tag = ber_scanf( ber, "[M]", &bva, &siz, 0 );
+       if ( tag != LBER_ERROR ) {
+               int i;
+
+               tool_write_ldif( LDIF_PUT_COMMENT, " what failed:", NULL, 0 );
+
+               for ( i = 0; bva[i].bv_val != NULL; i++ ) {
+                       tool_write_ldif( LDIF_PUT_COMMENT, NULL, bva[i].bv_val, bva[i].bv_len );
+               }
+
+               ldap_memfree( bva );
+       }
+
+        ber_free( ber, 1 );
+
+
+       return 0;
+}
+#endif
+
 #ifdef LDAP_CONTROL_PASSWORDPOLICYREQUEST
 static int
 print_ppolicy( LDAP *ld, LDAPControl *ctrl )
index 99c2474723ff9a4a9540331eac62e5447d2c9ebd..59dd2e45394f262fe3d0b3685626412708b56c2e 100644 (file)
@@ -323,6 +323,8 @@ typedef struct ldapcontrol {
                                                LDAP_CONTROL_X_SESSION_TRACKING ".3"
 /* Dereference Control (work in progress) */
 #define        LDAP_CONTROL_X_DEREF                    "1.3.6.1.4.1.4203.666.5.16"
+/* "What Failed?" Control (work in progress) */
+#define        LDAP_CONTROL_X_WHATFAILED               "1.3.6.1.4.1.4203.666.5.17"
 #endif /* LDAP_DEVEL */
 
 /* various expired works */
index db3f299b61f475af52fd8e7e200ee9cd83097690..ccbc938da50af416d3ba33de981e186baf2ddcc6 100644 (file)
@@ -946,6 +946,12 @@ backend_check_controls(
 
                        case LDAP_COMPARE_FALSE:
                                if ( !op->o_bd->be_ctrls[cid] && (*ctrls)->ldctl_iscritical ) {
+#ifdef SLAP_CONTROL_X_WHATFAILED
+                                       if ( get_whatFailed( op ) ) {
+                                               char *oids[ 2 ] = { (*ctrls)->ldctl_oid, NULL };
+                                               slap_ctrl_whatFailed_add( op, rs, oids );
+                                       }
+#endif
                                        /* RFC 4511 allows unavailableCriticalExtension to be
                                         * returned when the server is unwilling to perform
                                         * an operation extended by a recognized critical
index f2efdd1696255630eafbd4a0be30816e87d2c683..496524f10a87961bd74732a2ce5c455224551813 100644 (file)
@@ -48,6 +48,9 @@ static SLAP_CTRL_PARSE_FN parseValuesReturnFilter;
 #ifdef SLAP_CONTROL_X_SESSION_TRACKING
 static SLAP_CTRL_PARSE_FN parseSessionTracking;
 #endif
+#ifdef SLAP_CONTROL_X_WHATFAILED
+static SLAP_CTRL_PARSE_FN parseWhatFailed;
+#endif
 
 #undef sc_mask /* avoid conflict with Irix 6.5 <sys/signal.h> */
 
@@ -217,6 +220,14 @@ static struct slap_control control_defs[] = {
                session_tracking_extops, NULL,
                parseSessionTracking, LDAP_SLIST_ENTRY_INITIALIZER(next) },
 #endif
+#ifdef SLAP_CONTROL_X_WHATFAILED
+       { LDAP_CONTROL_X_WHATFAILED,
+               (int)offsetof(struct slap_control_ids, sc_whatFailed),
+               SLAP_CTRL_GLOBAL|SLAP_CTRL_ACCESS|SLAP_CTRL_HIDE,
+               NULL, NULL,
+               parseWhatFailed, LDAP_SLIST_ENTRY_INITIALIZER(next) },
+#endif
+
        { NULL, 0, 0, NULL, 0, NULL, LDAP_SLIST_ENTRY_INITIALIZER(next) }
 };
 
@@ -536,6 +547,7 @@ int slap_parse_ctrl(
        const char **text )
 {
        struct slap_control *sc;
+       int rc = LDAP_SUCCESS;
 
        sc = find_ctrl( control->ldctl_oid );
        if( sc != NULL ) {
@@ -591,31 +603,29 @@ int slap_parse_ctrl(
 
                if (( sc->sc_mask & tagmask ) == tagmask ) {
                        /* available extension */
-                       int     rc;
+                       if ( sc->sc_parse ) {
+                               rc = sc->sc_parse( op, rs, control );
+                               assert( rc != LDAP_UNAVAILABLE_CRITICAL_EXTENSION );
 
-                       if( !sc->sc_parse ) {
+                       } else if ( control->ldctl_iscritical ) {
                                *text = "not yet implemented";
-                               return LDAP_OTHER;
+                               rc = LDAP_OTHER;
                        }
 
-                       rc = sc->sc_parse( op, rs, control );
-                       if ( rc ) {
-                               assert( rc != LDAP_UNAVAILABLE_CRITICAL_EXTENSION );
-                               return rc;
-                       }
 
-               } else if( control->ldctl_iscritical ) {
+               } else if ( control->ldctl_iscritical ) {
                        /* unavailable CRITICAL control */
                        *text = "critical extension is unavailable";
-                       return LDAP_UNAVAILABLE_CRITICAL_EXTENSION;
+                       rc = LDAP_UNAVAILABLE_CRITICAL_EXTENSION;
                }
-       } else if( control->ldctl_iscritical ) {
+
+       } else if ( control->ldctl_iscritical ) {
                /* unrecognized CRITICAL control */
                *text = "critical extension is not recognized";
-               return LDAP_UNAVAILABLE_CRITICAL_EXTENSION;
+               rc = LDAP_UNAVAILABLE_CRITICAL_EXTENSION;
        }
 
-       return LDAP_SUCCESS;
+       return rc;
 }
 
 int get_ctrls(
@@ -629,6 +639,15 @@ int get_ctrls(
        char *opaque;
        BerElement *ber = op->o_ber;
        struct berval bv;
+#ifdef SLAP_CONTROL_X_WHATFAILED
+       /* NOTE: right now, slapd checks the validity of each control
+        * while parsing.  As a consequence, it can only detect one
+        * cause of failure at a time.  This results in returning
+        * exactly one OID with the whatFailed control, or no control
+        * at all.
+        */
+       char *failed_oid = NULL;
+#endif
 
        len = ber_pvt_ber_remaining(ber);
 
@@ -769,6 +788,9 @@ int get_ctrls(
 
                rs->sr_err = slap_parse_ctrl( op, rs, c, &rs->sr_text );
                if ( rs->sr_err != LDAP_SUCCESS ) {
+#ifdef SLAP_CONTROL_X_WHATFAILED
+                       failed_oid = c->ldctl_oid;
+#endif
                        goto return_results;
                }
        }
@@ -784,6 +806,69 @@ return_results:
                        send_ldap_disconnect( op, rs );
                        rs->sr_err = SLAPD_DISCONNECT;
                } else {
+#ifdef SLAP_CONTROL_X_WHATFAILED
+                       /* might have not been parsed yet? */
+                       if ( failed_oid != NULL ) {
+                               if ( !get_whatFailed( op ) ) {
+                                       /* look it up */
+
+                                       /* step through each remaining element */
+                                       for ( ; tag != LBER_ERROR; tag = ber_next_element( ber, &len, opaque ) )
+                                       {
+                                               LDAPControl c = { 0 };
+
+                                               tag = ber_scanf( ber, "{m" /*}*/, &bv );
+                                               c.ldctl_oid = bv.bv_val;
+
+                                               if ( tag == LBER_ERROR ) {
+                                                       slap_free_ctrls( op, op->o_ctrls );
+                                                       op->o_ctrls = NULL;
+                                                       break;
+
+                                               } else if ( c.ldctl_oid == NULL ) {
+                                                       slap_free_ctrls( op, op->o_ctrls );
+                                                       op->o_ctrls = NULL;
+                                                       break;
+                                               }
+
+                                               tag = ber_peek_tag( ber, &len );
+                                               if ( tag == LBER_BOOLEAN ) {
+                                                       ber_int_t crit;
+                                                       tag = ber_scanf( ber, "b", &crit );
+                                                       if( tag == LBER_ERROR ) {
+                                                               slap_free_ctrls( op, op->o_ctrls );
+                                                               op->o_ctrls = NULL;
+                                                               break;
+                                                       }
+
+                                                       tag = ber_peek_tag( ber, &len );
+                                               }
+
+                                               if ( tag == LBER_OCTETSTRING ) {
+                                                       tag = ber_scanf( ber, "m", &c.ldctl_value );
+
+                                                       if( tag == LBER_ERROR ) {
+                                                               slap_free_ctrls( op, op->o_ctrls );
+                                                               op->o_ctrls = NULL;
+                                                               break;
+                                                       }
+                                               }
+
+                                               if ( strcmp( c.ldctl_oid, LDAP_CONTROL_X_WHATFAILED ) == 0 ) {
+                                                       const char *text;
+                                                       slap_parse_ctrl( op, rs, &c, &text );
+                                                       break;
+                                               }
+                                       }
+                               }
+
+                               if ( get_whatFailed( op ) ) {
+                                       char *oids[ 2 ] = { failed_oid, NULL };
+                                       slap_ctrl_whatFailed_add( op, rs, oids );
+                               }
+                       }
+#endif
+
                        send_ldap_result( op, rs );
                }
        }
@@ -1112,11 +1197,11 @@ static int parsePagedResults (
     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_CONTROL_IGNORED;
 
@@ -1192,7 +1277,7 @@ static int parseAssert (
                rs->sr_text = "assert control: internal error";
                return LDAP_OTHER;
        }
-       
+
        rs->sr_err = get_filter( op, ber, (Filter **)&(op->o_assertion),
                &rs->sr_text);
        (void) ber_free( ber, 1 );
@@ -1377,7 +1462,7 @@ static int parseValuesReturnFilter (
                rs->sr_text = "internal error";
                return LDAP_OTHER;
        }
-       
+
        rs->sr_err = get_vrFilter( op, ber,
                (ValuesReturnFilter **)&(op->o_vrFilter), &rs->sr_text);
 
@@ -1865,3 +1950,87 @@ slap_ctrl_session_tracking_request_add( Operation *op, SlapReply *rs, LDAPContro
        return slap_ctrl_session_tracking_add( op, rs, &ip, &name, &id, ctrl );
 }
 #endif
+
+#ifdef SLAP_CONTROL_X_WHATFAILED
+static int parseWhatFailed(
+       Operation *op,
+       SlapReply *rs,
+       LDAPControl *ctrl )
+{
+       if ( op->o_whatFailed != SLAP_CONTROL_NONE ) {
+               rs->sr_text = "\"WHat Failed?\" control specified multiple times";
+               return LDAP_PROTOCOL_ERROR;
+       }
+
+       if ( !BER_BVISNULL( &ctrl->ldctl_value )) {
+               rs->sr_text = "\"What Failed?\" control value not absent";
+               return LDAP_PROTOCOL_ERROR;
+       }
+
+       op->o_whatFailed = ctrl->ldctl_iscritical
+               ? SLAP_CONTROL_CRITICAL
+               : SLAP_CONTROL_NONCRITICAL;
+
+       return LDAP_SUCCESS;
+}
+
+int
+slap_ctrl_whatFailed_add(
+       Operation *op,
+       SlapReply *rs,
+       char **oids )
+{
+       BerElementBuffer berbuf;
+       BerElement *ber = (BerElement *) &berbuf;
+       LDAPControl **ctrls = NULL;
+       struct berval ctrlval;
+       int i, rc = LDAP_SUCCESS;
+
+       ber_init2( ber, NULL, LBER_USE_DER );
+       ber_set_option( ber, LBER_OPT_BER_MEMCTX, &op->o_tmpmemctx );
+       ber_printf( ber, "[" /*]*/ );
+       for ( i = 0; oids[ i ] != NULL; i++ ) {
+               ber_printf( ber, "s", oids[ i ] );
+       }
+       ber_printf( ber, /*[*/ "]" );
+
+       if ( ber_flatten2( ber, &ctrlval, 0 ) == -1 ) {
+               rc = LDAP_OTHER;
+               goto done;
+       }
+
+       i = 0;
+       if ( rs->sr_ctrls != NULL ) {
+               for ( ; rs->sr_ctrls[ i ] != NULL; i++ ) {
+                       if ( strcmp( rs->sr_ctrls[ i ]->ldctl_oid, LDAP_CONTROL_X_WHATFAILED ) != 0 ) {
+                               /* TODO: add */
+                               assert( 0 );
+                       }
+               }
+       }
+
+       ctrls = op->o_tmprealloc( rs->sr_ctrls,
+                       sizeof(LDAPControl *)*( i + 2 )
+                       + sizeof(LDAPControl)
+                       + ctrlval.bv_len + 1,
+                       op->o_tmpmemctx );
+       if ( ctrls == NULL ) {
+               rc = LDAP_OTHER;
+               goto done;
+       }
+       ctrls[ i + 1 ] = NULL;
+       ctrls[ i ] = (LDAPControl *)&ctrls[ i + 2 ];
+       ctrls[ i ]->ldctl_oid = LDAP_CONTROL_X_WHATFAILED;
+       ctrls[ i ]->ldctl_iscritical = 0;
+       ctrls[ i ]->ldctl_value.bv_val = (char *)&ctrls[ i ][ 1 ];
+       AC_MEMCPY( ctrls[ i ]->ldctl_value.bv_val, ctrlval.bv_val, ctrlval.bv_len + 1 );
+       ctrls[ i ]->ldctl_value.bv_len = ctrlval.bv_len;
+
+       ber_free_buf( ber );
+
+       rs->sr_ctrls = ctrls;
+
+done:;
+       return rc;
+}
+#endif
index 42aa39fe5ad7d627e206a23150759b0c887140bd..3999334aa369f14617f77eecbe5471d5c07dccfb 100644 (file)
@@ -660,6 +660,13 @@ LDAP_SLAPD_F (int)
 slap_ctrl_session_tracking_request_add LDAP_P((
        Operation *op, SlapReply *rs, LDAPControl *ctrl ));
 #endif /* SLAP_CONTROL_X_SESSION_TRACKING */
+#ifdef SLAP_CONTROL_X_WHATFAILED
+LDAP_SLAPD_F (int)
+slap_ctrl_whatFailed_add LDAP_P((
+       Operation *op,
+       SlapReply *rs,
+       char **oids ));
+#endif /* SLAP_CONTROL_X_WHATFAILED */
 
 /*
  * config.c
index 4f3b19c021d6426267b5747304115139300f7093..53d7629ca53fa7ef0a02a943f0f7763e2cb302ef 100644 (file)
@@ -64,6 +64,7 @@ LDAP_BEGIN_DECL
 #define LDAP_SYNC_TIMESTAMP
 #define SLAP_CONTROL_X_SORTEDRESULTS
 #define SLAP_CONTROL_X_SESSION_TRACKING
+#define SLAP_CONTROL_X_WHATFAILED
 #define SLAP_CONFIG_DELETE
 #endif
 
@@ -2406,6 +2407,9 @@ struct slap_control_ids {
        int sc_sessionTracking;
 #endif
        int sc_valuesReturnFilter;
+#ifdef SLAP_CONTROL_X_WHATFAILED
+       int sc_whatFailed;
+#endif
 };
 
 /*
@@ -2675,6 +2679,11 @@ struct Operation {
 #define get_sessionTracking(op)                        ((int)(op)->o_session_tracking)
 #endif
 
+#ifdef SLAP_CONTROL_X_WHATFAILED
+#define o_whatFailed o_ctrlflag[slap_cids.sc_whatFailed]
+#define get_whatFailed(op)                             _SCM((op)->o_whatFailed)
+#endif
+
 #define o_sync                 o_ctrlflag[slap_cids.sc_LDAPsync]
 
        AuthorizationInformation o_authz;