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