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