]> git.sur5r.net Git - openldap/blob - servers/slapd/schemaparse.c
848456cf3c8168df40185e756ddd50fb31917770
[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->som_next)
191             {
192                 if ((pos = dscompare(om->som_name, oid, ':')))
193                 {
194                         suflen = strlen(oid + pos);
195                         new = ch_calloc(1, om->som_oidlen + suflen + 1);
196                         strcpy(new, om->som_oid);
197                         if (suflen)
198                         {
199                                 suflen = om->som_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 usage:  fprintf( stderr, "ObjectIdentifier <name> <oid>\n");
223                 exit( EXIT_FAILURE );
224         }
225
226         om = (OidMacro *) ch_malloc( sizeof(OidMacro) );
227         om->som_name = ch_strdup( argv[1] );
228         om->som_oid = find_oidm( argv[2] );
229
230         if (!om->som_oid) {
231                 fprintf( stderr, "%s: line %d: OID %s not recognized\n",
232                         fname, lineno, argv[2] );
233                 goto usage;
234         }
235
236         if (om->som_oid == argv[2]) {
237                 om->som_oid = ch_strdup( argv[2] );
238         }
239
240         om->som_oidlen = strlen( om->som_oid );
241         om->som_next = om_list;
242         om_list = om;
243 }
244
245 void
246 parse_oc(
247     const char  *fname,
248     int         lineno,
249     char        *line,
250     char        **argv
251 )
252 {
253         LDAP_OBJECT_CLASS *oc;
254         int             code;
255         const char      *err;
256         char            *oid = NULL;
257
258         oc = ldap_str2objectclass(line,&code,&err);
259         if ( !oc ) {
260                 fprintf( stderr, "%s: line %d: %s before %s\n",
261                          fname, lineno, ldap_scherr2str(code), err );
262                 oc_usage();
263         }
264         if ( oc->oc_oid ) {
265                 if ( !isdigit( oc->oc_oid[0] )) {
266                         /* Expand OID macros */
267                         oid = find_oidm( oc->oc_oid );
268                         if ( !oid ) {
269                                 fprintf(stderr,
270                                         "%s: line %d: OID %s not recognized\n",
271                                         fname, lineno, oc->oc_oid);
272                                 exit( EXIT_FAILURE );
273                         }
274                         if ( oid != oc->oc_oid ) {
275                                 ldap_memfree( oc->oc_oid );
276                                 oc->oc_oid = oid;
277                         }
278                 }
279         }
280         /* oc->oc_oid == NULL will be an error someday */
281         code = oc_add(oc,&err);
282         if ( code ) {
283                 fprintf( stderr, "%s: line %d: %s %s\n",
284                          fname, lineno, scherr2str(code), err);
285                 exit( EXIT_FAILURE );
286         }
287         ldap_memfree(oc);
288 }
289
290 static void
291 oc_usage( void )
292 {
293         fprintf( stderr, "ObjectClassDescription = \"(\" whsp\n");
294         fprintf( stderr, "  numericoid whsp      ; ObjectClass identifier\n");
295         fprintf( stderr, "  [ \"NAME\" qdescrs ]\n");
296         fprintf( stderr, "  [ \"DESC\" qdstring ]\n");
297         fprintf( stderr, "  [ \"OBSOLETE\" whsp ]\n");
298         fprintf( stderr, "  [ \"SUP\" oids ]       ; Superior ObjectClasses\n");
299         fprintf( stderr, "  [ ( \"ABSTRACT\" / \"STRUCTURAL\" / \"AUXILIARY\" ) whsp ]\n");
300         fprintf( stderr, "                       ; default structural\n");
301         fprintf( stderr, "  [ \"MUST\" oids ]      ; AttributeTypes\n");
302         fprintf( stderr, "  [ \"MAY\" oids ]       ; AttributeTypes\n");
303         fprintf( stderr, "whsp \")\"\n");
304         exit( EXIT_FAILURE );
305 }
306
307 static void
308 oc_usage_old( void )
309 {
310         fprintf( stderr, "<oc clause> ::= objectclass <ocname>\n" );
311         fprintf( stderr, "                [ requires <attrlist> ]\n" );
312         fprintf( stderr, "                [ allows <attrlist> ]\n" );
313         exit( EXIT_FAILURE );
314 }
315
316 static void
317 at_usage( void )
318 {
319         fprintf( stderr, "AttributeTypeDescription = \"(\" whsp\n");
320         fprintf( stderr, "  numericoid whsp      ; AttributeType identifier\n");
321         fprintf( stderr, "  [ \"NAME\" qdescrs ]             ; name used in AttributeType\n");
322         fprintf( stderr, "  [ \"DESC\" qdstring ]            ; description\n");
323         fprintf( stderr, "  [ \"OBSOLETE\" whsp ]\n");
324         fprintf( stderr, "  [ \"SUP\" woid ]                 ; derived from this other\n");
325         fprintf( stderr, "                                 ; AttributeType\n");
326         fprintf( stderr, "  [ \"EQUALITY\" woid ]            ; Matching Rule name\n");
327         fprintf( stderr, "  [ \"ORDERING\" woid ]            ; Matching Rule name\n");
328         fprintf( stderr, "  [ \"SUBSTR\" woid ]              ; Matching Rule name\n");
329         fprintf( stderr, "  [ \"SYNTAX\" whsp noidlen whsp ] ; see section 4.3\n");
330         fprintf( stderr, "  [ \"SINGLE-VALUE\" whsp ]        ; default multi-valued\n");
331         fprintf( stderr, "  [ \"COLLECTIVE\" whsp ]          ; default not collective\n");
332         fprintf( stderr, "  [ \"NO-USER-MODIFICATION\" whsp ]; default user modifiable\n");
333         fprintf( stderr, "  [ \"USAGE\" whsp AttributeUsage ]; default userApplications\n");
334         fprintf( stderr, "                                 ; userApplications\n");
335         fprintf( stderr, "                                 ; directoryOperation\n");
336         fprintf( stderr, "                                 ; distributedOperation\n");
337         fprintf( stderr, "                                 ; dSAOperation\n");
338         fprintf( stderr, "whsp \")\"\n");
339         exit( EXIT_FAILURE );
340 }
341
342 void
343 parse_at(
344     const char  *fname,
345     int         lineno,
346     char        *line,
347     char        **argv
348 )
349 {
350         LDAP_ATTRIBUTE_TYPE *at;
351         int             code;
352         const char      *err;
353         char            *oid = NULL;
354         char            *soid = NULL;
355
356         /* Kludge for OIDmacros for syntaxes. If the syntax field starts
357          * nonnumeric, look for and expand a macro. The macro's place in
358          * the input line will be replaced with a field of '0's to keep
359          * ldap_str2attributetype happy. The actual oid will be swapped
360          * into place afterwards.
361          */
362         for (; argv[3]; argv++)
363         {
364                 if (!strcasecmp(argv[3], "syntax") &&
365                     !isdigit(*argv[4]))
366                 {
367                         int slen;
368                         Syntax *syn;
369                         syn = syn_find_desc(argv[4], &slen);
370                         if (!syn)
371                         {
372                             fprintf(stderr, "%s: line %d: OID %s not found\n",
373                                 fname, lineno, argv[4]);
374                             exit( EXIT_FAILURE );
375                         }
376                         memset(strstr(line, argv[4]), '0', slen);
377                         soid = ch_strdup(syn->ssyn_syn.syn_oid );
378                         break;
379                 }
380         }
381         at = ldap_str2attributetype(line,&code,&err);
382         if ( !at ) {
383                 fprintf( stderr, "%s: line %d: %s before %s\n",
384                          fname, lineno, ldap_scherr2str(code), err );
385                 at_usage();
386         }
387         if ( at->at_oid ) {
388                 if ( !isdigit( at->at_oid[0] )) {
389                         /* Expand OID macros */
390                         oid = find_oidm( at->at_oid );
391                         if ( !oid ) {
392                                 fprintf(stderr,
393                                         "%s: line %d: OID %s not recognized\n",
394                                         fname, lineno, at->at_oid);
395                                 exit( EXIT_FAILURE );
396                         }
397                         if ( oid != at->at_oid ) {
398                                 ldap_memfree( at->at_oid );
399                                 at->at_oid = oid;
400                         }
401                 }
402         }
403         /* at->at_oid == NULL will be an error someday */
404         if (soid)
405         {
406                 ldap_memfree(at->at_syntax_oid);
407                 at->at_syntax_oid = soid;
408         }
409         code = at_add(at,&err);
410         if ( code ) {
411                 fprintf( stderr, "%s: line %d: %s %s\n",
412                          fname, lineno, scherr2str(code), err);
413                 exit( EXIT_FAILURE );
414         }
415         ldap_memfree(at);
416 }