X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;f=servers%2Fslapd%2Fcontrols.c;h=93476070d1a8b3a86e03933ef59d78cedca8d0ca;hb=9767c87531d193a4bef19286b77623aff18590fb;hp=f2efdd1696255630eafbd4a0be30816e87d2c683;hpb=4f26be5cf67f26143a09304c5ee8fbab9aad1663;p=openldap diff --git a/servers/slapd/controls.c b/servers/slapd/controls.c index f2efdd1696..93476070d1 100644 --- a/servers/slapd/controls.c +++ b/servers/slapd/controls.c @@ -1,7 +1,7 @@ /* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * - * Copyright 1998-2008 The OpenLDAP Foundation. + * Copyright 1998-2009 The OpenLDAP Foundation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -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 */ @@ -120,8 +123,7 @@ static char *session_tracking_extops[] = { static struct slap_control control_defs[] = { { LDAP_CONTROL_ASSERT, (int)offsetof(struct slap_control_ids, sc_assert), - SLAP_CTRL_DELETE|SLAP_CTRL_MODIFY|SLAP_CTRL_RENAME| - SLAP_CTRL_COMPARE|SLAP_CTRL_SEARCH, + SLAP_CTRL_UPDATE|SLAP_CTRL_COMPARE|SLAP_CTRL_SEARCH, NULL, NULL, parseAssert, LDAP_SLIST_ENTRY_INITIALIZER(next) }, { LDAP_CONTROL_PRE_READ, @@ -217,6 +219,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) } }; @@ -529,6 +539,37 @@ void slap_free_ctrls( op->o_tmpfree( ctrls, op->o_tmpmemctx ); } +int slap_add_ctrls( + Operation *op, + SlapReply *rs, + LDAPControl **ctrls ) +{ + int i = 0, j; + LDAPControl **ctrlsp; + + if ( rs->sr_ctrls ) { + for ( ; rs->sr_ctrls[ i ]; i++ ) ; + } + + for ( j=0; ctrls[j]; j++ ) ; + + ctrlsp = op->o_tmpalloc(( i+j+1 )*sizeof(LDAPControl *), op->o_tmpmemctx ); + i = 0; + if ( rs->sr_ctrls ) { + for ( ; rs->sr_ctrls[i]; i++ ) + ctrlsp[i] = rs->sr_ctrls[i]; + } + for ( j=0; ctrls[j]; j++) + ctrlsp[i++] = ctrls[j]; + ctrlsp[i] = NULL; + + if ( rs->sr_flags & REP_CTRLS_MUSTBEFREED ) + op->o_tmpfree( rs->sr_ctrls, op->o_tmpmemctx ); + rs->sr_ctrls = ctrlsp; + rs->sr_flags |= REP_CTRLS_MUSTBEFREED; + return i; +} + int slap_parse_ctrl( Operation *op, SlapReply *rs, @@ -536,6 +577,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 +633,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 +669,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 +818,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 +836,71 @@ 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 ]; + oids[ 0 ] = failed_oid; + oids[ 1 ] = NULL; + slap_ctrl_whatFailed_add( op, rs, oids ); + } + } +#endif + send_ldap_result( op, rs ); } } @@ -875,12 +992,17 @@ static int parseDontUseCopy ( return LDAP_PROTOCOL_ERROR; } - if ( !ctrl->ldctl_iscritical ) { + if ( ( global_disallows & SLAP_DISALLOW_DONTUSECOPY_N_CRIT ) + && !ctrl->ldctl_iscritical ) + { rs->sr_text = "dontUseCopy criticality of FALSE not allowed"; return LDAP_PROTOCOL_ERROR; } - op->o_dontUseCopy = SLAP_CONTROL_CRITICAL; + op->o_dontUseCopy = ctrl->ldctl_iscritical + ? SLAP_CONTROL_CRITICAL + : SLAP_CONTROL_NONCRITICAL; + return LDAP_SUCCESS; } @@ -946,6 +1068,13 @@ static int parseProxyAuthz ( return LDAP_PROTOCOL_ERROR; } + if ( ( global_disallows & SLAP_DISALLOW_PROXY_AUTHZ_N_CRIT ) + && !ctrl->ldctl_iscritical ) + { + rs->sr_text = "proxied authorization criticality of FALSE not allowed"; + return LDAP_PROTOCOL_ERROR; + } + if ( !( global_allows & SLAP_ALLOW_PROXY_AUTHZ_ANON ) && BER_BVISEMPTY( &op->o_ndn ) ) { @@ -1112,11 +1241,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 +1321,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 +1506,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 +1994,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