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