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