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