1/*	$NetBSD: schemaparse.c,v 1.1.1.3 2010/12/12 15:22:45 adam Exp $	*/
2
3/* schemaparse.c - routines to parse config file objectclass definitions */
4/* OpenLDAP: pkg/ldap/servers/slapd/schemaparse.c,v 1.80.2.8 2010/04/13 20:23:19 kurt Exp */
5/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
6 *
7 * Copyright 1998-2010 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
31static void		oc_usage(void);
32static void		at_usage(void);
33
34static 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
68char *
69scherr2str(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 */
79int 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 */
102int
103dscompare(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
115static void
116cr_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
131int
132parse_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
171done:;
172	if ( code ) {
173		ldap_contentrule_free( cr );
174
175	} else {
176		ldap_memfree( cr );
177	}
178
179	return code;
180}
181
182int
183parse_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
223done:;
224	if ( code ) {
225		ldap_objectclass_free( oc );
226
227	} else {
228		ldap_memfree( oc );
229	}
230
231	return code;
232}
233
234static void
235oc_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
251static void
252at_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
277int
278parse_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
328done:;
329	if ( code ) {
330		ldap_attributetype_free( at );
331
332	} else {
333		ldap_memfree( at );
334	}
335
336	return code;
337}
338
339static void
340syn_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
350int
351parse_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
392done:;
393	if ( code ) {
394		ldap_syntax_free( syn );
395
396	} else {
397		ldap_memfree( syn );
398	}
399
400	return code;
401}
402
403