1/* operational.c - bdb backend operational attributes function */ 2/* $OpenLDAP$ */ 3/* This work is part of OpenLDAP Software <http://www.openldap.org/>. 4 * 5 * Copyright 2000-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#include <ac/socket.h> 23 24#include "slap.h" 25#include "back-bdb.h" 26 27/* 28 * sets *hasSubordinates to LDAP_COMPARE_TRUE/LDAP_COMPARE_FALSE 29 * if the entry has children or not. 30 */ 31int 32bdb_hasSubordinates( 33 Operation *op, 34 Entry *e, 35 int *hasSubordinates ) 36{ 37 struct bdb_info *bdb = (struct bdb_info *) op->o_bd->be_private; 38 struct bdb_op_info *opinfo; 39 OpExtra *oex; 40 DB_TXN *rtxn; 41 int rc; 42 int release = 0; 43 44 assert( e != NULL ); 45 46 /* NOTE: this should never happen, but it actually happens 47 * when using back-relay; until we find a better way to 48 * preserve entry's private information while rewriting it, 49 * let's disable the hasSubordinate feature for back-relay. 50 */ 51 if ( BEI( e ) == NULL ) { 52 Entry *ee = NULL; 53 rc = be_entry_get_rw( op, &e->e_nname, NULL, NULL, 0, &ee ); 54 if ( rc != LDAP_SUCCESS || ee == NULL ) { 55 rc = LDAP_OTHER; 56 goto done; 57 } 58 e = ee; 59 release = 1; 60 if ( BEI( ee ) == NULL ) { 61 rc = LDAP_OTHER; 62 goto done; 63 } 64 } 65 66 /* Check for a txn in a parent op, otherwise use reader txn */ 67 LDAP_SLIST_FOREACH( oex, &op->o_extra, oe_next ) { 68 if ( oex->oe_key == bdb ) 69 break; 70 } 71 opinfo = (struct bdb_op_info *) oex; 72 if ( opinfo && opinfo->boi_txn ) { 73 rtxn = opinfo->boi_txn; 74 } else { 75 rc = bdb_reader_get(op, bdb->bi_dbenv, &rtxn); 76 if ( rc ) { 77 rc = LDAP_OTHER; 78 goto done; 79 } 80 } 81 82retry: 83 /* FIXME: we can no longer assume the entry's e_private 84 * field is correctly populated; so we need to reacquire 85 * it with reader lock */ 86 rc = bdb_cache_children( op, rtxn, e ); 87 88 switch( rc ) { 89 case DB_LOCK_DEADLOCK: 90 case DB_LOCK_NOTGRANTED: 91 goto retry; 92 93 case 0: 94 *hasSubordinates = LDAP_COMPARE_TRUE; 95 break; 96 97 case DB_NOTFOUND: 98 *hasSubordinates = LDAP_COMPARE_FALSE; 99 rc = LDAP_SUCCESS; 100 break; 101 102 default: 103 Debug(LDAP_DEBUG_ARGS, 104 "<=- " LDAP_XSTRING(bdb_hasSubordinates) 105 ": has_children failed: %s (%d)\n", 106 db_strerror(rc), rc, 0 ); 107 rc = LDAP_OTHER; 108 } 109 110done:; 111 if ( release && e != NULL ) be_entry_release_r( op, e ); 112 return rc; 113} 114 115/* 116 * sets the supported operational attributes (if required) 117 */ 118int 119bdb_operational( 120 Operation *op, 121 SlapReply *rs ) 122{ 123 Attribute **ap; 124 125 assert( rs->sr_entry != NULL ); 126 127 for ( ap = &rs->sr_operational_attrs; *ap; ap = &(*ap)->a_next ) { 128 if ( (*ap)->a_desc == slap_schema.si_ad_hasSubordinates ) { 129 break; 130 } 131 } 132 133 if ( *ap == NULL && 134 attr_find( rs->sr_entry->e_attrs, slap_schema.si_ad_hasSubordinates ) == NULL && 135 ( SLAP_OPATTRS( rs->sr_attr_flags ) || 136 ad_inlist( slap_schema.si_ad_hasSubordinates, rs->sr_attrs ) ) ) 137 { 138 int hasSubordinates, rc; 139 140 rc = bdb_hasSubordinates( op, rs->sr_entry, &hasSubordinates ); 141 if ( rc == LDAP_SUCCESS ) { 142 *ap = slap_operational_hasSubordinate( hasSubordinates == LDAP_COMPARE_TRUE ); 143 assert( *ap != NULL ); 144 145 ap = &(*ap)->a_next; 146 } 147 } 148 149 return LDAP_SUCCESS; 150} 151 152