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