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