~ttx/openldap/lucid-gssapi-495418

« back to all changes in this revision

Viewing changes to servers/slapd/schema_check.c

  • Committer: Bazaar Package Importer
  • Author(s): Mathias Gug
  • Date: 2008-07-10 14:45:49 UTC
  • Revision ID: james.westby@ubuntu.com-20080710144549-wck73med0e72gfyo
Tags: upstream-2.4.10
ImportĀ upstreamĀ versionĀ 2.4.10

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* schema_check.c - routines to enforce schema definitions */
 
2
/* $OpenLDAP: pkg/ldap/servers/slapd/schema_check.c,v 1.103.2.6 2008/04/18 22:33:55 ando 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
static char * oc_check_required(
 
28
        Entry *e,
 
29
        ObjectClass *oc,
 
30
        struct berval *ocname );
 
31
 
 
32
static int entry_naming_check(
 
33
        Entry *e,
 
34
        int manage,
 
35
        int add_naming,
 
36
        const char** text,
 
37
        char *textbuf, size_t textlen );
 
38
/*
 
39
 * entry_schema_check - check that entry e conforms to the schema required
 
40
 * by its object class(es).
 
41
 *
 
42
 * returns 0 if so, non-zero otherwise.
 
43
 */
 
44
 
 
45
int
 
46
entry_schema_check( 
 
47
        Operation *op,
 
48
        Entry *e,
 
49
        Attribute *oldattrs,
 
50
        int manage,
 
51
        int add,
 
52
        const char** text,
 
53
        char *textbuf, size_t textlen )
 
54
{
 
55
        Attribute       *a, *asc = NULL, *aoc = NULL;
 
56
        ObjectClass *sc, *oc, **socs = NULL;
 
57
        AttributeType *at;
 
58
        ContentRule *cr;
 
59
        int     rc, i;
 
60
        AttributeDescription *ad_structuralObjectClass
 
61
                = slap_schema.si_ad_structuralObjectClass;
 
62
        AttributeDescription *ad_objectClass
 
63
                = slap_schema.si_ad_objectClass;
 
64
        int extensible = 0;
 
65
        int subentry = is_entry_subentry( e );
 
66
        int collectiveSubentry = 0;
 
67
 
 
68
        if ( SLAP_NO_SCHEMA_CHECK( op->o_bd )) {
 
69
                return LDAP_SUCCESS;
 
70
        }
 
71
 
 
72
        if ( get_no_schema_check( op ) ) {
 
73
                return LDAP_SUCCESS;
 
74
        }
 
75
 
 
76
        if( subentry ) {
 
77
                collectiveSubentry = is_entry_collectiveAttributeSubentry( e );
 
78
        }
 
79
 
 
80
        *text = textbuf;
 
81
 
 
82
        /* misc attribute checks */
 
83
        for ( a = e->e_attrs; a != NULL; a = a->a_next ) {
 
84
                const char *type = a->a_desc->ad_cname.bv_val;
 
85
 
 
86
                /* there should be at least one value */
 
87
                assert( a->a_vals != NULL );
 
88
                assert( a->a_vals[0].bv_val != NULL ); 
 
89
 
 
90
                if( a->a_desc->ad_type->sat_check ) {
 
91
                        rc = (a->a_desc->ad_type->sat_check)(
 
92
                                op->o_bd, e, a, text, textbuf, textlen );
 
93
                        if( rc != LDAP_SUCCESS ) {
 
94
                                return rc;
 
95
                        }
 
96
                }
 
97
 
 
98
                if( a->a_desc == ad_structuralObjectClass )
 
99
                        asc = a;
 
100
                else if ( a->a_desc == ad_objectClass )
 
101
                        aoc = a;
 
102
 
 
103
                if( !collectiveSubentry && is_at_collective( a->a_desc->ad_type ) ) {
 
104
                        snprintf( textbuf, textlen,
 
105
                                "'%s' can only appear in collectiveAttributeSubentry",
 
106
                                type );
 
107
                        return LDAP_OBJECT_CLASS_VIOLATION;
 
108
                }
 
109
 
 
110
                /* if single value type, check for multiple values */
 
111
                if( is_at_single_value( a->a_desc->ad_type ) &&
 
112
                        a->a_vals[1].bv_val != NULL )
 
113
                {
 
114
                        snprintf( textbuf, textlen, 
 
115
                                "attribute '%s' cannot have multiple values",
 
116
                                type );
 
117
 
 
118
                        Debug( LDAP_DEBUG_ANY,
 
119
                            "Entry (%s), %s\n",
 
120
                            e->e_dn, textbuf, 0 );
 
121
 
 
122
                        return LDAP_CONSTRAINT_VIOLATION;
 
123
                }
 
124
        }
 
125
 
 
126
        /* check the object class attribute */
 
127
        if ( aoc == NULL ) {
 
128
                Debug( LDAP_DEBUG_ANY, "No objectClass for entry (%s)\n",
 
129
                    e->e_dn, 0, 0 );
 
130
 
 
131
                *text = "no objectClass attribute";
 
132
                return LDAP_OBJECT_CLASS_VIOLATION;
 
133
        }
 
134
 
 
135
        assert( aoc->a_vals != NULL );
 
136
        assert( aoc->a_vals[0].bv_val != NULL );
 
137
 
 
138
        /* check the structural object class attribute */
 
139
        if ( asc == NULL && !add ) {
 
140
                Debug( LDAP_DEBUG_ANY,
 
141
                        "No structuralObjectClass for entry (%s)\n",
 
142
                    e->e_dn, 0, 0 );
 
143
 
 
144
                *text = "no structuralObjectClass operational attribute";
 
145
                return LDAP_OTHER;
 
146
        }
 
147
 
 
148
        rc = structural_class( aoc->a_vals, &oc, &socs, text, textbuf, textlen,
 
149
                op->o_tmpmemctx );
 
150
        if( rc != LDAP_SUCCESS ) {
 
151
                return rc;
 
152
        }
 
153
 
 
154
        if ( asc == NULL && add ) {
 
155
                attr_merge_one( e, ad_structuralObjectClass, &oc->soc_cname, NULL );
 
156
                asc = attr_find( e->e_attrs, ad_structuralObjectClass );
 
157
                sc = oc;
 
158
                goto got_soc;
 
159
        }
 
160
 
 
161
        assert( asc->a_vals != NULL );
 
162
        assert( asc->a_vals[0].bv_val != NULL );
 
163
        assert( asc->a_vals[1].bv_val == NULL );
 
164
 
 
165
        sc = oc_bvfind( &asc->a_vals[0] );
 
166
        if( sc == NULL ) {
 
167
                snprintf( textbuf, textlen, 
 
168
                        "unrecognized structuralObjectClass '%s'",
 
169
                        asc->a_vals[0].bv_val );
 
170
 
 
171
                Debug( LDAP_DEBUG_ANY,
 
172
                        "entry_check_schema(%s): %s\n",
 
173
                        e->e_dn, textbuf, 0 );
 
174
 
 
175
                rc = LDAP_OBJECT_CLASS_VIOLATION;
 
176
                goto done;
 
177
        }
 
178
 
 
179
        if( sc->soc_kind != LDAP_SCHEMA_STRUCTURAL ) {
 
180
                snprintf( textbuf, textlen, 
 
181
                        "structuralObjectClass '%s' is not STRUCTURAL",
 
182
                        asc->a_vals[0].bv_val );
 
183
 
 
184
                Debug( LDAP_DEBUG_ANY,
 
185
                        "entry_check_schema(%s): %s\n",
 
186
                        e->e_dn, textbuf, 0 );
 
187
 
 
188
                rc = LDAP_OTHER;
 
189
                goto done;
 
190
        }
 
191
 
 
192
got_soc:
 
193
        if( !manage && sc->soc_obsolete ) {
 
194
                snprintf( textbuf, textlen, 
 
195
                        "structuralObjectClass '%s' is OBSOLETE",
 
196
                        asc->a_vals[0].bv_val );
 
197
 
 
198
                Debug( LDAP_DEBUG_ANY,
 
199
                        "entry_check_schema(%s): %s\n",
 
200
                        e->e_dn, textbuf, 0 );
 
201
 
 
202
                rc = LDAP_OBJECT_CLASS_VIOLATION;
 
203
                goto done;
 
204
        }
 
205
 
 
206
        *text = textbuf;
 
207
 
 
208
        if ( oc == NULL ) {
 
209
                snprintf( textbuf, textlen, 
 
210
                        "unrecognized objectClass '%s'",
 
211
                        aoc->a_vals[0].bv_val );
 
212
                rc = LDAP_OBJECT_CLASS_VIOLATION;
 
213
                goto done;
 
214
 
 
215
        } else if ( sc != slap_schema.si_oc_glue && sc != oc ) {
 
216
                snprintf( textbuf, textlen, 
 
217
                        "structural object class modification "
 
218
                        "from '%s' to '%s' not allowed",
 
219
                        asc->a_vals[0].bv_val, oc->soc_cname.bv_val );
 
220
                rc = LDAP_NO_OBJECT_CLASS_MODS;
 
221
                goto done;
 
222
        } else if ( sc == slap_schema.si_oc_glue ) {
 
223
                sc = oc;
 
224
        }
 
225
 
 
226
        /* naming check */
 
227
        if ( !is_entry_glue ( e ) ) {
 
228
                rc = entry_naming_check( e, manage, add, text, textbuf, textlen );
 
229
                if( rc != LDAP_SUCCESS ) {
 
230
                        goto done;
 
231
                }
 
232
        } else {
 
233
                /* Glue Entry */
 
234
        }
 
235
 
 
236
        /* find the content rule for the structural class */
 
237
        cr = cr_find( sc->soc_oid );
 
238
 
 
239
        /* the cr must be same as the structural class */
 
240
        assert( !cr || !strcmp( cr->scr_oid, sc->soc_oid ) );
 
241
 
 
242
        /* check that the entry has required attrs of the content rule */
 
243
        if( cr ) {
 
244
                if( !manage && cr->scr_obsolete ) {
 
245
                        snprintf( textbuf, textlen, 
 
246
                                "content rule '%s' is obsolete",
 
247
                                ldap_contentrule2name( &cr->scr_crule ));
 
248
 
 
249
                        Debug( LDAP_DEBUG_ANY,
 
250
                                "Entry (%s): %s\n",
 
251
                                e->e_dn, textbuf, 0 );
 
252
 
 
253
                        rc = LDAP_OBJECT_CLASS_VIOLATION;
 
254
                        goto done;
 
255
                }
 
256
 
 
257
                if( cr->scr_required ) for( i=0; cr->scr_required[i]; i++ ) {
 
258
                        at = cr->scr_required[i];
 
259
 
 
260
                        for ( a = e->e_attrs; a != NULL; a = a->a_next ) {
 
261
                                if( a->a_desc->ad_type == at ) {
 
262
                                        break;
 
263
                                }
 
264
                        }
 
265
 
 
266
                        /* not there => schema violation */
 
267
                        if ( a == NULL ) {
 
268
                                snprintf( textbuf, textlen, 
 
269
                                        "content rule '%s' requires attribute '%s'",
 
270
                                        ldap_contentrule2name( &cr->scr_crule ),
 
271
                                        at->sat_cname.bv_val );
 
272
 
 
273
                                Debug( LDAP_DEBUG_ANY,
 
274
                                        "Entry (%s): %s\n",
 
275
                                        e->e_dn, textbuf, 0 );
 
276
 
 
277
                                rc = LDAP_OBJECT_CLASS_VIOLATION;
 
278
                                goto done;
 
279
                        }
 
280
                }
 
281
 
 
282
                if( cr->scr_precluded ) for( i=0; cr->scr_precluded[i]; i++ ) {
 
283
                        at = cr->scr_precluded[i];
 
284
 
 
285
                        for ( a = e->e_attrs; a != NULL; a = a->a_next ) {
 
286
                                if( a->a_desc->ad_type == at ) {
 
287
                                        break;
 
288
                                }
 
289
                        }
 
290
 
 
291
                        /* there => schema violation */
 
292
                        if ( a != NULL ) {
 
293
                                snprintf( textbuf, textlen, 
 
294
                                        "content rule '%s' precluded attribute '%s'",
 
295
                                        ldap_contentrule2name( &cr->scr_crule ),
 
296
                                        at->sat_cname.bv_val );
 
297
 
 
298
                                Debug( LDAP_DEBUG_ANY,
 
299
                                        "Entry (%s): %s\n",
 
300
                                        e->e_dn, textbuf, 0 );
 
301
 
 
302
                                rc = LDAP_OBJECT_CLASS_VIOLATION;
 
303
                                goto done;
 
304
                        }
 
305
                }
 
306
        }
 
307
 
 
308
        /* check that the entry has required attrs for each oc */
 
309
        for ( i = 0; socs[i]; i++ ) {
 
310
                oc = socs[i];
 
311
                if ( !manage && oc->soc_obsolete ) {
 
312
                        /* disallow obsolete classes */
 
313
                        snprintf( textbuf, textlen, 
 
314
                                "objectClass '%s' is OBSOLETE",
 
315
                                aoc->a_vals[i].bv_val );
 
316
 
 
317
                        Debug( LDAP_DEBUG_ANY,
 
318
                                "entry_check_schema(%s): %s\n",
 
319
                                e->e_dn, textbuf, 0 );
 
320
 
 
321
                        rc = LDAP_OBJECT_CLASS_VIOLATION;
 
322
                        goto done;
 
323
                }
 
324
 
 
325
                if ( oc->soc_check ) {
 
326
                        rc = (oc->soc_check)( op->o_bd, e, oc,
 
327
                                text, textbuf, textlen );
 
328
                        if( rc != LDAP_SUCCESS ) {
 
329
                                goto done;
 
330
                        }
 
331
                }
 
332
 
 
333
                if ( oc->soc_kind == LDAP_SCHEMA_ABSTRACT ) {
 
334
                        /* object class is abstract */
 
335
                        if ( oc != slap_schema.si_oc_top &&
 
336
                                !is_object_subclass( oc, sc ))
 
337
                        {
 
338
                                int j;
 
339
                                ObjectClass *xc = NULL;
 
340
                                for( j=0; socs[j]; j++ ) {
 
341
                                        if( i != j ) {
 
342
                                                xc = socs[j];
 
343
 
 
344
                                                /* since we previous check against the
 
345
                                                 * structural object of this entry, the
 
346
                                                 * abstract class must be a (direct or indirect)
 
347
                                                 * superclass of one of the auxiliary classes of
 
348
                                                 * the entry.
 
349
                                                 */
 
350
                                                if ( xc->soc_kind == LDAP_SCHEMA_AUXILIARY &&
 
351
                                                        is_object_subclass( oc, xc ) )
 
352
                                                {
 
353
                                                        xc = NULL;
 
354
                                                        break;
 
355
                                                }
 
356
                                        }
 
357
                                }
 
358
 
 
359
                                if( xc != NULL ) {
 
360
                                        snprintf( textbuf, textlen, "instantiation of "
 
361
                                                "abstract objectClass '%s' not allowed",
 
362
                                                aoc->a_vals[i].bv_val );
 
363
 
 
364
                                        Debug( LDAP_DEBUG_ANY,
 
365
                                                "entry_check_schema(%s): %s\n",
 
366
                                                e->e_dn, textbuf, 0 );
 
367
 
 
368
                                        rc = LDAP_OBJECT_CLASS_VIOLATION;
 
369
                                        goto done;
 
370
                                }
 
371
                        }
 
372
 
 
373
                } else if ( oc->soc_kind != LDAP_SCHEMA_STRUCTURAL || oc == sc ) {
 
374
                        char *s;
 
375
 
 
376
                        if( oc->soc_kind == LDAP_SCHEMA_AUXILIARY ) {
 
377
                                int k;
 
378
 
 
379
                                if( cr ) {
 
380
                                        int j;
 
381
 
 
382
                                        k = -1;
 
383
                                        if( cr->scr_auxiliaries ) {
 
384
                                                for( j = 0; cr->scr_auxiliaries[j]; j++ ) {
 
385
                                                        if( cr->scr_auxiliaries[j] == oc ) {
 
386
                                                                k = 0;
 
387
                                                                break;
 
388
                                                        }
 
389
                                                }
 
390
                                        }
 
391
                                        if ( k ) {
 
392
                                                snprintf( textbuf, textlen, 
 
393
                                                        "class '%s' not allowed by content rule '%s'",
 
394
                                                        oc->soc_cname.bv_val,
 
395
                                                        ldap_contentrule2name( &cr->scr_crule ) );
 
396
                                        }
 
397
                                } else if ( global_disallows & SLAP_DISALLOW_AUX_WO_CR ) {
 
398
                                        k = -1;
 
399
                                        snprintf( textbuf, textlen, 
 
400
                                                "class '%s' not allowed by any content rule",
 
401
                                                oc->soc_cname.bv_val );
 
402
                                } else {
 
403
                                        k = 0;  
 
404
                                }
 
405
 
 
406
                                if( k == -1 ) {
 
407
                                        Debug( LDAP_DEBUG_ANY,
 
408
                                                "Entry (%s): %s\n",
 
409
                                                e->e_dn, textbuf, 0 );
 
410
 
 
411
                                        rc = LDAP_OBJECT_CLASS_VIOLATION;
 
412
                                        goto done;
 
413
                                }
 
414
                        }
 
415
 
 
416
                        s = oc_check_required( e, oc, &aoc->a_vals[i] );
 
417
                        if (s != NULL) {
 
418
                                snprintf( textbuf, textlen, 
 
419
                                        "object class '%s' requires attribute '%s'",
 
420
                                        aoc->a_vals[i].bv_val, s );
 
421
 
 
422
                                Debug( LDAP_DEBUG_ANY,
 
423
                                        "Entry (%s): %s\n",
 
424
                                        e->e_dn, textbuf, 0 );
 
425
 
 
426
                                rc = LDAP_OBJECT_CLASS_VIOLATION;
 
427
                                goto done;
 
428
                        }
 
429
 
 
430
                        if( oc == slap_schema.si_oc_extensibleObject ) {
 
431
                                extensible=1;
 
432
                        }
 
433
                }
 
434
        }
 
435
 
 
436
        if( extensible ) {
 
437
                *text = NULL;
 
438
                rc = LDAP_SUCCESS;
 
439
                goto done;
 
440
        }
 
441
 
 
442
        /* check that each attr in the entry is allowed by some oc */
 
443
        for ( a = e->e_attrs; a != NULL; a = a->a_next ) {
 
444
                rc = LDAP_OBJECT_CLASS_VIOLATION;
 
445
 
 
446
                if( cr && cr->scr_required ) {
 
447
                        for( i=0; cr->scr_required[i]; i++ ) {
 
448
                                if( cr->scr_required[i] == a->a_desc->ad_type ) {
 
449
                                        rc = LDAP_SUCCESS;
 
450
                                        break;
 
451
                                }
 
452
                        }
 
453
                }
 
454
 
 
455
                if( rc != LDAP_SUCCESS && cr && cr->scr_allowed ) {
 
456
                        for( i=0; cr->scr_allowed[i]; i++ ) {
 
457
                                if( cr->scr_allowed[i] == a->a_desc->ad_type ) {
 
458
                                        rc = LDAP_SUCCESS;
 
459
                                        break;
 
460
                                }
 
461
                        }
 
462
                }
 
463
 
 
464
                if( rc != LDAP_SUCCESS ) 
 
465
                {
 
466
                        rc = oc_check_allowed( a->a_desc->ad_type, socs, sc );
 
467
                }
 
468
 
 
469
                if ( rc != LDAP_SUCCESS ) {
 
470
                        char *type = a->a_desc->ad_cname.bv_val;
 
471
 
 
472
                        snprintf( textbuf, textlen, 
 
473
                                "attribute '%s' not allowed",
 
474
                                type );
 
475
 
 
476
                        Debug( LDAP_DEBUG_ANY,
 
477
                            "Entry (%s), %s\n",
 
478
                            e->e_dn, textbuf, 0 );
 
479
 
 
480
                        goto done;
 
481
                }
 
482
        }
 
483
 
 
484
        *text = NULL;
 
485
done:
 
486
        slap_sl_free( socs, op->o_tmpmemctx );
 
487
        return rc;
 
488
}
 
489
 
 
490
static char *
 
491
oc_check_required(
 
492
        Entry *e,
 
493
        ObjectClass *oc,
 
494
        struct berval *ocname )
 
495
{
 
496
        AttributeType   *at;
 
497
        int             i;
 
498
        Attribute       *a;
 
499
 
 
500
        Debug( LDAP_DEBUG_TRACE,
 
501
                "oc_check_required entry (%s), objectClass \"%s\"\n",
 
502
                e->e_dn, ocname->bv_val, 0 );
 
503
 
 
504
 
 
505
        /* check for empty oc_required */
 
506
        if(oc->soc_required == NULL) {
 
507
                return NULL;
 
508
        }
 
509
 
 
510
        /* for each required attribute */
 
511
        for ( i = 0; oc->soc_required[i] != NULL; i++ ) {
 
512
                at = oc->soc_required[i];
 
513
                /* see if it's in the entry */
 
514
                for ( a = e->e_attrs; a != NULL; a = a->a_next ) {
 
515
                        if( a->a_desc->ad_type == at ) {
 
516
                                break;
 
517
                        }
 
518
                }
 
519
                /* not there => schema violation */
 
520
                if ( a == NULL ) {
 
521
                        return at->sat_cname.bv_val;
 
522
                }
 
523
        }
 
524
 
 
525
        return( NULL );
 
526
}
 
527
 
 
528
int oc_check_allowed(
 
529
        AttributeType *at,
 
530
        ObjectClass **socs,
 
531
        ObjectClass *sc )
 
532
{
 
533
        int             i, j;
 
534
 
 
535
        Debug( LDAP_DEBUG_TRACE,
 
536
                "oc_check_allowed type \"%s\"\n",
 
537
                at->sat_cname.bv_val, 0, 0 );
 
538
 
 
539
        /* always allow objectClass attribute */
 
540
        if ( strcasecmp( at->sat_cname.bv_val, "objectClass" ) == 0 ) {
 
541
                return LDAP_SUCCESS;
 
542
        }
 
543
 
 
544
        /*
 
545
         * All operational attributions are allowed by schema rules.
 
546
         */
 
547
        if( is_at_operational(at) ) {
 
548
                return LDAP_SUCCESS;
 
549
        }
 
550
 
 
551
        /* check to see if its allowed by the structuralObjectClass */
 
552
        if( sc ) {
 
553
                /* does it require the type? */
 
554
                for ( j = 0; sc->soc_required != NULL && 
 
555
                        sc->soc_required[j] != NULL; j++ )
 
556
                {
 
557
                        if( at == sc->soc_required[j] ) {
 
558
                                return LDAP_SUCCESS;
 
559
                        }
 
560
                }
 
561
 
 
562
                /* does it allow the type? */
 
563
                for ( j = 0; sc->soc_allowed != NULL && 
 
564
                        sc->soc_allowed[j] != NULL; j++ )
 
565
                {
 
566
                        if( at == sc->soc_allowed[j] ) {
 
567
                                return LDAP_SUCCESS;
 
568
                        }
 
569
                }
 
570
        }
 
571
 
 
572
        /* check that the type appears as req or opt in at least one oc */
 
573
        for ( i = 0; socs[i]; i++ ) {
 
574
                /* if we know about the oc */
 
575
                ObjectClass     *oc = socs[i];
 
576
                /* extensibleObject allows all */
 
577
                if ( oc == slap_schema.si_oc_extensibleObject ) {
 
578
                        return LDAP_SUCCESS;
 
579
                }
 
580
                if ( oc != NULL && oc->soc_kind != LDAP_SCHEMA_ABSTRACT &&
 
581
                        ( sc == NULL || oc->soc_kind == LDAP_SCHEMA_AUXILIARY ))
 
582
                {
 
583
                        /* does it require the type? */
 
584
                        for ( j = 0; oc->soc_required != NULL && 
 
585
                                oc->soc_required[j] != NULL; j++ )
 
586
                        {
 
587
                                if( at == oc->soc_required[j] ) {
 
588
                                        return LDAP_SUCCESS;
 
589
                                }
 
590
                        }
 
591
                        /* does it allow the type? */
 
592
                        for ( j = 0; oc->soc_allowed != NULL && 
 
593
                                oc->soc_allowed[j] != NULL; j++ )
 
594
                        {
 
595
                                if( at == oc->soc_allowed[j] ) {
 
596
                                        return LDAP_SUCCESS;
 
597
                                }
 
598
                        }
 
599
                }
 
600
        }
 
601
 
 
602
        /* not allowed by any oc */
 
603
        return LDAP_OBJECT_CLASS_VIOLATION;
 
604
}
 
605
 
 
606
/*
 
607
 * Determine the structural object class from a set of OIDs
 
608
 */
 
609
int structural_class(
 
610
        BerVarray ocs,
 
611
        ObjectClass **scp,
 
612
        ObjectClass ***socsp,
 
613
        const char **text,
 
614
        char *textbuf, size_t textlen,
 
615
        void *ctx )
 
616
{
 
617
        int i, nocs;
 
618
        ObjectClass *oc, **socs;
 
619
        ObjectClass *sc = NULL;
 
620
        int scn = -1;
 
621
 
 
622
        *text = "structural_class: internal error";
 
623
 
 
624
        /* count them */
 
625
        for( i=0; ocs[i].bv_val; i++ ) ;
 
626
        nocs = i;
 
627
        
 
628
        socs = slap_sl_malloc( (nocs+1) * sizeof(ObjectClass *), ctx );
 
629
 
 
630
        for( i=0; ocs[i].bv_val; i++ ) {
 
631
                socs[i] = oc_bvfind( &ocs[i] );
 
632
 
 
633
                if( socs[i] == NULL ) {
 
634
                        snprintf( textbuf, textlen,
 
635
                                "unrecognized objectClass '%s'",
 
636
                                ocs[i].bv_val );
 
637
                        *text = textbuf;
 
638
                        goto fail;
 
639
                }
 
640
        }
 
641
        socs[i] = NULL;
 
642
 
 
643
        for( i=0; ocs[i].bv_val; i++ ) {
 
644
                oc = socs[i];
 
645
                if( oc->soc_kind == LDAP_SCHEMA_STRUCTURAL ) {
 
646
                        if( sc == NULL || is_object_subclass( sc, oc ) ) {
 
647
                                sc = oc;
 
648
                                scn = i;
 
649
 
 
650
                        } else if ( !is_object_subclass( oc, sc ) ) {
 
651
                                int j;
 
652
                                ObjectClass *xc = NULL;
 
653
 
 
654
                                /* find common superior */
 
655
                                for( j=i+1; ocs[j].bv_val; j++ ) {
 
656
                                        xc = socs[j];
 
657
 
 
658
                                        if( xc == NULL ) {
 
659
                                                snprintf( textbuf, textlen,
 
660
                                                        "unrecognized objectClass '%s'",
 
661
                                                        ocs[j].bv_val );
 
662
                                                *text = textbuf;
 
663
                                                goto fail;
 
664
                                        }
 
665
 
 
666
                                        if( xc->soc_kind != LDAP_SCHEMA_STRUCTURAL ) {
 
667
                                                xc = NULL;
 
668
                                                continue;
 
669
                                        }
 
670
 
 
671
                                        if( is_object_subclass( sc, xc ) &&
 
672
                                                is_object_subclass( oc, xc ) )
 
673
                                        {
 
674
                                                /* found common subclass */
 
675
                                                break;
 
676
                                        }
 
677
 
 
678
                                        xc = NULL;
 
679
                                }
 
680
 
 
681
                                if( xc == NULL ) {
 
682
                                        /* no common subclass */
 
683
                                        snprintf( textbuf, textlen,
 
684
                                                "invalid structural object class chain (%s/%s)",
 
685
                                                ocs[scn].bv_val, ocs[i].bv_val );
 
686
                                        *text = textbuf;
 
687
                                        goto fail;
 
688
                                }
 
689
                        }
 
690
                }
 
691
        }
 
692
 
 
693
        if( scp ) {
 
694
                *scp = sc;
 
695
        }
 
696
 
 
697
        if( sc == NULL ) {
 
698
                *text = "no structural object class provided";
 
699
                goto fail;
 
700
        }
 
701
 
 
702
        if( scn < 0 ) {
 
703
                *text = "invalid structural object class";
 
704
                goto fail;
 
705
        }
 
706
 
 
707
        if ( socsp ) {
 
708
                *socsp = socs;
 
709
        } else {
 
710
                slap_sl_free( socs, ctx );
 
711
        }
 
712
        *text = NULL;
 
713
 
 
714
        return LDAP_SUCCESS;
 
715
 
 
716
fail:
 
717
        slap_sl_free( socs, ctx );
 
718
        return LDAP_OBJECT_CLASS_VIOLATION;
 
719
}
 
720
 
 
721
/*
 
722
 * Return structural object class from list of modifications
 
723
 */
 
724
int mods_structural_class(
 
725
        Modifications *mods,
 
726
        struct berval *sc,
 
727
        const char **text,
 
728
        char *textbuf, size_t textlen, void *ctx )
 
729
{
 
730
        Modifications *ocmod = NULL;
 
731
        ObjectClass *ssc;
 
732
        int rc;
 
733
 
 
734
        for( ; mods != NULL; mods = mods->sml_next ) {
 
735
                if( mods->sml_desc == slap_schema.si_ad_objectClass ) {
 
736
                        if( ocmod != NULL ) {
 
737
                                *text = "entry has multiple objectClass attributes";
 
738
                                return LDAP_OBJECT_CLASS_VIOLATION;
 
739
                        }
 
740
                        ocmod = mods;
 
741
                }
 
742
        }
 
743
 
 
744
        if( ocmod == NULL ) {
 
745
                *text = "entry has no objectClass attribute";
 
746
                return LDAP_OBJECT_CLASS_VIOLATION;
 
747
        }
 
748
 
 
749
        if( ocmod->sml_values == NULL || ocmod->sml_values[0].bv_val == NULL ) {
 
750
                *text = "objectClass attribute has no values";
 
751
                return LDAP_OBJECT_CLASS_VIOLATION;
 
752
        }
 
753
 
 
754
        rc = structural_class( ocmod->sml_values, &ssc, NULL,
 
755
                text, textbuf, textlen, ctx );
 
756
        if ( rc == LDAP_SUCCESS )
 
757
                *sc = ssc->soc_cname;
 
758
        return rc;
 
759
}
 
760
 
 
761
 
 
762
static int
 
763
entry_naming_check(
 
764
        Entry *e,
 
765
        int manage,
 
766
        int add_naming,
 
767
        const char** text,
 
768
        char *textbuf, size_t textlen )
 
769
{
 
770
        /* naming check */
 
771
        LDAPRDN         rdn = NULL;
 
772
        const char      *p = NULL;
 
773
        ber_len_t       cnt;
 
774
        int             rc = LDAP_SUCCESS;
 
775
 
 
776
        if ( BER_BVISEMPTY( &e->e_name )) {
 
777
                return LDAP_SUCCESS;
 
778
        }
 
779
 
 
780
        /*
 
781
         * Get attribute type(s) and attribute value(s) of our RDN
 
782
         */
 
783
        if ( ldap_bv2rdn( &e->e_name, &rdn, (char **)&p,
 
784
                LDAP_DN_FORMAT_LDAP ) )
 
785
        {
 
786
                *text = "unrecongized attribute type(s) in RDN";
 
787
                return LDAP_INVALID_DN_SYNTAX;
 
788
        }
 
789
 
 
790
        /* Check that each AVA of the RDN is present in the entry */
 
791
        /* FIXME: Should also check that each AVA lists a distinct type */
 
792
        for ( cnt = 0; rdn[cnt]; cnt++ ) {
 
793
                LDAPAVA *ava = rdn[cnt];
 
794
                AttributeDescription *desc = NULL;
 
795
                Attribute *attr;
 
796
                const char *errtext;
 
797
                int add = 0;
 
798
 
 
799
                if( ava->la_flags & LDAP_AVA_BINARY ) {
 
800
                        snprintf( textbuf, textlen, 
 
801
                                "value of naming attribute '%s' in unsupported BER form",
 
802
                                ava->la_attr.bv_val );
 
803
                        rc = LDAP_NAMING_VIOLATION;
 
804
                }
 
805
 
 
806
                rc = slap_bv2ad( &ava->la_attr, &desc, &errtext );
 
807
                if ( rc != LDAP_SUCCESS ) {
 
808
                        snprintf( textbuf, textlen, "%s (in RDN)", errtext );
 
809
                        break;
 
810
                }
 
811
 
 
812
                if( desc->ad_type->sat_usage ) {
 
813
                        snprintf( textbuf, textlen, 
 
814
                                "naming attribute '%s' is operational",
 
815
                                ava->la_attr.bv_val );
 
816
                        rc = LDAP_NAMING_VIOLATION;
 
817
                        break;
 
818
                }
 
819
 
 
820
                if( desc->ad_type->sat_collective ) {
 
821
                        snprintf( textbuf, textlen, 
 
822
                                "naming attribute '%s' is collective",
 
823
                                ava->la_attr.bv_val );
 
824
                        rc = LDAP_NAMING_VIOLATION;
 
825
                        break;
 
826
                }
 
827
 
 
828
                if( !manage && desc->ad_type->sat_obsolete ) {
 
829
                        snprintf( textbuf, textlen, 
 
830
                                "naming attribute '%s' is obsolete",
 
831
                                ava->la_attr.bv_val );
 
832
                        rc = LDAP_NAMING_VIOLATION;
 
833
                        break;
 
834
                }
 
835
 
 
836
                if( !desc->ad_type->sat_equality ) {
 
837
                        snprintf( textbuf, textlen, 
 
838
                                "naming attribute '%s' has no equality matching rule",
 
839
                                ava->la_attr.bv_val );
 
840
                        rc = LDAP_NAMING_VIOLATION;
 
841
                        break;
 
842
                }
 
843
 
 
844
                if( !desc->ad_type->sat_equality->smr_match ) {
 
845
                        snprintf( textbuf, textlen, 
 
846
                                "naming attribute '%s' has unsupported equality matching rule",
 
847
                                ava->la_attr.bv_val );
 
848
                        rc = LDAP_NAMING_VIOLATION;
 
849
                        break;
 
850
                }
 
851
 
 
852
                /* find the naming attribute */
 
853
                attr = attr_find( e->e_attrs, desc );
 
854
                if ( attr == NULL ) {
 
855
                        snprintf( textbuf, textlen, 
 
856
                                "naming attribute '%s' is not present in entry",
 
857
                                ava->la_attr.bv_val );
 
858
                        if ( add_naming ) {
 
859
                                add = 1;
 
860
 
 
861
                        } else {
 
862
                                rc = LDAP_NAMING_VIOLATION;
 
863
                        }
 
864
 
 
865
                } else {
 
866
                        rc = attr_valfind( attr, SLAP_MR_VALUE_OF_ASSERTION_SYNTAX|
 
867
                                SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH,
 
868
                                &ava->la_value, NULL, NULL );
 
869
 
 
870
                        if( rc != 0 ) {
 
871
                                switch( rc ) {
 
872
                                case LDAP_INAPPROPRIATE_MATCHING:
 
873
                                        snprintf( textbuf, textlen, 
 
874
                                                "inappropriate matching for naming attribute '%s'",
 
875
                                                ava->la_attr.bv_val );
 
876
                                        break;
 
877
                                case LDAP_INVALID_SYNTAX:
 
878
                                        snprintf( textbuf, textlen, 
 
879
                                                "value of naming attribute '%s' is invalid",
 
880
                                                ava->la_attr.bv_val );
 
881
                                        break;
 
882
                                case LDAP_NO_SUCH_ATTRIBUTE:
 
883
                                        snprintf( textbuf, textlen, 
 
884
                                                "value of naming attribute '%s' is not present in entry",
 
885
                                                ava->la_attr.bv_val );
 
886
                                        if ( add_naming ) {
 
887
                                                add = 1;
 
888
                                        }
 
889
                                        break;
 
890
                                default:
 
891
                                        snprintf( textbuf, textlen, 
 
892
                                                "naming attribute '%s' is inappropriate",
 
893
                                                ava->la_attr.bv_val );
 
894
                                }
 
895
                                rc = LDAP_NAMING_VIOLATION;
 
896
                        }
 
897
                }
 
898
 
 
899
                if ( add ) {
 
900
                        attr_merge_normalize_one( e, desc, &ava->la_value, NULL );
 
901
 
 
902
                } else if ( rc != LDAP_SUCCESS ) {
 
903
                        break;
 
904
                }
 
905
        }
 
906
 
 
907
        ldap_rdnfree( rdn );
 
908
        return rc;
 
909
}
 
910