]> git.sur5r.net Git - openldap/blob - servers/slapd/schemaparse.c
25374fee690481963c71d2ee4ff750638f35d8e8
[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 #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         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->som_next)
188             {
189                 if ((pos = dscompare(om->som_name, oid, ':')))
190                 {
191                         suflen = strlen(oid + pos);
192                         new = ch_calloc(1, om->som_oid.bv_len + suflen + 1);
193                         strcpy(new, om->som_oid.bv_val);
194                         if (suflen)
195                         {
196                                 suflen = om->som_oid.bv_len;
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 usage:  fprintf( stderr, "ObjectIdentifier <name> <oid>\n");
220                 exit( EXIT_FAILURE );
221         }
222
223         om = (OidMacro *) ch_malloc( sizeof(OidMacro) );
224         om->som_name = ch_strdup( argv[1] );
225         om->som_oid.bv_val = find_oidm( argv[2] );
226
227         if (!om->som_oid.bv_val) {
228                 fprintf( stderr, "%s: line %d: OID %s not recognized\n",
229                         fname, lineno, argv[2] );
230                 goto usage;
231         }
232
233         if (om->som_oid.bv_val == argv[2]) {
234                 om->som_oid.bv_val = ch_strdup( argv[2] );
235         }
236
237         om->som_oid.bv_len = strlen( om->som_oid.bv_val );
238         om->som_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 #ifndef SLAPD_SCHEMA_NOT_COMPAT
305 static void
306 oc_usage_old( void )
307 {
308         fprintf( stderr, "<oc clause> ::= objectclass <ocname>\n" );
309         fprintf( stderr, "                [ requires <attrlist> ]\n" );
310         fprintf( stderr, "                [ allows <attrlist> ]\n" );
311         exit( EXIT_FAILURE );
312 }
313 #endif
314
315 static void
316 at_usage( void )
317 {
318         fprintf( stderr, "AttributeTypeDescription = \"(\" whsp\n");
319         fprintf( stderr, "  numericoid whsp      ; AttributeType identifier\n");
320         fprintf( stderr, "  [ \"NAME\" qdescrs ]             ; name used in AttributeType\n");
321         fprintf( stderr, "  [ \"DESC\" qdstring ]            ; description\n");
322         fprintf( stderr, "  [ \"OBSOLETE\" whsp ]\n");
323         fprintf( stderr, "  [ \"SUP\" woid ]                 ; derived from this other\n");
324         fprintf( stderr, "                                 ; AttributeType\n");
325         fprintf( stderr, "  [ \"EQUALITY\" woid ]            ; Matching Rule name\n");
326         fprintf( stderr, "  [ \"ORDERING\" woid ]            ; Matching Rule name\n");
327         fprintf( stderr, "  [ \"SUBSTR\" woid ]              ; Matching Rule name\n");
328         fprintf( stderr, "  [ \"SYNTAX\" whsp noidlen whsp ] ; see section 4.3\n");
329         fprintf( stderr, "  [ \"SINGLE-VALUE\" whsp ]        ; default multi-valued\n");
330         fprintf( stderr, "  [ \"COLLECTIVE\" whsp ]          ; default not collective\n");
331         fprintf( stderr, "  [ \"NO-USER-MODIFICATION\" whsp ]; default user modifiable\n");
332         fprintf( stderr, "  [ \"USAGE\" whsp AttributeUsage ]; default userApplications\n");
333         fprintf( stderr, "                                 ; userApplications\n");
334         fprintf( stderr, "                                 ; directoryOperation\n");
335         fprintf( stderr, "                                 ; distributedOperation\n");
336         fprintf( stderr, "                                 ; dSAOperation\n");
337         fprintf( stderr, "whsp \")\"\n");
338         exit( EXIT_FAILURE );
339 }
340
341 void
342 parse_at(
343     const char  *fname,
344     int         lineno,
345     char        *line,
346     char        **argv
347 )
348 {
349         LDAP_ATTRIBUTE_TYPE *at;
350         int             code;
351         const char      *err;
352         char            *oid = NULL;
353         char            *soid = NULL;
354
355         /* Kludge for OIDmacros for syntaxes. If the syntax field starts
356          * nonnumeric, look for and expand a macro. The macro's place in
357          * the input line will be replaced with a field of '0's to keep
358          * ldap_str2attributetype happy. The actual oid will be swapped
359          * into place afterwards.
360          */
361         for (; argv[3]; argv++)
362         {
363                 if (!strcasecmp(argv[3], "syntax") &&
364                     !isdigit(*argv[4]))
365                 {
366                         int slen;
367                         Syntax *syn;
368                         syn = syn_find_desc(argv[4], &slen);
369                         if (!syn)
370                         {
371                             fprintf(stderr, "%s: line %d: OID %s not found\n",
372                                 fname, lineno, argv[4]);
373                             exit( EXIT_FAILURE );
374                         }
375                         memset(strstr(line, argv[4]), '0', slen);
376                         soid = ch_strdup(syn->ssyn_syn.syn_oid );
377                         break;
378                 }
379         }
380         at = ldap_str2attributetype(line,&code,&err);
381         if ( !at ) {
382                 fprintf( stderr, "%s: line %d: %s before %s\n",
383                          fname, lineno, ldap_scherr2str(code), err );
384                 at_usage();
385         }
386         if ( at->at_oid ) {
387                 if ( !isdigit( at->at_oid[0] )) {
388                         /* Expand OID macros */
389                         oid = find_oidm( at->at_oid );
390                         if ( !oid ) {
391                                 fprintf(stderr,
392                                         "%s: line %d: OID %s not recognized\n",
393                                         fname, lineno, at->at_oid);
394                                 exit( EXIT_FAILURE );
395                         }
396                         if ( oid != at->at_oid ) {
397                                 ldap_memfree( at->at_oid );
398                                 at->at_oid = oid;
399                         }
400                 }
401         }
402         /* at->at_oid == NULL will be an error someday */
403         if (soid)
404         {
405                 ldap_memfree(at->at_syntax_oid);
406                 at->at_syntax_oid = soid;
407         }
408         code = at_add(at,&err);
409         if ( code ) {
410                 fprintf( stderr, "%s: line %d: %s %s\n",
411                          fname, lineno, scherr2str(code), err);
412                 exit( EXIT_FAILURE );
413         }
414         ldap_memfree(at);
415 }