xref: /netbsd-src/external/bsd/openldap/dist/servers/slapd/schemaparse.c (revision 549b59ed3ccf0d36d3097190a0db27b770f3a839)
1*549b59edSchristos /*	$NetBSD: schemaparse.c,v 1.3 2021/08/14 16:14:58 christos Exp $	*/
24e6df137Slukem 
32de962bdSlukem /* schemaparse.c - routines to parse config file objectclass definitions */
4d11b170bStron /* $OpenLDAP$ */
52de962bdSlukem /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
62de962bdSlukem  *
7*549b59edSchristos  * Copyright 1998-2021 The OpenLDAP Foundation.
82de962bdSlukem  * All rights reserved.
92de962bdSlukem  *
102de962bdSlukem  * Redistribution and use in source and binary forms, with or without
112de962bdSlukem  * modification, are permitted only as authorized by the OpenLDAP
122de962bdSlukem  * Public License.
132de962bdSlukem  *
142de962bdSlukem  * A copy of this license is available in the file LICENSE in the
152de962bdSlukem  * top-level directory of the distribution or, alternatively, at
162de962bdSlukem  * <http://www.OpenLDAP.org/license.html>.
172de962bdSlukem  */
182de962bdSlukem 
19376af7d7Schristos #include <sys/cdefs.h>
20*549b59edSchristos __RCSID("$NetBSD: schemaparse.c,v 1.3 2021/08/14 16:14:58 christos Exp $");
21376af7d7Schristos 
222de962bdSlukem #include "portable.h"
232de962bdSlukem 
242de962bdSlukem #include <stdio.h>
252de962bdSlukem 
262de962bdSlukem #include <ac/ctype.h>
272de962bdSlukem #include <ac/string.h>
282de962bdSlukem #include <ac/socket.h>
292de962bdSlukem 
302de962bdSlukem #include "slap.h"
312de962bdSlukem #include "ldap_schema.h"
32*549b59edSchristos #include "slap-config.h"
332de962bdSlukem 
342de962bdSlukem static void		oc_usage(void);
352de962bdSlukem static void		at_usage(void);
362de962bdSlukem 
372de962bdSlukem static char *const err2text[] = {
382de962bdSlukem 	"Success",
392de962bdSlukem 	"Out of memory",
402de962bdSlukem 	"ObjectClass not found",
412de962bdSlukem 	"user-defined ObjectClass includes operational attributes",
422de962bdSlukem 	"user-defined ObjectClass has inappropriate SUPerior",
432de962bdSlukem 	"Duplicate objectClass",
442de962bdSlukem 	"Inconsistent duplicate objectClass",
452de962bdSlukem 	"AttributeType not found",
462de962bdSlukem 	"AttributeType inappropriate matching rule",
472de962bdSlukem 	"AttributeType inappropriate USAGE",
482de962bdSlukem 	"AttributeType inappropriate SUPerior",
492de962bdSlukem 	"AttributeType SYNTAX or SUPerior required",
502de962bdSlukem 	"Duplicate attributeType",
512de962bdSlukem 	"Inconsistent duplicate attributeType",
522de962bdSlukem 	"MatchingRule not found",
532de962bdSlukem 	"MatchingRule incomplete",
542de962bdSlukem 	"Duplicate matchingRule",
552de962bdSlukem 	"Syntax not found",
562de962bdSlukem 	"Duplicate ldapSyntax",
572de962bdSlukem 	"Superior syntax not found",
584e6df137Slukem 	"Substitute syntax not specified",
594e6df137Slukem 	"Substitute syntax not found",
602de962bdSlukem 	"OID or name required",
612de962bdSlukem 	"Qualifier not supported",
622de962bdSlukem 	"Invalid NAME",
632de962bdSlukem 	"OID could not be expanded",
642de962bdSlukem 	"Duplicate Content Rule",
652de962bdSlukem 	"Content Rule not for STRUCTURAL object class",
662de962bdSlukem 	"Content Rule AUX contains inappropriate object class",
672de962bdSlukem 	"Content Rule attribute type list contains duplicate",
682de962bdSlukem 	NULL
692de962bdSlukem };
702de962bdSlukem 
712de962bdSlukem char *
scherr2str(int code)722de962bdSlukem scherr2str(int code)
732de962bdSlukem {
742de962bdSlukem 	if ( code < 0 || SLAP_SCHERR_LAST <= code ) {
752de962bdSlukem 		return "Unknown error";
762de962bdSlukem 	} else {
772de962bdSlukem 		return err2text[code];
782de962bdSlukem 	}
792de962bdSlukem }
802de962bdSlukem 
812de962bdSlukem /* check schema descr validity */
slap_valid_descr(const char * descr)822de962bdSlukem int slap_valid_descr( const char *descr )
832de962bdSlukem {
842de962bdSlukem 	int i=0;
852de962bdSlukem 
862de962bdSlukem 	if( !DESC_LEADCHAR( descr[i] ) ) {
872de962bdSlukem 		return 0;
882de962bdSlukem 	}
892de962bdSlukem 
902de962bdSlukem 	while( descr[++i] ) {
912de962bdSlukem 		if( !DESC_CHAR( descr[i] ) ) {
922de962bdSlukem 			return 0;
932de962bdSlukem 		}
942de962bdSlukem 	}
952de962bdSlukem 
962de962bdSlukem 	return 1;
972de962bdSlukem }
982de962bdSlukem 
992de962bdSlukem 
1002de962bdSlukem /* OID Macros */
1012de962bdSlukem 
1022de962bdSlukem /* String compare with delimiter check. Return 0 if not
1032de962bdSlukem  * matched, otherwise return length matched.
1042de962bdSlukem  */
1052de962bdSlukem int
dscompare(const char * s1,const char * s2,char delim)1062de962bdSlukem dscompare(const char *s1, const char *s2, char delim)
1072de962bdSlukem {
1082de962bdSlukem 	const char *orig = s1;
1092de962bdSlukem 	while (*s1++ == *s2++)
1102de962bdSlukem 		if (!s1[-1]) break;
1112de962bdSlukem 	--s1;
1122de962bdSlukem 	--s2;
1132de962bdSlukem 	if (!*s1 && (!*s2 || *s2 == delim))
1142de962bdSlukem 		return s1 - orig;
1152de962bdSlukem 	return 0;
1162de962bdSlukem }
1172de962bdSlukem 
1182de962bdSlukem static void
cr_usage(void)1192de962bdSlukem cr_usage( void )
1202de962bdSlukem {
1212de962bdSlukem 	fprintf( stderr,
1222de962bdSlukem 		"DITContentRuleDescription = \"(\" whsp\n"
1232de962bdSlukem 		"  numericoid whsp       ; StructuralObjectClass identifier\n"
1242de962bdSlukem 		"  [ \"NAME\" qdescrs ]\n"
1252de962bdSlukem 		"  [ \"DESC\" qdstring ]\n"
1262de962bdSlukem 		"  [ \"OBSOLETE\" whsp ]\n"
1272de962bdSlukem 		"  [ \"AUX\" oids ]      ; Auxiliary ObjectClasses\n"
1282de962bdSlukem 		"  [ \"MUST\" oids ]     ; AttributeTypes\n"
1292de962bdSlukem 		"  [ \"MAY\" oids ]      ; AttributeTypes\n"
1302de962bdSlukem 		"  [ \"NOT\" oids ]      ; AttributeTypes\n"
1312de962bdSlukem 		"  whsp \")\"\n" );
1322de962bdSlukem }
1332de962bdSlukem 
1342de962bdSlukem int
parse_cr(struct config_args_s * c,ContentRule ** scr)1352de962bdSlukem parse_cr(
1362de962bdSlukem 	struct config_args_s *c,
1372de962bdSlukem 	ContentRule	**scr )
1382de962bdSlukem {
1392de962bdSlukem 	LDAPContentRule *cr;
1402de962bdSlukem 	int		code;
1412de962bdSlukem 	const char	*err;
1422de962bdSlukem 	char *line = strchr( c->line, '(' );
1432de962bdSlukem 
1442de962bdSlukem 	cr = ldap_str2contentrule( line, &code, &err, LDAP_SCHEMA_ALLOW_ALL );
1452de962bdSlukem 	if ( !cr ) {
1462de962bdSlukem 		snprintf( c->cr_msg, sizeof( c->cr_msg ), "%s: %s before %s",
1472de962bdSlukem 			c->argv[0], ldap_scherr2str( code ), err );
1482de962bdSlukem 		Debug( LDAP_DEBUG_CONFIG|LDAP_DEBUG_NONE,
149*549b59edSchristos 			"%s %s\n", c->log, c->cr_msg );
1502de962bdSlukem 		cr_usage();
1512de962bdSlukem 		return 1;
1522de962bdSlukem 	}
1532de962bdSlukem 
1542de962bdSlukem 	if ( cr->cr_oid == NULL ) {
1552de962bdSlukem 		snprintf( c->cr_msg, sizeof( c->cr_msg ), "%s: OID is missing",
1562de962bdSlukem 			c->argv[0] );
1572de962bdSlukem 		Debug( LDAP_DEBUG_CONFIG|LDAP_DEBUG_NONE,
158*549b59edSchristos 			"%s %s\n", c->log, c->cr_msg );
1592de962bdSlukem 		cr_usage();
1602de962bdSlukem 		code = 1;
1612de962bdSlukem 		goto done;
1622de962bdSlukem 	}
1632de962bdSlukem 
1642de962bdSlukem 	code = cr_add( cr, 1, scr, &err );
1652de962bdSlukem 	if ( code ) {
1662de962bdSlukem 		snprintf( c->cr_msg, sizeof( c->cr_msg ), "%s: %s: \"%s\"",
1672de962bdSlukem 			c->argv[0], scherr2str(code), err);
1682de962bdSlukem 		Debug( LDAP_DEBUG_CONFIG|LDAP_DEBUG_NONE,
169*549b59edSchristos 			"%s %s\n", c->log, c->cr_msg );
1702de962bdSlukem 		code = 1;
1712de962bdSlukem 		goto done;
1722de962bdSlukem 	}
1732de962bdSlukem 
1742de962bdSlukem done:;
1752de962bdSlukem 	if ( code ) {
1762de962bdSlukem 		ldap_contentrule_free( cr );
1772de962bdSlukem 
1782de962bdSlukem 	} else {
1792de962bdSlukem 		ldap_memfree( cr );
1802de962bdSlukem 	}
1812de962bdSlukem 
1822de962bdSlukem 	return code;
1832de962bdSlukem }
1842de962bdSlukem 
1852de962bdSlukem int
parse_oc(struct config_args_s * c,ObjectClass ** soc,ObjectClass * prev)1862de962bdSlukem parse_oc(
1872de962bdSlukem 	struct config_args_s *c,
1882de962bdSlukem 	ObjectClass	**soc,
1892de962bdSlukem 	ObjectClass *prev )
1902de962bdSlukem {
1912de962bdSlukem 	LDAPObjectClass *oc;
1922de962bdSlukem 	int		code;
1932de962bdSlukem 	const char	*err;
1942de962bdSlukem 	char *line = strchr( c->line, '(' );
1952de962bdSlukem 
1962de962bdSlukem 	oc = ldap_str2objectclass(line, &code, &err, LDAP_SCHEMA_ALLOW_ALL );
1972de962bdSlukem 	if ( !oc ) {
1982de962bdSlukem 		snprintf( c->cr_msg, sizeof( c->cr_msg ), "%s: %s before %s",
1992de962bdSlukem 			c->argv[0], ldap_scherr2str( code ), err );
2002de962bdSlukem 		Debug( LDAP_DEBUG_CONFIG|LDAP_DEBUG_NONE,
201*549b59edSchristos 			"%s %s\n", c->log, c->cr_msg );
2022de962bdSlukem 		oc_usage();
2032de962bdSlukem 		return 1;
2042de962bdSlukem 	}
2052de962bdSlukem 
2062de962bdSlukem 	if ( oc->oc_oid == NULL ) {
2072de962bdSlukem 		snprintf( c->cr_msg, sizeof( c->cr_msg ), "%s: OID is missing",
2082de962bdSlukem 			c->argv[0] );
2092de962bdSlukem 		Debug( LDAP_DEBUG_CONFIG|LDAP_DEBUG_NONE,
210*549b59edSchristos 			"%s %s\n", c->log, c->cr_msg );
2112de962bdSlukem 		oc_usage();
2122de962bdSlukem 		code = 1;
2132de962bdSlukem 		goto done;
2142de962bdSlukem 	}
2152de962bdSlukem 
2162de962bdSlukem 	code = oc_add( oc, 1, soc, prev, &err );
2172de962bdSlukem 	if ( code ) {
2182de962bdSlukem 		snprintf( c->cr_msg, sizeof( c->cr_msg ), "%s: %s: \"%s\"",
2192de962bdSlukem 			c->argv[0], scherr2str(code), err);
2202de962bdSlukem 		Debug( LDAP_DEBUG_CONFIG|LDAP_DEBUG_NONE,
221*549b59edSchristos 			"%s %s\n", c->log, c->cr_msg );
2222de962bdSlukem 		code = 1;
2232de962bdSlukem 		goto done;
2242de962bdSlukem 	}
2252de962bdSlukem 
2262de962bdSlukem done:;
2272de962bdSlukem 	if ( code ) {
2282de962bdSlukem 		ldap_objectclass_free( oc );
2292de962bdSlukem 
2302de962bdSlukem 	} else {
2312de962bdSlukem 		ldap_memfree( oc );
2322de962bdSlukem 	}
2332de962bdSlukem 
2342de962bdSlukem 	return code;
2352de962bdSlukem }
2362de962bdSlukem 
2372de962bdSlukem static void
oc_usage(void)2382de962bdSlukem oc_usage( void )
2392de962bdSlukem {
2402de962bdSlukem 	fprintf( stderr,
2412de962bdSlukem 		"ObjectClassDescription = \"(\" whsp\n"
2422de962bdSlukem 		"  numericoid whsp                 ; ObjectClass identifier\n"
2432de962bdSlukem 		"  [ \"NAME\" qdescrs ]\n"
2442de962bdSlukem 		"  [ \"DESC\" qdstring ]\n"
2452de962bdSlukem 		"  [ \"OBSOLETE\" whsp ]\n"
2462de962bdSlukem 		"  [ \"SUP\" oids ]                ; Superior ObjectClasses\n"
2472de962bdSlukem 		"  [ ( \"ABSTRACT\" / \"STRUCTURAL\" / \"AUXILIARY\" ) whsp ]\n"
2482de962bdSlukem 		"                                  ; default structural\n"
2492de962bdSlukem 		"  [ \"MUST\" oids ]               ; AttributeTypes\n"
2502de962bdSlukem 		"  [ \"MAY\" oids ]                ; AttributeTypes\n"
2512de962bdSlukem 		"  whsp \")\"\n" );
2522de962bdSlukem }
2532de962bdSlukem 
2542de962bdSlukem static void
at_usage(void)2552de962bdSlukem at_usage( void )
2562de962bdSlukem {
2572de962bdSlukem 	fprintf( stderr, "%s%s%s",
2582de962bdSlukem 		"AttributeTypeDescription = \"(\" whsp\n"
2592de962bdSlukem 		"  numericoid whsp      ; AttributeType identifier\n"
2602de962bdSlukem 		"  [ \"NAME\" qdescrs ]             ; name used in AttributeType\n"
2612de962bdSlukem 		"  [ \"DESC\" qdstring ]            ; description\n"
2622de962bdSlukem 		"  [ \"OBSOLETE\" whsp ]\n"
2632de962bdSlukem 		"  [ \"SUP\" woid ]                 ; derived from this other\n"
2642de962bdSlukem 		"                                   ; AttributeType\n",
2652de962bdSlukem 		"  [ \"EQUALITY\" woid ]            ; Matching Rule name\n"
2662de962bdSlukem 		"  [ \"ORDERING\" woid ]            ; Matching Rule name\n"
2672de962bdSlukem 		"  [ \"SUBSTR\" woid ]              ; Matching Rule name\n"
2682de962bdSlukem 		"  [ \"SYNTAX\" whsp noidlen whsp ] ; see section 4.3\n"
2692de962bdSlukem 		"  [ \"SINGLE-VALUE\" whsp ]        ; default multi-valued\n"
2702de962bdSlukem 		"  [ \"COLLECTIVE\" whsp ]          ; default not collective\n",
2712de962bdSlukem 		"  [ \"NO-USER-MODIFICATION\" whsp ]; default user modifiable\n"
2722de962bdSlukem 		"  [ \"USAGE\" whsp AttributeUsage ]; default userApplications\n"
2732de962bdSlukem 		"                                   ; userApplications\n"
2742de962bdSlukem 		"                                   ; directoryOperation\n"
2752de962bdSlukem 		"                                   ; distributedOperation\n"
2762de962bdSlukem 		"                                   ; dSAOperation\n"
2772de962bdSlukem 		"  whsp \")\"\n");
2782de962bdSlukem }
2792de962bdSlukem 
2802de962bdSlukem int
parse_at(struct config_args_s * c,AttributeType ** sat,AttributeType * prev)2812de962bdSlukem parse_at(
2822de962bdSlukem 	struct config_args_s *c,
2832de962bdSlukem 	AttributeType	**sat,
2842de962bdSlukem 	AttributeType	*prev )
2852de962bdSlukem {
2862de962bdSlukem 	LDAPAttributeType *at;
2872de962bdSlukem 	int		code;
2882de962bdSlukem 	const char	*err;
2892de962bdSlukem 	char *line = strchr( c->line, '(' );
2902de962bdSlukem 
2912de962bdSlukem 	at = ldap_str2attributetype( line, &code, &err, LDAP_SCHEMA_ALLOW_ALL );
2922de962bdSlukem 	if ( !at ) {
2932de962bdSlukem 		snprintf( c->cr_msg, sizeof( c->cr_msg ), "%s: %s before %s",
2942de962bdSlukem 			c->argv[0], ldap_scherr2str(code), err );
2952de962bdSlukem 		Debug( LDAP_DEBUG_CONFIG|LDAP_DEBUG_NONE,
296*549b59edSchristos 			"%s %s\n", c->log, c->cr_msg );
2972de962bdSlukem 		at_usage();
2982de962bdSlukem 		return 1;
2992de962bdSlukem 	}
3002de962bdSlukem 
3012de962bdSlukem 	if ( at->at_oid == NULL ) {
3022de962bdSlukem 		snprintf( c->cr_msg, sizeof( c->cr_msg ), "%s: OID is missing",
3032de962bdSlukem 			c->argv[0] );
3042de962bdSlukem 		Debug( LDAP_DEBUG_CONFIG|LDAP_DEBUG_NONE,
305*549b59edSchristos 			"%s %s\n", c->log, c->cr_msg );
3062de962bdSlukem 		at_usage();
3072de962bdSlukem 		code = 1;
3082de962bdSlukem 		goto done;
3092de962bdSlukem 	}
3102de962bdSlukem 
3112de962bdSlukem 	/* operational attributes should be defined internally */
3122de962bdSlukem 	if ( at->at_usage ) {
3132de962bdSlukem 		snprintf( c->cr_msg, sizeof( c->cr_msg ), "%s: \"%s\" is operational",
3142de962bdSlukem 			c->argv[0], at->at_oid );
3152de962bdSlukem 		Debug( LDAP_DEBUG_CONFIG|LDAP_DEBUG_NONE,
316*549b59edSchristos 			"%s %s\n", c->log, c->cr_msg );
3172de962bdSlukem 		code = 1;
3182de962bdSlukem 		goto done;
3192de962bdSlukem 	}
3202de962bdSlukem 
3212de962bdSlukem 	code = at_add( at, 1, sat, prev, &err);
3222de962bdSlukem 	if ( code ) {
3232de962bdSlukem 		snprintf( c->cr_msg, sizeof( c->cr_msg ), "%s: %s: \"%s\"",
3242de962bdSlukem 			c->argv[0], scherr2str(code), err);
3252de962bdSlukem 		Debug( LDAP_DEBUG_CONFIG|LDAP_DEBUG_NONE,
326*549b59edSchristos 			"%s %s\n", c->log, c->cr_msg );
3272de962bdSlukem 		code = 1;
3282de962bdSlukem 		goto done;
3292de962bdSlukem 	}
3302de962bdSlukem 
3312de962bdSlukem done:;
3322de962bdSlukem 	if ( code ) {
3332de962bdSlukem 		ldap_attributetype_free( at );
3342de962bdSlukem 
3352de962bdSlukem 	} else {
3362de962bdSlukem 		ldap_memfree( at );
3372de962bdSlukem 	}
3382de962bdSlukem 
3392de962bdSlukem 	return code;
3402de962bdSlukem }
3414e6df137Slukem 
3424e6df137Slukem static void
syn_usage(void)3434e6df137Slukem syn_usage( void )
3444e6df137Slukem {
3454e6df137Slukem 	fprintf( stderr, "%s",
3464e6df137Slukem 		"SyntaxDescription = \"(\" whsp\n"
3474e6df137Slukem 		"  numericoid whsp                  ; object identifier\n"
3484e6df137Slukem 		"  [ whsp \"DESC\" whsp qdstring ]  ; description\n"
3494e6df137Slukem 		"  extensions whsp \")\"            ; extensions\n"
3504e6df137Slukem 		"  whsp \")\"\n");
3514e6df137Slukem }
3524e6df137Slukem 
3534e6df137Slukem int
parse_syn(struct config_args_s * c,Syntax ** ssyn,Syntax * prev)3544e6df137Slukem parse_syn(
3554e6df137Slukem 	struct config_args_s *c,
3564e6df137Slukem 	Syntax **ssyn,
3574e6df137Slukem 	Syntax *prev )
3584e6df137Slukem {
3594e6df137Slukem 	LDAPSyntax		*syn;
3604e6df137Slukem 	slap_syntax_defs_rec	def = { 0 };
3614e6df137Slukem 	int			code;
3624e6df137Slukem 	const char		*err;
3634e6df137Slukem 	char			*line = strchr( c->line, '(' );
3644e6df137Slukem 
3654e6df137Slukem 	syn = ldap_str2syntax( line, &code, &err, LDAP_SCHEMA_ALLOW_ALL );
3664e6df137Slukem 	if ( !syn ) {
3674e6df137Slukem 		snprintf( c->cr_msg, sizeof( c->cr_msg ), "%s: %s before %s",
3684e6df137Slukem 			c->argv[0], ldap_scherr2str(code), err );
3694e6df137Slukem 		Debug( LDAP_DEBUG_CONFIG|LDAP_DEBUG_NONE,
370*549b59edSchristos 			"%s %s\n", c->log, c->cr_msg );
3714e6df137Slukem 		syn_usage();
3724e6df137Slukem 		return 1;
3734e6df137Slukem 	}
3744e6df137Slukem 
3754e6df137Slukem 	if ( syn->syn_oid == NULL ) {
3764e6df137Slukem 		snprintf( c->cr_msg, sizeof( c->cr_msg ), "%s: OID is missing",
3774e6df137Slukem 			c->argv[0] );
3784e6df137Slukem 		Debug( LDAP_DEBUG_CONFIG|LDAP_DEBUG_NONE,
379*549b59edSchristos 			"%s %s\n", c->log, c->cr_msg );
3804e6df137Slukem 		syn_usage();
3814e6df137Slukem 		code = 1;
3824e6df137Slukem 		goto done;
3834e6df137Slukem 	}
3844e6df137Slukem 
3854e6df137Slukem 	code = syn_add( syn, 1, &def, ssyn, prev, &err );
3864e6df137Slukem 	if ( code ) {
3874e6df137Slukem 		snprintf( c->cr_msg, sizeof( c->cr_msg ), "%s: %s: \"%s\"",
3884e6df137Slukem 			c->argv[0], scherr2str(code), err);
3894e6df137Slukem 		Debug( LDAP_DEBUG_CONFIG|LDAP_DEBUG_NONE,
390*549b59edSchristos 			"%s %s\n", c->log, c->cr_msg );
3914e6df137Slukem 		code = 1;
3924e6df137Slukem 		goto done;
3934e6df137Slukem 	}
3944e6df137Slukem 
3954e6df137Slukem done:;
3964e6df137Slukem 	if ( code ) {
3974e6df137Slukem 		ldap_syntax_free( syn );
3984e6df137Slukem 
3994e6df137Slukem 	} else {
4004e6df137Slukem 		ldap_memfree( syn );
4014e6df137Slukem 	}
4024e6df137Slukem 
4034e6df137Slukem 	return code;
4044e6df137Slukem }
4054e6df137Slukem 
406