xref: /netbsd-src/external/bsd/openldap/dist/servers/slapd/cr.c (revision 274254cdae52594c1aa480a736aef78313d15c9c)
1 /* cr.c - content rule routines */
2 /* $OpenLDAP: pkg/ldap/servers/slapd/cr.c,v 1.22.2.3 2008/02/11 23:26:44 kurt Exp $ */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
4  *
5  * Copyright 1998-2008 The OpenLDAP Foundation.
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted only as authorized by the OpenLDAP
10  * Public License.
11  *
12  * A copy of this license is available in the file LICENSE in the
13  * top-level directory of the distribution or, alternatively, at
14  * <http://www.OpenLDAP.org/license.html>.
15  */
16 
17 #include "portable.h"
18 
19 #include <stdio.h>
20 
21 #include <ac/ctype.h>
22 #include <ac/string.h>
23 #include <ac/socket.h>
24 
25 #include "slap.h"
26 
27 struct cindexrec {
28 	struct berval	cir_name;
29 	ContentRule	*cir_cr;
30 };
31 
32 static Avlnode	*cr_index = NULL;
33 static LDAP_STAILQ_HEAD(CRList, ContentRule) cr_list
34 	= LDAP_STAILQ_HEAD_INITIALIZER(cr_list);
35 
36 static int
37 cr_index_cmp(
38     const void	*v_cir1,
39     const void	*v_cir2 )
40 {
41 	const struct cindexrec	*cir1 = v_cir1;
42 	const struct cindexrec	*cir2 = v_cir2;
43 	int i = cir1->cir_name.bv_len - cir2->cir_name.bv_len;
44 	if (i) return i;
45 	return strcasecmp( cir1->cir_name.bv_val, cir2->cir_name.bv_val );
46 }
47 
48 static int
49 cr_index_name_cmp(
50     const void	*v_name,
51     const void	*v_cir )
52 {
53 	const struct berval    *name = v_name;
54 	const struct cindexrec *cir  = v_cir;
55 	int i = name->bv_len - cir->cir_name.bv_len;
56 	if (i) return i;
57 	return strncasecmp( name->bv_val, cir->cir_name.bv_val, name->bv_len );
58 }
59 
60 ContentRule *
61 cr_find( const char *crname )
62 {
63 	struct berval bv;
64 
65 	bv.bv_val = (char *)crname;
66 	bv.bv_len = strlen( crname );
67 
68 	return( cr_bvfind( &bv ) );
69 }
70 
71 ContentRule *
72 cr_bvfind( struct berval *crname )
73 {
74 	struct cindexrec	*cir;
75 
76 	cir = avl_find( cr_index, crname, cr_index_name_cmp );
77 
78 	if ( cir != NULL ) {
79 		return( cir->cir_cr );
80 	}
81 
82 	return( NULL );
83 }
84 
85 static int
86 cr_destroy_one( ContentRule *c )
87 {
88 	assert( c != NULL );
89 
90 	if (c->scr_auxiliaries) ldap_memfree(c->scr_auxiliaries);
91 	if (c->scr_required) ldap_memfree(c->scr_required);
92 	if (c->scr_allowed) ldap_memfree(c->scr_allowed);
93 	if (c->scr_precluded) ldap_memfree(c->scr_precluded);
94 	ldap_contentrule_free((LDAPContentRule *)c);
95 
96 	return 0;
97 }
98 
99 void
100 cr_destroy( void )
101 {
102 	ContentRule *c;
103 
104 	avl_free(cr_index, ldap_memfree);
105 
106 	while( !LDAP_STAILQ_EMPTY(&cr_list) ) {
107 		c = LDAP_STAILQ_FIRST(&cr_list);
108 		LDAP_STAILQ_REMOVE_HEAD(&cr_list, scr_next);
109 
110 		cr_destroy_one( c );
111 	}
112 }
113 
114 static int
115 cr_insert(
116     ContentRule		*scr,
117     const char		**err
118 )
119 {
120 	struct cindexrec	*cir;
121 	char			**names;
122 
123 	if ( scr->scr_oid ) {
124 		cir = (struct cindexrec *)
125 			ch_calloc( 1, sizeof(struct cindexrec) );
126 		cir->cir_name.bv_val = scr->scr_oid;
127 		cir->cir_name.bv_len = strlen( scr->scr_oid );
128 		cir->cir_cr = scr;
129 
130 		assert( cir->cir_name.bv_val != NULL );
131 		assert( cir->cir_cr != NULL );
132 
133 		if ( avl_insert( &cr_index, (caddr_t) cir,
134 		                 cr_index_cmp, avl_dup_error ) )
135 		{
136 			*err = scr->scr_oid;
137 			ldap_memfree(cir);
138 			return SLAP_SCHERR_CR_DUP;
139 		}
140 
141 		/* FIX: temporal consistency check */
142 		assert( cr_bvfind(&cir->cir_name) != NULL );
143 	}
144 
145 	if ( (names = scr->scr_names) ) {
146 		while ( *names ) {
147 			cir = (struct cindexrec *)
148 				ch_calloc( 1, sizeof(struct cindexrec) );
149 			cir->cir_name.bv_val = *names;
150 			cir->cir_name.bv_len = strlen( *names );
151 			cir->cir_cr = scr;
152 
153 			assert( cir->cir_name.bv_val != NULL );
154 			assert( cir->cir_cr != NULL );
155 
156 			if ( avl_insert( &cr_index, (caddr_t) cir,
157 			                 cr_index_cmp, avl_dup_error ) )
158 			{
159 				*err = *names;
160 				ldap_memfree(cir);
161 				return SLAP_SCHERR_CR_DUP;
162 			}
163 
164 			/* FIX: temporal consistency check */
165 			assert( cr_bvfind(&cir->cir_name) != NULL );
166 
167 			names++;
168 		}
169 	}
170 
171 	LDAP_STAILQ_INSERT_TAIL(&cr_list, scr, scr_next);
172 
173 	return 0;
174 }
175 
176 static int
177 cr_add_auxiliaries(
178     ContentRule		*scr,
179 	int			*op,
180     const char		**err )
181 {
182 	int naux;
183 
184 	if( scr->scr_oc_oids_aux == NULL ) return 0;
185 
186 	for( naux=0; scr->scr_oc_oids_aux[naux]; naux++ ) {
187 		/* count them */ ;
188 	}
189 
190 	scr->scr_auxiliaries = ch_calloc( naux+1, sizeof(ObjectClass *));
191 
192 	for( naux=0; scr->scr_oc_oids_aux[naux]; naux++ ) {
193 		ObjectClass *soc = scr->scr_auxiliaries[naux]
194 			= oc_find(scr->scr_oc_oids_aux[naux]);
195 		if ( !soc ) {
196 			*err = scr->scr_oc_oids_aux[naux];
197 			return SLAP_SCHERR_CLASS_NOT_FOUND;
198 		}
199 
200 		if( soc->soc_flags & SLAP_OC_OPERATIONAL &&
201 			soc != slap_schema.si_oc_extensibleObject )
202 		{
203 			(*op)++;
204 		}
205 
206 		if( soc->soc_kind != LDAP_SCHEMA_AUXILIARY ) {
207 			*err = scr->scr_oc_oids_aux[naux];
208 			return SLAP_SCHERR_CR_BAD_AUX;
209 		}
210 	}
211 
212 	scr->scr_auxiliaries[naux] = NULL;
213 	return 0;
214 }
215 
216 static int
217 cr_create_required(
218     ContentRule		*scr,
219 	int			*op,
220     const char		**err )
221 {
222     char		**attrs = scr->scr_at_oids_must;
223 	char		**attrs1;
224 	AttributeType	*sat;
225 
226 	if ( attrs ) {
227 		attrs1 = attrs;
228 		while ( *attrs1 ) {
229 			sat = at_find(*attrs1);
230 			if ( !sat ) {
231 				*err = *attrs1;
232 				return SLAP_SCHERR_ATTR_NOT_FOUND;
233 			}
234 
235 			if( is_at_operational( sat )) (*op)++;
236 
237 			if ( at_find_in_list(sat, scr->scr_required) < 0) {
238 				if ( at_append_to_list(sat, &scr->scr_required) ) {
239 					*err = *attrs1;
240 					return SLAP_SCHERR_OUTOFMEM;
241 				}
242 			} else {
243 				*err = *attrs1;
244 				return SLAP_SCHERR_CR_BAD_AT;
245 			}
246 			attrs1++;
247 		}
248 	}
249 	return 0;
250 }
251 
252 static int
253 cr_create_allowed(
254     ContentRule		*scr,
255 	int			*op,
256     const char		**err )
257 {
258     char		**attrs = scr->scr_at_oids_may;
259 	char		**attrs1;
260 	AttributeType	*sat;
261 
262 	if ( attrs ) {
263 		attrs1 = attrs;
264 		while ( *attrs1 ) {
265 			sat = at_find(*attrs1);
266 			if ( !sat ) {
267 				*err = *attrs1;
268 				return SLAP_SCHERR_ATTR_NOT_FOUND;
269 			}
270 
271 			if( is_at_operational( sat )) (*op)++;
272 
273 			if ( at_find_in_list(sat, scr->scr_required) < 0 &&
274 				at_find_in_list(sat, scr->scr_allowed) < 0 )
275 			{
276 				if ( at_append_to_list(sat, &scr->scr_allowed) ) {
277 					*err = *attrs1;
278 					return SLAP_SCHERR_OUTOFMEM;
279 				}
280 			} else {
281 				*err = *attrs1;
282 				return SLAP_SCHERR_CR_BAD_AT;
283 			}
284 			attrs1++;
285 		}
286 	}
287 	return 0;
288 }
289 
290 static int
291 cr_create_precluded(
292     ContentRule		*scr,
293 	int			*op,
294     const char		**err )
295 {
296     char		**attrs = scr->scr_at_oids_not;
297 	char		**attrs1;
298 	AttributeType	*sat;
299 
300 	if ( attrs ) {
301 		attrs1 = attrs;
302 		while ( *attrs1 ) {
303 			sat = at_find(*attrs1);
304 			if ( !sat ) {
305 				*err = *attrs1;
306 				return SLAP_SCHERR_ATTR_NOT_FOUND;
307 			}
308 
309 			if( is_at_operational( sat )) (*op)++;
310 
311 			/* FIXME: should also make sure attribute type is not
312 				a required attribute of the structural class or
313 				any auxiliary class */
314 			if ( at_find_in_list(sat, scr->scr_required) < 0 &&
315 				at_find_in_list(sat, scr->scr_allowed) < 0 &&
316 				at_find_in_list(sat, scr->scr_precluded) < 0 )
317 			{
318 				if ( at_append_to_list(sat, &scr->scr_precluded) ) {
319 					*err = *attrs1;
320 					return SLAP_SCHERR_OUTOFMEM;
321 				}
322 			} else {
323 				*err = *attrs1;
324 				return SLAP_SCHERR_CR_BAD_AT;
325 			}
326 			attrs1++;
327 		}
328 	}
329 	return 0;
330 }
331 
332 int
333 cr_add(
334     LDAPContentRule	*cr,
335 	int user,
336 	ContentRule **rscr,
337     const char		**err
338 )
339 {
340 	ContentRule	*scr;
341 	int		code;
342 	int		op = 0;
343 	char	*oidm = NULL;
344 
345 	if ( cr->cr_names != NULL ) {
346 		int i;
347 
348 		for( i=0; cr->cr_names[i]; i++ ) {
349 			if( !slap_valid_descr( cr->cr_names[i] ) ) {
350 				return SLAP_SCHERR_BAD_DESCR;
351 			}
352 		}
353 	}
354 
355 	if ( !OID_LEADCHAR( cr->cr_oid[0] )) {
356 		/* Expand OID macros */
357 		char *oid = oidm_find( cr->cr_oid );
358 		if ( !oid ) {
359 			*err = cr->cr_oid;
360 			return SLAP_SCHERR_OIDM;
361 		}
362 		if ( oid != cr->cr_oid ) {
363 			oidm = cr->cr_oid;
364 			cr->cr_oid = oid;
365 		}
366 	}
367 
368 	scr = (ContentRule *) ch_calloc( 1, sizeof(ContentRule) );
369 	AC_MEMCPY( &scr->scr_crule, cr, sizeof(LDAPContentRule) );
370 
371 	scr->scr_oidmacro = oidm;
372 	scr->scr_sclass = oc_find(cr->cr_oid);
373 	if ( !scr->scr_sclass ) {
374 		*err = cr->cr_oid;
375 		code = SLAP_SCHERR_CLASS_NOT_FOUND;
376 		goto fail;
377 	}
378 
379 	/* check object class usage */
380 	if( scr->scr_sclass->soc_kind != LDAP_SCHEMA_STRUCTURAL )
381 	{
382 		*err = cr->cr_oid;
383 		code = SLAP_SCHERR_CR_BAD_STRUCT;
384 		goto fail;
385 	}
386 
387 	if( scr->scr_sclass->soc_flags & SLAP_OC_OPERATIONAL ) op++;
388 
389 	code = cr_add_auxiliaries( scr, &op, err );
390 	if ( code != 0 ) goto fail;
391 
392 	code = cr_create_required( scr, &op, err );
393 	if ( code != 0 ) goto fail;
394 
395 	code = cr_create_allowed( scr, &op, err );
396 	if ( code != 0 ) goto fail;
397 
398 	code = cr_create_precluded( scr, &op, err );
399 	if ( code != 0 ) goto fail;
400 
401 	if( user && op ) {
402 		code = SLAP_SCHERR_CR_BAD_AUX;
403 		goto fail;
404 	}
405 
406 	code = cr_insert(scr,err);
407 	if ( code == 0 && rscr )
408 		*rscr = scr;
409 	return code;
410 fail:
411 	ch_free( scr );
412 	return code;
413 }
414 
415 void
416 cr_unparse( BerVarray *res, ContentRule *start, ContentRule *end, int sys )
417 {
418 	ContentRule *cr;
419 	int i, num;
420 	struct berval bv, *bva = NULL, idx;
421 	char ibuf[32];
422 
423 	if ( !start )
424 		start = LDAP_STAILQ_FIRST( &cr_list );
425 
426 	/* count the result size */
427 	i = 0;
428 	for ( cr=start; cr; cr=LDAP_STAILQ_NEXT(cr, scr_next)) {
429 		if ( sys && !(cr->scr_flags & SLAP_CR_HARDCODE)) continue;
430 		i++;
431 		if ( cr == end ) break;
432 	}
433 	if (!i) return;
434 
435 	num = i;
436 	bva = ch_malloc( (num+1) * sizeof(struct berval) );
437 	BER_BVZERO( bva );
438 	idx.bv_val = ibuf;
439 	if ( sys ) {
440 		idx.bv_len = 0;
441 		ibuf[0] = '\0';
442 	}
443 	i = 0;
444 	for ( cr=start; cr; cr=LDAP_STAILQ_NEXT(cr, scr_next)) {
445 		LDAPContentRule lcr, *lcrp;
446 		if ( sys && !(cr->scr_flags & SLAP_CR_HARDCODE)) continue;
447 		if ( cr->scr_oidmacro ) {
448 			lcr = cr->scr_crule;
449 			lcr.cr_oid = cr->scr_oidmacro;
450 			lcrp = &lcr;
451 		} else {
452 			lcrp = &cr->scr_crule;
453 		}
454 		if ( ldap_contentrule2bv( lcrp, &bv ) == NULL ) {
455 			ber_bvarray_free( bva );
456 		}
457 		if ( !sys ) {
458 			idx.bv_len = sprintf(idx.bv_val, "{%d}", i);
459 		}
460 		bva[i].bv_len = idx.bv_len + bv.bv_len;
461 		bva[i].bv_val = ch_malloc( bva[i].bv_len + 1 );
462 		strcpy( bva[i].bv_val, ibuf );
463 		strcpy( bva[i].bv_val + idx.bv_len, bv.bv_val );
464 		i++;
465 		bva[i].bv_val = NULL;
466 		ldap_memfree( bv.bv_val );
467 		if ( cr == end ) break;
468 	}
469 	*res = bva;
470 }
471 
472 int
473 cr_schema_info( Entry *e )
474 {
475 	AttributeDescription *ad_ditContentRules
476 		= slap_schema.si_ad_ditContentRules;
477 	ContentRule	*cr;
478 
479 	struct berval	val;
480 	struct berval	nval;
481 
482 	LDAP_STAILQ_FOREACH(cr, &cr_list, scr_next) {
483 		if ( ldap_contentrule2bv( &cr->scr_crule, &val ) == NULL ) {
484 			return -1;
485 		}
486 
487 #if 0
488 		if( cr->scr_flags & SLAP_CR_HIDE ) continue;
489 #endif
490 #if 0
491 		Debug( LDAP_DEBUG_TRACE, "Merging cr [%ld] %s\n",
492 	       (long) val.bv_len, val.bv_val, 0 );
493 #endif
494 
495 		nval.bv_val = cr->scr_oid;
496 		nval.bv_len = strlen(cr->scr_oid);
497 
498 		if( attr_merge_one( e, ad_ditContentRules, &val, &nval ) )
499 		{
500 			return -1;
501 		}
502 		ldap_memfree( val.bv_val );
503 	}
504 	return 0;
505 }
506