]> git.sur5r.net Git - openldap/blob - servers/slapd/schema.c
b14680fda0677ef931d0fac47ca717d0c5f10576
[openldap] / servers / slapd / schema.c
1 /* schema.c - routines to enforce schema definitions */
2 /*
3  * Copyright 1998-1999 The OpenLDAP Foundation, All Rights Reserved.
4  * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
5  */
6
7 #include "portable.h"
8
9 #include <stdio.h>
10
11 #include <ac/ctype.h>
12 #include <ac/string.h>
13 #include <ac/socket.h>
14
15 #include "ldap_defaults.h"
16 #include "slap.h"
17
18 static char *   oc_check_required(Entry *e, char *ocname);
19 static int              oc_check_allowed(char *type, struct berval **ocl);
20
21
22 /*
23  * oc_check - check that entry e conforms to the schema required by
24  * its object class(es). returns 0 if so, non-zero otherwise.
25  */
26
27 int
28 oc_schema_check( Entry *e )
29 {
30         Attribute       *a, *aoc;
31         int             i;
32         int             ret = 0;
33
34         /* find the object class attribute - could error out here */
35         if ( (aoc = attr_find( e->e_attrs, "objectclass" )) == NULL ) {
36                 Debug( LDAP_DEBUG_ANY, "No object class for entry (%s)\n",
37                     e->e_dn, 0, 0 );
38                 return( 1 );
39         }
40
41         /* check that the entry has required attrs for each oc */
42         for ( i = 0; aoc->a_vals[i] != NULL; i++ ) {
43                 char *s = oc_check_required( e, aoc->a_vals[i]->bv_val );
44
45                 if (s != NULL) {
46                         Debug( LDAP_DEBUG_ANY,
47                             "Entry (%s), oc \"%s\" requires attr \"%s\"\n",
48                             e->e_dn, aoc->a_vals[i]->bv_val, s );
49                         ret = 1;
50                 }
51         }
52
53         if ( ret != 0 ) {
54             return( ret );
55         }
56
57         /* check that each attr in the entry is allowed by some oc */
58         for ( a = e->e_attrs; a != NULL; a = a->a_next ) {
59                 if ( oc_check_allowed( a->a_type, aoc->a_vals ) != 0 ) {
60                         Debug( LDAP_DEBUG_ANY,
61                             "Entry (%s), attr \"%s\" not allowed\n",
62                             e->e_dn, a->a_type, 0 );
63                         ret = 1;
64                 }
65         }
66
67         return( ret );
68 }
69
70 static char *
71 oc_check_required( Entry *e, char *ocname )
72 {
73         ObjectClass     *oc;
74         AttributeType   *at;
75         int             i;
76         Attribute       *a;
77         char            **pp;
78
79         Debug( LDAP_DEBUG_TRACE,
80                "oc_check_required entry (%s), objectclass \"%s\"\n",
81                e->e_dn, ocname, 0 );
82
83         /* find global oc defn. it we don't know about it assume it's ok */
84         if ( (oc = oc_find( ocname )) == NULL ) {
85                 return( 0 );
86         }
87
88         /* check for empty oc_required */
89         if(oc->soc_required == NULL) {
90                 return( 0 );
91         }
92
93         /* for each required attribute */
94         for ( i = 0; oc->soc_required[i] != NULL; i++ ) {
95                 at = oc->soc_required[i];
96                 /* see if it's in the entry */
97                 for ( a = e->e_attrs; a != NULL; a = a->a_next ) {
98                         if ( at->sat_oid &&
99                              strcmp( a->a_type, at->sat_oid ) == 0 ) {
100                                 break;
101                         }
102                         pp = at->sat_names;
103                         if ( pp  == NULL ) {
104                                 /* Empty name list => not found */
105                                 a = NULL;
106                                 break;
107                         }
108                         while ( *pp ) {
109                                 if ( strcasecmp( a->a_type, *pp ) == 0 ) {
110                                         break;
111                                 }
112                                 pp++;
113                         }
114                         if ( *pp ) {
115                                 break;
116                         }
117                 }
118                 /* not there => schema violation */
119                 if ( a == NULL ) {
120                         if ( at->sat_names && at->sat_names[0] ) {
121                                 return at->sat_names[0];
122                         } else {
123                                 return at->sat_oid;
124                         }
125                 }
126         }
127
128         return( NULL );
129 }
130
131 static char *oc_usermod_attrs[] = {
132         /*
133          * OpenLDAP doesn't support any user modification of
134          * operational attributes.
135          */
136         NULL
137 };
138
139 static char *oc_operational_attrs[] = {
140         /*
141          * these are operational attributes 
142          * most could be user modifiable
143          */
144         "objectClasses",
145         "attributeTypes",
146         "matchingRules",
147         "matchingRuleUse",
148         "dITStructureRules",
149         "dITContentRules",
150         "nameForms",
151         "ldapSyntaxes",
152         "namingContexts",
153         "supportedExtension",
154         "supportedControl",
155         "supportedSASLMechanisms",
156         "supportedLDAPversion",
157         "subschemaSubentry",            /* NO USER MOD */
158         NULL
159
160 };
161
162 /* this list should be extensible  */
163 static char *oc_no_usermod_attrs[] = {
164         /*
165          * Operational and 'no user modification' attributes
166          * which are STORED in the directory server.
167          */
168
169         /* RFC2252, 3.2.1 */
170         "creatorsName",
171         "createTimestamp",
172         "modifiersName",
173         "modifyTimestamp",
174
175         NULL
176 };
177
178
179 /*
180  * check to see if attribute is 'operational' or not.
181  */
182 int
183 oc_check_operational_attr( char *type )
184 {
185         return charray_inlist( oc_operational_attrs, type )
186                 || charray_inlist( oc_usermod_attrs, type )
187                 || charray_inlist( oc_no_usermod_attrs, type );
188 }
189
190 /*
191  * check to see if attribute can be user modified or not.
192  */
193 int
194 oc_check_usermod_attr( char *type )
195 {
196         return charray_inlist( oc_usermod_attrs, type );
197 }
198
199 /*
200  * check to see if attribute is 'no user modification' or not.
201  */
202 int
203 oc_check_no_usermod_attr( char *type )
204 {
205         return charray_inlist( oc_no_usermod_attrs, type );
206 }
207
208
209 static int
210 oc_check_allowed( char *type, struct berval **ocl )
211 {
212         ObjectClass     *oc;
213         AttributeType   *at;
214         int             i, j;
215         char            **pp;
216
217         Debug( LDAP_DEBUG_TRACE,
218                "oc_check_allowed type \"%s\"\n", type, 0, 0 );
219
220         /* always allow objectclass attribute */
221         if ( strcasecmp( type, "objectclass" ) == 0 ) {
222                 return( 0 );
223         }
224
225         /*
226          * All operational attributions are allowed by schema rules.
227          * However, we only check attributions which are stored in the
228          * the directory regardless if they are user or non-user modified.
229          */
230         if ( oc_check_usermod_attr( type ) || oc_check_no_usermod_attr( type ) ) {
231                 return( 0 );
232         }
233
234         /* check that the type appears as req or opt in at least one oc */
235         for ( i = 0; ocl[i] != NULL; i++ ) {
236                 /* if we know about the oc */
237                 if ( (oc = oc_find( ocl[i]->bv_val )) != NULL ) {
238                         /* does it require the type? */
239                         for ( j = 0; oc->soc_required != NULL && 
240                                 oc->soc_required[j] != NULL; j++ ) {
241                                 at = oc->soc_required[j];
242                                 if ( at->sat_oid &&
243                                      strcmp(at->sat_oid, type ) == 0 ) {
244                                         return( 0 );
245                                 }
246                                 pp = at->sat_names;
247                                 if ( pp == NULL )
248                                         continue;
249                                 while ( *pp ) {
250                                         if ( strcasecmp( *pp, type ) == 0 ) {
251                                                 return( 0 );
252                                         }
253                                         pp++;
254                                 }
255                         }
256                         /* does it allow the type? */
257                         for ( j = 0; oc->soc_allowed != NULL && 
258                                 oc->soc_allowed[j] != NULL; j++ ) {
259                                 at = oc->soc_allowed[j];
260                                 if ( at->sat_oid &&
261                                      strcmp(at->sat_oid, type ) == 0 ) {
262                                         return( 0 );
263                                 }
264                                 pp = at->sat_names;
265                                 if ( pp == NULL )
266                                         continue;
267                                 while ( *pp ) {
268                                         if ( strcasecmp( *pp, type ) == 0 ||
269                                              strcmp( *pp, "*" ) == 0 ) {
270                                                 return( 0 );
271                                         }
272                                         pp++;
273                                 }
274                         }
275                         /* maybe the next oc allows it */
276
277                 /* we don't know about the oc. assume it allows it */
278                 } else {
279                         return( 0 );
280                 }
281         }
282
283         /* not allowed by any oc */
284         return( 1 );
285 }
286
287 struct oindexrec {
288         char            *oir_name;
289         ObjectClass     *oir_oc;
290 };
291
292 static Avlnode  *oc_index = NULL;
293 static ObjectClass *oc_list = NULL;
294
295 static int
296 oc_index_cmp(
297     struct oindexrec    *oir1,
298     struct oindexrec    *oir2
299 )
300 {
301         return (strcasecmp( oir1->oir_name, oir2->oir_name ));
302 }
303
304 static int
305 oc_index_name_cmp(
306     char                *name,
307     struct oindexrec    *oir
308 )
309 {
310         return (strcasecmp( name, oir->oir_name ));
311 }
312
313 ObjectClass *
314 oc_find( const char *ocname )
315 {
316         struct oindexrec        *oir = NULL;
317
318         if ( (oir = (struct oindexrec *) avl_find( oc_index, ocname,
319             (AVL_CMP) oc_index_name_cmp )) != NULL ) {
320                 return( oir->oir_oc );
321         }
322         return( NULL );
323 }
324
325 static int
326 oc_create_required(
327     ObjectClass         *soc,
328     char                **attrs,
329     const char          **err
330 )
331 {
332         char            **attrs1;
333         AttributeType   *sat;
334         AttributeType   **satp;
335         int             i;
336
337         if ( attrs ) {
338                 attrs1 = attrs;
339                 while ( *attrs1 ) {
340                         sat = at_find(*attrs1);
341                         if ( !sat ) {
342                                 *err = *attrs1;
343                                 return SLAP_SCHERR_ATTR_NOT_FOUND;
344                         }
345                         if ( at_find_in_list(sat, soc->soc_required) < 0) {
346                                 if ( at_append_to_list(sat, &soc->soc_required) ) {
347                                         *err = *attrs1;
348                                         return SLAP_SCHERR_OUTOFMEM;
349                                 }
350                         }
351                         attrs1++;
352                 }
353                 /* Now delete duplicates from the allowed list */
354                 for ( satp = soc->soc_required; *satp; satp++ ) {
355                         i = at_find_in_list(*satp,soc->soc_allowed);
356                         if ( i >= 0 ) {
357                                 at_delete_from_list(i, &soc->soc_allowed);
358                         }
359                 }
360         }
361         return 0;
362 }
363
364 static int
365 oc_create_allowed(
366     ObjectClass         *soc,
367     char                **attrs,
368     const char          **err
369 )
370 {
371         char            **attrs1;
372         AttributeType   *sat;
373
374         if ( attrs ) {
375                 attrs1 = attrs;
376                 while ( *attrs1 ) {
377                         sat = at_find(*attrs1);
378                         if ( !sat ) {
379                                 *err = *attrs1;
380                                 return SLAP_SCHERR_ATTR_NOT_FOUND;
381                         }
382                         if ( at_find_in_list(sat, soc->soc_required) < 0 &&
383                              at_find_in_list(sat, soc->soc_allowed) < 0 ) {
384                                 if ( at_append_to_list(sat, &soc->soc_allowed) ) {
385                                         *err = *attrs1;
386                                         return SLAP_SCHERR_OUTOFMEM;
387                                 }
388                         }
389                         attrs1++;
390                 }
391         }
392         return 0;
393 }
394
395 static int
396 oc_add_sups(
397     ObjectClass         *soc,
398     char                **sups,
399     const char          **err
400 )
401 {
402         int             code;
403         ObjectClass     *soc1;
404         int             nsups;
405         char            **sups1;
406         int             add_sups = 0;
407
408         if ( sups ) {
409                 if ( !soc->soc_sups ) {
410                         /* We are at the first recursive level */
411                         add_sups = 1;
412                         nsups = 0;
413                         sups1 = sups;
414                         while ( *sups1 ) {
415                                 nsups++;
416                                 sups1++;
417                         }
418                         nsups++;
419                         soc->soc_sups = (ObjectClass **)ch_calloc(1,
420                                           nsups*sizeof(ObjectClass *));
421                 }
422                 nsups = 0;
423                 sups1 = sups;
424                 while ( *sups1 ) {
425                         soc1 = oc_find(*sups1);
426                         if ( !soc1 ) {
427                                 *err = *sups1;
428                                 return SLAP_SCHERR_CLASS_NOT_FOUND;
429                         }
430
431                         if ( add_sups )
432                                 soc->soc_sups[nsups] = soc1;
433
434                         code = oc_add_sups(soc,soc1->soc_sup_oids, err);
435                         if ( code )
436                                 return code;
437                         
438                         if ( code = oc_create_required(soc,
439                                 soc1->soc_at_oids_must,err) )
440                                 return code;
441                         if ( code = oc_create_allowed(soc,
442                                 soc1->soc_at_oids_may,err) )
443                                 return code;
444                         nsups++;
445                         sups1++;
446                 }
447         }
448         return 0;
449 }
450
451 static int
452 oc_insert(
453     ObjectClass         *soc,
454     const char          **err
455 )
456 {
457         ObjectClass     **ocp;
458         struct oindexrec        *oir;
459         char                    **names;
460
461         ocp = &oc_list;
462         while ( *ocp != NULL ) {
463                 ocp = &(*ocp)->soc_next;
464         }
465         *ocp = soc;
466
467         if ( soc->soc_oid ) {
468                 oir = (struct oindexrec *)
469                         ch_calloc( 1, sizeof(struct oindexrec) );
470                 oir->oir_name = soc->soc_oid;
471                 oir->oir_oc = soc;
472                 if ( avl_insert( &oc_index, (caddr_t) oir,
473                                  (AVL_CMP) oc_index_cmp,
474                                  (AVL_DUP) avl_dup_error ) ) {
475                         *err = soc->soc_oid;
476                         ldap_memfree(oir);
477                         return SLAP_SCHERR_DUP_CLASS;
478                 }
479                 /* FIX: temporal consistency check */
480                 oc_find(oir->oir_name);
481         }
482         if ( (names = soc->soc_names) ) {
483                 while ( *names ) {
484                         oir = (struct oindexrec *)
485                                 ch_calloc( 1, sizeof(struct oindexrec) );
486                         oir->oir_name = ch_strdup(*names);
487                         oir->oir_oc = soc;
488                         if ( avl_insert( &oc_index, (caddr_t) oir,
489                                          (AVL_CMP) oc_index_cmp,
490                                          (AVL_DUP) avl_dup_error ) ) {
491                                 *err = *names;
492                                 ldap_memfree(oir);
493                                 return SLAP_SCHERR_DUP_CLASS;
494                         }
495                         /* FIX: temporal consistency check */
496                         oc_find(oir->oir_name);
497                         names++;
498                 }
499         }
500         return 0;
501 }
502
503 int
504 oc_add(
505     LDAP_OBJECT_CLASS   *oc,
506     const char          **err
507 )
508 {
509         ObjectClass     *soc;
510         int             code;
511
512         soc = (ObjectClass *) ch_calloc( 1, sizeof(ObjectClass) );
513         memcpy( &soc->soc_oclass, oc, sizeof(LDAP_OBJECT_CLASS));
514         if ( code = oc_add_sups(soc,soc->soc_sup_oids,err) )
515                 return code;
516         if ( code = oc_create_required(soc,soc->soc_at_oids_must,err) )
517                 return code;
518         if ( code = oc_create_allowed(soc,soc->soc_at_oids_may,err) )
519                 return code;
520         code = oc_insert(soc,err);
521         return code;
522 }
523
524 struct sindexrec {
525         char            *sir_name;
526         Syntax          *sir_syn;
527 };
528
529 static Avlnode  *syn_index = NULL;
530 static Syntax *syn_list = NULL;
531
532 static int
533 syn_index_cmp(
534     struct sindexrec    *sir1,
535     struct sindexrec    *sir2
536 )
537 {
538         return (strcmp( sir1->sir_name, sir2->sir_name ));
539 }
540
541 static int
542 syn_index_name_cmp(
543     char                *name,
544     struct sindexrec    *sir
545 )
546 {
547         return (strcmp( name, sir->sir_name ));
548 }
549
550 Syntax *
551 syn_find( const char *synname )
552 {
553         struct sindexrec        *sir = NULL;
554
555         if ( (sir = (struct sindexrec *) avl_find( syn_index, synname,
556             (AVL_CMP) syn_index_name_cmp )) != NULL ) {
557                 return( sir->sir_syn );
558         }
559         return( NULL );
560 }
561
562 Syntax *
563 syn_find_desc( const char *syndesc, int *len )
564 {
565         Syntax          *synp;
566
567         for (synp = syn_list; synp; synp = synp->ssyn_next)
568                 if ((*len = dscompare( synp->ssyn_syn.syn_desc, (char *)syndesc, '{')))
569                         return synp;
570         return( NULL );
571 }
572
573 static int
574 syn_insert(
575     Syntax              *ssyn,
576     const char          **err
577 )
578 {
579         Syntax          **synp;
580         struct sindexrec        *sir;
581
582         synp = &syn_list;
583         while ( *synp != NULL ) {
584                 synp = &(*synp)->ssyn_next;
585         }
586         *synp = ssyn;
587
588         if ( ssyn->ssyn_oid ) {
589                 sir = (struct sindexrec *)
590                         ch_calloc( 1, sizeof(struct sindexrec) );
591                 sir->sir_name = ssyn->ssyn_oid;
592                 sir->sir_syn = ssyn;
593                 if ( avl_insert( &syn_index, (caddr_t) sir,
594                                  (AVL_CMP) syn_index_cmp,
595                                  (AVL_DUP) avl_dup_error ) ) {
596                         *err = ssyn->ssyn_oid;
597                         ldap_memfree(sir);
598                         return SLAP_SCHERR_DUP_SYNTAX;
599                 }
600                 /* FIX: temporal consistency check */
601                 syn_find(sir->sir_name);
602         }
603         return 0;
604 }
605
606 int
607 syn_add(
608     LDAP_SYNTAX         *syn,
609     slap_syntax_check_func      *check,
610     const char          **err
611 )
612 {
613         Syntax          *ssyn;
614         int             code;
615
616         ssyn = (Syntax *) ch_calloc( 1, sizeof(Syntax) );
617         memcpy( &ssyn->ssyn_syn, syn, sizeof(LDAP_SYNTAX));
618         ssyn->ssyn_check = check;
619         code = syn_insert(ssyn,err);
620         return code;
621 }
622
623 struct mindexrec {
624         char            *mir_name;
625         MatchingRule    *mir_mr;
626 };
627
628 static Avlnode  *mr_index = NULL;
629 static MatchingRule *mr_list = NULL;
630
631 static int
632 mr_index_cmp(
633     struct mindexrec    *mir1,
634     struct mindexrec    *mir2
635 )
636 {
637         return (strcmp( mir1->mir_name, mir2->mir_name ));
638 }
639
640 static int
641 mr_index_name_cmp(
642     char                *name,
643     struct mindexrec    *mir
644 )
645 {
646         return (strcmp( name, mir->mir_name ));
647 }
648
649 MatchingRule *
650 mr_find( const char *mrname )
651 {
652         struct mindexrec        *mir = NULL;
653
654         if ( (mir = (struct mindexrec *) avl_find( mr_index, mrname,
655             (AVL_CMP) mr_index_name_cmp )) != NULL ) {
656                 return( mir->mir_mr );
657         }
658         return( NULL );
659 }
660
661 static int
662 mr_insert(
663     MatchingRule        *smr,
664     const char          **err
665 )
666 {
667         MatchingRule            **mrp;
668         struct mindexrec        *mir;
669         char                    **names;
670
671         mrp = &mr_list;
672         while ( *mrp != NULL ) {
673                 mrp = &(*mrp)->smr_next;
674         }
675         *mrp = smr;
676
677         if ( smr->smr_oid ) {
678                 mir = (struct mindexrec *)
679                         ch_calloc( 1, sizeof(struct mindexrec) );
680                 mir->mir_name = smr->smr_oid;
681                 mir->mir_mr = smr;
682                 if ( avl_insert( &mr_index, (caddr_t) mir,
683                                  (AVL_CMP) mr_index_cmp,
684                                  (AVL_DUP) avl_dup_error ) ) {
685                         *err = smr->smr_oid;
686                         ldap_memfree(mir);
687                         return SLAP_SCHERR_DUP_RULE;
688                 }
689                 /* FIX: temporal consistency check */
690                 mr_find(mir->mir_name);
691         }
692         if ( (names = smr->smr_names) ) {
693                 while ( *names ) {
694                         mir = (struct mindexrec *)
695                                 ch_calloc( 1, sizeof(struct mindexrec) );
696                         mir->mir_name = ch_strdup(*names);
697                         mir->mir_mr = smr;
698                         if ( avl_insert( &mr_index, (caddr_t) mir,
699                                          (AVL_CMP) mr_index_cmp,
700                                          (AVL_DUP) avl_dup_error ) ) {
701                                 *err = *names;
702                                 ldap_memfree(mir);
703                                 return SLAP_SCHERR_DUP_RULE;
704                         }
705                         /* FIX: temporal consistency check */
706                         mr_find(mir->mir_name);
707                         names++;
708                 }
709         }
710         return 0;
711 }
712
713 int
714 mr_add(
715     LDAP_MATCHING_RULE          *mr,
716     slap_mr_normalize_func      *normalize,
717     slap_mr_compare_func        *compare,
718     const char          **err
719 )
720 {
721         MatchingRule    *smr;
722         Syntax          *syn;
723         int             code;
724
725         smr = (MatchingRule *) ch_calloc( 1, sizeof(MatchingRule) );
726         memcpy( &smr->smr_mrule, mr, sizeof(LDAP_MATCHING_RULE));
727         smr->smr_normalize = normalize;
728         smr->smr_compare = compare;
729         if ( smr->smr_syntax_oid ) {
730                 if ( (syn = syn_find(smr->smr_syntax_oid)) ) {
731                         smr->smr_syntax = syn;
732                 } else {
733                         *err = smr->smr_syntax_oid;
734                         return SLAP_SCHERR_SYN_NOT_FOUND;
735                 }
736         } else {
737                 *err = "";
738                 return SLAP_SCHERR_MR_INCOMPLETE;
739         }
740         code = mr_insert(smr,err);
741         return code;
742 }
743
744 static int
745 case_exact_normalize(
746         struct berval *val,
747         struct berval **normalized
748 )
749 {
750         struct berval *newval;
751         char *p, *q;
752
753         newval = ber_bvdup( val );
754         p = q = newval->bv_val;
755         /* Ignore initial whitespace */
756         while ( isspace( *p++ ) )
757                 ;
758         while ( *p ) {
759                 if ( isspace( *p ) ) {
760                         *q++ = *p++;
761                         /* Ignore the extra whitespace */
762                         while ( isspace(*p++) )
763                                 ;
764                 } else {
765                         *q++ = *p++;
766                 }
767         }
768         /*
769          * If the string ended in space, backup the pointer one
770          * position.  One is enough because the above loop collapsed
771          * all whitespace to a single space.
772          */
773         if ( p != newval->bv_val && isspace( *(p-1) ) ) {
774                 *(q-1) = '\0';
775         }
776         newval->bv_len = strlen( newval->bv_val );
777         normalized = &newval;
778
779         return 0;
780 }
781
782 static int
783 case_exact_compare(
784         struct berval *val1,
785         struct berval *val2
786 )
787 {
788         return strcmp( val1->bv_val, val2->bv_val );
789 }
790
791 int
792 case_ignore_normalize(
793         struct berval *val,
794         struct berval **normalized
795 )
796 {
797         struct berval *newval;
798         char *p, *q;
799
800         newval = ber_bvdup( val );
801         p = q = newval->bv_val;
802         /* Ignore initial whitespace */
803         while ( isspace( *p++ ) )
804                 ;
805         while ( *p ) {
806                 if ( isspace( *p ) ) {
807                         *q++ = *p++;
808                         /* Ignore the extra whitespace */
809                         while ( isspace(*p++) )
810                                 ;
811                 } else {
812                         *q++ = TOUPPER( *p++ );
813                 }
814         }
815         /*
816          * If the string ended in space, backup the pointer one
817          * position.  One is enough because the above loop collapsed
818          * all whitespace to a single space.
819          */
820         if ( p != newval->bv_val && isspace( *(p-1) ) ) {
821                 *(q-1) = '\0';
822         }
823         newval->bv_len = strlen( newval->bv_val );
824         normalized = &newval;
825
826         return 0;
827 }
828
829 static int
830 case_ignore_compare(
831         struct berval *val1,
832         struct berval *val2
833 )
834 {
835         return strcasecmp( val1->bv_val, val2->bv_val );
836 }
837
838 int
839 register_syntax(
840         char * desc,
841         slap_syntax_check_func *check )
842 {
843         LDAP_SYNTAX     *syn;
844         int             code;
845         const char      *err;
846
847         syn = ldap_str2syntax( desc, &code, &err);
848         if ( !syn ) {
849                 Debug( LDAP_DEBUG_ANY, "Error in register_syntax: %s before %s in %s\n",
850                     ldap_scherr2str(code), err, desc );
851                 return( -1 );
852         }
853         code = syn_add( syn, check, &err );
854         if ( code ) {
855                 Debug( LDAP_DEBUG_ANY, "Error in register_syntax: %s %s in %s\n",
856                     scherr2str(code), err, desc );
857                 return( -1 );
858         }
859         return( 0 );
860 }
861
862 int
863 register_matching_rule(
864         char * desc,
865         slap_mr_normalize_func *normalize,
866         slap_mr_compare_func *compare )
867 {
868         LDAP_MATCHING_RULE *mr;
869         int             code;
870         const char      *err;
871
872         mr = ldap_str2matchingrule( desc, &code, &err);
873         if ( !mr ) {
874                 Debug( LDAP_DEBUG_ANY, "Error in register_matching_rule: %s before %s in %s\n",
875                     ldap_scherr2str(code), err, desc );
876                 return( -1 );
877         }
878         code = mr_add( mr, normalize, compare, &err );
879         if ( code ) {
880                 Debug( LDAP_DEBUG_ANY, "Error in register_syntax: %s for %s in %s\n",
881                     scherr2str(code), err, desc );
882                 return( -1 );
883         }
884         return( 0 );
885 }
886
887 struct syntax_defs_rec {
888         char *sd_desc;
889         slap_syntax_check_func *sd_check;
890 };
891
892 struct syntax_defs_rec syntax_defs[] = {
893         {"( 1.3.6.1.4.1.1466.115.121.1.3 DESC 'AttributeTypeDescription' )", NULL},
894         {"( 1.3.6.1.4.1.1466.115.121.1.4 DESC 'Audio' )", NULL},
895         {"( 1.3.6.1.4.1.1466.115.121.1.5 DESC 'Binary' )", NULL},
896         {"( 1.3.6.1.4.1.1466.115.121.1.6 DESC 'BitString' )", NULL},
897         {"( 1.3.6.1.4.1.1466.115.121.1.8 DESC 'Certificate' )", NULL},
898         {"( 1.3.6.1.4.1.1466.115.121.1.9 DESC 'CertificateList' )", NULL},
899         {"( 1.3.6.1.4.1.1466.115.121.1.10 DESC 'CertificatePair' )", NULL},
900         {"( 1.3.6.1.4.1.1466.115.121.1.12 DESC 'DN' )", NULL},
901         {"( 1.3.6.1.4.1.1466.115.121.1.14 DESC 'DeliveryMethod' )", NULL},
902         {"( 1.3.6.1.4.1.1466.115.121.1.15 DESC 'DirectoryString' )", NULL},
903         {"( 1.3.6.1.4.1.1466.115.121.1.16 DESC 'DITContentRuleDescription' )", NULL},
904         {"( 1.3.6.1.4.1.1466.115.121.1.17 DESC 'DITStructureRuleDescription' )", NULL},
905         {"( 1.3.6.1.4.1.1466.115.121.1.21 DESC 'EnhancedGuide' )", NULL},
906         {"( 1.3.6.1.4.1.1466.115.121.1.22 DESC 'FacsimileTelephoneNumber' )", NULL},
907         {"( 1.3.6.1.4.1.1466.115.121.1.24 DESC 'GeneralizedTime' )", NULL},
908         {"( 1.3.6.1.4.1.1466.115.121.1.25 DESC 'Guide' )", NULL},
909         {"( 1.3.6.1.4.1.1466.115.121.1.26 DESC 'IA5String' )", NULL},
910         {"( 1.3.6.1.4.1.1466.115.121.1.27 DESC 'Integer' )", NULL},
911         {"( 1.3.6.1.4.1.1466.115.121.1.30 DESC 'MatchingRuleDescription' )", NULL},
912         {"( 1.3.6.1.4.1.1466.115.121.1.31 DESC 'MatchingRuleUseDescription' )", NULL},
913         {"( 1.3.6.1.4.1.1466.115.121.1.32 DESC 'MailPreference' )", NULL},
914         {"( 1.3.6.1.4.1.1466.115.121.1.34 DESC 'NameAndOptionalUID' )", NULL},
915         {"( 1.3.6.1.4.1.1466.115.121.1.35 DESC 'NameFormDescription' )", NULL},
916         {"( 1.3.6.1.4.1.1466.115.121.1.36 DESC 'NumericString' )", NULL},
917         {"( 1.3.6.1.4.1.1466.115.121.1.37 DESC 'ObjectClassDescription' )", NULL},
918         {"( 1.3.6.1.4.1.1466.115.121.1.38 DESC 'OID' )", NULL},
919         {"( 1.3.6.1.4.1.1466.115.121.1.39 DESC 'OtherMailbox' )", NULL},
920         {"( 1.3.6.1.4.1.1466.115.121.1.40 DESC 'OctetString' )", NULL},
921         {"( 1.3.6.1.4.1.1466.115.121.1.41 DESC 'PostalAddress' )", NULL},
922         {"( 1.3.6.1.4.1.1466.115.121.1.42 DESC 'ProtocolInformation' )", NULL},
923         {"( 1.3.6.1.4.1.1466.115.121.1.43 DESC 'PresentationAddress' )", NULL},
924         {"( 1.3.6.1.4.1.1466.115.121.1.44 DESC 'PrintableString' )", NULL},
925         {"( 1.3.6.1.4.1.1466.115.121.1.49 DESC 'SupportedAlgorithm' )", NULL},
926         {"( 1.3.6.1.4.1.1466.115.121.1.50 DESC 'TelephoneNumber' )", NULL},
927         {"( 1.3.6.1.4.1.1466.115.121.1.51 DESC 'TeletexTerminalIdentifier' )", NULL},
928         {"( 1.3.6.1.4.1.1466.115.121.1.52 DESC 'TelexNumber' )", NULL},
929         {"( 1.3.6.1.4.1.1466.115.121.1.53 DESC 'UTCTime' )", NULL},
930         {"( 1.3.6.1.4.1.1466.115.121.1.54 DESC 'LDAPSyntaxDescription' )", NULL},
931         {"( 1.3.6.1.4.1.1466.115.121.1.58 DESC 'SubstringAssertion' )", NULL},
932         {"( 1.3.6.1.1.1.0.0 DESC 'NISnetgrouptriple' )", NULL},
933         {"( 1.3.6.1.1.1.0.1 DESC 'Bootparameter' )", NULL},
934         {NULL, NULL}
935 };
936
937 struct mrule_defs_rec {
938         char *mrd_desc;
939         slap_mr_normalize_func *mrd_normalize;
940         slap_mr_compare_func *mrd_compare;
941 };
942
943 /*
944  * Other matching rules in X.520 that we do not use:
945  *
946  * 2.5.13.9     numericStringOrderingMatch
947  * 2.5.13.12    caseIgnoreListSubstringsMatch
948  * 2.5.13.13    booleanMatch
949  * 2.5.13.15    integerOrderingMatch
950  * 2.5.13.18    octetStringOrderingMatch
951  * 2.5.13.19    octetStringSubstringsMatch
952  * 2.5.13.25    uTCTimeMatch
953  * 2.5.13.26    uTCTimeOrderingMatch
954  * 2.5.13.31    directoryStringFirstComponentMatch
955  * 2.5.13.32    wordMatch
956  * 2.5.13.33    keywordMatch
957  * 2.5.13.34    certificateExactMatch
958  * 2.5.13.35    certificateMatch
959  * 2.5.13.36    certificatePairExactMatch
960  * 2.5.13.37    certificatePairMatch
961  * 2.5.13.38    certificateListExactMatch
962  * 2.5.13.39    certificateListMatch
963  * 2.5.13.40    algorithmIdentifierMatch
964  * 2.5.13.41    storedPrefixMatch
965  * 2.5.13.42    attributeCertificateMatch
966  * 2.5.13.43    readerAndKeyIDMatch
967  * 2.5.13.44    attributeIntegrityMatch
968  */
969
970 struct mrule_defs_rec mrule_defs[] = {
971         {"( 2.5.13.0 NAME 'objectIdentifierMatch' SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 )", NULL, NULL},
972         {"( 2.5.13.1 NAME 'distinguishedNameMatch' SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 )", NULL, NULL},
973         {"( 2.5.13.2 NAME 'caseIgnoreMatch' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
974          case_ignore_normalize, case_ignore_compare},
975         {"( 2.5.13.3 NAME 'caseIgnoreOrderingMatch' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
976          case_ignore_normalize, case_ignore_compare},
977         {"( 2.5.13.4 NAME 'caseIgnoreSubstringsMatch' SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )",
978          case_ignore_normalize, case_ignore_compare},
979         /* Next three are not in the RFC's, but are needed for compatibility */
980         {"( 2.5.13.5 NAME 'caseExactMatch' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
981          case_exact_normalize, case_exact_compare},
982         {"( 2.5.13.6 NAME 'caseExactOrderingMatch' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )",
983          case_exact_normalize, case_exact_compare},
984         {"( 2.5.13.7 NAME 'caseExactSubstringsMatch' SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )",
985          case_exact_normalize, case_exact_compare},
986         {"( 2.5.13.8 NAME 'numericStringMatch' SYNTAX 1.3.6.1.4.1.1466.115.121.1.36 )", NULL, NULL},
987         {"( 2.5.13.10 NAME 'numericStringSubstringsMatch' SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )", NULL, NULL},
988         {"( 2.5.13.11 NAME 'caseIgnoreListMatch' SYNTAX 1.3.6.1.4.1.1466.115.121.1.41 )", NULL, NULL},
989         {"( 2.5.13.14 NAME 'integerMatch' SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )", NULL, NULL},
990         {"( 2.5.13.16 NAME 'bitStringMatch' SYNTAX 1.3.6.1.4.1.1466.115.121.1.6 )", NULL, NULL},
991         {"( 2.5.13.17 NAME 'octetStringMatch' SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 )", NULL, NULL},
992         {"( 2.5.13.20 NAME 'telephoneNumberMatch' SYNTAX 1.3.6.1.4.1.1466.115.121.1.50 )", NULL, NULL},
993         {"( 2.5.13.21 NAME 'telephoneNumberSubstringsMatch' SYNTAX 1.3.6.1.4.1.1466.115.121.1.58 )", NULL, NULL},
994         {"( 2.5.13.22 NAME 'presentationAddressMatch' SYNTAX 1.3.6.1.4.1.1466.115.121.1.43 )", NULL, NULL},
995         {"( 2.5.13.23 NAME 'uniqueMemberMatch' SYNTAX 1.3.6.1.4.1.1466.115.121.1.34 )", NULL, NULL},
996         {"( 2.5.13.24 NAME 'protocolInformationMatch' SYNTAX 1.3.6.1.4.1.1466.115.121.1.42 )", NULL, NULL},
997         {"( 2.5.13.27 NAME 'generalizedTimeMatch' SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 )", NULL, NULL},
998         {"( 2.5.13.28 NAME 'generalizedTimeOrderingMatch' SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 )", NULL, NULL},
999         {"( 2.5.13.29 NAME 'integerFirstComponentMatch' SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 )", NULL, NULL},
1000         {"( 2.5.13.30 NAME 'objectIdentifierFirstComponentMatch' SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 )", NULL, NULL},
1001         {"( 1.3.6.1.4.1.1466.109.114.1 NAME 'caseExactIA5Match' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
1002          case_exact_normalize, case_exact_compare},
1003         {"( 1.3.6.1.4.1.1466.109.114.2 NAME 'caseIgnoreIA5Match' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 )",
1004          case_ignore_normalize, case_ignore_compare},
1005         {NULL, NULL, NULL}
1006 };
1007
1008 int
1009 schema_init( void )
1010 {
1011         int             res;
1012         int             i;
1013         static int      schema_init_done = 0;
1014
1015         /* We are called from read_config that is recursive */
1016         if ( schema_init_done )
1017                 return( 0 );
1018         for ( i=0; syntax_defs[i].sd_desc != NULL; i++ ) {
1019                 res = register_syntax( syntax_defs[i].sd_desc,
1020                     syntax_defs[i].sd_check );
1021                 if ( res ) {
1022                         fprintf( stderr, "schema_init: Error registering syntax %s\n",
1023                                  syntax_defs[i].sd_desc );
1024                         exit( EXIT_FAILURE );
1025                 }
1026         }
1027         for ( i=0; mrule_defs[i].mrd_desc != NULL; i++ ) {
1028                 res = register_matching_rule( mrule_defs[i].mrd_desc,
1029                     ( mrule_defs[i].mrd_normalize ?
1030                       mrule_defs[i].mrd_normalize : case_ignore_normalize ),
1031                     ( mrule_defs[i].mrd_compare ?
1032                       mrule_defs[i].mrd_compare : case_ignore_compare ) );
1033                 if ( res ) {
1034                         fprintf( stderr, "schema_init: Error registering matching rule %s\n",
1035                                  mrule_defs[i].mrd_desc );
1036                         exit( EXIT_FAILURE );
1037                 }
1038         }
1039         schema_init_done = 1;
1040         return( 0 );
1041 }
1042
1043 #if defined( SLAPD_SCHEMA_DN )
1044
1045 static int
1046 syn_schema_info( Entry *e )
1047 {
1048         struct berval   val;
1049         struct berval   *vals[2];
1050         Syntax          *syn;
1051
1052         vals[0] = &val;
1053         vals[1] = NULL;
1054
1055         for ( syn = syn_list; syn; syn = syn->ssyn_next ) {
1056                 val.bv_val = ldap_syntax2str( &syn->ssyn_syn );
1057                 if ( val.bv_val ) {
1058                         val.bv_len = strlen( val.bv_val );
1059                         Debug( LDAP_DEBUG_TRACE, "Merging syn [%d] %s\n",
1060                                val.bv_len, val.bv_val, 0 );
1061                         attr_merge( e, "ldapSyntaxes", vals );
1062                         ldap_memfree( val.bv_val );
1063                 } else {
1064                         return -1;
1065                 }
1066         }
1067         return 0;
1068 }
1069
1070 static int
1071 mr_schema_info( Entry *e )
1072 {
1073         struct berval   val;
1074         struct berval   *vals[2];
1075         MatchingRule    *mr;
1076
1077         vals[0] = &val;
1078         vals[1] = NULL;
1079
1080         for ( mr = mr_list; mr; mr = mr->smr_next ) {
1081                 val.bv_val = ldap_matchingrule2str( &mr->smr_mrule );
1082                 if ( val.bv_val ) {
1083                         val.bv_len = strlen( val.bv_val );
1084                         Debug( LDAP_DEBUG_TRACE, "Merging mr [%d] %s\n",
1085                                val.bv_len, val.bv_val, 0 );
1086                         attr_merge( e, "matchingRules", vals );
1087                         ldap_memfree( val.bv_val );
1088                 } else {
1089                         return -1;
1090                 }
1091         }
1092         return 0;
1093 }
1094
1095 static int
1096 oc_schema_info( Entry *e )
1097 {
1098         struct berval   val;
1099         struct berval   *vals[2];
1100         ObjectClass     *oc;
1101
1102         vals[0] = &val;
1103         vals[1] = NULL;
1104
1105         for ( oc = oc_list; oc; oc = oc->soc_next ) {
1106                 val.bv_val = ldap_objectclass2str( &oc->soc_oclass );
1107                 if ( val.bv_val ) {
1108                         val.bv_len = strlen( val.bv_val );
1109                         Debug( LDAP_DEBUG_TRACE, "Merging oc [%d] %s\n",
1110                                val.bv_len, val.bv_val, 0 );
1111                         attr_merge( e, "objectClasses", vals );
1112                         ldap_memfree( val.bv_val );
1113                 } else {
1114                         return -1;
1115                 }
1116         }
1117         return 0;
1118 }
1119
1120 void
1121 schema_info( Connection *conn, Operation *op, char **attrs, int attrsonly )
1122 {
1123         Entry           *e;
1124         struct berval   val;
1125         struct berval   *vals[2];
1126
1127         vals[0] = &val;
1128         vals[1] = NULL;
1129
1130         e = (Entry *) ch_calloc( 1, sizeof(Entry) );
1131
1132         e->e_attrs = NULL;
1133         e->e_dn = ch_strdup( SLAPD_SCHEMA_DN );
1134         e->e_ndn = ch_strdup( SLAPD_SCHEMA_DN );
1135         (void) dn_normalize_case( e->e_ndn );
1136         e->e_private = NULL;
1137
1138         {
1139                 char *rdn = ch_strdup( SLAPD_SCHEMA_DN );
1140                 val.bv_val = strchr( rdn, '=' );
1141
1142                 if( val.bv_val != NULL ) {
1143                         *val.bv_val = '\0';
1144                         val.bv_len = strlen( ++val.bv_val );
1145
1146                         attr_merge( e, rdn, vals );
1147                 }
1148
1149                 free( rdn );
1150         }
1151
1152         if ( syn_schema_info( e ) ) {
1153                 /* Out of memory, do something about it */
1154                 entry_free( e );
1155                 return;
1156         }
1157         if ( mr_schema_info( e ) ) {
1158                 /* Out of memory, do something about it */
1159                 entry_free( e );
1160                 return;
1161         }
1162         if ( at_schema_info( e ) ) {
1163                 /* Out of memory, do something about it */
1164                 entry_free( e );
1165                 return;
1166         }
1167         if ( oc_schema_info( e ) ) {
1168                 /* Out of memory, do something about it */
1169                 entry_free( e );
1170                 return;
1171         }
1172         
1173         val.bv_val = "top";
1174         val.bv_len = sizeof("top")-1;
1175         attr_merge( e, "objectClass", vals );
1176
1177         val.bv_val = "LDAPsubentry";
1178         val.bv_len = sizeof("LDAPsubentry")-1;
1179         attr_merge( e, "objectClass", vals );
1180
1181         val.bv_val = "subschema";
1182         val.bv_len = sizeof("subschema")-1;
1183         attr_merge( e, "objectClass", vals );
1184
1185         val.bv_val = "extensibleObject";
1186         val.bv_len = sizeof("extensibleObject")-1;
1187         attr_merge( e, "objectClass", vals );
1188
1189         send_search_entry( &backends[0], conn, op,
1190                 e, attrs, attrsonly, NULL );
1191         send_search_result( conn, op, LDAP_SUCCESS,
1192                 NULL, NULL, NULL, NULL, 1 );
1193
1194         entry_free( e );
1195 }
1196 #endif
1197
1198 #ifdef LDAP_DEBUG
1199
1200 static void
1201 oc_print( ObjectClass *oc )
1202 {
1203         int     i;
1204         const char *mid;
1205
1206         printf( "objectclass %s\n", ldap_objectclass2name( &oc->soc_oclass ) );
1207         if ( oc->soc_required != NULL ) {
1208                 mid = "\trequires ";
1209                 for ( i = 0; oc->soc_required[i] != NULL; i++, mid = "," )
1210                         printf( "%s%s", mid,
1211                                 ldap_attributetype2name( &oc->soc_required[i]->sat_atype ) );
1212                 printf( "\n" );
1213         }
1214         if ( oc->soc_allowed != NULL ) {
1215                 mid = "\tallows ";
1216                 for ( i = 0; oc->soc_allowed[i] != NULL; i++, mid = "," )
1217                         printf( "%s%s", mid,
1218                                 ldap_attributetype2name( &oc->soc_allowed[i]->sat_atype ) );
1219                 printf( "\n" );
1220         }
1221 }
1222
1223 #endif
1224
1225
1226 int is_entry_objectclass(
1227         Entry*  e,
1228         char*   oc)
1229 {
1230         Attribute *attr;
1231         struct berval bv;
1232
1233         if( e == NULL || oc == NULL || *oc == '\0' )
1234                 return 0;
1235
1236         /*
1237          * find objectClass attribute
1238          */
1239         attr = attr_find(e->e_attrs, "objectclass");
1240
1241         if( attr == NULL ) {
1242                 /* no objectClass attribute */
1243                 return 0;
1244         }
1245
1246         bv.bv_val = oc;
1247         bv.bv_len = strlen( bv.bv_val );
1248
1249         if( value_find(attr->a_vals, &bv, attr->a_syntax, 1) != 0) {
1250                 /* entry is not of this objectclass */
1251                 return 0;
1252         }
1253
1254         return 1;
1255 }