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