]> git.sur5r.net Git - openldap/blob - servers/slapd/schemaparse.c
48249d3f75f484cc5cf5008bc7eb182bedacc63c
[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 #ifdef SLAPD_SCHEMA_COMPAT
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
73         if ( strcasecmp( oc->oc_names[0], "top" ) ) {
74                 /*
75                  * no way to distinguish "auxiliary" from "structural"
76                  * This may lead to future problems.
77                  */
78                 oc->oc_kind = LDAP_SCHEMA_STRUCTURAL;
79         }
80         for ( i = 2; i < argc; i++ ) {
81                 /* required attributes */
82                 if ( strcasecmp( argv[i], "requires" ) == 0 ) {
83                         do {
84                                 i++;
85                                 if ( i < argc ) {
86                                         char **s = str2charray( argv[i], "," );
87                                         last = argv[i][strlen( argv[i] ) - 1];
88                                         charray_merge( &oc->oc_at_oids_must, s );
89                                         charray_free( s );
90                                 }
91                         } while ( i < argc && last == ',' );
92
93                 /* optional attributes */
94                 } else if ( strcasecmp( argv[i], "allows" ) == 0 ) {
95                         do {
96                                 i++;
97                                 if ( i < argc ) {
98                                         char **s = str2charray( argv[i], "," );
99                                         last = argv[i][strlen( argv[i] ) - 1];
100                                         
101                                         charray_merge( &oc->oc_at_oids_may, s );
102                                         charray_free( s );
103                                 }
104                         } while ( i < argc && last == ',' );
105
106                 } else {
107                         fprintf( stderr,
108             "%s: line %d: expecting \"requires\" or \"allows\" got \"%s\"\n",
109                             fname, lineno, argv[i] );
110                         oc_usage_old();
111                 }
112         }
113
114         /*
115          * There was no requirement in the old schema that all attributes
116          * types were defined before use and they would just default to
117          * SYNTAX_CIS.  To support this, we need to make attribute types
118          * out of thin air.
119          */
120         if ( oc->oc_at_oids_must ) {
121                 for( namep = oc->oc_at_oids_must; *namep ; 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                 }
129         }
130         if ( oc->oc_at_oids_may ) {
131                 for( namep = oc->oc_at_oids_may; *namep; namep++ ) {
132                         code = at_fake_if_needed( *namep );
133                         if ( code ) {
134                                 fprintf( stderr, "%s: line %d: %s %s\n",
135                                          fname, lineno, scherr2str(code), *namep);
136                                 exit( EXIT_FAILURE );
137                         }
138                 }
139         }
140         
141         code = oc_add(oc,&err);
142         if ( code ) {
143                 fprintf( stderr, "%s: line %d: %s %s\n",
144                          fname, lineno, scherr2str(code), err);
145                 exit( EXIT_FAILURE );
146         }
147         ldap_memfree(oc);
148
149 #else
150         fprintf( stderr, "%s: line %d: %s %s\n",
151                  fname, lineno, "not built with -DSLAPD_SCHEMA_COMPAT\n");
152         exit( EXIT_FAILURE );
153 #endif
154 }
155
156 /* OID Macros */
157
158 /* String compare with delimiter check. Return 0 if not
159  * matched, otherwise return length matched.
160  */
161 int
162 dscompare(const char *s1, const char *s2, char delim)
163 {
164         const char *orig = s1;
165         while (*s1++ == *s2++)
166                 if (!s1[-1]) break;
167         --s1;
168         --s2;
169         if (!*s1 && (!*s2 || *s2 == delim))
170                 return s1 - orig;
171         return 0;
172 }
173
174 static OidMacro *om_list = NULL;
175
176 /* Replace an OID Macro invocation with its full numeric OID.
177  * If the macro is used with "macroname:suffix" append ".suffix"
178  * to the expansion.
179  */
180 static char *
181 find_oidm(char *oid)
182 {
183         OidMacro *om;
184         char *new;
185         int pos, suflen;
186
187         /* OID macros must start alpha */
188         if ( !isdigit( *oid ) )
189         {
190             for (om = om_list; om; om=om->next)
191             {
192                 if ((pos = dscompare(om->name, oid, ':')))
193                 {
194                         suflen = strlen(oid + pos);
195                         new = ch_calloc(1, om->oidlen + suflen + 1);
196                         strcpy(new, om->oid);
197                         if (suflen)
198                         {
199                                 suflen = om->oidlen;
200                                 new[suflen++] = '.';
201                                 strcpy(new+suflen, oid+pos+1);
202                         }
203                         return new;
204                 }
205             }
206             return NULL;
207         }
208         return oid;
209 }
210
211 void
212 parse_oidm(
213     const char  *fname,
214     int         lineno,
215     int         argc,
216     char        **argv
217 )
218 {
219         OidMacro *om;
220
221         if (argc != 3)
222         {
223 usage:          fprintf( stderr, "ObjectIdentifier <name> <oid>\n");
224                 exit( EXIT_FAILURE );
225         }
226         om = (OidMacro *) ch_malloc( sizeof(OidMacro) );
227         om->name = ch_strdup( argv[1] );
228         om->oid = find_oidm( argv[2] );
229         if (!om->oid)
230         {
231                 fprintf( stderr, "%s: line %d: OID %s not recognized\n",
232                         fname, lineno, argv[2] );
233                 goto usage;
234         }
235         if (om->oid == argv[2])
236                 om->oid = ch_strdup( argv[2] );
237         om->oidlen = strlen( om->oid );
238         om->next = om_list;
239         om_list = om;
240 }
241
242 void
243 parse_oc(
244     const char  *fname,
245     int         lineno,
246     char        *line,
247     char        **argv
248 )
249 {
250         LDAP_OBJECT_CLASS *oc;
251         int             code;
252         const char      *err;
253         char            *oid = NULL;
254
255         oc = ldap_str2objectclass(line,&code,&err);
256         if ( !oc ) {
257                 fprintf( stderr, "%s: line %d: %s before %s\n",
258                          fname, lineno, ldap_scherr2str(code), err );
259                 oc_usage();
260         }
261         if ( oc->oc_oid ) {
262                 if ( !isdigit( oc->oc_oid[0] )) {
263                         /* Expand OID macros */
264                         oid = find_oidm( oc->oc_oid );
265                         if ( !oid ) {
266                                 fprintf(stderr,
267                                         "%s: line %d: OID %s not recognized\n",
268                                         fname, lineno, oc->oc_oid);
269                                 exit( EXIT_FAILURE );
270                         }
271                         if ( oid != oc->oc_oid ) {
272                                 ldap_memfree( oc->oc_oid );
273                                 oc->oc_oid = oid;
274                         }
275                 }
276         }
277         /* oc->oc_oid == NULL will be an error someday */
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 for syntaxes. If the syntax field starts
354          * nonnumeric, look for and expand a macro. The macro's place in
355          * the input line will be replaced with a field of '0's to keep
356          * ldap_str2attributetype happy. The actual oid will be swapped
357          * into place afterwards.
358          */
359         for (; argv[3]; argv++)
360         {
361                 if (!strcasecmp(argv[3], "syntax") &&
362                     !isdigit(*argv[4]))
363                 {
364                         int slen;
365                         Syntax *syn;
366                         syn = syn_find_desc(argv[4], &slen);
367                         if (!syn)
368                         {
369                             fprintf(stderr, "%s: line %d: OID %s not found\n",
370                                 fname, lineno, argv[4]);
371                             exit( EXIT_FAILURE );
372                         }
373                         memset(strstr(line, argv[4]), '0', slen);
374                         soid = ch_strdup(syn->ssyn_syn.syn_oid );
375                         break;
376                 }
377         }
378         at = ldap_str2attributetype(line,&code,&err);
379         if ( !at ) {
380                 fprintf( stderr, "%s: line %d: %s before %s\n",
381                          fname, lineno, ldap_scherr2str(code), err );
382                 at_usage();
383         }
384         if ( at->at_oid ) {
385                 if ( !isdigit( at->at_oid[0] )) {
386                         /* Expand OID macros */
387                         oid = find_oidm( at->at_oid );
388                         if ( !oid ) {
389                                 fprintf(stderr,
390                                         "%s: line %d: OID %s not recognized\n",
391                                         fname, lineno, at->at_oid);
392                                 exit( EXIT_FAILURE );
393                         }
394                         if ( oid != at->at_oid ) {
395                                 ldap_memfree( at->at_oid );
396                                 at->at_oid = oid;
397                         }
398                 }
399         }
400         /* at->at_oid == NULL will be an error someday */
401         if (soid)
402         {
403                 ldap_memfree(at->at_syntax_oid);
404                 at->at_syntax_oid = soid;
405         }
406         code = at_add(at,&err);
407         if ( code ) {
408                 fprintf( stderr, "%s: line %d: %s %s\n",
409                          fname, lineno, scherr2str(code), err);
410                 exit( EXIT_FAILURE );
411         }
412         ldap_memfree(at);
413 }