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