xref: /netbsd-src/external/bsd/openldap/dist/servers/slapd/schemaparse.c (revision b7b7574d3bf8eeb51a1fa3977b59142ec6434a55)
1 /*	$NetBSD: schemaparse.c,v 1.1.1.4 2014/05/28 09:58:47 tron Exp $	*/
2 
3 /* schemaparse.c - routines to parse config file objectclass definitions */
4 /* $OpenLDAP$ */
5 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
6  *
7  * Copyright 1998-2014 The OpenLDAP Foundation.
8  * All rights reserved.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted only as authorized by the OpenLDAP
12  * Public License.
13  *
14  * A copy of this license is available in the file LICENSE in the
15  * top-level directory of the distribution or, alternatively, at
16  * <http://www.OpenLDAP.org/license.html>.
17  */
18 
19 #include "portable.h"
20 
21 #include <stdio.h>
22 
23 #include <ac/ctype.h>
24 #include <ac/string.h>
25 #include <ac/socket.h>
26 
27 #include "slap.h"
28 #include "ldap_schema.h"
29 #include "config.h"
30 
31 static void		oc_usage(void);
32 static void		at_usage(void);
33 
34 static char *const err2text[] = {
35 	"Success",
36 	"Out of memory",
37 	"ObjectClass not found",
38 	"user-defined ObjectClass includes operational attributes",
39 	"user-defined ObjectClass has inappropriate SUPerior",
40 	"Duplicate objectClass",
41 	"Inconsistent duplicate objectClass",
42 	"AttributeType not found",
43 	"AttributeType inappropriate matching rule",
44 	"AttributeType inappropriate USAGE",
45 	"AttributeType inappropriate SUPerior",
46 	"AttributeType SYNTAX or SUPerior required",
47 	"Duplicate attributeType",
48 	"Inconsistent duplicate attributeType",
49 	"MatchingRule not found",
50 	"MatchingRule incomplete",
51 	"Duplicate matchingRule",
52 	"Syntax not found",
53 	"Duplicate ldapSyntax",
54 	"Superior syntax not found",
55 	"Substitute syntax not specified",
56 	"Substitute syntax not found",
57 	"OID or name required",
58 	"Qualifier not supported",
59 	"Invalid NAME",
60 	"OID could not be expanded",
61 	"Duplicate Content Rule",
62 	"Content Rule not for STRUCTURAL object class",
63 	"Content Rule AUX contains inappropriate object class",
64 	"Content Rule attribute type list contains duplicate",
65 	NULL
66 };
67 
68 char *
69 scherr2str(int code)
70 {
71 	if ( code < 0 || SLAP_SCHERR_LAST <= code ) {
72 		return "Unknown error";
73 	} else {
74 		return err2text[code];
75 	}
76 }
77 
78 /* check schema descr validity */
79 int slap_valid_descr( const char *descr )
80 {
81 	int i=0;
82 
83 	if( !DESC_LEADCHAR( descr[i] ) ) {
84 		return 0;
85 	}
86 
87 	while( descr[++i] ) {
88 		if( !DESC_CHAR( descr[i] ) ) {
89 			return 0;
90 		}
91 	}
92 
93 	return 1;
94 }
95 
96 
97 /* OID Macros */
98 
99 /* String compare with delimiter check. Return 0 if not
100  * matched, otherwise return length matched.
101  */
102 int
103 dscompare(const char *s1, const char *s2, char delim)
104 {
105 	const char *orig = s1;
106 	while (*s1++ == *s2++)
107 		if (!s1[-1]) break;
108 	--s1;
109 	--s2;
110 	if (!*s1 && (!*s2 || *s2 == delim))
111 		return s1 - orig;
112 	return 0;
113 }
114 
115 static void
116 cr_usage( void )
117 {
118 	fprintf( stderr,
119 		"DITContentRuleDescription = \"(\" whsp\n"
120 		"  numericoid whsp       ; StructuralObjectClass identifier\n"
121 		"  [ \"NAME\" qdescrs ]\n"
122 		"  [ \"DESC\" qdstring ]\n"
123 		"  [ \"OBSOLETE\" whsp ]\n"
124 		"  [ \"AUX\" oids ]      ; Auxiliary ObjectClasses\n"
125 		"  [ \"MUST\" oids ]     ; AttributeTypes\n"
126 		"  [ \"MAY\" oids ]      ; AttributeTypes\n"
127 		"  [ \"NOT\" oids ]      ; AttributeTypes\n"
128 		"  whsp \")\"\n" );
129 }
130 
131 int
132 parse_cr(
133 	struct config_args_s *c,
134 	ContentRule	**scr )
135 {
136 	LDAPContentRule *cr;
137 	int		code;
138 	const char	*err;
139 	char *line = strchr( c->line, '(' );
140 
141 	cr = ldap_str2contentrule( line, &code, &err, LDAP_SCHEMA_ALLOW_ALL );
142 	if ( !cr ) {
143 		snprintf( c->cr_msg, sizeof( c->cr_msg ), "%s: %s before %s",
144 			c->argv[0], ldap_scherr2str( code ), err );
145 		Debug( LDAP_DEBUG_CONFIG|LDAP_DEBUG_NONE,
146 			"%s %s\n", c->log, c->cr_msg, 0 );
147 		cr_usage();
148 		return 1;
149 	}
150 
151 	if ( cr->cr_oid == NULL ) {
152 		snprintf( c->cr_msg, sizeof( c->cr_msg ), "%s: OID is missing",
153 			c->argv[0] );
154 		Debug( LDAP_DEBUG_CONFIG|LDAP_DEBUG_NONE,
155 			"%s %s\n", c->log, c->cr_msg, 0 );
156 		cr_usage();
157 		code = 1;
158 		goto done;
159 	}
160 
161 	code = cr_add( cr, 1, scr, &err );
162 	if ( code ) {
163 		snprintf( c->cr_msg, sizeof( c->cr_msg ), "%s: %s: \"%s\"",
164 			c->argv[0], scherr2str(code), err);
165 		Debug( LDAP_DEBUG_CONFIG|LDAP_DEBUG_NONE,
166 			"%s %s\n", c->log, c->cr_msg, 0 );
167 		code = 1;
168 		goto done;
169 	}
170 
171 done:;
172 	if ( code ) {
173 		ldap_contentrule_free( cr );
174 
175 	} else {
176 		ldap_memfree( cr );
177 	}
178 
179 	return code;
180 }
181 
182 int
183 parse_oc(
184 	struct config_args_s *c,
185 	ObjectClass	**soc,
186 	ObjectClass *prev )
187 {
188 	LDAPObjectClass *oc;
189 	int		code;
190 	const char	*err;
191 	char *line = strchr( c->line, '(' );
192 
193 	oc = ldap_str2objectclass(line, &code, &err, LDAP_SCHEMA_ALLOW_ALL );
194 	if ( !oc ) {
195 		snprintf( c->cr_msg, sizeof( c->cr_msg ), "%s: %s before %s",
196 			c->argv[0], ldap_scherr2str( code ), err );
197 		Debug( LDAP_DEBUG_CONFIG|LDAP_DEBUG_NONE,
198 			"%s %s\n", c->log, c->cr_msg, 0 );
199 		oc_usage();
200 		return 1;
201 	}
202 
203 	if ( oc->oc_oid == NULL ) {
204 		snprintf( c->cr_msg, sizeof( c->cr_msg ), "%s: OID is missing",
205 			c->argv[0] );
206 		Debug( LDAP_DEBUG_CONFIG|LDAP_DEBUG_NONE,
207 			"%s %s\n", c->log, c->cr_msg, 0 );
208 		oc_usage();
209 		code = 1;
210 		goto done;
211 	}
212 
213 	code = oc_add( oc, 1, soc, prev, &err );
214 	if ( code ) {
215 		snprintf( c->cr_msg, sizeof( c->cr_msg ), "%s: %s: \"%s\"",
216 			c->argv[0], scherr2str(code), err);
217 		Debug( LDAP_DEBUG_CONFIG|LDAP_DEBUG_NONE,
218 			"%s %s\n", c->log, c->cr_msg, 0 );
219 		code = 1;
220 		goto done;
221 	}
222 
223 done:;
224 	if ( code ) {
225 		ldap_objectclass_free( oc );
226 
227 	} else {
228 		ldap_memfree( oc );
229 	}
230 
231 	return code;
232 }
233 
234 static void
235 oc_usage( void )
236 {
237 	fprintf( stderr,
238 		"ObjectClassDescription = \"(\" whsp\n"
239 		"  numericoid whsp                 ; ObjectClass identifier\n"
240 		"  [ \"NAME\" qdescrs ]\n"
241 		"  [ \"DESC\" qdstring ]\n"
242 		"  [ \"OBSOLETE\" whsp ]\n"
243 		"  [ \"SUP\" oids ]                ; Superior ObjectClasses\n"
244 		"  [ ( \"ABSTRACT\" / \"STRUCTURAL\" / \"AUXILIARY\" ) whsp ]\n"
245 		"                                  ; default structural\n"
246 		"  [ \"MUST\" oids ]               ; AttributeTypes\n"
247 		"  [ \"MAY\" oids ]                ; AttributeTypes\n"
248 		"  whsp \")\"\n" );
249 }
250 
251 static void
252 at_usage( void )
253 {
254 	fprintf( stderr, "%s%s%s",
255 		"AttributeTypeDescription = \"(\" whsp\n"
256 		"  numericoid whsp      ; AttributeType identifier\n"
257 		"  [ \"NAME\" qdescrs ]             ; name used in AttributeType\n"
258 		"  [ \"DESC\" qdstring ]            ; description\n"
259 		"  [ \"OBSOLETE\" whsp ]\n"
260 		"  [ \"SUP\" woid ]                 ; derived from this other\n"
261 		"                                   ; AttributeType\n",
262 		"  [ \"EQUALITY\" woid ]            ; Matching Rule name\n"
263 		"  [ \"ORDERING\" woid ]            ; Matching Rule name\n"
264 		"  [ \"SUBSTR\" woid ]              ; Matching Rule name\n"
265 		"  [ \"SYNTAX\" whsp noidlen whsp ] ; see section 4.3\n"
266 		"  [ \"SINGLE-VALUE\" whsp ]        ; default multi-valued\n"
267 		"  [ \"COLLECTIVE\" whsp ]          ; default not collective\n",
268 		"  [ \"NO-USER-MODIFICATION\" whsp ]; default user modifiable\n"
269 		"  [ \"USAGE\" whsp AttributeUsage ]; default userApplications\n"
270 		"                                   ; userApplications\n"
271 		"                                   ; directoryOperation\n"
272 		"                                   ; distributedOperation\n"
273 		"                                   ; dSAOperation\n"
274 		"  whsp \")\"\n");
275 }
276 
277 int
278 parse_at(
279 	struct config_args_s *c,
280 	AttributeType	**sat,
281 	AttributeType	*prev )
282 {
283 	LDAPAttributeType *at;
284 	int		code;
285 	const char	*err;
286 	char *line = strchr( c->line, '(' );
287 
288 	at = ldap_str2attributetype( line, &code, &err, LDAP_SCHEMA_ALLOW_ALL );
289 	if ( !at ) {
290 		snprintf( c->cr_msg, sizeof( c->cr_msg ), "%s: %s before %s",
291 			c->argv[0], ldap_scherr2str(code), err );
292 		Debug( LDAP_DEBUG_CONFIG|LDAP_DEBUG_NONE,
293 			"%s %s\n", c->log, c->cr_msg, 0 );
294 		at_usage();
295 		return 1;
296 	}
297 
298 	if ( at->at_oid == NULL ) {
299 		snprintf( c->cr_msg, sizeof( c->cr_msg ), "%s: OID is missing",
300 			c->argv[0] );
301 		Debug( LDAP_DEBUG_CONFIG|LDAP_DEBUG_NONE,
302 			"%s %s\n", c->log, c->cr_msg, 0 );
303 		at_usage();
304 		code = 1;
305 		goto done;
306 	}
307 
308 	/* operational attributes should be defined internally */
309 	if ( at->at_usage ) {
310 		snprintf( c->cr_msg, sizeof( c->cr_msg ), "%s: \"%s\" is operational",
311 			c->argv[0], at->at_oid );
312 		Debug( LDAP_DEBUG_CONFIG|LDAP_DEBUG_NONE,
313 			"%s %s\n", c->log, c->cr_msg, 0 );
314 		code = 1;
315 		goto done;
316 	}
317 
318 	code = at_add( at, 1, sat, prev, &err);
319 	if ( code ) {
320 		snprintf( c->cr_msg, sizeof( c->cr_msg ), "%s: %s: \"%s\"",
321 			c->argv[0], scherr2str(code), err);
322 		Debug( LDAP_DEBUG_CONFIG|LDAP_DEBUG_NONE,
323 			"%s %s\n", c->log, c->cr_msg, 0 );
324 		code = 1;
325 		goto done;
326 	}
327 
328 done:;
329 	if ( code ) {
330 		ldap_attributetype_free( at );
331 
332 	} else {
333 		ldap_memfree( at );
334 	}
335 
336 	return code;
337 }
338 
339 static void
340 syn_usage( void )
341 {
342 	fprintf( stderr, "%s",
343 		"SyntaxDescription = \"(\" whsp\n"
344 		"  numericoid whsp                  ; object identifier\n"
345 		"  [ whsp \"DESC\" whsp qdstring ]  ; description\n"
346 		"  extensions whsp \")\"            ; extensions\n"
347 		"  whsp \")\"\n");
348 }
349 
350 int
351 parse_syn(
352 	struct config_args_s *c,
353 	Syntax **ssyn,
354 	Syntax *prev )
355 {
356 	LDAPSyntax		*syn;
357 	slap_syntax_defs_rec	def = { 0 };
358 	int			code;
359 	const char		*err;
360 	char			*line = strchr( c->line, '(' );
361 
362 	syn = ldap_str2syntax( line, &code, &err, LDAP_SCHEMA_ALLOW_ALL );
363 	if ( !syn ) {
364 		snprintf( c->cr_msg, sizeof( c->cr_msg ), "%s: %s before %s",
365 			c->argv[0], ldap_scherr2str(code), err );
366 		Debug( LDAP_DEBUG_CONFIG|LDAP_DEBUG_NONE,
367 			"%s %s\n", c->log, c->cr_msg, 0 );
368 		syn_usage();
369 		return 1;
370 	}
371 
372 	if ( syn->syn_oid == NULL ) {
373 		snprintf( c->cr_msg, sizeof( c->cr_msg ), "%s: OID is missing",
374 			c->argv[0] );
375 		Debug( LDAP_DEBUG_CONFIG|LDAP_DEBUG_NONE,
376 			"%s %s\n", c->log, c->cr_msg, 0 );
377 		syn_usage();
378 		code = 1;
379 		goto done;
380 	}
381 
382 	code = syn_add( syn, 1, &def, ssyn, prev, &err );
383 	if ( code ) {
384 		snprintf( c->cr_msg, sizeof( c->cr_msg ), "%s: %s: \"%s\"",
385 			c->argv[0], scherr2str(code), err);
386 		Debug( LDAP_DEBUG_CONFIG|LDAP_DEBUG_NONE,
387 			"%s %s\n", c->log, c->cr_msg, 0 );
388 		code = 1;
389 		goto done;
390 	}
391 
392 done:;
393 	if ( code ) {
394 		ldap_syntax_free( syn );
395 
396 	} else {
397 		ldap_memfree( syn );
398 	}
399 
400 	return code;
401 }
402 
403