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