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