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