add "What Failed?" LDAP control (ITS#5784)

This commit is contained in:
Pierangelo Masarati 2008-11-01 15:15:57 +00:00
parent d023222ee4
commit 7ad03166b6
6 changed files with 255 additions and 19 deletions

View 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 )

View 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 */

View 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

View 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 ) {
*text = "not yet implemented";
return LDAP_OTHER;
}
if ( sc->sc_parse ) {
rc = sc->sc_parse( op, rs, control );
if ( rc ) {
assert( rc != LDAP_UNAVAILABLE_CRITICAL_EXTENSION );
return rc;
} else if ( control->ldctl_iscritical ) {
*text = "not yet implemented";
rc = LDAP_OTHER;
}
} 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 ) {
/* 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 );
}
}
@ -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

View 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

View 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;