1 /*        $NetBSD: mra.c,v 1.3 2021/08/14 16:14:58 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-2021 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.3 2021/08/14 16:14:58 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
mra_free(Operation * op,MatchingRuleAssertion * mra,int freeit)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
get_mra(Operation * op,BerElement * ber,Filter * f,const char ** text)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