xref: /netbsd-src/external/bsd/openldap/dist/servers/slapd/cr.c (revision b7b7574d3bf8eeb51a1fa3977b59142ec6434a55)
1 /*	$NetBSD: cr.c,v 1.1.1.4 2014/05/28 09:58:46 tron Exp $	*/
2 
3 /* cr.c - content rule routines */
4 /* $OpenLDAP$ */
5 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
6  *
7  * Copyright 1998-2014 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 	assert( scr != NULL );
126 
127 	if ( scr->scr_oid ) {
128 		cir = (struct cindexrec *)
129 			ch_calloc( 1, sizeof(struct cindexrec) );
130 		cir->cir_name.bv_val = scr->scr_oid;
131 		cir->cir_name.bv_len = strlen( scr->scr_oid );
132 		cir->cir_cr = scr;
133 
134 		if ( avl_insert( &cr_index, (caddr_t) cir,
135 		                 cr_index_cmp, avl_dup_error ) )
136 		{
137 			*err = scr->scr_oid;
138 			ldap_memfree(cir);
139 			return SLAP_SCHERR_CR_DUP;
140 		}
141 
142 		/* FIX: temporal consistency check */
143 		assert( cr_bvfind(&cir->cir_name) != NULL );
144 	}
145 
146 	if ( (names = scr->scr_names) ) {
147 		while ( *names ) {
148 			cir = (struct cindexrec *)
149 				ch_calloc( 1, sizeof(struct cindexrec) );
150 			cir->cir_name.bv_val = *names;
151 			cir->cir_name.bv_len = strlen( *names );
152 			cir->cir_cr = scr;
153 
154 			if ( avl_insert( &cr_index, (caddr_t) cir,
155 			                 cr_index_cmp, avl_dup_error ) )
156 			{
157 				*err = *names;
158 				ldap_memfree(cir);
159 				return SLAP_SCHERR_CR_DUP;
160 			}
161 
162 			/* FIX: temporal consistency check */
163 			assert( cr_bvfind(&cir->cir_name) != NULL );
164 
165 			names++;
166 		}
167 	}
168 
169 	LDAP_STAILQ_INSERT_TAIL(&cr_list, scr, scr_next);
170 
171 	return 0;
172 }
173 
174 static int
175 cr_add_auxiliaries(
176     ContentRule		*scr,
177 	int			*op,
178     const char		**err )
179 {
180 	int naux;
181 
182 	if( scr->scr_oc_oids_aux == NULL ) return 0;
183 
184 	for( naux=0; scr->scr_oc_oids_aux[naux]; naux++ ) {
185 		/* count them */ ;
186 	}
187 
188 	scr->scr_auxiliaries = ch_calloc( naux+1, sizeof(ObjectClass *));
189 
190 	for( naux=0; scr->scr_oc_oids_aux[naux]; naux++ ) {
191 		ObjectClass *soc = scr->scr_auxiliaries[naux]
192 			= oc_find(scr->scr_oc_oids_aux[naux]);
193 		if ( !soc ) {
194 			*err = scr->scr_oc_oids_aux[naux];
195 			return SLAP_SCHERR_CLASS_NOT_FOUND;
196 		}
197 
198 		if( soc->soc_flags & SLAP_OC_OPERATIONAL &&
199 			soc != slap_schema.si_oc_extensibleObject )
200 		{
201 			(*op)++;
202 		}
203 
204 		if( soc->soc_kind != LDAP_SCHEMA_AUXILIARY ) {
205 			*err = scr->scr_oc_oids_aux[naux];
206 			return SLAP_SCHERR_CR_BAD_AUX;
207 		}
208 	}
209 
210 	scr->scr_auxiliaries[naux] = NULL;
211 	return 0;
212 }
213 
214 static int
215 cr_create_required(
216     ContentRule		*scr,
217 	int			*op,
218     const char		**err )
219 {
220     char		**attrs = scr->scr_at_oids_must;
221 	char		**attrs1;
222 	AttributeType	*sat;
223 
224 	if ( attrs ) {
225 		attrs1 = attrs;
226 		while ( *attrs1 ) {
227 			sat = at_find(*attrs1);
228 			if ( !sat ) {
229 				*err = *attrs1;
230 				return SLAP_SCHERR_ATTR_NOT_FOUND;
231 			}
232 
233 			if( is_at_operational( sat )) (*op)++;
234 
235 			if ( at_find_in_list(sat, scr->scr_required) < 0) {
236 				if ( at_append_to_list(sat, &scr->scr_required) ) {
237 					*err = *attrs1;
238 					return SLAP_SCHERR_OUTOFMEM;
239 				}
240 			} else {
241 				*err = *attrs1;
242 				return SLAP_SCHERR_CR_BAD_AT;
243 			}
244 			attrs1++;
245 		}
246 	}
247 	return 0;
248 }
249 
250 static int
251 cr_create_allowed(
252     ContentRule		*scr,
253 	int			*op,
254     const char		**err )
255 {
256     char		**attrs = scr->scr_at_oids_may;
257 	char		**attrs1;
258 	AttributeType	*sat;
259 
260 	if ( attrs ) {
261 		attrs1 = attrs;
262 		while ( *attrs1 ) {
263 			sat = at_find(*attrs1);
264 			if ( !sat ) {
265 				*err = *attrs1;
266 				return SLAP_SCHERR_ATTR_NOT_FOUND;
267 			}
268 
269 			if( is_at_operational( sat )) (*op)++;
270 
271 			if ( at_find_in_list(sat, scr->scr_required) < 0 &&
272 				at_find_in_list(sat, scr->scr_allowed) < 0 )
273 			{
274 				if ( at_append_to_list(sat, &scr->scr_allowed) ) {
275 					*err = *attrs1;
276 					return SLAP_SCHERR_OUTOFMEM;
277 				}
278 			} else {
279 				*err = *attrs1;
280 				return SLAP_SCHERR_CR_BAD_AT;
281 			}
282 			attrs1++;
283 		}
284 	}
285 	return 0;
286 }
287 
288 static int
289 cr_create_precluded(
290     ContentRule		*scr,
291 	int			*op,
292     const char		**err )
293 {
294     char		**attrs = scr->scr_at_oids_not;
295 	char		**attrs1;
296 	AttributeType	*sat;
297 
298 	if ( attrs ) {
299 		attrs1 = attrs;
300 		while ( *attrs1 ) {
301 			sat = at_find(*attrs1);
302 			if ( !sat ) {
303 				*err = *attrs1;
304 				return SLAP_SCHERR_ATTR_NOT_FOUND;
305 			}
306 
307 			if( is_at_operational( sat )) (*op)++;
308 
309 			/* FIXME: should also make sure attribute type is not
310 				a required attribute of the structural class or
311 				any auxiliary class */
312 			if ( at_find_in_list(sat, scr->scr_required) < 0 &&
313 				at_find_in_list(sat, scr->scr_allowed) < 0 &&
314 				at_find_in_list(sat, scr->scr_precluded) < 0 )
315 			{
316 				if ( at_append_to_list(sat, &scr->scr_precluded) ) {
317 					*err = *attrs1;
318 					return SLAP_SCHERR_OUTOFMEM;
319 				}
320 			} else {
321 				*err = *attrs1;
322 				return SLAP_SCHERR_CR_BAD_AT;
323 			}
324 			attrs1++;
325 		}
326 	}
327 	return 0;
328 }
329 
330 int
331 cr_add(
332     LDAPContentRule	*cr,
333 	int user,
334 	ContentRule **rscr,
335     const char		**err
336 )
337 {
338 	ContentRule	*scr;
339 	int		code;
340 	int		op = 0;
341 	char	*oidm = NULL;
342 
343 	if ( cr->cr_names != NULL ) {
344 		int i;
345 
346 		for( i=0; cr->cr_names[i]; i++ ) {
347 			if( !slap_valid_descr( cr->cr_names[i] ) ) {
348 				return SLAP_SCHERR_BAD_DESCR;
349 			}
350 		}
351 	}
352 
353 	if ( !OID_LEADCHAR( cr->cr_oid[0] )) {
354 		/* Expand OID macros */
355 		char *oid = oidm_find( cr->cr_oid );
356 		if ( !oid ) {
357 			*err = cr->cr_oid;
358 			return SLAP_SCHERR_OIDM;
359 		}
360 		if ( oid != cr->cr_oid ) {
361 			oidm = cr->cr_oid;
362 			cr->cr_oid = oid;
363 		}
364 	}
365 
366 	scr = (ContentRule *) ch_calloc( 1, sizeof(ContentRule) );
367 	AC_MEMCPY( &scr->scr_crule, cr, sizeof(LDAPContentRule) );
368 
369 	scr->scr_oidmacro = oidm;
370 	scr->scr_sclass = oc_find(cr->cr_oid);
371 	if ( !scr->scr_sclass ) {
372 		*err = cr->cr_oid;
373 		code = SLAP_SCHERR_CLASS_NOT_FOUND;
374 		goto fail;
375 	}
376 
377 	/* check object class usage */
378 	if( scr->scr_sclass->soc_kind != LDAP_SCHEMA_STRUCTURAL )
379 	{
380 		*err = cr->cr_oid;
381 		code = SLAP_SCHERR_CR_BAD_STRUCT;
382 		goto fail;
383 	}
384 
385 	if( scr->scr_sclass->soc_flags & SLAP_OC_OPERATIONAL ) op++;
386 
387 	code = cr_add_auxiliaries( scr, &op, err );
388 	if ( code != 0 ) goto fail;
389 
390 	code = cr_create_required( scr, &op, err );
391 	if ( code != 0 ) goto fail;
392 
393 	code = cr_create_allowed( scr, &op, err );
394 	if ( code != 0 ) goto fail;
395 
396 	code = cr_create_precluded( scr, &op, err );
397 	if ( code != 0 ) goto fail;
398 
399 	if( user && op ) {
400 		code = SLAP_SCHERR_CR_BAD_AUX;
401 		goto fail;
402 	}
403 
404 	code = cr_insert(scr,err);
405 	if ( code == 0 && rscr )
406 		*rscr = scr;
407 	return code;
408 fail:
409 	ch_free( scr );
410 	return code;
411 }
412 
413 void
414 cr_unparse( BerVarray *res, ContentRule *start, ContentRule *end, int sys )
415 {
416 	ContentRule *cr;
417 	int i, num;
418 	struct berval bv, *bva = NULL, idx;
419 	char ibuf[32];
420 
421 	if ( !start )
422 		start = LDAP_STAILQ_FIRST( &cr_list );
423 
424 	/* count the result size */
425 	i = 0;
426 	for ( cr=start; cr; cr=LDAP_STAILQ_NEXT(cr, scr_next)) {
427 		if ( sys && !(cr->scr_flags & SLAP_CR_HARDCODE)) continue;
428 		i++;
429 		if ( cr == end ) break;
430 	}
431 	if (!i) return;
432 
433 	num = i;
434 	bva = ch_malloc( (num+1) * sizeof(struct berval) );
435 	BER_BVZERO( bva );
436 	idx.bv_val = ibuf;
437 	if ( sys ) {
438 		idx.bv_len = 0;
439 		ibuf[0] = '\0';
440 	}
441 	i = 0;
442 	for ( cr=start; cr; cr=LDAP_STAILQ_NEXT(cr, scr_next)) {
443 		LDAPContentRule lcr, *lcrp;
444 		if ( sys && !(cr->scr_flags & SLAP_CR_HARDCODE)) continue;
445 		if ( cr->scr_oidmacro ) {
446 			lcr = cr->scr_crule;
447 			lcr.cr_oid = cr->scr_oidmacro;
448 			lcrp = &lcr;
449 		} else {
450 			lcrp = &cr->scr_crule;
451 		}
452 		if ( ldap_contentrule2bv( lcrp, &bv ) == NULL ) {
453 			ber_bvarray_free( bva );
454 		}
455 		if ( !sys ) {
456 			idx.bv_len = sprintf(idx.bv_val, "{%d}", i);
457 		}
458 		bva[i].bv_len = idx.bv_len + bv.bv_len;
459 		bva[i].bv_val = ch_malloc( bva[i].bv_len + 1 );
460 		strcpy( bva[i].bv_val, ibuf );
461 		strcpy( bva[i].bv_val + idx.bv_len, bv.bv_val );
462 		i++;
463 		bva[i].bv_val = NULL;
464 		ldap_memfree( bv.bv_val );
465 		if ( cr == end ) break;
466 	}
467 	*res = bva;
468 }
469 
470 int
471 cr_schema_info( Entry *e )
472 {
473 	AttributeDescription *ad_ditContentRules
474 		= slap_schema.si_ad_ditContentRules;
475 	ContentRule	*cr;
476 
477 	struct berval	val;
478 	struct berval	nval;
479 
480 	LDAP_STAILQ_FOREACH(cr, &cr_list, scr_next) {
481 		if ( ldap_contentrule2bv( &cr->scr_crule, &val ) == NULL ) {
482 			return -1;
483 		}
484 
485 #if 0
486 		if( cr->scr_flags & SLAP_CR_HIDE ) continue;
487 #endif
488 #if 0
489 		Debug( LDAP_DEBUG_TRACE, "Merging cr [%ld] %s\n",
490 	       (long) val.bv_len, val.bv_val, 0 );
491 #endif
492 
493 		nval.bv_val = cr->scr_oid;
494 		nval.bv_len = strlen(cr->scr_oid);
495 
496 		if( attr_merge_one( e, ad_ditContentRules, &val, &nval ) )
497 		{
498 			return -1;
499 		}
500 		ldap_memfree( val.bv_val );
501 	}
502 	return 0;
503 }
504