xref: /netbsd-src/external/bsd/openldap/dist/contrib/slapd-modules/vc/vc.c (revision 549b59ed3ccf0d36d3097190a0db27b770f3a839)
1*549b59edSchristos /*	$NetBSD: vc.c,v 1.2 2021/08/14 16:14:54 christos Exp $	*/
2e670fd5cSchristos 
3e670fd5cSchristos /* vc.c - LDAP Verify Credentials extop (no spec yet) */
4e670fd5cSchristos /* $OpenLDAP$ */
5e670fd5cSchristos /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
6e670fd5cSchristos  *
7e670fd5cSchristos  * Copyright 2010-2021 The OpenLDAP Foundation.
8e670fd5cSchristos  * All rights reserved.
9e670fd5cSchristos  *
10e670fd5cSchristos  * Redistribution and use in source and binary forms, with or without
11e670fd5cSchristos  * modification, are permitted only as authorized by the OpenLDAP
12e670fd5cSchristos  * Public License.
13e670fd5cSchristos  *
14e670fd5cSchristos  * A copy of this license is available in the file LICENSE in the
15e670fd5cSchristos  * top-level directory of the distribution or, alternatively, at
16e670fd5cSchristos  * <http://www.OpenLDAP.org/license.html>.
17e670fd5cSchristos  */
18e670fd5cSchristos /* ACKNOWLEDGEMENTS:
19e670fd5cSchristos  * This work was initially developed by Pierangelo Masarati for inclusion
20e670fd5cSchristos  * in OpenLDAP Software.
21e670fd5cSchristos  */
22e670fd5cSchristos 
23e670fd5cSchristos /*
24e670fd5cSchristos  * LDAP Verify Credentials: suggested by Kurt Zeilenga
25e670fd5cSchristos  * no spec yet
26e670fd5cSchristos  */
27e670fd5cSchristos 
28e670fd5cSchristos #include <sys/cdefs.h>
29*549b59edSchristos __RCSID("$NetBSD: vc.c,v 1.2 2021/08/14 16:14:54 christos Exp $");
30e670fd5cSchristos 
31e670fd5cSchristos #include "portable.h"
32e670fd5cSchristos 
33e670fd5cSchristos #include "slap.h"
34e670fd5cSchristos #include "ac/string.h"
35e670fd5cSchristos 
36e670fd5cSchristos typedef struct vc_conn_t {
37e670fd5cSchristos 	struct vc_conn_t *conn;
38e670fd5cSchristos 	Connection connbuf;
39e670fd5cSchristos 	OperationBuffer opbuf;
40e670fd5cSchristos 	Operation *op;
41e670fd5cSchristos 	int refcnt;
42e670fd5cSchristos } vc_conn_t;
43e670fd5cSchristos 
44e670fd5cSchristos static const struct berval vc_exop_oid_bv = BER_BVC(LDAP_EXOP_VERIFY_CREDENTIALS);
45e670fd5cSchristos static ldap_pvt_thread_mutex_t vc_mutex;
46e670fd5cSchristos static Avlnode *vc_tree;
47e670fd5cSchristos 
48e670fd5cSchristos static int
vc_conn_cmp(const void * c1,const void * c2)49e670fd5cSchristos vc_conn_cmp( const void *c1, const void *c2 )
50e670fd5cSchristos {
51e670fd5cSchristos 	const vc_conn_t *vc1 = (const vc_conn_t *)c1;
52e670fd5cSchristos 	const vc_conn_t *vc2 = (const vc_conn_t *)c2;
53e670fd5cSchristos 
54e670fd5cSchristos 	return SLAP_PTRCMP( vc1->conn, vc2->conn );
55e670fd5cSchristos }
56e670fd5cSchristos 
57e670fd5cSchristos static int
vc_conn_dup(void * c1,void * c2)58e670fd5cSchristos vc_conn_dup( void *c1, void *c2 )
59e670fd5cSchristos {
60e670fd5cSchristos 	vc_conn_t *vc1 = (vc_conn_t *)c1;
61e670fd5cSchristos 	vc_conn_t *vc2 = (vc_conn_t *)c2;
62e670fd5cSchristos 
63e670fd5cSchristos 	if ( vc1->conn == vc2->conn ) {
64e670fd5cSchristos 		return -1;
65e670fd5cSchristos 	}
66e670fd5cSchristos 
67e670fd5cSchristos 	return 0;
68e670fd5cSchristos }
69e670fd5cSchristos 
70e670fd5cSchristos static int
vc_create_response(void * conn,int resultCode,const char * diagnosticMessage,struct berval * servercred,struct berval * authzid,LDAPControl ** ctrls,struct berval ** val)71e670fd5cSchristos vc_create_response(
72e670fd5cSchristos 	void *conn,
73e670fd5cSchristos 	int resultCode,
74e670fd5cSchristos 	const char *diagnosticMessage,
75e670fd5cSchristos 	struct berval *servercred,
76e670fd5cSchristos 	struct berval *authzid,
77e670fd5cSchristos 	LDAPControl **ctrls,
78e670fd5cSchristos 	struct berval **val )
79e670fd5cSchristos {
80e670fd5cSchristos 	BerElementBuffer berbuf;
81e670fd5cSchristos 	BerElement *ber = (BerElement *)&berbuf;
82e670fd5cSchristos 	struct berval bv;
83e670fd5cSchristos 	int rc;
84e670fd5cSchristos 
85e670fd5cSchristos 	assert( val != NULL );
86e670fd5cSchristos 
87e670fd5cSchristos 	*val = NULL;
88e670fd5cSchristos 
89e670fd5cSchristos 	ber_init2( ber, NULL, LBER_USE_DER );
90e670fd5cSchristos 
91e670fd5cSchristos 	(void)ber_printf( ber, "{is" /*}*/ , resultCode, diagnosticMessage ? diagnosticMessage : "" );
92e670fd5cSchristos 
93e670fd5cSchristos 	if ( conn ) {
94e670fd5cSchristos 		struct berval cookie;
95e670fd5cSchristos 
96e670fd5cSchristos 		cookie.bv_len = sizeof( conn );
97e670fd5cSchristos 		cookie.bv_val = (char *)&conn;
98e670fd5cSchristos 		(void)ber_printf( ber, "tO", 0, LDAP_TAG_EXOP_VERIFY_CREDENTIALS_COOKIE, &cookie );
99e670fd5cSchristos 	}
100e670fd5cSchristos 
101e670fd5cSchristos 	if ( servercred ) {
102e670fd5cSchristos 		ber_printf( ber, "tO", LDAP_TAG_EXOP_VERIFY_CREDENTIALS_SCREDS, servercred );
103e670fd5cSchristos 	}
104e670fd5cSchristos 
105e670fd5cSchristos #if 0
106e670fd5cSchristos 	if ( authzid ) {
107e670fd5cSchristos 		ber_printf( ber, "tO", LDAP_TAG_EXOP_VERIFY_CREDENTIALS_AUTHZID, authzid );
108e670fd5cSchristos 	}
109e670fd5cSchristos #endif
110e670fd5cSchristos 
111e670fd5cSchristos 	if ( ctrls ) {
112e670fd5cSchristos 		int c;
113e670fd5cSchristos 
114e670fd5cSchristos 		rc = ber_printf( ber, "t{"/*}*/, LDAP_TAG_EXOP_VERIFY_CREDENTIALS_CONTROLS );
115e670fd5cSchristos 		if ( rc == -1 ) goto done;
116e670fd5cSchristos 
117e670fd5cSchristos 		for ( c = 0; ctrls[c] != NULL; c++ ) {
118e670fd5cSchristos 			rc = ber_printf( ber, "{s" /*}*/, ctrls[c]->ldctl_oid );
119e670fd5cSchristos 
120e670fd5cSchristos 			if ( ctrls[c]->ldctl_iscritical ) {
121e670fd5cSchristos 				rc = ber_printf( ber, "b", (ber_int_t)ctrls[c]->ldctl_iscritical ) ;
122e670fd5cSchristos 				if ( rc == -1 ) goto done;
123e670fd5cSchristos 			}
124e670fd5cSchristos 
125e670fd5cSchristos 			if ( ctrls[c]->ldctl_value.bv_val != NULL ) {
126e670fd5cSchristos 				rc = ber_printf( ber, "O", &ctrls[c]->ldctl_value );
127e670fd5cSchristos 				if( rc == -1 ) goto done;
128e670fd5cSchristos 			}
129e670fd5cSchristos 
130e670fd5cSchristos 			rc = ber_printf( ber, /*{*/"N}" );
131e670fd5cSchristos 			if ( rc == -1 ) goto done;
132e670fd5cSchristos 		}
133e670fd5cSchristos 
134e670fd5cSchristos 		rc = ber_printf( ber, /*{*/"N}" );
135e670fd5cSchristos 		if ( rc == -1 ) goto done;
136e670fd5cSchristos 	}
137e670fd5cSchristos 
138e670fd5cSchristos 	rc = ber_printf( ber, /*{*/ "}" );
139e670fd5cSchristos 	if ( rc == -1 ) goto done;
140e670fd5cSchristos 
141e670fd5cSchristos 	rc = ber_flatten2( ber, &bv, 0 );
142e670fd5cSchristos 	if ( rc == 0 ) {
143e670fd5cSchristos 		*val = ber_bvdup( &bv );
144e670fd5cSchristos 	}
145e670fd5cSchristos 
146e670fd5cSchristos done:;
147e670fd5cSchristos 	ber_free_buf( ber );
148e670fd5cSchristos 
149e670fd5cSchristos 	return rc;
150e670fd5cSchristos }
151e670fd5cSchristos 
152e670fd5cSchristos typedef struct vc_cb_t {
153e670fd5cSchristos 	struct berval sasldata;
154e670fd5cSchristos 	LDAPControl **ctrls;
155e670fd5cSchristos } vc_cb_t;
156e670fd5cSchristos 
157e670fd5cSchristos static int
vc_cb(Operation * op,SlapReply * rs)158e670fd5cSchristos vc_cb(
159e670fd5cSchristos 	Operation	*op,
160e670fd5cSchristos 	SlapReply	*rs )
161e670fd5cSchristos {
162e670fd5cSchristos 	vc_cb_t *vc = (vc_cb_t *)op->o_callback->sc_private;
163e670fd5cSchristos 
164e670fd5cSchristos 	if ( rs->sr_tag == LDAP_RES_BIND ) {
165e670fd5cSchristos 		if ( rs->sr_sasldata != NULL ) {
166e670fd5cSchristos 			ber_dupbv( &vc->sasldata, rs->sr_sasldata );
167e670fd5cSchristos 		}
168e670fd5cSchristos 
169e670fd5cSchristos 		if ( rs->sr_ctrls != NULL ) {
170e670fd5cSchristos 			vc->ctrls = ldap_controls_dup( rs->sr_ctrls );
171e670fd5cSchristos 		}
172e670fd5cSchristos 	}
173e670fd5cSchristos 
174e670fd5cSchristos 	return 0;
175e670fd5cSchristos }
176e670fd5cSchristos 
177e670fd5cSchristos static int
vc_exop(Operation * op,SlapReply * rs)178e670fd5cSchristos vc_exop(
179e670fd5cSchristos 	Operation	*op,
180e670fd5cSchristos 	SlapReply	*rs )
181e670fd5cSchristos {
182e670fd5cSchristos 	int rc = LDAP_SUCCESS;
183e670fd5cSchristos 	ber_tag_t tag;
184e670fd5cSchristos 	ber_len_t len = -1;
185e670fd5cSchristos 	BerElementBuffer berbuf;
186e670fd5cSchristos 	BerElement *ber = (BerElement *)&berbuf;
187e670fd5cSchristos 	struct berval reqdata = BER_BVNULL;
188e670fd5cSchristos 
189e670fd5cSchristos 	struct berval cookie = BER_BVNULL;
190e670fd5cSchristos 	struct berval bdn = BER_BVNULL;
191e670fd5cSchristos 	ber_tag_t authtag;
192e670fd5cSchristos 	struct berval cred = BER_BVNULL;
193e670fd5cSchristos 	struct berval ndn = BER_BVNULL;
194e670fd5cSchristos 	struct berval mechanism = BER_BVNULL;
195e670fd5cSchristos 
196e670fd5cSchristos 	vc_conn_t *conn = NULL;
197e670fd5cSchristos 	vc_cb_t vc = { 0 };
198e670fd5cSchristos 	slap_callback sc = { 0 };
199e670fd5cSchristos 	SlapReply rs2 = { 0 };
200e670fd5cSchristos 
201e670fd5cSchristos 	if ( op->ore_reqdata == NULL || op->ore_reqdata->bv_len == 0 ) {
202e670fd5cSchristos 		rs->sr_text = "empty request data field in VerifyCredentials exop";
203e670fd5cSchristos 		return LDAP_PROTOCOL_ERROR;
204e670fd5cSchristos 	}
205e670fd5cSchristos 
206e670fd5cSchristos 	/* optimistic */
207e670fd5cSchristos 	rs->sr_err = LDAP_SUCCESS;
208e670fd5cSchristos 
209e670fd5cSchristos 	ber_dupbv_x( &reqdata, op->ore_reqdata, op->o_tmpmemctx );
210e670fd5cSchristos 
211e670fd5cSchristos 	/* ber_init2 uses reqdata directly, doesn't allocate new buffers */
212e670fd5cSchristos 	ber_init2( ber, &reqdata, 0 );
213e670fd5cSchristos 
214e670fd5cSchristos 	tag = ber_scanf( ber, "{" /*}*/ );
215e670fd5cSchristos 	if ( tag != LBER_SEQUENCE ) {
216e670fd5cSchristos 		rs->sr_err = LDAP_PROTOCOL_ERROR;
217e670fd5cSchristos 		goto done;
218e670fd5cSchristos 	}
219e670fd5cSchristos 
220e670fd5cSchristos 	tag = ber_peek_tag( ber, &len );
221e670fd5cSchristos 	if ( tag == LDAP_TAG_EXOP_VERIFY_CREDENTIALS_COOKIE ) {
222e670fd5cSchristos 		/*
223e670fd5cSchristos 		 * cookie: the pointer to the connection
224e670fd5cSchristos 		 * of this operation
225e670fd5cSchristos 		 */
226e670fd5cSchristos 
227e670fd5cSchristos 		ber_scanf( ber, "m", &cookie );
228e670fd5cSchristos 		if ( cookie.bv_len != sizeof(Connection *) ) {
229e670fd5cSchristos 			rs->sr_err = LDAP_PROTOCOL_ERROR;
230e670fd5cSchristos 			goto done;
231e670fd5cSchristos 		}
232e670fd5cSchristos 	}
233e670fd5cSchristos 
234e670fd5cSchristos 	/* DN, authtag */
235e670fd5cSchristos 	tag = ber_scanf( ber, "mt", &bdn, &authtag );
236e670fd5cSchristos 	if ( tag == LBER_ERROR ) {
237e670fd5cSchristos 		rs->sr_err = LDAP_PROTOCOL_ERROR;
238e670fd5cSchristos 		goto done;
239e670fd5cSchristos 	}
240e670fd5cSchristos 
241e670fd5cSchristos 	rc = dnNormalize( 0, NULL, NULL, &bdn, &ndn, op->o_tmpmemctx );
242e670fd5cSchristos 	if ( rc != LDAP_SUCCESS ) {
243e670fd5cSchristos 		rs->sr_err = LDAP_PROTOCOL_ERROR;
244e670fd5cSchristos 		goto done;
245e670fd5cSchristos 	}
246e670fd5cSchristos 
247e670fd5cSchristos 	switch ( authtag ) {
248e670fd5cSchristos 	case LDAP_AUTH_SIMPLE:
249e670fd5cSchristos 		/* cookie only makes sense for SASL bind (so far) */
250e670fd5cSchristos 		if ( !BER_BVISNULL( &cookie ) ) {
251e670fd5cSchristos 			rs->sr_err = LDAP_PROTOCOL_ERROR;
252e670fd5cSchristos 			goto done;
253e670fd5cSchristos 		}
254e670fd5cSchristos 
255e670fd5cSchristos 		tag = ber_scanf( ber, "m", &cred );
256e670fd5cSchristos 		if ( tag == LBER_ERROR ) {
257e670fd5cSchristos 			rs->sr_err = LDAP_PROTOCOL_ERROR;
258e670fd5cSchristos 			goto done;
259e670fd5cSchristos 		}
260e670fd5cSchristos 		break;
261e670fd5cSchristos 
262e670fd5cSchristos 	case LDAP_AUTH_SASL:
263e670fd5cSchristos 		tag = ber_scanf( ber, "{m" /*}*/ , &mechanism );
264e670fd5cSchristos 		if ( tag == LBER_ERROR ||
265e670fd5cSchristos 			BER_BVISNULL( &mechanism ) || BER_BVISEMPTY( &mechanism ) )
266e670fd5cSchristos 		{
267e670fd5cSchristos 			rs->sr_err = LDAP_PROTOCOL_ERROR;
268e670fd5cSchristos 			goto done;
269e670fd5cSchristos 		}
270e670fd5cSchristos 
271e670fd5cSchristos 		tag = ber_peek_tag( ber, &len );
272e670fd5cSchristos 		if ( tag == LBER_OCTETSTRING ) {
273e670fd5cSchristos 			ber_scanf( ber, "m", &cred );
274e670fd5cSchristos 		}
275e670fd5cSchristos 
276e670fd5cSchristos 		tag = ber_scanf( ber, /*{*/ "}" );
277e670fd5cSchristos 		break;
278e670fd5cSchristos 
279e670fd5cSchristos 	default:
280e670fd5cSchristos 		rs->sr_err = LDAP_PROTOCOL_ERROR;
281e670fd5cSchristos 		goto done;
282e670fd5cSchristos 	}
283e670fd5cSchristos 
284e670fd5cSchristos 	if ( !BER_BVISNULL( &cookie ) ) {
285e670fd5cSchristos 		vc_conn_t tmp = { 0 };
286e670fd5cSchristos 
287e670fd5cSchristos 		AC_MEMCPY( (char *)&tmp.conn, (const char *)cookie.bv_val, cookie.bv_len );
288e670fd5cSchristos 		ldap_pvt_thread_mutex_lock( &vc_mutex );
289e670fd5cSchristos 		conn = (vc_conn_t *)ldap_avl_find( vc_tree, (caddr_t)&tmp, vc_conn_cmp );
290e670fd5cSchristos 		if ( conn == NULL || ( conn != NULL && conn->refcnt != 0 ) ) {
291e670fd5cSchristos 			conn = NULL;
292e670fd5cSchristos 			ldap_pvt_thread_mutex_unlock( &vc_mutex );
293e670fd5cSchristos 			rs->sr_err = LDAP_PROTOCOL_ERROR;
294e670fd5cSchristos 			goto done;
295e670fd5cSchristos 		}
296e670fd5cSchristos 		conn->refcnt++;
297e670fd5cSchristos 		ldap_pvt_thread_mutex_unlock( &vc_mutex );
298e670fd5cSchristos 
299e670fd5cSchristos 	} else {
300e670fd5cSchristos 		void *thrctx;
301e670fd5cSchristos 
302e670fd5cSchristos 		conn = (vc_conn_t *)SLAP_CALLOC( 1, sizeof( vc_conn_t ) );
303e670fd5cSchristos 		conn->refcnt = 1;
304e670fd5cSchristos 
305e670fd5cSchristos 		thrctx = ldap_pvt_thread_pool_context();
306e670fd5cSchristos 		connection_fake_init2( &conn->connbuf, &conn->opbuf, thrctx, 0 );
307e670fd5cSchristos 		conn->op = &conn->opbuf.ob_op;
308e670fd5cSchristos 		snprintf( conn->op->o_log_prefix, sizeof( conn->op->o_log_prefix ),
309e670fd5cSchristos 			"%s VERIFYCREDENTIALS", op->o_log_prefix );
310e670fd5cSchristos 	}
311e670fd5cSchristos 
312e670fd5cSchristos 	conn->op->o_tag = LDAP_REQ_BIND;
313e670fd5cSchristos 	memset( &conn->op->oq_bind, 0, sizeof( conn->op->oq_bind ) );
314e670fd5cSchristos 	conn->op->o_req_dn = ndn;
315e670fd5cSchristos 	conn->op->o_req_ndn = ndn;
316e670fd5cSchristos 	conn->op->o_protocol = LDAP_VERSION3;
317e670fd5cSchristos 	conn->op->orb_method = authtag;
318e670fd5cSchristos 	conn->op->o_callback = &sc;
319e670fd5cSchristos 
320e670fd5cSchristos 	/* TODO: controls */
321e670fd5cSchristos 	tag = ber_peek_tag( ber, &len );
322e670fd5cSchristos 	if ( tag == LDAP_TAG_EXOP_VERIFY_CREDENTIALS_CONTROLS ) {
323e670fd5cSchristos 		conn->op->o_ber = ber;
324e670fd5cSchristos 		rc = get_ctrls2( conn->op, &rs2, 0, LDAP_TAG_EXOP_VERIFY_CREDENTIALS_CONTROLS );
325e670fd5cSchristos 		if ( rc != LDAP_SUCCESS ) {
326e670fd5cSchristos 			rs->sr_err = LDAP_PROTOCOL_ERROR;
327e670fd5cSchristos 			goto done;
328e670fd5cSchristos 		}
329e670fd5cSchristos 	}
330e670fd5cSchristos 
331e670fd5cSchristos 	tag = ber_skip_tag( ber, &len );
332e670fd5cSchristos 	if ( len || tag != LBER_DEFAULT ) {
333e670fd5cSchristos 		rs->sr_err = LDAP_PROTOCOL_ERROR;
334e670fd5cSchristos 		goto done;
335e670fd5cSchristos 	}
336e670fd5cSchristos 
337e670fd5cSchristos 	switch ( authtag ) {
338e670fd5cSchristos 	case LDAP_AUTH_SIMPLE:
339e670fd5cSchristos 		break;
340e670fd5cSchristos 
341e670fd5cSchristos 	case LDAP_AUTH_SASL:
342e670fd5cSchristos 		conn->op->orb_mech = mechanism;
343e670fd5cSchristos 		break;
344e670fd5cSchristos 	}
345e670fd5cSchristos 
346e670fd5cSchristos 	conn->op->orb_cred = cred;
347e670fd5cSchristos 	sc.sc_response = vc_cb;
348e670fd5cSchristos 	sc.sc_private = &vc;
349e670fd5cSchristos 
350e670fd5cSchristos 	conn->op->o_bd = frontendDB;
351e670fd5cSchristos 	rs->sr_err = frontendDB->be_bind( conn->op, &rs2 );
352e670fd5cSchristos 
353e670fd5cSchristos 	if ( conn->op->o_conn->c_sasl_bind_in_progress ) {
354e670fd5cSchristos 		rc = vc_create_response( conn, rs2.sr_err, rs2.sr_text,
355e670fd5cSchristos 			!BER_BVISEMPTY( &vc.sasldata ) ? &vc.sasldata : NULL,
356e670fd5cSchristos 			NULL,
357e670fd5cSchristos 			vc.ctrls, &rs->sr_rspdata );
358e670fd5cSchristos 
359e670fd5cSchristos 	} else {
360e670fd5cSchristos 		rc = vc_create_response( NULL, rs2.sr_err, rs2.sr_text,
361e670fd5cSchristos 			NULL,
362e670fd5cSchristos 			&conn->op->o_conn->c_dn,
363e670fd5cSchristos 			vc.ctrls, &rs->sr_rspdata );
364e670fd5cSchristos 	}
365e670fd5cSchristos 
366e670fd5cSchristos 	if ( rc != 0 ) {
367e670fd5cSchristos 		rs->sr_err = LDAP_OTHER;
368e670fd5cSchristos 		goto done;
369e670fd5cSchristos 	}
370e670fd5cSchristos 
371e670fd5cSchristos 	if ( !BER_BVISNULL( &conn->op->o_conn->c_dn ) &&
372e670fd5cSchristos 		conn->op->o_conn->c_dn.bv_val != conn->op->o_conn->c_ndn.bv_val )
373e670fd5cSchristos 		ber_memfree( conn->op->o_conn->c_dn.bv_val );
374e670fd5cSchristos 	if ( !BER_BVISNULL( &conn->op->o_conn->c_ndn ) )
375e670fd5cSchristos 		ber_memfree( conn->op->o_conn->c_ndn.bv_val );
376e670fd5cSchristos 
377e670fd5cSchristos done:;
378e670fd5cSchristos 	if ( conn ) {
379e670fd5cSchristos 		if ( conn->op->o_conn->c_sasl_bind_in_progress ) {
380e670fd5cSchristos 			if ( conn->conn == NULL ) {
381e670fd5cSchristos 				conn->conn = conn;
382e670fd5cSchristos 				conn->refcnt--;
383e670fd5cSchristos 				ldap_pvt_thread_mutex_lock( &vc_mutex );
384e670fd5cSchristos 				rc = ldap_avl_insert( &vc_tree, (caddr_t)conn,
385e670fd5cSchristos 					vc_conn_cmp, vc_conn_dup );
386e670fd5cSchristos 				ldap_pvt_thread_mutex_unlock( &vc_mutex );
387e670fd5cSchristos 				assert( rc == 0 );
388e670fd5cSchristos 
389e670fd5cSchristos 			} else {
390e670fd5cSchristos 				ldap_pvt_thread_mutex_lock( &vc_mutex );
391e670fd5cSchristos 				conn->refcnt--;
392e670fd5cSchristos 				ldap_pvt_thread_mutex_unlock( &vc_mutex );
393e670fd5cSchristos 			}
394e670fd5cSchristos 
395e670fd5cSchristos 		} else {
396e670fd5cSchristos 			if ( conn->conn != NULL ) {
397e670fd5cSchristos 				vc_conn_t *tmp;
398e670fd5cSchristos 
399e670fd5cSchristos 				ldap_pvt_thread_mutex_lock( &vc_mutex );
400e670fd5cSchristos 				tmp = ldap_avl_delete( &vc_tree, (caddr_t)conn, vc_conn_cmp );
401e670fd5cSchristos 				ldap_pvt_thread_mutex_unlock( &vc_mutex );
402e670fd5cSchristos 			}
403e670fd5cSchristos 			SLAP_FREE( conn );
404e670fd5cSchristos 		}
405e670fd5cSchristos 	}
406e670fd5cSchristos 
407e670fd5cSchristos 	if ( vc.ctrls ) {
408e670fd5cSchristos 		ldap_controls_free( vc.ctrls );
409e670fd5cSchristos 		vc.ctrls = NULL;
410e670fd5cSchristos 	}
411e670fd5cSchristos 
412e670fd5cSchristos 	if ( !BER_BVISNULL( &ndn ) ) {
413e670fd5cSchristos 		op->o_tmpfree( ndn.bv_val, op->o_tmpmemctx );
414e670fd5cSchristos 		BER_BVZERO( &ndn );
415e670fd5cSchristos 	}
416e670fd5cSchristos 
417e670fd5cSchristos 	op->o_tmpfree( reqdata.bv_val, op->o_tmpmemctx );
418e670fd5cSchristos 	BER_BVZERO( &reqdata );
419e670fd5cSchristos 
420e670fd5cSchristos         return rs->sr_err;
421e670fd5cSchristos }
422e670fd5cSchristos 
423e670fd5cSchristos static int
vc_initialize(void)424e670fd5cSchristos vc_initialize( void )
425e670fd5cSchristos {
426e670fd5cSchristos 	int rc;
427e670fd5cSchristos 
428e670fd5cSchristos 	rc = load_extop2( (struct berval *)&vc_exop_oid_bv,
429e670fd5cSchristos 		SLAP_EXOP_HIDE, vc_exop, 0 );
430e670fd5cSchristos 	if ( rc != LDAP_SUCCESS ) {
431e670fd5cSchristos 		Debug( LDAP_DEBUG_ANY,
432e670fd5cSchristos 			"vc_initialize: unable to register VerifyCredentials exop: %d.\n",
433e670fd5cSchristos 			rc );
434e670fd5cSchristos 	}
435e670fd5cSchristos 
436e670fd5cSchristos 	ldap_pvt_thread_mutex_init( &vc_mutex );
437e670fd5cSchristos 
438e670fd5cSchristos 	return rc;
439e670fd5cSchristos }
440e670fd5cSchristos 
441e670fd5cSchristos int
init_module(int argc,char * argv[])442e670fd5cSchristos init_module( int argc, char *argv[] )
443e670fd5cSchristos {
444e670fd5cSchristos 	return vc_initialize();
445e670fd5cSchristos }
446e670fd5cSchristos 
447