1/* $NetBSD$ */ 2 3/* syntax.c - routines to manage syntax definitions */ 4/* OpenLDAP: pkg/ldap/servers/slapd/syntax.c,v 1.43.2.7 2010/04/13 20:23:22 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 29struct sindexrec { 30 char *sir_name; 31 Syntax *sir_syn; 32}; 33 34static Avlnode *syn_index = NULL; 35static LDAP_STAILQ_HEAD(SyntaxList, Syntax) syn_list 36 = LDAP_STAILQ_HEAD_INITIALIZER(syn_list); 37 38/* Last hardcoded attribute registered */ 39Syntax *syn_sys_tail; 40 41static int 42syn_index_cmp( 43 const void *v_sir1, 44 const void *v_sir2 45) 46{ 47 const struct sindexrec *sir1 = v_sir1, *sir2 = v_sir2; 48 return (strcmp( sir1->sir_name, sir2->sir_name )); 49} 50 51static int 52syn_index_name_cmp( 53 const void *name, 54 const void *sir 55) 56{ 57 return (strcmp( name, ((const struct sindexrec *)sir)->sir_name )); 58} 59 60Syntax * 61syn_find( const char *synname ) 62{ 63 struct sindexrec *sir = NULL; 64 65 if ( (sir = avl_find( syn_index, synname, syn_index_name_cmp )) != NULL ) { 66 return( sir->sir_syn ); 67 } 68 return( NULL ); 69} 70 71Syntax * 72syn_find_desc( const char *syndesc, int *len ) 73{ 74 Syntax *synp; 75 76 LDAP_STAILQ_FOREACH(synp, &syn_list, ssyn_next) { 77 if ((*len = dscompare( synp->ssyn_syn.syn_desc, syndesc, '{' /*'}'*/ ))) { 78 return synp; 79 } 80 } 81 return( NULL ); 82} 83 84int 85syn_is_sup( Syntax *syn, Syntax *sup ) 86{ 87 int i; 88 89 assert( syn != NULL ); 90 assert( sup != NULL ); 91 92 if ( syn == sup ) { 93 return 1; 94 } 95 96 if ( syn->ssyn_sups == NULL ) { 97 return 0; 98 } 99 100 for ( i = 0; syn->ssyn_sups[i]; i++ ) { 101 if ( syn->ssyn_sups[i] == sup ) { 102 return 1; 103 } 104 105 if ( syn_is_sup( syn->ssyn_sups[i], sup ) ) { 106 return 1; 107 } 108 } 109 110 return 0; 111} 112 113void 114syn_destroy( void ) 115{ 116 Syntax *s; 117 118 avl_free( syn_index, ldap_memfree ); 119 while( !LDAP_STAILQ_EMPTY( &syn_list ) ) { 120 s = LDAP_STAILQ_FIRST( &syn_list ); 121 LDAP_STAILQ_REMOVE_HEAD( &syn_list, ssyn_next ); 122 if ( s->ssyn_sups ) { 123 SLAP_FREE( s->ssyn_sups ); 124 } 125 ldap_syntax_free( (LDAPSyntax *)s ); 126 } 127} 128 129static int 130syn_insert( 131 Syntax *ssyn, 132 Syntax *prev, 133 const char **err ) 134{ 135 struct sindexrec *sir; 136 137 LDAP_STAILQ_NEXT( ssyn, ssyn_next ) = NULL; 138 139 if ( ssyn->ssyn_oid ) { 140 sir = (struct sindexrec *) 141 SLAP_CALLOC( 1, sizeof(struct sindexrec) ); 142 if( sir == NULL ) { 143 Debug( LDAP_DEBUG_ANY, "SLAP_CALLOC Error\n", 0, 0, 0 ); 144 return LDAP_OTHER; 145 } 146 sir->sir_name = ssyn->ssyn_oid; 147 sir->sir_syn = ssyn; 148 if ( avl_insert( &syn_index, (caddr_t) sir, 149 syn_index_cmp, avl_dup_error ) ) { 150 *err = ssyn->ssyn_oid; 151 ldap_memfree(sir); 152 return SLAP_SCHERR_SYN_DUP; 153 } 154 /* FIX: temporal consistency check */ 155 syn_find(sir->sir_name); 156 } 157 158 if ( ssyn->ssyn_flags & SLAP_AT_HARDCODE ) { 159 prev = syn_sys_tail; 160 syn_sys_tail = ssyn; 161 } 162 163 if ( prev ) { 164 LDAP_STAILQ_INSERT_AFTER( &syn_list, prev, ssyn, ssyn_next ); 165 } else { 166 LDAP_STAILQ_INSERT_TAIL( &syn_list, ssyn, ssyn_next ); 167 } 168 return 0; 169} 170 171int 172syn_add( 173 LDAPSyntax *syn, 174 int user, 175 slap_syntax_defs_rec *def, 176 Syntax **ssynp, 177 Syntax *prev, 178 const char **err ) 179{ 180 Syntax *ssyn; 181 int code = 0; 182 183 if ( ssynp != NULL ) { 184 *ssynp = NULL; 185 } 186 187 ssyn = (Syntax *) SLAP_CALLOC( 1, sizeof(Syntax) ); 188 if ( ssyn == NULL ) { 189 Debug( LDAP_DEBUG_ANY, "SLAP_CALLOC Error\n", 0, 0, 0 ); 190 return SLAP_SCHERR_OUTOFMEM; 191 } 192 193 AC_MEMCPY( &ssyn->ssyn_syn, syn, sizeof(LDAPSyntax) ); 194 195 LDAP_STAILQ_NEXT(ssyn,ssyn_next) = NULL; 196 197 /* 198 * note: ssyn_bvoid uses the same memory of ssyn_syn.syn_oid; 199 * ssyn_oidlen is #defined as ssyn_bvoid.bv_len 200 */ 201 ssyn->ssyn_bvoid.bv_val = ssyn->ssyn_syn.syn_oid; 202 ssyn->ssyn_oidlen = strlen(syn->syn_oid); 203 ssyn->ssyn_flags = def->sd_flags; 204 ssyn->ssyn_validate = def->sd_validate; 205 ssyn->ssyn_pretty = def->sd_pretty; 206 207 ssyn->ssyn_sups = NULL; 208 209#ifdef SLAPD_BINARY_CONVERSION 210 ssyn->ssyn_ber2str = def->sd_ber2str; 211 ssyn->ssyn_str2ber = def->sd_str2ber; 212#endif 213 214 if ( def->sd_validate == NULL && def->sd_pretty == NULL && syn->syn_extensions != NULL ) { 215 LDAPSchemaExtensionItem **lsei; 216 Syntax *subst = NULL; 217 218 for ( lsei = syn->syn_extensions; *lsei != NULL; lsei++) { 219 if ( strcmp( (*lsei)->lsei_name, "X-SUBST" ) != 0 ) { 220 continue; 221 } 222 223 assert( (*lsei)->lsei_values != NULL ); 224 if ( (*lsei)->lsei_values[0] == '\0' 225 || (*lsei)->lsei_values[1] != '\0' ) 226 { 227 Debug( LDAP_DEBUG_ANY, "syn_add(%s): exactly one substitute syntax must be present\n", 228 ssyn->ssyn_syn.syn_oid, 0, 0 ); 229 return SLAP_SCHERR_SYN_SUBST_NOT_SPECIFIED; 230 } 231 232 subst = syn_find( (*lsei)->lsei_values[0] ); 233 if ( subst == NULL ) { 234 Debug( LDAP_DEBUG_ANY, "syn_add(%s): substitute syntax %s not found\n", 235 ssyn->ssyn_syn.syn_oid, (*lsei)->lsei_values[0], 0 ); 236 return SLAP_SCHERR_SYN_SUBST_NOT_FOUND; 237 } 238 break; 239 } 240 241 if ( subst != NULL ) { 242 ssyn->ssyn_flags = subst->ssyn_flags; 243 ssyn->ssyn_validate = subst->ssyn_validate; 244 ssyn->ssyn_pretty = subst->ssyn_pretty; 245 246 ssyn->ssyn_sups = NULL; 247 248#ifdef SLAPD_BINARY_CONVERSION 249 ssyn->ssyn_ber2str = subst->ssyn_ber2str; 250 ssyn->ssyn_str2ber = subst->ssyn_str2ber; 251#endif 252 } 253 } 254 255 if ( def->sd_sups != NULL ) { 256 int cnt; 257 258 for ( cnt = 0; def->sd_sups[cnt] != NULL; cnt++ ) 259 ; 260 261 ssyn->ssyn_sups = (Syntax **)SLAP_CALLOC( cnt + 1, 262 sizeof( Syntax * ) ); 263 if ( ssyn->ssyn_sups == NULL ) { 264 Debug( LDAP_DEBUG_ANY, "SLAP_CALLOC Error\n", 0, 0, 0 ); 265 code = SLAP_SCHERR_OUTOFMEM; 266 267 } else { 268 for ( cnt = 0; def->sd_sups[cnt] != NULL; cnt++ ) { 269 ssyn->ssyn_sups[cnt] = syn_find( def->sd_sups[cnt] ); 270 if ( ssyn->ssyn_sups[cnt] == NULL ) { 271 *err = def->sd_sups[cnt]; 272 code = SLAP_SCHERR_SYN_SUP_NOT_FOUND; 273 } 274 } 275 } 276 } 277 278 if ( !user ) 279 ssyn->ssyn_flags |= SLAP_SYNTAX_HARDCODE; 280 281 if ( code == 0 ) { 282 code = syn_insert( ssyn, prev, err ); 283 } 284 285 if ( code != 0 && ssyn != NULL ) { 286 if ( ssyn->ssyn_sups != NULL ) { 287 SLAP_FREE( ssyn->ssyn_sups ); 288 } 289 SLAP_FREE( ssyn ); 290 ssyn = NULL; 291 } 292 293 if (ssynp ) { 294 *ssynp = ssyn; 295 } 296 297 return code; 298} 299 300int 301register_syntax( 302 slap_syntax_defs_rec *def ) 303{ 304 LDAPSyntax *syn; 305 int code; 306 const char *err; 307 308 syn = ldap_str2syntax( def->sd_desc, &code, &err, LDAP_SCHEMA_ALLOW_ALL); 309 if ( !syn ) { 310 Debug( LDAP_DEBUG_ANY, "Error in register_syntax: %s before %s in %s\n", 311 ldap_scherr2str(code), err, def->sd_desc ); 312 313 return( -1 ); 314 } 315 316 code = syn_add( syn, 0, def, NULL, NULL, &err ); 317 318 if ( code ) { 319 Debug( LDAP_DEBUG_ANY, "Error in register_syntax: %s %s in %s\n", 320 scherr2str(code), err, def->sd_desc ); 321 ldap_syntax_free( syn ); 322 323 return( -1 ); 324 } 325 326 ldap_memfree( syn ); 327 328 return( 0 ); 329} 330 331int 332syn_schema_info( Entry *e ) 333{ 334 AttributeDescription *ad_ldapSyntaxes = slap_schema.si_ad_ldapSyntaxes; 335 Syntax *syn; 336 struct berval val; 337 struct berval nval; 338 339 LDAP_STAILQ_FOREACH(syn, &syn_list, ssyn_next ) { 340 if ( ! syn->ssyn_validate ) { 341 /* skip syntaxes without validators */ 342 continue; 343 } 344 if ( syn->ssyn_flags & SLAP_SYNTAX_HIDE ) { 345 /* hide syntaxes */ 346 continue; 347 } 348 349 if ( ldap_syntax2bv( &syn->ssyn_syn, &val ) == NULL ) { 350 return -1; 351 } 352#if 0 353 Debug( LDAP_DEBUG_TRACE, "Merging syn [%ld] %s\n", 354 (long) val.bv_len, val.bv_val, 0 ); 355#endif 356 357 nval.bv_val = syn->ssyn_oid; 358 nval.bv_len = strlen(syn->ssyn_oid); 359 360 if( attr_merge_one( e, ad_ldapSyntaxes, &val, &nval ) ) 361 { 362 return -1; 363 } 364 ldap_memfree( val.bv_val ); 365 } 366 return 0; 367} 368 369void 370syn_delete( Syntax *syn ) 371{ 372 LDAP_STAILQ_REMOVE(&syn_list, syn, Syntax, ssyn_next); 373} 374 375int 376syn_start( Syntax **syn ) 377{ 378 assert( syn != NULL ); 379 380 *syn = LDAP_STAILQ_FIRST(&syn_list); 381 382 return (*syn != NULL); 383} 384 385int 386syn_next( Syntax **syn ) 387{ 388 assert( syn != NULL ); 389 390#if 0 /* pedantic check: don't use this */ 391 { 392 Syntax *tmp = NULL; 393 394 LDAP_STAILQ_FOREACH(tmp,&syn_list,ssyn_next) { 395 if ( tmp == *syn ) { 396 break; 397 } 398 } 399 400 assert( tmp != NULL ); 401 } 402#endif 403 404 *syn = LDAP_STAILQ_NEXT(*syn,ssyn_next); 405 406 return (*syn != NULL); 407} 408 409void 410syn_unparse( BerVarray *res, Syntax *start, Syntax *end, int sys ) 411{ 412 Syntax *syn; 413 int i, num; 414 struct berval bv, *bva = NULL, idx; 415 char ibuf[32]; 416 417 if ( !start ) 418 start = LDAP_STAILQ_FIRST( &syn_list ); 419 420 /* count the result size */ 421 i = 0; 422 for ( syn = start; syn; syn = LDAP_STAILQ_NEXT( syn, ssyn_next ) ) { 423 if ( sys && !( syn->ssyn_flags & SLAP_SYNTAX_HARDCODE ) ) break; 424 i++; 425 if ( syn == end ) break; 426 } 427 if ( !i ) return; 428 429 num = i; 430 bva = ch_malloc( (num+1) * sizeof(struct berval) ); 431 BER_BVZERO( bva ); 432 idx.bv_val = ibuf; 433 if ( sys ) { 434 idx.bv_len = 0; 435 ibuf[0] = '\0'; 436 } 437 i = 0; 438 for ( syn = start; syn; syn = LDAP_STAILQ_NEXT( syn, ssyn_next ) ) { 439 if ( sys && !( syn->ssyn_flags & SLAP_SYNTAX_HARDCODE ) ) break; 440 if ( ldap_syntax2bv( &syn->ssyn_syn, &bv ) == NULL ) { 441 ber_bvarray_free( bva ); 442 } 443 if ( !sys ) { 444 idx.bv_len = sprintf(idx.bv_val, "{%d}", i); 445 } 446 bva[i].bv_len = idx.bv_len + bv.bv_len; 447 bva[i].bv_val = ch_malloc( bva[i].bv_len + 1 ); 448 strcpy( bva[i].bv_val, ibuf ); 449 strcpy( bva[i].bv_val + idx.bv_len, bv.bv_val ); 450 i++; 451 bva[i].bv_val = NULL; 452 ldap_memfree( bv.bv_val ); 453 if ( syn == end ) break; 454 } 455 *res = bva; 456} 457 458