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