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