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