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