1/* root_dse.c - Provides the Root DSA-Specific Entry */ 2/* $OpenLDAP$ */ 3/* This work is part of OpenLDAP Software <http://www.openldap.org/>. 4 * 5 * Copyright 1999-2011 The OpenLDAP Foundation. 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted only as authorized by the OpenLDAP 10 * Public License. 11 * 12 * A copy of this license is available in the file LICENSE in the 13 * top-level directory of the distribution or, alternatively, at 14 * <http://www.OpenLDAP.org/license.html>. 15 */ 16 17#include "portable.h" 18 19#include <stdio.h> 20 21#include <ac/string.h> 22 23#include "slap.h" 24#include <ldif.h> 25#include "lber_pvt.h" 26 27#ifdef LDAP_SLAPI 28#include "slapi/slapi.h" 29#endif 30 31static struct berval builtin_supportedFeatures[] = { 32 BER_BVC(LDAP_FEATURE_MODIFY_INCREMENT), /* Modify/increment */ 33 BER_BVC(LDAP_FEATURE_ALL_OP_ATTRS), /* All Op Attrs (+) */ 34 BER_BVC(LDAP_FEATURE_OBJECTCLASS_ATTRS), /* OCs in Attrs List (@class) */ 35 BER_BVC(LDAP_FEATURE_ABSOLUTE_FILTERS), /* (&) and (|) search filters */ 36 BER_BVC(LDAP_FEATURE_LANGUAGE_TAG_OPTIONS), /* Language Tag Options */ 37 BER_BVC(LDAP_FEATURE_LANGUAGE_RANGE_OPTIONS), /* Language Range Options */ 38#ifdef LDAP_DEVEL 39 BER_BVC(LDAP_FEATURE_SUBORDINATE_SCOPE), /* "children" search scope */ 40#endif 41 BER_BVNULL 42}; 43static struct berval *supportedFeatures; 44 45static Entry *usr_attr = NULL; 46 47/* 48 * allow modules to register functions that muck with the root DSE entry 49 */ 50 51typedef struct entry_info_t { 52 SLAP_ENTRY_INFO_FN func; 53 void *arg; 54 struct entry_info_t *next; 55} entry_info_t; 56 57static entry_info_t *extra_info; 58 59int 60entry_info_register( SLAP_ENTRY_INFO_FN func, void *arg ) 61{ 62 entry_info_t *ei = ch_calloc( 1, sizeof( entry_info_t ) ); 63 64 ei->func = func; 65 ei->arg = arg; 66 67 ei->next = extra_info; 68 extra_info = ei; 69 70 return 0; 71} 72 73int 74entry_info_unregister( SLAP_ENTRY_INFO_FN func, void *arg ) 75{ 76 entry_info_t **eip; 77 78 for ( eip = &extra_info; *eip != NULL; eip = &(*eip)->next ) { 79 if ( (*eip)->func == func && (*eip)->arg == arg ) { 80 entry_info_t *ei = *eip; 81 82 *eip = ei->next; 83 84 ch_free( ei ); 85 86 return 0; 87 } 88 } 89 90 return -1; 91} 92 93void 94entry_info_destroy( void ) 95{ 96 entry_info_t **eip; 97 98 for ( eip = &extra_info; *eip != NULL; ) { 99 entry_info_t *ei = *eip; 100 101 eip = &(*eip)->next; 102 103 ch_free( ei ); 104 } 105} 106 107/* 108 * Allow modules to register supported features 109 */ 110 111static int 112supported_feature_init( void ) 113{ 114 int i; 115 116 if ( supportedFeatures != NULL ) { 117 return 0; 118 } 119 120 for ( i = 0; !BER_BVISNULL( &builtin_supportedFeatures[ i ] ); i++ ) 121 ; 122 123 supportedFeatures = ch_calloc( sizeof( struct berval ), i + 1 ); 124 if ( supportedFeatures == NULL ) { 125 return -1; 126 } 127 128 for ( i = 0; !BER_BVISNULL( &builtin_supportedFeatures[ i ] ); i++ ) { 129 ber_dupbv( &supportedFeatures[ i ], &builtin_supportedFeatures[ i ] ); 130 } 131 BER_BVZERO( &supportedFeatures[ i ] ); 132 133 return 0; 134} 135 136int 137supported_feature_destroy( void ) 138{ 139 int i; 140 141 if ( supportedFeatures == NULL ) { 142 return 0; 143 } 144 145 for ( i = 0; !BER_BVISNULL( &supportedFeatures[ i ] ); i++ ) { 146 ch_free( supportedFeatures[ i ].bv_val ); 147 } 148 149 ch_free( supportedFeatures ); 150 supportedFeatures = NULL; 151 152 return 0; 153} 154 155int 156supported_feature_load( struct berval *f ) 157{ 158 struct berval *tmp; 159 int i; 160 161 supported_feature_init(); 162 163 for ( i = 0; !BER_BVISNULL( &supportedFeatures[ i ] ); i++ ) 164 ; 165 166 tmp = ch_realloc( supportedFeatures, sizeof( struct berval ) * ( i + 2 ) ); 167 if ( tmp == NULL ) { 168 return -1; 169 } 170 supportedFeatures = tmp; 171 172 ber_dupbv( &supportedFeatures[ i ], f ); 173 BER_BVZERO( &supportedFeatures[ i + 1 ] ); 174 175 return 0; 176} 177 178int 179root_dse_info( 180 Connection *conn, 181 Entry **entry, 182 const char **text ) 183{ 184 Entry *e; 185 struct berval val; 186#ifdef LDAP_SLAPI 187 struct berval *bv; 188#endif 189 int i, j; 190 char ** supportedSASLMechanisms; 191 BackendDB *be; 192 193 AttributeDescription *ad_structuralObjectClass 194 = slap_schema.si_ad_structuralObjectClass; 195 AttributeDescription *ad_objectClass 196 = slap_schema.si_ad_objectClass; 197 AttributeDescription *ad_namingContexts 198 = slap_schema.si_ad_namingContexts; 199#ifdef LDAP_SLAPI 200 AttributeDescription *ad_supportedExtension 201 = slap_schema.si_ad_supportedExtension; 202#endif 203 AttributeDescription *ad_supportedLDAPVersion 204 = slap_schema.si_ad_supportedLDAPVersion; 205 AttributeDescription *ad_supportedSASLMechanisms 206 = slap_schema.si_ad_supportedSASLMechanisms; 207 AttributeDescription *ad_supportedFeatures 208 = slap_schema.si_ad_supportedFeatures; 209 AttributeDescription *ad_monitorContext 210 = slap_schema.si_ad_monitorContext; 211 AttributeDescription *ad_configContext 212 = slap_schema.si_ad_configContext; 213 AttributeDescription *ad_ref 214 = slap_schema.si_ad_ref; 215 216 e = entry_alloc(); 217 if( e == NULL ) { 218 Debug( LDAP_DEBUG_ANY, 219 "root_dse_info: entry_alloc failed", 0, 0, 0 ); 220 return LDAP_OTHER; 221 } 222 223 e->e_attrs = NULL; 224 e->e_name.bv_val = ch_strdup( LDAP_ROOT_DSE ); 225 e->e_name.bv_len = sizeof( LDAP_ROOT_DSE )-1; 226 e->e_nname.bv_val = ch_strdup( LDAP_ROOT_DSE ); 227 e->e_nname.bv_len = sizeof( LDAP_ROOT_DSE )-1; 228 229 /* the DN is an empty string so no pretty/normalization is needed */ 230 assert( !e->e_name.bv_len ); 231 assert( !e->e_nname.bv_len ); 232 233 e->e_private = NULL; 234 235 /* FIXME: is this really needed? */ 236 BER_BVSTR( &val, "top" ); 237 if( attr_merge_one( e, ad_objectClass, &val, NULL ) ) { 238fail: 239 entry_free( e ); 240 return LDAP_OTHER; 241 } 242 243 BER_BVSTR( &val, "OpenLDAProotDSE" ); 244 if( attr_merge_one( e, ad_objectClass, &val, NULL ) ) { 245 goto fail; 246 } 247 if( attr_merge_one( e, ad_structuralObjectClass, &val, NULL ) ) { 248 goto fail; 249 } 250 251 LDAP_STAILQ_FOREACH( be, &backendDB, be_next ) { 252 if ( be->be_suffix == NULL 253 || be->be_nsuffix == NULL ) { 254 /* no suffix! */ 255 continue; 256 } 257 if ( SLAP_MONITOR( be )) { 258 if( attr_merge_one( e, ad_monitorContext, 259 &be->be_suffix[0], 260 &be->be_nsuffix[0] ) ) 261 { 262 goto fail; 263 } 264 continue; 265 } 266 if ( SLAP_CONFIG( be )) { 267 if( attr_merge_one( e, ad_configContext, 268 &be->be_suffix[0], 269 & be->be_nsuffix[0] ) ) 270 { 271 goto fail; 272 } 273 continue; 274 } 275 if ( SLAP_GLUE_SUBORDINATE( be ) && !SLAP_GLUE_ADVERTISE( be ) ) { 276 continue; 277 } 278 for ( j = 0; be->be_suffix[j].bv_val != NULL; j++ ) { 279 if(memcmp(be->be_suffix[j].bv_val, "cn=authdata", be->be_suffix[j].bv_len) != 0) 280 { 281 if( attr_merge_one( e, ad_namingContexts, 282 &be->be_suffix[j], NULL ) ) 283 { 284 goto fail; 285 } 286 } 287 } 288 } 289 290 /* altServer unsupported */ 291 292 /* supportedControl */ 293 if ( controls_root_dse_info( e ) != 0 ) { 294 goto fail; 295 } 296 297 /* supportedExtension */ 298 if ( exop_root_dse_info( e ) != 0 ) { 299 goto fail; 300 } 301 302#ifdef LDAP_SLAPI 303 /* netscape supportedExtension */ 304 for ( i = 0; (bv = slapi_int_get_supported_extop(i)) != NULL; i++ ) { 305 if( attr_merge_one( e, ad_supportedExtension, bv, NULL ) ) { 306 goto fail; 307 } 308 } 309#endif /* LDAP_SLAPI */ 310 311 /* supportedFeatures */ 312 if ( supportedFeatures == NULL ) { 313 supported_feature_init(); 314 } 315 316 if( attr_merge( e, ad_supportedFeatures, supportedFeatures, NULL ) ) { 317 goto fail; 318 } 319 320 /* supportedLDAPVersion */ 321 /* don't publish version 2 as we don't really support it 322 * (even when configured to accept version 2 Bind requests) 323 * and the value would never be used by true LDAPv2 (or LDAPv3) 324 * clients. 325 */ 326 for ( i=LDAP_VERSION3; i<=LDAP_VERSION_MAX; i++ ) { 327 char buf[sizeof("255")]; 328 snprintf(buf, sizeof buf, "%d", i); 329 val.bv_val = buf; 330 val.bv_len = strlen( val.bv_val ); 331 if( attr_merge_one( e, ad_supportedLDAPVersion, &val, NULL ) ) { 332 goto fail; 333 } 334 } 335 336 /* supportedSASLMechanism */ 337 supportedSASLMechanisms = slap_sasl_mechs( conn ); 338 339 if( supportedSASLMechanisms != NULL ) { 340 for ( i=0; supportedSASLMechanisms[i] != NULL; i++ ) { 341 val.bv_val = supportedSASLMechanisms[i]; 342 val.bv_len = strlen( val.bv_val ); 343 if( attr_merge_one( e, ad_supportedSASLMechanisms, &val, NULL ) ) { 344 ldap_charray_free( supportedSASLMechanisms ); 345 goto fail; 346 } 347 } 348 ldap_charray_free( supportedSASLMechanisms ); 349 } 350 351 if ( default_referral != NULL ) { 352 if( attr_merge( e, ad_ref, default_referral, NULL /* FIXME */ ) ) { 353 goto fail; 354 } 355 } 356 357 if( usr_attr != NULL) { 358 Attribute *a; 359 for( a = usr_attr->e_attrs; a != NULL; a = a->a_next ) { 360 if( attr_merge( e, a->a_desc, a->a_vals, 361 (a->a_nvals == a->a_vals) ? NULL : a->a_nvals ) ) 362 { 363 goto fail; 364 } 365 } 366 } 367 368 if ( extra_info ) { 369 entry_info_t *ei = extra_info; 370 371 for ( ; ei; ei = ei->next ) { 372 ei->func( ei->arg, e ); 373 } 374 } 375 376 *entry = e; 377 return LDAP_SUCCESS; 378} 379 380int 381root_dse_init( void ) 382{ 383 return 0; 384} 385 386int 387root_dse_destroy( void ) 388{ 389 if ( usr_attr ) { 390 entry_free( usr_attr ); 391 usr_attr = NULL; 392 } 393 394 return 0; 395} 396 397/* 398 * Read the entries specified in fname and merge the attributes 399 * to the user defined rootDSE. Note thaat if we find any errors 400 * what so ever, we will discard the entire entries, print an 401 * error message and return. 402 */ 403int 404root_dse_read_file( const char *fname ) 405{ 406 struct LDIFFP *fp; 407 int rc = 0, lineno = 0, lmax = 0, ldifrc; 408 char *buf = NULL; 409 410 if ( (fp = ldif_open( fname, "r" )) == NULL ) { 411 Debug( LDAP_DEBUG_ANY, 412 "root_dse_read_file: could not open rootdse attr file \"%s\" - absolute path?\n", 413 fname, 0, 0 ); 414 perror( fname ); 415 return EXIT_FAILURE; 416 } 417 418 usr_attr = entry_alloc(); 419 if( usr_attr == NULL ) { 420 Debug( LDAP_DEBUG_ANY, 421 "root_dse_read_file: entry_alloc failed", 0, 0, 0 ); 422 ldif_close( fp ); 423 return LDAP_OTHER; 424 } 425 usr_attr->e_attrs = NULL; 426 427 while(( ldifrc = ldif_read_record( fp, &lineno, &buf, &lmax )) > 0 ) { 428 Entry *e = str2entry( buf ); 429 Attribute *a; 430 431 if( e == NULL ) { 432 Debug( LDAP_DEBUG_ANY, "root_dse_read_file: " 433 "could not parse entry (file=\"%s\" line=%d)\n", 434 fname, lineno, 0 ); 435 rc = LDAP_OTHER; 436 break; 437 } 438 439 /* make sure the DN is the empty DN */ 440 if( e->e_nname.bv_len ) { 441 Debug( LDAP_DEBUG_ANY, 442 "root_dse_read_file: invalid rootDSE " 443 "- dn=\"%s\" (file=\"%s\" line=%d)\n", 444 e->e_dn, fname, lineno ); 445 entry_free( e ); 446 rc = LDAP_OTHER; 447 break; 448 } 449 450 /* 451 * we found a valid entry, so walk thru all the attributes in the 452 * entry, and add each attribute type and description to the 453 * usr_attr entry 454 */ 455 456 for(a = e->e_attrs; a != NULL; a = a->a_next) { 457 if( attr_merge( usr_attr, a->a_desc, a->a_vals, 458 (a->a_nvals == a->a_vals) ? NULL : a->a_nvals ) ) 459 { 460 rc = LDAP_OTHER; 461 break; 462 } 463 } 464 465 entry_free( e ); 466 if (rc) break; 467 } 468 469 if ( ldifrc < 0 ) 470 rc = LDAP_OTHER; 471 472 if (rc) { 473 entry_free( usr_attr ); 474 usr_attr = NULL; 475 } 476 477 ch_free( buf ); 478 479 ldif_close( fp ); 480 481 Debug(LDAP_DEBUG_CONFIG, "rootDSE file=\"%s\" read.\n", fname, 0, 0); 482 return rc; 483} 484 485int 486slap_discover_feature( 487 slap_bindconf *sb, 488 const char *attr, 489 const char *val ) 490{ 491 LDAP *ld = NULL; 492 LDAPMessage *res = NULL, *entry; 493 int rc, i; 494 struct berval bv_val, 495 **values = NULL; 496 char *attrs[ 2 ] = { NULL, NULL }; 497 498 rc = slap_client_connect( &ld, sb ); 499 if ( rc != LDAP_SUCCESS ) { 500 goto done; 501 } 502 503 attrs[ 0 ] = (char *) attr; 504 rc = ldap_search_ext_s( ld, "", LDAP_SCOPE_BASE, "(objectClass=*)", 505 attrs, 0, NULL, NULL, NULL, 0, &res ); 506 if ( rc != LDAP_SUCCESS ) { 507 goto done; 508 } 509 510 entry = ldap_first_entry( ld, res ); 511 if ( entry == NULL ) { 512 goto done; 513 } 514 515 values = ldap_get_values_len( ld, entry, attrs[ 0 ] ); 516 if ( values == NULL ) { 517 rc = LDAP_NO_SUCH_ATTRIBUTE; 518 goto done; 519 } 520 521 ber_str2bv( val, 0, 0, &bv_val ); 522 for ( i = 0; values[ i ] != NULL; i++ ) { 523 if ( bvmatch( &bv_val, values[ i ] ) ) { 524 rc = LDAP_COMPARE_TRUE; 525 goto done; 526 } 527 } 528 529 rc = LDAP_COMPARE_FALSE; 530 531done:; 532 if ( values != NULL ) { 533 ldap_value_free_len( values ); 534 } 535 536 if ( res != NULL ) { 537 ldap_msgfree( res ); 538 } 539 540 ldap_unbind_ext( ld, NULL, NULL ); 541 542 return rc; 543} 544 545