]> git.sur5r.net Git - openldap/blob - servers/slapd/schemaparse.c
3f65bc41edac37afd10f8be36bbb898660216a76
[openldap] / servers / slapd / schemaparse.c
1 /* schemaparse.c - routines to parse config file objectclass definitions */
2 /*
3  * Copyright 1998-1999 The OpenLDAP Foundation, All Rights Reserved.
4  * COPYING RESTRICTIONS APPLY, see COPYRIGHT file
5  */
6
7 #include "portable.h"
8
9 #include <stdio.h>
10
11 #include <ac/ctype.h>
12 #include <ac/string.h>
13 #include <ac/socket.h>
14
15 #include "slap.h"
16 #include "ldap_schema.h"
17
18 static Avlnode          *object_classes = NULL;
19
20 int     global_schemacheck = 1; /* schemacheck on is default */
21
22 static void             oc_usage_old(void) LDAP_GCCATTR((noreturn));
23 static void             oc_usage(void)     LDAP_GCCATTR((noreturn));
24 static void             at_usage(void)     LDAP_GCCATTR((noreturn));
25
26 static char *err2text[] = {
27         "",
28         "Out of memory",
29         "Objectclass not found",
30         "Attribute type not found",
31         "Duplicate objectclass",
32         "Duplicate attributetype",
33         "Duplicate syntax",
34         "Duplicate matchingrule",
35         "OID or name required",
36         "Syntax or superior required",
37         "Matchingrule not found",
38         "Syntax not found",
39         "Syntax required"
40 };
41
42 char *
43 scherr2str(int code)
44 {
45         if ( code < 1 || code >= (sizeof(err2text)/sizeof(char *)) ) {
46                 return "Unknown error";
47         } else {
48                 return err2text[code];
49         }
50 }
51
52 void
53 parse_oc_old(
54     Backend     *be,
55     const char  *fname,
56     int         lineno,
57     int         argc,
58     char        **argv
59 )
60 {
61         int             i;
62         char            last;
63         LDAP_OBJECT_CLASS       *oc;
64         int             code;
65         const char      *err;
66         char            **namep;
67
68         oc = (LDAP_OBJECT_CLASS *) ch_calloc( 1, sizeof(LDAP_OBJECT_CLASS) );
69         oc->oc_names = ch_calloc( 2, sizeof(char *) );
70         oc->oc_names[0] = ch_strdup( argv[1] );
71         oc->oc_names[1] = NULL;
72         if ( strcasecmp( oc->oc_names[0], "top" ) ) {
73                 oc->oc_kind = LDAP_SCHEMA_STRUCTURAL;
74         }
75         for ( i = 2; i < argc; i++ ) {
76                 /* required attributes */
77                 if ( strcasecmp( argv[i], "requires" ) == 0 ) {
78                         do {
79                                 i++;
80                                 if ( i < argc ) {
81                                         char **s = str2charray( argv[i], "," );
82                                         last = argv[i][strlen( argv[i] ) - 1];
83                                         charray_merge( &oc->oc_at_oids_must, s );
84                                         charray_free( s );
85                                 }
86                         } while ( i < argc && last == ',' );
87
88                 /* optional attributes */
89                 } else if ( strcasecmp( argv[i], "allows" ) == 0 ) {
90                         do {
91                                 i++;
92                                 if ( i < argc ) {
93                                         char **s = str2charray( argv[i], "," );
94                                         last = argv[i][strlen( argv[i] ) - 1];
95                                         
96                                         charray_merge( &oc->oc_at_oids_may, s );
97                                         charray_free( s );
98                                 }
99                         } while ( i < argc && last == ',' );
100
101                 } else {
102                         fprintf( stderr,
103             "%s: line %d: expecting \"requires\" or \"allows\" got \"%s\"\n",
104                             fname, lineno, argv[i] );
105                         oc_usage_old();
106                 }
107         }
108
109         /*
110          * There was no requirement in the old schema that all attributes
111          * types were defined before use and they would just default to
112          * SYNTAX_CIS.  To support this, we need to make attribute types
113          * out of thin air.
114          */
115         if ( oc->oc_at_oids_must ) {
116                 namep = oc->oc_at_oids_must;
117                 while ( *namep ) {
118                         code = at_fake_if_needed( *namep );
119                         if ( code ) {
120                                 fprintf( stderr, "%s: line %d: %s %s\n",
121                                          fname, lineno, scherr2str(code), *namep);
122                                 exit( EXIT_FAILURE );
123                         }
124                         namep++;
125                 }
126         }
127         if ( oc->oc_at_oids_may ) {
128                 namep = oc->oc_at_oids_may;
129                 while ( *namep ) {
130                         code = at_fake_if_needed( *namep );
131                         if ( code ) {
132                                 fprintf( stderr, "%s: line %d: %s %s\n",
133                                          fname, lineno, scherr2str(code), *namep);
134                                 exit( EXIT_FAILURE );
135                         }
136                         namep++;
137                 }
138         }
139         
140         code = oc_add(oc,&err);
141         if ( code ) {
142                 fprintf( stderr, "%s: line %d: %s %s\n",
143                          fname, lineno, scherr2str(code), err);
144                 exit( EXIT_FAILURE );
145         }
146         ldap_memfree(oc);
147 }
148
149 /* OID Macros */
150
151 /* String compare with delimiter check. Return 0 if not
152  * matched, otherwise return length matched.
153  */
154 int
155 dscompare(const char *s1, const char *s2, char delim)
156 {
157         const char *orig = s1;
158         while (*s1++ == *s2++)
159                 if (!s1[-1]) break;
160         --s1;
161         --s2;
162         if (!*s1 && (!*s2 || *s2 == delim))
163                 return s1 - orig;
164         return 0;
165 }
166
167 static OidMacro *om_list = NULL;
168
169 /* Replace an OID Macro invocation with its full numeric OID.
170  * If the macro is used with "macroname:suffix" append ".suffix"
171  * to the expansion.
172  */
173 static char *
174 find_oidm(char *oid)
175 {
176         OidMacro *om;
177         char *new;
178         int pos, suflen;
179
180         /* OID macros must start alpha */
181         if ( !isdigit( *oid ) )
182         {
183             for (om = om_list; om; om=om->next)
184             {
185                 if ((pos = dscompare(om->name, oid, ':')))
186                 {
187                         suflen = strlen(oid + pos);
188                         new = ch_calloc(1, om->oidlen + suflen + 1);
189                         strcpy(new, om->oid);
190                         if (suflen)
191                         {
192                                 suflen = om->oidlen;
193                                 new[suflen++] = '.';
194                                 strcpy(new+suflen, oid+pos+1);
195                         }
196                         return new;
197                 }
198             }
199             return NULL;
200         }
201         return oid;
202 }
203
204 void
205 parse_oidm(
206     const char  *fname,
207     int         lineno,
208     int         argc,
209     char        **argv
210 )
211 {
212         OidMacro *om;
213
214         if (argc != 3)
215         {
216 usage:          fprintf( stderr, "ObjectIdentifier <name> <oid>\n");
217                 exit( EXIT_FAILURE );
218         }
219         om = (OidMacro *) ch_malloc( sizeof(OidMacro) );
220         om->name = ch_strdup( argv[1] );
221         om->oid = find_oidm( argv[2] );
222         if (!om->oid)
223         {
224                 fprintf( stderr, "%s: line %d: OID %s not recognized\n",
225                         fname, lineno, argv[2] );
226                 goto usage;
227         }
228         if (om->oid == argv[2])
229                 om->oid = ch_strdup( argv[2] );
230         om->oidlen = strlen( om->oid );
231         om->next = om_list;
232         om_list = om;
233 }
234
235 void
236 parse_oc(
237     const char  *fname,
238     int         lineno,
239     char        *line,
240     char        **argv
241 )
242 {
243         LDAP_OBJECT_CLASS *oc;
244         int             code;
245         const char      *err;
246         char            *oid = NULL;
247
248         /* Kludge for OIDmacros. If the numericOid field starts nonnumeric
249          * look for and expand a macro. The macro's place in the input line
250          * will be replaced with a field of '0's to keep ldap_str2objectclass
251          * happy. The actual oid will be swapped into place afterward.
252          */
253         if ( !isdigit( *argv[2] ))
254         {
255                 oid = find_oidm(argv[2]);
256                 if (!oid)
257                 {
258                         fprintf(stderr, "%s: line %d: OID %s not recognized\n",
259                                 fname, lineno, argv[2]);
260                         exit( EXIT_FAILURE );
261                 }
262                 if (oid != argv[2])
263                         memset(strstr(line, argv[2]), '0', strlen(argv[2]));
264                 else
265                         oid = NULL;
266         }
267         oc = ldap_str2objectclass(line,&code,&err);
268         if ( !oc ) {
269                 fprintf( stderr, "%s: line %d: %s before %s\n",
270                          fname, lineno, ldap_scherr2str(code), err );
271                 oc_usage();
272         }
273         if (oid)
274         {
275                 ldap_memfree(oc->oc_oid);
276                 oc->oc_oid = oid;
277         }
278         code = oc_add(oc,&err);
279         if ( code ) {
280                 fprintf( stderr, "%s: line %d: %s %s\n",
281                          fname, lineno, scherr2str(code), err);
282                 exit( EXIT_FAILURE );
283         }
284         ldap_memfree(oc);
285 }
286
287 static void
288 oc_usage( void )
289 {
290         fprintf( stderr, "ObjectClassDescription = \"(\" whsp\n");
291         fprintf( stderr, "  numericoid whsp      ; ObjectClass identifier\n");
292         fprintf( stderr, "  [ \"NAME\" qdescrs ]\n");
293         fprintf( stderr, "  [ \"DESC\" qdstring ]\n");
294         fprintf( stderr, "  [ \"OBSOLETE\" whsp ]\n");
295         fprintf( stderr, "  [ \"SUP\" oids ]       ; Superior ObjectClasses\n");
296         fprintf( stderr, "  [ ( \"ABSTRACT\" / \"STRUCTURAL\" / \"AUXILIARY\" ) whsp ]\n");
297         fprintf( stderr, "                       ; default structural\n");
298         fprintf( stderr, "  [ \"MUST\" oids ]      ; AttributeTypes\n");
299         fprintf( stderr, "  [ \"MAY\" oids ]       ; AttributeTypes\n");
300         fprintf( stderr, "whsp \")\"\n");
301         exit( EXIT_FAILURE );
302 }
303
304 static void
305 oc_usage_old( void )
306 {
307         fprintf( stderr, "<oc clause> ::= objectclass <ocname>\n" );
308         fprintf( stderr, "                [ requires <attrlist> ]\n" );
309         fprintf( stderr, "                [ allows <attrlist> ]\n" );
310         exit( EXIT_FAILURE );
311 }
312
313 static void
314 at_usage( void )
315 {
316         fprintf( stderr, "AttributeTypeDescription = \"(\" whsp\n");
317         fprintf( stderr, "  numericoid whsp      ; AttributeType identifier\n");
318         fprintf( stderr, "  [ \"NAME\" qdescrs ]             ; name used in AttributeType\n");
319         fprintf( stderr, "  [ \"DESC\" qdstring ]            ; description\n");
320         fprintf( stderr, "  [ \"OBSOLETE\" whsp ]\n");
321         fprintf( stderr, "  [ \"SUP\" woid ]                 ; derived from this other\n");
322         fprintf( stderr, "                                 ; AttributeType\n");
323         fprintf( stderr, "  [ \"EQUALITY\" woid ]            ; Matching Rule name\n");
324         fprintf( stderr, "  [ \"ORDERING\" woid ]            ; Matching Rule name\n");
325         fprintf( stderr, "  [ \"SUBSTR\" woid ]              ; Matching Rule name\n");
326         fprintf( stderr, "  [ \"SYNTAX\" whsp noidlen whsp ] ; see section 4.3\n");
327         fprintf( stderr, "  [ \"SINGLE-VALUE\" whsp ]        ; default multi-valued\n");
328         fprintf( stderr, "  [ \"COLLECTIVE\" whsp ]          ; default not collective\n");
329         fprintf( stderr, "  [ \"NO-USER-MODIFICATION\" whsp ]; default user modifiable\n");
330         fprintf( stderr, "  [ \"USAGE\" whsp AttributeUsage ]; default userApplications\n");
331         fprintf( stderr, "                                 ; userApplications\n");
332         fprintf( stderr, "                                 ; directoryOperation\n");
333         fprintf( stderr, "                                 ; distributedOperation\n");
334         fprintf( stderr, "                                 ; dSAOperation\n");
335         fprintf( stderr, "whsp \")\"\n");
336         exit( EXIT_FAILURE );
337 }
338
339 void
340 parse_at(
341     const char  *fname,
342     int         lineno,
343     char        *line,
344     char        **argv
345 )
346 {
347         LDAP_ATTRIBUTE_TYPE *at;
348         int             code;
349         const char      *err;
350         char            *oid = NULL;
351         char            *soid = NULL;
352
353         /* Kludge for OIDmacros. If the numericOid field starts nonnumeric
354          * look for and expand a macro. The macro's place in the input line
355          * will be replaced with a field of '0's to keep ldap_str2attr
356          * happy. The actual oid will be swapped into place afterward.
357          */
358         if ( !isdigit( *argv[2] ))
359         {
360                 oid = find_oidm(argv[2]);
361                 if (!oid)
362                 {
363                         fprintf(stderr, "%s: line %d: OID %s not recognized\n",
364                                 fname, lineno, argv[2]);
365                         exit( EXIT_FAILURE );
366                 }
367                 if (oid != argv[2])
368                         memset(strstr(line, argv[2]), '0', strlen(argv[2]));
369                 else
370                         oid = NULL;
371         }
372         for (; argv[3]; argv++)
373         {
374                 if (!strcasecmp(argv[3], "syntax") &&
375                     !isdigit(*argv[4]))
376                 {
377                         int slen;
378                         Syntax *syn;
379                         syn = syn_find_desc(argv[4], &slen);
380                         if (!syn)
381                         {
382                             fprintf(stderr, "%s: line %d: OID %s not found\n",
383                                 fname, lineno, argv[4]);
384                             exit( EXIT_FAILURE );
385                         }
386                         memset(strstr(line, argv[4]), '0', slen);
387                         soid = ch_strdup(syn->ssyn_syn.syn_oid );
388                         break;
389                 }
390         }
391         at = ldap_str2attributetype(line,&code,&err);
392         if ( !at ) {
393                 fprintf( stderr, "%s: line %d: %s before %s\n",
394                          fname, lineno, ldap_scherr2str(code), err );
395                 at_usage();
396         }
397         if (oid)
398         {
399                 ldap_memfree(at->at_oid);
400                 at->at_oid = oid;
401         }
402         if (soid)
403         {
404                 ldap_memfree(at->at_syntax_oid);
405                 at->at_syntax_oid = soid;
406         }
407         code = at_add(at,&err);
408         if ( code ) {
409                 fprintf( stderr, "%s: line %d: %s %s\n",
410                          fname, lineno, scherr2str(code), err);
411                 exit( EXIT_FAILURE );
412         }
413         ldap_memfree(at);
414 }