Home | History | Annotate | Line # | Download | only in slapd
      1 /*	$NetBSD: mra.c,v 1.4 2025/09/05 21:16:25 christos Exp $	*/
      2 
      3 /* mra.c - routines for dealing with extensible matching rule assertions */
      4 /* $OpenLDAP$ */
      5 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
      6  *
      7  * Copyright 1998-2024 The OpenLDAP Foundation.
      8  * All rights reserved.
      9  *
     10  * Redistribution and use in source and binary forms, with or without
     11  * modification, are permitted only as authorized by the OpenLDAP
     12  * Public License.
     13  *
     14  * A copy of this license is available in the file LICENSE in the
     15  * top-level directory of the distribution or, alternatively, at
     16  * <http://www.OpenLDAP.org/license.html>.
     17  */
     18 
     19 #include <sys/cdefs.h>
     20 __RCSID("$NetBSD: mra.c,v 1.4 2025/09/05 21:16:25 christos Exp $");
     21 
     22 #include "portable.h"
     23 
     24 #include <stdio.h>
     25 
     26 #include <ac/string.h>
     27 #include <ac/socket.h>
     28 
     29 #include "slap.h"
     30 
     31 #ifdef LDAP_COMP_MATCH
     32 #include "component.h"
     33 #endif
     34 
     35 void
     36 mra_free(
     37 	Operation *op,
     38 	MatchingRuleAssertion *mra,
     39 	int	freeit )
     40 {
     41 #ifdef LDAP_COMP_MATCH
     42 	/* free component assertion */
     43 	if ( mra->ma_rule->smr_usage & SLAP_MR_COMPONENT && mra->ma_cf ) {
     44 		component_free( mra->ma_cf );
     45 	}
     46 #endif
     47 	/* op->o_tmpfree( mra->ma_value.bv_val, op->o_tmpmemctx ); */
     48 	ch_free( mra->ma_value.bv_val );
     49 	if ( mra->ma_desc && mra->ma_desc->ad_flags & SLAP_DESC_TEMPORARY )
     50 		op->o_tmpfree( mra->ma_desc, op->o_tmpmemctx );
     51 	if ( freeit ) op->o_tmpfree( (char *) mra, op->o_tmpmemctx );
     52 }
     53 
     54 int
     55 get_mra(
     56 	Operation *op,
     57 	BerElement	*ber,
     58 	Filter *f,
     59 	const char **text )
     60 {
     61 	int rc;
     62 	ber_tag_t tag, rtag;
     63 	ber_len_t length;
     64 	struct berval type = BER_BVNULL;
     65 	struct berval value = BER_BVNULL;
     66 	struct berval rule_text = BER_BVNULL;
     67 	MatchingRuleAssertion ma = { 0 };
     68 #ifdef LDAP_COMP_MATCH
     69 	AttributeAliasing* aa = NULL;
     70 #endif
     71 
     72 	rtag = ber_scanf( ber, "{t" /*"}"*/, &tag );
     73 
     74 	if( rtag == LBER_ERROR ) {
     75 		Debug( LDAP_DEBUG_ANY, "  get_mra ber_scanf\n" );
     76 
     77 		*text = "Error parsing matching rule assertion";
     78 		return SLAPD_DISCONNECT;
     79 	}
     80 
     81 	if ( tag == LDAP_FILTER_EXT_OID ) {
     82 		rtag = ber_scanf( ber, "m", &rule_text );
     83 		if ( rtag == LBER_ERROR ) {
     84 			Debug( LDAP_DEBUG_ANY, "  get_mra ber_scanf for mr\n" );
     85 
     86 			*text = "Error parsing matching rule in matching rule assertion";
     87 			return SLAPD_DISCONNECT;
     88 		}
     89 
     90 		rtag = ber_scanf( ber, "t", &tag );
     91 		if( rtag == LBER_ERROR ) {
     92 			Debug( LDAP_DEBUG_ANY, "  get_mra ber_scanf\n" );
     93 
     94 			*text = "Error parsing matching rule assertion";
     95 			return SLAPD_DISCONNECT;
     96 		}
     97 	}
     98 
     99 	if ( tag == LDAP_FILTER_EXT_TYPE ) {
    100 		rtag = ber_scanf( ber, "m", &type );
    101 		if ( rtag == LBER_ERROR ) {
    102 			Debug( LDAP_DEBUG_ANY, "  get_mra ber_scanf for ad\n" );
    103 
    104 			*text = "Error parsing attribute description in matching rule assertion";
    105 			return SLAPD_DISCONNECT;
    106 		}
    107 
    108 		rtag = ber_scanf( ber, "t", &tag );
    109 		if( rtag == LBER_ERROR ) {
    110 			Debug( LDAP_DEBUG_ANY, "  get_mra ber_scanf\n" );
    111 
    112 			*text = "Error parsing matching rule assertion";
    113 			return SLAPD_DISCONNECT;
    114 		}
    115 	}
    116 
    117 	if ( tag != LDAP_FILTER_EXT_VALUE ) {
    118 		Debug( LDAP_DEBUG_ANY, "  get_mra ber_scanf missing value\n" );
    119 
    120 		*text = "Missing value in matching rule assertion";
    121 		return SLAPD_DISCONNECT;
    122 	}
    123 
    124 	rtag = ber_scanf( ber, "m", &value );
    125 
    126 	if( rtag == LBER_ERROR ) {
    127 		Debug( LDAP_DEBUG_ANY, "  get_mra ber_scanf\n" );
    128 
    129 		*text = "Error decoding value in matching rule assertion";
    130 		return SLAPD_DISCONNECT;
    131 	}
    132 
    133 	tag = ber_peek_tag( ber, &length );
    134 
    135 	if ( tag == LDAP_FILTER_EXT_DNATTRS ) {
    136 		rtag = ber_scanf( ber, /*"{"*/ "b}", &ma.ma_dnattrs );
    137 	} else {
    138 		rtag = ber_scanf( ber, /*"{"*/ "}" );
    139 	}
    140 
    141 	if( rtag == LBER_ERROR ) {
    142 		Debug( LDAP_DEBUG_ANY, "  get_mra ber_scanf\n" );
    143 
    144 		*text = "Error decoding dnattrs matching rule assertion";
    145 		return SLAPD_DISCONNECT;
    146 	}
    147 
    148 	if( type.bv_val != NULL ) {
    149 		rc = slap_bv2ad( &type, &ma.ma_desc, text );
    150 		if( rc != LDAP_SUCCESS ) {
    151 			f->f_choice |= SLAPD_FILTER_UNDEFINED;
    152 			rc = slap_bv2undef_ad( &type, &ma.ma_desc, text,
    153 				SLAP_AD_PROXIED|SLAP_AD_NOINSERT );
    154 
    155 			if( rc != LDAP_SUCCESS ) {
    156 				ma.ma_desc = slap_bv2tmp_ad( &type, op->o_tmpmemctx );
    157 				rc = LDAP_SUCCESS;
    158 			}
    159 		}
    160 	}
    161 
    162 	if( rule_text.bv_val != NULL ) {
    163 		ma.ma_rule = mr_bvfind( &rule_text );
    164 		if( ma.ma_rule == NULL ) {
    165 			*text = "matching rule not recognized";
    166 			return LDAP_INAPPROPRIATE_MATCHING;
    167 		}
    168 	}
    169 
    170 	if ( ma.ma_rule == NULL ) {
    171 		/*
    172 		 * Need either type or rule ...
    173 		 */
    174 		if ( ma.ma_desc == NULL ) {
    175 			*text = "no matching rule or type";
    176 			return LDAP_INAPPROPRIATE_MATCHING;
    177 		}
    178 
    179 		if ( ma.ma_desc->ad_type->sat_equality != NULL &&
    180 			ma.ma_desc->ad_type->sat_equality->smr_usage & SLAP_MR_EXT )
    181 		{
    182 			/* no matching rule was provided, use the attribute's
    183 			   equality rule if it supports extensible matching. */
    184 			ma.ma_rule = ma.ma_desc->ad_type->sat_equality;
    185 
    186 		} else {
    187 			*text = "no appropriate rule to use for type";
    188 			return LDAP_INAPPROPRIATE_MATCHING;
    189 		}
    190 	}
    191 
    192 	if ( ma.ma_desc != NULL ) {
    193 		if( !mr_usable_with_at( ma.ma_rule, ma.ma_desc->ad_type ) ) {
    194 			*text = "matching rule use with this attribute not appropriate";
    195 			return LDAP_INAPPROPRIATE_MATCHING;
    196 		}
    197 
    198 	}
    199 
    200 	/*
    201 	 * Normalize per matching rule
    202 	 */
    203 	rc = asserted_value_validate_normalize( ma.ma_desc,
    204 		ma.ma_rule,
    205 		SLAP_MR_EXT|SLAP_MR_VALUE_OF_ASSERTION_SYNTAX,
    206 		&value, &ma.ma_value, text, op->o_tmpmemctx );
    207 
    208 	if( rc != LDAP_SUCCESS ) return rc;
    209 
    210 #ifdef LDAP_COMP_MATCH
    211 	/* Check If this attribute is aliased */
    212 	if ( is_aliased_attribute && ma.ma_desc && ( aa = is_aliased_attribute ( ma.ma_desc ) ) ) {
    213 		rc = get_aliased_filter ( op, &ma, aa, text );
    214 		if ( rc != LDAP_SUCCESS ) return rc;
    215 	}
    216 	else if ( ma.ma_rule && ma.ma_rule->smr_usage & SLAP_MR_COMPONENT ) {
    217 		/* Matching Rule for Component Matching */
    218 		rc = get_comp_filter( op, &ma.ma_value, &ma.ma_cf, text );
    219 		if ( rc != LDAP_SUCCESS ) return rc;
    220 	}
    221 #endif
    222 
    223 	length = sizeof(ma);
    224 	/* Append rule_text to end of struct */
    225 	if (rule_text.bv_val) length += rule_text.bv_len + 1;
    226 	f->f_mra = op->o_tmpalloc( length, op->o_tmpmemctx );
    227 	*f->f_mra = ma;
    228 	if (rule_text.bv_val) {
    229 		f->f_mra->ma_rule_text.bv_len = rule_text.bv_len;
    230 		f->f_mra->ma_rule_text.bv_val = (char *)(f->f_mra+1);
    231 		AC_MEMCPY(f->f_mra->ma_rule_text.bv_val, rule_text.bv_val,
    232 			rule_text.bv_len+1);
    233 	}
    234 
    235 	return LDAP_SUCCESS;
    236 }
    237