1/*	$NetBSD: operational.c,v 1.3 2021/08/14 16:15:01 christos Exp $	*/
2
3/* $OpenLDAP$ */
4/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
5 *
6 * Copyright 1999-2021 The OpenLDAP Foundation.
7 * Portions Copyright 1999 Dmitry Kovalev.
8 * Portions Copyright 2002 Pierangelo Masarati.
9 * All rights reserved.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted only as authorized by the OpenLDAP
13 * Public License.
14 *
15 * A copy of this license is available in the file LICENSE in the
16 * top-level directory of the distribution or, alternatively, at
17 * <http://www.OpenLDAP.org/license.html>.
18 */
19/* ACKNOWLEDGEMENTS:
20 * This work was initially developed by Dmitry Kovalev for inclusion
21 * by OpenLDAP Software.  Additional significant contributors include
22 * Pierangelo Masarati.
23 */
24
25#include <sys/cdefs.h>
26__RCSID("$NetBSD: operational.c,v 1.3 2021/08/14 16:15:01 christos Exp $");
27
28#include "portable.h"
29
30#include <stdio.h>
31#include <sys/types.h>
32
33#include "slap.h"
34#include "proto-sql.h"
35#include "lutil.h"
36
37/*
38 * sets the supported operational attributes (if required)
39 */
40
41Attribute *
42backsql_operational_entryUUID( backsql_info *bi, backsql_entryID *id )
43{
44	int			rc;
45	struct berval		val, nval;
46	AttributeDescription	*desc = slap_schema.si_ad_entryUUID;
47	Attribute		*a;
48
49	backsql_entryUUID( bi, id, &val, NULL );
50
51	rc = (*desc->ad_type->sat_equality->smr_normalize)(
52			SLAP_MR_VALUE_OF_ATTRIBUTE_SYNTAX,
53			desc->ad_type->sat_syntax,
54			desc->ad_type->sat_equality,
55			&val, &nval, NULL );
56	if ( rc != LDAP_SUCCESS ) {
57		ber_memfree( val.bv_val );
58		return NULL;
59	}
60
61	a = attr_alloc( desc );
62
63	a->a_numvals = 1;
64	a->a_vals = (BerVarray) ch_malloc( 2 * sizeof( struct berval ) );
65	a->a_vals[ 0 ] = val;
66	BER_BVZERO( &a->a_vals[ 1 ] );
67
68	a->a_nvals = (BerVarray) ch_malloc( 2 * sizeof( struct berval ) );
69	a->a_nvals[ 0 ] = nval;
70	BER_BVZERO( &a->a_nvals[ 1 ] );
71
72	return a;
73}
74
75Attribute *
76backsql_operational_entryCSN( Operation *op )
77{
78	char		csnbuf[ LDAP_PVT_CSNSTR_BUFSIZE ];
79	struct berval	entryCSN;
80	Attribute	*a;
81
82	a = attr_alloc( slap_schema.si_ad_entryCSN );
83	a->a_numvals = 1;
84	a->a_vals = ch_malloc( 2 * sizeof( struct berval ) );
85	BER_BVZERO( &a->a_vals[ 1 ] );
86
87#ifdef BACKSQL_SYNCPROV
88	if ( op->o_sync && op->o_tag == LDAP_REQ_SEARCH && op->o_private != NULL ) {
89		assert( op->o_private != NULL );
90
91		entryCSN = *((struct berval *)op->o_private);
92
93	} else
94#endif /* BACKSQL_SYNCPROV */
95	{
96		entryCSN.bv_val = csnbuf;
97		entryCSN.bv_len = sizeof( csnbuf );
98		slap_get_csn( op, &entryCSN, 0 );
99	}
100
101	ber_dupbv( &a->a_vals[ 0 ], &entryCSN );
102
103	a->a_nvals = a->a_vals;
104
105	return a;
106}
107
108int
109backsql_operational(
110	Operation	*op,
111	SlapReply	*rs )
112{
113
114	backsql_info 	*bi = (backsql_info*)op->o_bd->be_private;
115	SQLHDBC 	dbh = SQL_NULL_HDBC;
116	int		rc = 0;
117	Attribute	**ap;
118	enum {
119		BACKSQL_OP_HASSUBORDINATES = 0,
120		BACKSQL_OP_ENTRYUUID,
121		BACKSQL_OP_ENTRYCSN,
122
123		BACKSQL_OP_LAST
124	};
125	int		get_conn = BACKSQL_OP_LAST,
126			got[ BACKSQL_OP_LAST ] = { 0 };
127
128	Debug( LDAP_DEBUG_TRACE, "==>backsql_operational(): entry \"%s\"\n",
129			rs->sr_entry->e_nname.bv_val );
130
131	for ( ap = &rs->sr_entry->e_attrs; *ap; ap = &(*ap)->a_next ) {
132		if ( (*ap)->a_desc == slap_schema.si_ad_hasSubordinates ) {
133			get_conn--;
134			got[ BACKSQL_OP_HASSUBORDINATES ] = 1;
135
136		} else if ( (*ap)->a_desc == slap_schema.si_ad_entryUUID ) {
137			get_conn--;
138			got[ BACKSQL_OP_ENTRYUUID ] = 1;
139
140		} else if ( (*ap)->a_desc == slap_schema.si_ad_entryCSN ) {
141			get_conn--;
142			got[ BACKSQL_OP_ENTRYCSN ] = 1;
143		}
144	}
145
146	for ( ap = &rs->sr_operational_attrs; *ap; ap = &(*ap)->a_next ) {
147		if ( !got[ BACKSQL_OP_HASSUBORDINATES ] &&
148			(*ap)->a_desc == slap_schema.si_ad_hasSubordinates )
149		{
150			get_conn--;
151			got[ BACKSQL_OP_HASSUBORDINATES ] = 1;
152
153		} else if ( !got[ BACKSQL_OP_ENTRYUUID ] &&
154			(*ap)->a_desc == slap_schema.si_ad_entryUUID )
155		{
156			get_conn--;
157			got[ BACKSQL_OP_ENTRYUUID ] = 1;
158
159		} else if ( !got[ BACKSQL_OP_ENTRYCSN ] &&
160			(*ap)->a_desc == slap_schema.si_ad_entryCSN )
161		{
162			get_conn--;
163			got[ BACKSQL_OP_ENTRYCSN ] = 1;
164		}
165	}
166
167	if ( !get_conn ) {
168		return 0;
169	}
170
171	rc = backsql_get_db_conn( op, &dbh );
172	if ( rc != LDAP_SUCCESS ) {
173		Debug( LDAP_DEBUG_TRACE, "backsql_operational(): "
174			"could not get connection handle - exiting\n" );
175		return 1;
176	}
177
178	if ( ( SLAP_OPATTRS( rs->sr_attr_flags ) || ad_inlist( slap_schema.si_ad_hasSubordinates, rs->sr_attrs ) )
179			&& !got[ BACKSQL_OP_HASSUBORDINATES ]
180			&& attr_find( rs->sr_entry->e_attrs, slap_schema.si_ad_hasSubordinates ) == NULL )
181	{
182		rc = backsql_has_children( op, dbh, &rs->sr_entry->e_nname );
183
184		switch( rc ) {
185		case LDAP_COMPARE_TRUE:
186		case LDAP_COMPARE_FALSE:
187			*ap = slap_operational_hasSubordinate( rc == LDAP_COMPARE_TRUE );
188			assert( *ap != NULL );
189			ap = &(*ap)->a_next;
190			rc = 0;
191			break;
192
193		default:
194			Debug( LDAP_DEBUG_TRACE, "backsql_operational(): "
195				"has_children failed( %d)\n", rc );
196			return 1;
197		}
198	}
199
200	if ( ( SLAP_OPATTRS( rs->sr_attr_flags ) || ad_inlist( slap_schema.si_ad_entryUUID, rs->sr_attrs ) )
201			&& !got[ BACKSQL_OP_ENTRYUUID ]
202			&& attr_find( rs->sr_entry->e_attrs, slap_schema.si_ad_entryUUID ) == NULL )
203	{
204		backsql_srch_info	bsi = { 0 };
205
206		rc = backsql_init_search( &bsi, &rs->sr_entry->e_nname,
207				LDAP_SCOPE_BASE,
208				(time_t)(-1), NULL, dbh, op, rs, NULL,
209				BACKSQL_ISF_GET_ID );
210		if ( rc != LDAP_SUCCESS ) {
211			Debug( LDAP_DEBUG_TRACE, "backsql_operational(): "
212				"could not retrieve entry ID - no such entry\n" );
213			return 1;
214		}
215
216		*ap = backsql_operational_entryUUID( bi, &bsi.bsi_base_id );
217
218		(void)backsql_free_entryID( &bsi.bsi_base_id, 0, op->o_tmpmemctx );
219
220		if ( bsi.bsi_attrs != NULL ) {
221			op->o_tmpfree( bsi.bsi_attrs, op->o_tmpmemctx );
222		}
223
224		if ( *ap == NULL ) {
225			Debug( LDAP_DEBUG_TRACE, "backsql_operational(): "
226				"could not retrieve entryUUID\n" );
227			return 1;
228		}
229
230		ap = &(*ap)->a_next;
231	}
232
233	if ( ( SLAP_OPATTRS( rs->sr_attr_flags ) || ad_inlist( slap_schema.si_ad_entryCSN, rs->sr_attrs ) )
234			&& !got[ BACKSQL_OP_ENTRYCSN ]
235			&& attr_find( rs->sr_entry->e_attrs, slap_schema.si_ad_entryCSN ) == NULL )
236	{
237		*ap = backsql_operational_entryCSN( op );
238		if ( *ap == NULL ) {
239			Debug( LDAP_DEBUG_TRACE, "backsql_operational(): "
240				"could not retrieve entryCSN\n" );
241			return 1;
242		}
243
244		ap = &(*ap)->a_next;
245	}
246
247	Debug( LDAP_DEBUG_TRACE, "<==backsql_operational(%d)\n", rc );
248
249	return rc;
250}
251
252