mr.c 12.3 KB
Newer Older
1
2
/* mr.c - routines to manage matching rule definitions */
/* $OpenLDAP$ */
Kurt Zeilenga's avatar
Kurt Zeilenga committed
3
4
/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
 *
Kurt Zeilenga's avatar
Kurt Zeilenga committed
5
 * Copyright 1998-2012 The OpenLDAP Foundation.
Kurt Zeilenga's avatar
Kurt Zeilenga committed
6
7
8
9
10
11
12
13
14
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted only as authorized by the OpenLDAP
 * Public License.
 *
 * A copy of this license is available in the file LICENSE in the
 * top-level directory of the distribution or, alternatively, at
 * <http://www.OpenLDAP.org/license.html>.
15
16
17
18
19
20
21
22
23
24
25
26
27
 */

#include "portable.h"

#include <stdio.h>

#include <ac/ctype.h>
#include <ac/string.h>
#include <ac/socket.h>

#include "slap.h"

struct mindexrec {
Howard Chu's avatar
Howard Chu committed
28
	struct berval	mir_name;
29
30
31
32
	MatchingRule	*mir_mr;
};

static Avlnode	*mr_index = NULL;
33
static LDAP_SLIST_HEAD(MRList, MatchingRule) mr_list
34
	= LDAP_SLIST_HEAD_INITIALIZER(&mr_list);
35
static LDAP_SLIST_HEAD(MRUList, MatchingRuleUse) mru_list
36
	= LDAP_SLIST_HEAD_INITIALIZER(&mru_list);
37
38
39

static int
mr_index_cmp(
40
41
    const void	*v_mir1,
    const void	*v_mir2
42
43
)
{
44
45
	const struct mindexrec	*mir1 = v_mir1;
	const struct mindexrec	*mir2 = v_mir2;
Howard Chu's avatar
Howard Chu committed
46
47
	int i = mir1->mir_name.bv_len - mir2->mir_name.bv_len;
	if (i) return i;
48
	return (strcasecmp( mir1->mir_name.bv_val, mir2->mir_name.bv_val ));
49
50
51
52
}

static int
mr_index_name_cmp(
53
54
    const void	*v_name,
    const void	*v_mir
55
56
)
{
57
58
	const struct berval    *name = v_name;
	const struct mindexrec *mir  = v_mir;
Howard Chu's avatar
Howard Chu committed
59
60
	int i = name->bv_len - mir->mir_name.bv_len;
	if (i) return i;
61
	return (strncasecmp( name->bv_val, mir->mir_name.bv_val, name->bv_len ));
62
63
64
65
}

MatchingRule *
mr_find( const char *mrname )
Howard Chu's avatar
Howard Chu committed
66
67
68
{
	struct berval bv;

Howard Chu's avatar
Howard Chu committed
69
	bv.bv_val = (char *)mrname;
Howard Chu's avatar
Howard Chu committed
70
71
72
73
74
75
	bv.bv_len = strlen( mrname );
	return mr_bvfind( &bv );
}

MatchingRule *
mr_bvfind( struct berval *mrname )
76
77
78
{
	struct mindexrec	*mir = NULL;

79
	if ( (mir = avl_find( mr_index, mrname, mr_index_name_cmp )) != NULL ) {
80
81
82
83
84
		return( mir->mir_mr );
	}
	return( NULL );
}

85
86
87
void
mr_destroy( void )
{
88
	MatchingRule *m;
89
90

	avl_free(mr_index, ldap_memfree);
91
92
93
	while( !LDAP_SLIST_EMPTY(&mr_list) ) {
		m = LDAP_SLIST_FIRST(&mr_list);
		LDAP_SLIST_REMOVE_HEAD(&mr_list, smr_next);
94
		ch_free( m->smr_str.bv_val );
95
		ch_free( m->smr_compat_syntaxes );
96
97
98
99
		ldap_matchingrule_free((LDAPMatchingRule *)m);
	}
}

100
101
102
103
104
105
106
107
108
static int
mr_insert(
    MatchingRule	*smr,
    const char		**err
)
{
	struct mindexrec	*mir;
	char			**names;

Kurt Zeilenga's avatar
Kurt Zeilenga committed
109
	LDAP_SLIST_NEXT( smr, smr_next ) = NULL;
110
	LDAP_SLIST_INSERT_HEAD(&mr_list, smr, smr_next);
111
112
113
114

	if ( smr->smr_oid ) {
		mir = (struct mindexrec *)
			ch_calloc( 1, sizeof(struct mindexrec) );
Howard Chu's avatar
Howard Chu committed
115
116
		mir->mir_name.bv_val = smr->smr_oid;
		mir->mir_name.bv_len = strlen( smr->smr_oid );
117
118
		mir->mir_mr = smr;
		if ( avl_insert( &mr_index, (caddr_t) mir,
119
		                 mr_index_cmp, avl_dup_error ) ) {
120
121
			*err = smr->smr_oid;
			ldap_memfree(mir);
122
			return SLAP_SCHERR_MR_DUP;
123
124
		}
		/* FIX: temporal consistency check */
Howard Chu's avatar
Howard Chu committed
125
		mr_bvfind(&mir->mir_name);
126
127
128
129
130
	}
	if ( (names = smr->smr_names) ) {
		while ( *names ) {
			mir = (struct mindexrec *)
				ch_calloc( 1, sizeof(struct mindexrec) );
Howard Chu's avatar
Howard Chu committed
131
132
			mir->mir_name.bv_val = *names;
			mir->mir_name.bv_len = strlen( *names );
133
134
			mir->mir_mr = smr;
			if ( avl_insert( &mr_index, (caddr_t) mir,
135
			                 mr_index_cmp, avl_dup_error ) ) {
136
137
				*err = *names;
				ldap_memfree(mir);
138
				return SLAP_SCHERR_MR_DUP;
139
140
			}
			/* FIX: temporal consistency check */
Howard Chu's avatar
Howard Chu committed
141
			mr_bvfind(&mir->mir_name);
142
143
144
145
146
147
			names++;
		}
	}
	return 0;
}

148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
int
mr_make_syntax_compat_with_mr(
	Syntax		*syn,
	MatchingRule	*mr )
{
	int		n = 0;

	assert( syn != NULL );
	assert( mr != NULL );

	if ( mr->smr_compat_syntaxes ) {
		/* count esisting */
		for ( n = 0;
			mr->smr_compat_syntaxes[ n ];
			n++ )
		{
			if ( mr->smr_compat_syntaxes[ n ] == syn ) {
				/* already compatible; mmmmh... */
				return 1;
			}
		}
	}

	mr->smr_compat_syntaxes = ch_realloc(
		mr->smr_compat_syntaxes,
		sizeof( Syntax * )*(n + 2) );
	mr->smr_compat_syntaxes[ n ] = syn;
	mr->smr_compat_syntaxes[ n + 1 ] = NULL;

	return 0;
}

int
mr_make_syntax_compat_with_mrs(
	const char *syntax,
	char *const *mrs )
{
	int	r, rc = 0;
	Syntax	*syn;

	assert( syntax != NULL );
	assert( mrs != NULL );

	syn = syn_find( syntax );
	if ( syn == NULL ) {
		return -1;
	}

	for ( r = 0; mrs[ r ] != NULL; r++ ) {
		MatchingRule	*mr = mr_find( mrs[ r ] );
		if ( mr == NULL ) {
			/* matchingRule not found -- ignore by now */
			continue;
		}

		rc += mr_make_syntax_compat_with_mr( syn, mr );
	}

	return rc;
}

209
210
int
mr_add(
211
    LDAPMatchingRule		*mr,
212
    slap_mrule_defs_rec	*def,
213
	MatchingRule	*amr,
214
215
216
217
218
    const char		**err
)
{
	MatchingRule	*smr;
	Syntax		*syn;
219
	Syntax		**compat_syn = NULL;
220
221
	int		code;

222
223
224
225
226
227
228
229
230
231
232
	if( def->mrd_compat_syntaxes ) {
		int i;
		for( i=0; def->mrd_compat_syntaxes[i]; i++ ) {
			/* just count em */
		}

		compat_syn = ch_malloc( sizeof(Syntax *) * (i+1) );

		for( i=0; def->mrd_compat_syntaxes[i]; i++ ) {
			compat_syn[i] = syn_find( def->mrd_compat_syntaxes[i] );
			if( compat_syn[i] == NULL ) {
Howard Chu's avatar
Howard Chu committed
233
				ch_free( compat_syn );
234
235
236
237
238
239
240
				return SLAP_SCHERR_SYN_NOT_FOUND;
			}
		}

		compat_syn[i] = NULL;
	}

241
	smr = (MatchingRule *) ch_calloc( 1, sizeof(MatchingRule) );
Kurt Zeilenga's avatar
Kurt Zeilenga committed
242
	AC_MEMCPY( &smr->smr_mrule, mr, sizeof(LDAPMatchingRule));
243

244
245
246
247
248
	/*
	 * note: smr_bvoid uses the same memory of smr_mrule.mr_oid;
	 * smr_oidlen is #defined as smr_bvoid.bv_len
	 */
	smr->smr_bvoid.bv_val = smr->smr_mrule.mr_oid;
249
	smr->smr_oidlen = strlen( mr->mr_oid );
250
	smr->smr_usage = def->mrd_usage;
251
	smr->smr_compat_syntaxes = compat_syn;
252
253
254
255
	smr->smr_normalize = def->mrd_normalize;
	smr->smr_match = def->mrd_match;
	smr->smr_indexer = def->mrd_indexer;
	smr->smr_filter = def->mrd_filter;
256
	smr->smr_associated = amr;
257
258
259
260
261
262

	if ( smr->smr_syntax_oid ) {
		if ( (syn = syn_find(smr->smr_syntax_oid)) ) {
			smr->smr_syntax = syn;
		} else {
			*err = smr->smr_syntax_oid;
Howard Chu's avatar
Howard Chu committed
263
			ch_free( smr );
264
265
266
267
			return SLAP_SCHERR_SYN_NOT_FOUND;
		}
	} else {
		*err = "";
Howard Chu's avatar
Howard Chu committed
268
		ch_free( smr );
269
270
271
272
273
274
275
276
		return SLAP_SCHERR_MR_INCOMPLETE;
	}
	code = mr_insert(smr,err);
	return code;
}

int
register_matching_rule(
277
	slap_mrule_defs_rec *def )
278
{
279
	LDAPMatchingRule *mr;
280
	MatchingRule *amr = NULL;
281
282
283
	int		code;
	const char	*err;

284
	if( def->mrd_usage == SLAP_MR_NONE && def->mrd_compat_syntaxes == NULL ) {
285
		Debug( LDAP_DEBUG_ANY, "register_matching_rule: not usable %s\n",
286
		    def->mrd_desc, 0, 0 );
287

288
289
290
		return -1;
	}

291
292
	if( def->mrd_associated != NULL ) {
		amr = mr_find( def->mrd_associated );
293
		if( amr == NULL ) {
294
295
			Debug( LDAP_DEBUG_ANY, "register_matching_rule: "
				"could not locate associated matching rule %s for %s\n",
296
				def->mrd_associated, def->mrd_desc, 0 );
297

298
299
			return -1;
		}
300
301
302
303
304
305
306

		if (( def->mrd_usage & SLAP_MR_EQUALITY ) &&
			(( def->mrd_usage & SLAP_MR_SUBTYPE_MASK ) == SLAP_MR_NONE ))
		{
			if (( def->mrd_usage & SLAP_MR_EQUALITY ) &&
				(( def->mrd_usage & SLAP_MR_SUBTYPE_MASK ) != SLAP_MR_NONE ))
			{
307
308
				Debug( LDAP_DEBUG_ANY, "register_matching_rule: "
						"inappropriate (approx) association %s for %s\n",
309
310
311
312
313
					def->mrd_associated, def->mrd_desc, 0 );
				return -1;
			}

		} else if (!( amr->smr_usage & SLAP_MR_EQUALITY )) {
314
315
				Debug( LDAP_DEBUG_ANY, "register_matching_rule: "
					"inappropriate (equalilty) association %s for %s\n",
316
317
318
					def->mrd_associated, def->mrd_desc, 0 );
				return -1;
		}
319
320
	}

321
322
	mr = ldap_str2matchingrule( def->mrd_desc, &code, &err,
		LDAP_SCHEMA_ALLOW_ALL );
323
	if ( !mr ) {
324
325
		Debug( LDAP_DEBUG_ANY,
			"Error in register_matching_rule: %s before %s in %s\n",
326
		    ldap_scherr2str(code), err, def->mrd_desc );
327

328
		return -1;
329
330
	}

331

332
	code = mr_add( mr, def, amr, &err );
333

334
335
	ldap_memfree( mr );

336
	if ( code ) {
337
338
		Debug( LDAP_DEBUG_ANY,
			"Error in register_matching_rule: %s for %s in %s\n",
339
		    scherr2str(code), err, def->mrd_desc );
340

341
		return -1;
342
	}
343

344
	return 0;
345
346
}

347
348
349
void
mru_destroy( void )
{
350
351
352
353
354
	MatchingRuleUse *m;

	while( !LDAP_SLIST_EMPTY(&mru_list) ) {
		m = LDAP_SLIST_FIRST(&mru_list);
		LDAP_SLIST_REMOVE_HEAD(&mru_list, smru_next);
355
356
357

		if ( m->smru_str.bv_val ) {
			ch_free( m->smru_str.bv_val );
Kurt Zeilenga's avatar
cleanup    
Kurt Zeilenga committed
358
			m->smru_str.bv_val = NULL;
359
360
361
362
363
364
		}
		/* memory borrowed from m->smru_mr */
		m->smru_oid = NULL;
		m->smru_names = NULL;
		m->smru_desc = NULL;

Kurt Zeilenga's avatar
cleanup    
Kurt Zeilenga committed
365
		/* free what's left (basically smru_mruleuse.mru_applies_oids) */
366
367
368
369
370
371
372
373
		ldap_matchingruleuse_free((LDAPMatchingRuleUse *)m);
	}
}

int
matching_rule_use_init( void )
{
	MatchingRule	*mr;
374
	MatchingRuleUse	**mru_ptr = &LDAP_SLIST_FIRST(&mru_list);
375
376
377

	Debug( LDAP_DEBUG_TRACE, "matching_rule_use_init\n", 0, 0, 0 );

378
	LDAP_SLIST_FOREACH( mr, &mr_list, smr_next ) {
379
		AttributeType	*at;
380
		MatchingRuleUse	mru_storage = {{ 0 }},
381
				*mru = &mru_storage;
382

383
384
		char		**applies_oids = NULL;

385
386
387
388
389
390
391
		mr->smr_mru = NULL;

		/* hide rules marked as HIDE */
		if ( mr->smr_usage & SLAP_MR_HIDE ) {
			continue;
		}

392
393
394
395
396
397
398
399
		/* hide rules not marked as designed for extensibility */
		/* MR_EXT means can be used any attribute type whose
		 * syntax is same as the assertion syntax.
		 * Another mechanism is needed where rule can be used
		 * with attribute of other syntaxes.
		 * Framework doesn't support this (yet).
		 */

400
401
402
		if (!( ( mr->smr_usage & SLAP_MR_EXT )
			|| mr->smr_compat_syntaxes ) )
		{
403
404
405
406
407
408
409
410
411
412
			continue;
		}

		/*
		 * Note: we're using the same values of the corresponding 
		 * MatchingRule structure; maybe we'd copy them ...
		 */
		mru->smru_mr = mr;
		mru->smru_obsolete = mr->smr_obsolete;
		mru->smru_applies_oids = NULL;
413
		LDAP_SLIST_NEXT(mru, smru_next) = NULL;
414
415
416
417
418
419
420
421
		mru->smru_oid = mr->smr_oid;
		mru->smru_names = mr->smr_names;
		mru->smru_desc = mr->smr_desc;

		Debug( LDAP_DEBUG_TRACE, "    %s (%s): ", 
				mru->smru_oid, 
				mru->smru_names ? mru->smru_names[ 0 ] : "", 0 );

422
423
		at = NULL;
		for ( at_start( &at ); at; at_next( &at ) ) {
424
			if( at->sat_flags & SLAP_AT_HIDE ) continue;
425

426
427
			if( mr_usable_with_at( mr, at )) {
				ldap_charray_add( &applies_oids, at->sat_cname.bv_val );
428
429
430
431
432
433
434
435
			}
		}

		/*
		 * Note: the matchingRules that are not used
		 * by any attributeType are not listed as
		 * matchingRuleUse
		 */
436
437
		if ( applies_oids != NULL ) {
			mru->smru_applies_oids = applies_oids;
438
			{
439
				char *str = ldap_matchingruleuse2str( &mru->smru_mruleuse );
440
441
442
443
				Debug( LDAP_DEBUG_TRACE, "matchingRuleUse: %s\n", str, 0, 0 );
				ldap_memfree( str );
			}

444
445
			mru = (MatchingRuleUse *)ber_memalloc( sizeof( MatchingRuleUse ) );
			/* call-forward from MatchingRule to MatchingRuleUse */
446
			mr->smr_mru = mru;
447
			/* copy static data to newly allocated struct */
448
			*mru = mru_storage;
449
			/* append the struct pointer to the end of the list */
450
			*mru_ptr = mru;
451
			/* update the list head pointer */
452
			mru_ptr = &LDAP_SLIST_NEXT(mru,smru_next);
453
454
455
456
457
458
		}
	}

	return( 0 );
}

Pierangelo Masarati's avatar
...    
Pierangelo Masarati committed
459
460
461
462
int
mr_usable_with_at(
	MatchingRule	*mr,
	AttributeType	*at )
463
{
Pierangelo Masarati's avatar
...    
Pierangelo Masarati committed
464
	if ( ( mr->smr_usage & SLAP_MR_EXT ) && (
465
		mr->smr_syntax == at->sat_syntax ||
Pierangelo Masarati's avatar
...    
Pierangelo Masarati committed
466
467
468
		mr == at->sat_equality ||
		mr == at->sat_approx ||
		syn_is_sup( at->sat_syntax, mr->smr_syntax ) ) )
469
470
471
472
473
474
475
476
477
478
479
480
481
482
	{
		return 1;
	}

	if ( mr->smr_compat_syntaxes ) {
		int i;
		for( i=0; mr->smr_compat_syntaxes[i]; i++ ) {
			if( at->sat_syntax == mr->smr_compat_syntaxes[i] ) {
				return 1;
			}
		}
	}
	return 0;
}
483
484
485

int mr_schema_info( Entry *e )
{
486
	AttributeDescription *ad_matchingRules = slap_schema.si_ad_matchingRules;
487
488
	MatchingRule *mr;
	struct berval nval;
489

490
	LDAP_SLIST_FOREACH(mr, &mr_list, smr_next ) {
491
492
493
494
495
		if ( mr->smr_usage & SLAP_MR_HIDE ) {
			/* skip hidden rules */
			continue;
		}

496
497
498
499
500
		if ( ! mr->smr_match ) {
			/* skip rules without matching functions */
			continue;
		}

501
502
503
504
		if ( mr->smr_str.bv_val == NULL ) {
			if ( ldap_matchingrule2bv( &mr->smr_mrule, &mr->smr_str ) == NULL ) {
				return -1;
			}
505
		}
506
#if 0
507
508
		Debug( LDAP_DEBUG_TRACE, "Merging mr [%lu] %s\n",
			mr->smr_str.bv_len, mr->smr_str.bv_val, 0 );
509
#endif
Kurt Zeilenga's avatar
cleanup    
Kurt Zeilenga committed
510

511
512
		nval.bv_val = mr->smr_oid;
		nval.bv_len = strlen(mr->smr_oid);
Kurt Zeilenga's avatar
cleanup    
Kurt Zeilenga committed
513
		if( attr_merge_one( e, ad_matchingRules, &mr->smr_str, &nval ) ) {
Julius Enarusai's avatar
   
Julius Enarusai committed
514
			return -1;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
515
		}
516
517
518
519
	}
	return 0;
}

Kurt Zeilenga's avatar
Kurt Zeilenga committed
520
521
int mru_schema_info( Entry *e )
{
522
523
	AttributeDescription *ad_matchingRuleUse 
		= slap_schema.si_ad_matchingRuleUse;
524
525
	MatchingRuleUse	*mru;
	struct berval nval;
526

527
	LDAP_SLIST_FOREACH( mru, &mru_list, smru_next ) {
528
529
530
531
532
533
534
535
536
537
538
539
540
		assert( !( mru->smru_usage & SLAP_MR_HIDE ) );

		if ( mru->smru_str.bv_val == NULL ) {
			if ( ldap_matchingruleuse2bv( &mru->smru_mruleuse, &mru->smru_str )
					== NULL ) {
				return -1;
			}
		}

#if 0
		Debug( LDAP_DEBUG_TRACE, "Merging mru [%lu] %s\n",
			mru->smru_str.bv_len, mru->smru_str.bv_val, 0 );
#endif
Kurt Zeilenga's avatar
cleanup    
Kurt Zeilenga committed
541

542
543
		nval.bv_val = mru->smru_oid;
		nval.bv_len = strlen(mru->smru_oid);
Kurt Zeilenga's avatar
cleanup    
Kurt Zeilenga committed
544
		if( attr_merge_one( e, ad_matchingRuleUse, &mru->smru_str, &nval ) ) {
Julius Enarusai's avatar
   
Julius Enarusai committed
545
			return -1;
Kurt Zeilenga's avatar
Kurt Zeilenga committed
546
		}
547
	}
Kurt Zeilenga's avatar
Kurt Zeilenga committed
548
549
	return 0;
}