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