From: Pierangelo Masarati Date: Sat, 1 Nov 2008 15:15:57 +0000 (+0000) Subject: add "What Failed?" LDAP control (ITS#5784) X-Git-Tag: ACLCHECK_0~1172 X-Git-Url: https://git.sur5r.net/?a=commitdiff_plain;h=7ad03166b6ae9c4efbc446b5c82809628c93216e;p=openldap add "What Failed?" LDAP control (ITS#5784) --- diff --git a/clients/tools/common.c b/clients/tools/common.c index 58d5e6bf49..cda39c9f8c 100644 --- a/clients/tools/common.c +++ b/clients/tools/common.c @@ -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 ) diff --git a/include/ldap.h b/include/ldap.h index 99c2474723..59dd2e4539 100644 --- a/include/ldap.h +++ b/include/ldap.h @@ -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 */ diff --git a/servers/slapd/backend.c b/servers/slapd/backend.c index db3f299b61..ccbc938da5 100644 --- a/servers/slapd/backend.c +++ b/servers/slapd/backend.c @@ -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 diff --git a/servers/slapd/controls.c b/servers/slapd/controls.c index f2efdd1696..496524f10a 100644 --- a/servers/slapd/controls.c +++ b/servers/slapd/controls.c @@ -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 */ @@ -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 diff --git a/servers/slapd/proto-slap.h b/servers/slapd/proto-slap.h index 42aa39fe5a..3999334aa3 100644 --- a/servers/slapd/proto-slap.h +++ b/servers/slapd/proto-slap.h @@ -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 diff --git a/servers/slapd/slap.h b/servers/slapd/slap.h index 4f3b19c021..53d7629ca5 100644 --- a/servers/slapd/slap.h +++ b/servers/slapd/slap.h @@ -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;