+ SlapReply *rs,
+ LDAPControl *ctrl )
+{
+ if ( op->o_relax != SLAP_CONTROL_NONE ) {
+ rs->sr_text = "relax control specified multiple times";
+ return LDAP_PROTOCOL_ERROR;
+ }
+
+ if ( !BER_BVISNULL( &ctrl->ldctl_value )) {
+ rs->sr_text = "relax control value not absent";
+ return LDAP_PROTOCOL_ERROR;
+ }
+
+ op->o_relax = ctrl->ldctl_iscritical
+ ? SLAP_CONTROL_CRITICAL
+ : SLAP_CONTROL_NONCRITICAL;
+
+ return LDAP_SUCCESS;
+}
+
+static int parseManageDSAit (
+ Operation *op,
+ SlapReply *rs,
+ LDAPControl *ctrl )
+{
+ if ( op->o_managedsait != SLAP_CONTROL_NONE ) {
+ rs->sr_text = "manageDSAit control specified multiple times";
+ return LDAP_PROTOCOL_ERROR;
+ }
+
+ if ( !BER_BVISNULL( &ctrl->ldctl_value )) {
+ rs->sr_text = "manageDSAit control value not absent";
+ return LDAP_PROTOCOL_ERROR;
+ }
+
+ op->o_managedsait = ctrl->ldctl_iscritical
+ ? SLAP_CONTROL_CRITICAL
+ : SLAP_CONTROL_NONCRITICAL;
+
+ return LDAP_SUCCESS;
+}
+
+static int parseProxyAuthz (
+ Operation *op,
+ SlapReply *rs,
+ LDAPControl *ctrl )
+{
+ int rc;
+ struct berval dn = BER_BVNULL;
+
+ if ( op->o_proxy_authz != SLAP_CONTROL_NONE ) {
+ rs->sr_text = "proxy authorization control specified multiple times";
+ return LDAP_PROTOCOL_ERROR;
+ }
+
+ if ( BER_BVISNULL( &ctrl->ldctl_value )) {
+ rs->sr_text = "proxy authorization control value absent";
+ 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 ) )
+ {
+ rs->sr_text = "anonymous proxied authorization not allowed";
+ return LDAP_PROXIED_AUTHORIZATION_DENIED;
+ }
+
+ op->o_proxy_authz = ctrl->ldctl_iscritical
+ ? SLAP_CONTROL_CRITICAL
+ : SLAP_CONTROL_NONCRITICAL;
+
+ Debug( LDAP_DEBUG_ARGS,
+ "parseProxyAuthz: conn %lu authzid=\"%s\"\n",
+ op->o_connid,
+ ctrl->ldctl_value.bv_len ? ctrl->ldctl_value.bv_val : "anonymous",
+ 0 );
+
+ if ( BER_BVISEMPTY( &ctrl->ldctl_value )) {
+ Debug( LDAP_DEBUG_TRACE,
+ "parseProxyAuthz: conn=%lu anonymous\n",
+ op->o_connid, 0, 0 );
+
+ /* anonymous */
+ if ( !BER_BVISNULL( &op->o_ndn ) ) {
+ op->o_ndn.bv_val[ 0 ] = '\0';
+ }
+ op->o_ndn.bv_len = 0;
+
+ if ( !BER_BVISNULL( &op->o_dn ) ) {
+ op->o_dn.bv_val[ 0 ] = '\0';
+ }
+ op->o_dn.bv_len = 0;
+
+ return LDAP_SUCCESS;
+ }
+
+ rc = slap_sasl_getdn( op->o_conn, op, &ctrl->ldctl_value,
+ NULL, &dn, SLAP_GETDN_AUTHZID );
+
+ /* FIXME: empty DN in proxyAuthz control should be legal... */
+ if( rc != LDAP_SUCCESS /* || !dn.bv_len */ ) {
+ if ( dn.bv_val ) {
+ ch_free( dn.bv_val );
+ }
+ rs->sr_text = "authzId mapping failed";
+ return LDAP_PROXIED_AUTHORIZATION_DENIED;
+ }
+
+ Debug( LDAP_DEBUG_TRACE,
+ "parseProxyAuthz: conn=%lu \"%s\"\n",
+ op->o_connid,
+ dn.bv_len ? dn.bv_val : "(NULL)", 0 );
+
+ rc = slap_sasl_authorized( op, &op->o_ndn, &dn );
+
+ if ( rc ) {
+ ch_free( dn.bv_val );
+ rs->sr_text = "not authorized to assume identity";
+ return LDAP_PROXIED_AUTHORIZATION_DENIED;
+ }
+
+ ch_free( op->o_ndn.bv_val );
+ ch_free( op->o_dn.bv_val );
+
+ /*
+ * NOTE: since slap_sasl_getdn() returns a normalized dn,
+ * from now on op->o_dn is normalized
+ */
+ op->o_ndn = dn;
+ ber_dupbv( &op->o_dn, &dn );
+
+ Statslog( LDAP_DEBUG_STATS, "%s PROXYAUTHZ dn=\"%s\"\n",
+ op->o_log_prefix, dn.bv_val, 0, 0, 0 );
+
+ return LDAP_SUCCESS;
+}
+
+static int parseNoOp (
+ Operation *op,
+ SlapReply *rs,
+ LDAPControl *ctrl )
+{
+ if ( op->o_noop != SLAP_CONTROL_NONE ) {
+ rs->sr_text = "noop control specified multiple times";
+ return LDAP_PROTOCOL_ERROR;
+ }
+
+ if ( !BER_BVISNULL( &ctrl->ldctl_value ) ) {
+ rs->sr_text = "noop control value not empty";
+ return LDAP_PROTOCOL_ERROR;
+ }
+
+ op->o_noop = ctrl->ldctl_iscritical
+ ? SLAP_CONTROL_CRITICAL
+ : SLAP_CONTROL_NONCRITICAL;
+
+ return LDAP_SUCCESS;
+}
+
+static int parsePagedResults (
+ Operation *op,
+ SlapReply *rs,
+ LDAPControl *ctrl )
+{
+ BerElementBuffer berbuf;
+ BerElement *ber = (BerElement *)&berbuf;
+ struct berval cookie;
+ PagedResultsState *ps;
+ int rc = LDAP_SUCCESS;
+ ber_tag_t tag;
+ ber_int_t size;
+
+ if ( op->o_pagedresults != SLAP_CONTROL_NONE ) {
+ rs->sr_text = "paged results control specified multiple times";
+ return LDAP_PROTOCOL_ERROR;
+ }
+
+ if ( BER_BVISNULL( &ctrl->ldctl_value ) ) {
+ rs->sr_text = "paged results control value is absent";
+ return LDAP_PROTOCOL_ERROR;
+ }
+
+ if ( BER_BVISEMPTY( &ctrl->ldctl_value ) ) {
+ rs->sr_text = "paged results control value is empty";
+ return LDAP_PROTOCOL_ERROR;
+ }
+
+ /* Parse the control value
+ * realSearchControlValue ::= SEQUENCE {
+ * size INTEGER (0..maxInt),
+ * -- requested page size from client
+ * -- result set size estimate from server
+ * cookie OCTET STRING
+ * }
+ */
+ ber_init2( ber, &ctrl->ldctl_value, LBER_USE_DER );
+
+ tag = ber_scanf( ber, "{im}", &size, &cookie );
+
+ if ( tag == LBER_ERROR ) {
+ rs->sr_text = "paged results control could not be decoded";
+ rc = LDAP_PROTOCOL_ERROR;
+ goto done;
+ }
+
+ if ( size < 0 ) {
+ rs->sr_text = "paged results control size invalid";
+ rc = LDAP_PROTOCOL_ERROR;
+ goto done;
+ }
+
+ ps = op->o_tmpalloc( sizeof(PagedResultsState), op->o_tmpmemctx );
+ *ps = op->o_conn->c_pagedresults_state;
+ ps->ps_size = size;
+ ps->ps_cookieval = cookie;
+ op->o_pagedresults_state = ps;
+ if ( !cookie.bv_len ) {
+ ps->ps_count = 0;
+ ps->ps_cookie = 0;
+ /* taint ps_cookie, to detect whether it's set */
+ op->o_conn->c_pagedresults_state.ps_cookie = NOID;
+ }
+
+ /* NOTE: according to RFC 2696 3.:
+
+ 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;
+
+ } else if ( ctrl->ldctl_iscritical ) {
+ op->o_pagedresults = SLAP_CONTROL_CRITICAL;
+
+ } else {
+ op->o_pagedresults = SLAP_CONTROL_NONCRITICAL;
+ }
+
+done:;
+ return rc;
+}
+
+#ifdef SLAP_CONTROL_X_SORTEDRESULTS
+static int parseSortedResults (
+ Operation *op,
+ SlapReply *rs,
+ LDAPControl *ctrl )
+{
+ int rc = LDAP_SUCCESS;
+
+ if ( op->o_sortedresults != SLAP_CONTROL_NONE ) {
+ rs->sr_text = "sorted results control specified multiple times";
+ return LDAP_PROTOCOL_ERROR;
+ }
+
+ if ( BER_BVISNULL( &ctrl->ldctl_value ) ) {
+ rs->sr_text = "sorted results control value is absent";
+ return LDAP_PROTOCOL_ERROR;
+ }
+
+ if ( BER_BVISEMPTY( &ctrl->ldctl_value ) ) {
+ rs->sr_text = "sorted results control value is empty";
+ return LDAP_PROTOCOL_ERROR;
+ }
+
+ /* blow off parsing the value */
+
+ op->o_sortedresults = ctrl->ldctl_iscritical
+ ? SLAP_CONTROL_CRITICAL
+ : SLAP_CONTROL_NONCRITICAL;
+
+ return rc;
+}
+#endif
+
+static int parseAssert (
+ Operation *op,
+ SlapReply *rs,
+ LDAPControl *ctrl )
+{
+ BerElement *ber;
+ struct berval fstr = BER_BVNULL;
+
+ if ( op->o_assert != SLAP_CONTROL_NONE ) {
+ rs->sr_text = "assert control specified multiple times";
+ return LDAP_PROTOCOL_ERROR;
+ }
+
+ if ( BER_BVISNULL( &ctrl->ldctl_value )) {
+ rs->sr_text = "assert control value is absent";
+ return LDAP_PROTOCOL_ERROR;
+ }
+
+ if ( BER_BVISEMPTY( &ctrl->ldctl_value )) {
+ rs->sr_text = "assert control value is empty";
+ return LDAP_PROTOCOL_ERROR;
+ }
+
+ ber = ber_init( &(ctrl->ldctl_value) );
+ if (ber == NULL) {
+ 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 );
+ if( rs->sr_err != LDAP_SUCCESS ) {
+ if( rs->sr_err == SLAPD_DISCONNECT ) {
+ rs->sr_err = LDAP_PROTOCOL_ERROR;
+ send_ldap_disconnect( op, rs );
+ rs->sr_err = SLAPD_DISCONNECT;
+ } else {
+ send_ldap_result( op, rs );
+ }
+ if( op->o_assertion != NULL ) {
+ filter_free_x( op, op->o_assertion, 1 );
+ }
+ return rs->sr_err;
+ }
+
+#ifdef LDAP_DEBUG
+ filter2bv_x( op, op->o_assertion, &fstr );
+
+ Debug( LDAP_DEBUG_ARGS, "parseAssert: conn %ld assert: %s\n",
+ op->o_connid, fstr.bv_len ? fstr.bv_val : "empty" , 0 );
+ op->o_tmpfree( fstr.bv_val, op->o_tmpmemctx );
+#endif
+
+ op->o_assert = ctrl->ldctl_iscritical
+ ? SLAP_CONTROL_CRITICAL
+ : SLAP_CONTROL_NONCRITICAL;
+
+ rs->sr_err = LDAP_SUCCESS;
+ return LDAP_SUCCESS;
+}
+
+#define READMSG(post, msg) \
+ ( post ? "postread control: " msg : "preread control: " msg )
+
+static int
+parseReadAttrs(
+ Operation *op,
+ SlapReply *rs,
+ LDAPControl *ctrl,
+ int post )
+{
+ ber_len_t siz, off, i;
+ BerElement *ber;
+ AttributeName *an = NULL;
+
+ if ( ( post && op->o_postread != SLAP_CONTROL_NONE ) ||
+ ( !post && op->o_preread != SLAP_CONTROL_NONE ) )
+ {
+ rs->sr_text = READMSG( post, "specified multiple times" );
+ return LDAP_PROTOCOL_ERROR;
+ }
+
+ if ( BER_BVISNULL( &ctrl->ldctl_value ) ) {
+ rs->sr_text = READMSG( post, "value is absent" );
+ return LDAP_PROTOCOL_ERROR;
+ }
+
+ if ( BER_BVISEMPTY( &ctrl->ldctl_value ) ) {
+ rs->sr_text = READMSG( post, "value is empty" );
+ return LDAP_PROTOCOL_ERROR;
+ }
+
+#ifdef LDAP_X_TXN
+ if ( op->o_txnSpec ) { /* temporary limitation */
+ rs->sr_text = READMSG( post, "cannot perform in transaction" );
+ return LDAP_UNWILLING_TO_PERFORM;
+ }
+#endif
+
+ ber = ber_init( &ctrl->ldctl_value );
+ if ( ber == NULL ) {
+ rs->sr_text = READMSG( post, "internal error" );
+ return LDAP_OTHER;
+ }
+
+ rs->sr_err = LDAP_SUCCESS;
+ siz = sizeof( AttributeName );
+ off = offsetof( AttributeName, an_name );
+ if ( ber_scanf( ber, "{M}", &an, &siz, off ) == LBER_ERROR ) {
+ rs->sr_text = READMSG( post, "decoding error" );
+ rs->sr_err = LDAP_PROTOCOL_ERROR;
+ goto done;
+ }
+
+ for ( i = 0; i < siz; i++ ) {
+ const char *dummy = NULL;
+ int rc;
+
+ an[i].an_desc = NULL;
+ an[i].an_oc = NULL;
+ an[i].an_flags = 0;
+ rc = slap_bv2ad( &an[i].an_name, &an[i].an_desc, &dummy );
+ if ( rc == LDAP_SUCCESS ) {
+ an[i].an_name = an[i].an_desc->ad_cname;
+
+ } else {
+ int j;
+ static struct berval special_attrs[] = {
+ BER_BVC( LDAP_NO_ATTRS ),
+ BER_BVC( LDAP_ALL_USER_ATTRIBUTES ),
+ BER_BVC( LDAP_ALL_OPERATIONAL_ATTRIBUTES ),
+ BER_BVNULL
+ };
+
+ /* deal with special attribute types */
+ for ( j = 0; !BER_BVISNULL( &special_attrs[ j ] ); j++ ) {
+ if ( bvmatch( &an[i].an_name, &special_attrs[ j ] ) ) {
+ an[i].an_name = special_attrs[ j ];
+ break;
+ }
+ }
+
+ if ( BER_BVISNULL( &special_attrs[ j ] ) && ctrl->ldctl_iscritical ) {
+ rs->sr_err = rc;
+ rs->sr_text = dummy ? dummy
+ : READMSG( post, "unknown attributeType" );
+ goto done;
+ }
+ }
+ }
+
+ if ( post ) {
+ op->o_postread_attrs = an;
+ op->o_postread = ctrl->ldctl_iscritical
+ ? SLAP_CONTROL_CRITICAL
+ : SLAP_CONTROL_NONCRITICAL;
+ } else {
+ op->o_preread_attrs = an;
+ op->o_preread = ctrl->ldctl_iscritical
+ ? SLAP_CONTROL_CRITICAL
+ : SLAP_CONTROL_NONCRITICAL;
+ }
+
+done:
+ (void) ber_free( ber, 1 );
+ return rs->sr_err;
+}
+
+static int parsePreRead (
+ Operation *op,
+ SlapReply *rs,
+ LDAPControl *ctrl )
+{
+ return parseReadAttrs( op, rs, ctrl, 0 );
+}
+
+static int parsePostRead (
+ Operation *op,
+ SlapReply *rs,
+ LDAPControl *ctrl )
+{
+ return parseReadAttrs( op, rs, ctrl, 1 );
+}
+
+static int parseValuesReturnFilter (
+ Operation *op,
+ SlapReply *rs,
+ LDAPControl *ctrl )
+{
+ BerElement *ber;
+ struct berval fstr = BER_BVNULL;
+
+ if ( op->o_valuesreturnfilter != SLAP_CONTROL_NONE ) {
+ rs->sr_text = "valuesReturnFilter control specified multiple times";
+ return LDAP_PROTOCOL_ERROR;
+ }
+
+ if ( BER_BVISNULL( &ctrl->ldctl_value )) {
+ rs->sr_text = "valuesReturnFilter control value is absent";
+ return LDAP_PROTOCOL_ERROR;
+ }
+
+ if ( BER_BVISEMPTY( &ctrl->ldctl_value )) {
+ rs->sr_text = "valuesReturnFilter control value is empty";
+ return LDAP_PROTOCOL_ERROR;
+ }
+
+ ber = ber_init( &(ctrl->ldctl_value) );
+ if (ber == NULL) {
+ rs->sr_text = "internal error";
+ return LDAP_OTHER;
+ }
+
+ rs->sr_err = get_vrFilter( op, ber,
+ (ValuesReturnFilter **)&(op->o_vrFilter), &rs->sr_text);
+
+ (void) ber_free( ber, 1 );
+
+ if( rs->sr_err != LDAP_SUCCESS ) {
+ if( rs->sr_err == SLAPD_DISCONNECT ) {
+ rs->sr_err = LDAP_PROTOCOL_ERROR;
+ send_ldap_disconnect( op, rs );
+ rs->sr_err = SLAPD_DISCONNECT;
+ } else {
+ send_ldap_result( op, rs );
+ }
+ if( op->o_vrFilter != NULL) vrFilter_free( op, op->o_vrFilter );
+ }
+#ifdef LDAP_DEBUG
+ else {
+ vrFilter2bv( op, op->o_vrFilter, &fstr );
+ }
+
+ Debug( LDAP_DEBUG_ARGS, " vrFilter: %s\n",
+ fstr.bv_len ? fstr.bv_val : "empty", 0, 0 );
+ op->o_tmpfree( fstr.bv_val, op->o_tmpmemctx );
+#endif
+
+ op->o_valuesreturnfilter = ctrl->ldctl_iscritical
+ ? SLAP_CONTROL_CRITICAL
+ : SLAP_CONTROL_NONCRITICAL;
+
+ rs->sr_err = LDAP_SUCCESS;
+ return LDAP_SUCCESS;
+}
+
+static int parseSubentries (
+ Operation *op,
+ SlapReply *rs,
+ LDAPControl *ctrl )