]> git.sur5r.net Git - openldap/blob - contrib/slapd-modules/authzid/authzid.c
Happy New Year
[openldap] / contrib / slapd-modules / authzid / authzid.c
1 /* authzid.c - RFC 3829 Authzid Control */
2 /* $OpenLDAP$ */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
4  *
5  * Copyright 2010-2011 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  * RFC 3829 Authzid
23  */
24
25 #include "portable.h"
26
27 #include "slap.h"
28 #include "lutil.h"
29 #include "ac/string.h"
30
31 typedef struct authzid_conn_t {
32         Connection *conn;
33         int refcnt;
34         char authzid_flag;
35 } authzid_conn_t;
36
37 static ldap_pvt_thread_mutex_t authzid_mutex;
38 static Avlnode *authzid_tree;
39
40 static int
41 authzid_conn_cmp( const void *c1, const void *c2 )
42 {
43         const authzid_conn_t *ac1 = (const authzid_conn_t *)c1;
44         const authzid_conn_t *ac2 = (const authzid_conn_t *)c2;
45
46         return SLAP_PTRCMP( ac1->conn, ac2->conn );
47 }
48
49 static int
50 authzid_conn_dup( void *c1, void *c2 )
51 {
52         authzid_conn_t *ac1 = (authzid_conn_t *)c1;
53         authzid_conn_t *ac2 = (authzid_conn_t *)c2;
54
55         if ( ac1->conn == ac2->conn ) {
56                 return -1;
57         }
58
59         return 0;
60 }
61
62 static int authzid_cid;
63 static slap_overinst authzid;
64
65 static authzid_conn_t *
66 authzid_conn_find( Connection *c )
67 {
68         authzid_conn_t *ac = NULL, tmp = { 0 };
69
70         tmp.conn = c;
71         ac = (authzid_conn_t *)avl_find( authzid_tree, (caddr_t)&tmp, authzid_conn_cmp );
72         if ( ac == NULL || ( ac != NULL && ac->refcnt != 0 ) ) {
73                 ac = NULL;
74                 ldap_pvt_thread_mutex_unlock( &authzid_mutex );
75         }
76         if ( ac ) {
77                 ac->refcnt++;
78         }
79
80         return ac;
81 }
82
83 static authzid_conn_t *
84 authzid_conn_get( Connection *c )
85 {
86         authzid_conn_t *ac = NULL;
87
88         ldap_pvt_thread_mutex_lock( &authzid_mutex );
89         ac = authzid_conn_find( c );
90         if ( ac && ac->refcnt ) ac = NULL;
91         if ( ac ) ac->refcnt++;
92         ldap_pvt_thread_mutex_unlock( &authzid_mutex );
93
94         return ac;
95 }
96
97 static void
98 authzid_conn_release( authzid_conn_t *ac )
99 {
100         ldap_pvt_thread_mutex_lock( &authzid_mutex );
101         ac->refcnt--;
102         ldap_pvt_thread_mutex_unlock( &authzid_mutex );
103 }
104
105 static int
106 authzid_conn_insert( Connection *c, char flag )
107 {
108         authzid_conn_t *ac;
109         int rc;
110
111         ldap_pvt_thread_mutex_lock( &authzid_mutex );
112         ac = authzid_conn_find( c );
113         if ( ac ) {
114                 ldap_pvt_thread_mutex_unlock( &authzid_mutex );
115                 return -1;
116         }
117
118         ac = SLAP_MALLOC( sizeof( authzid_conn_t ) );
119         ac->conn = c;
120         ac->refcnt = 0;
121         ac->authzid_flag = flag;
122         rc = avl_insert( &authzid_tree, (caddr_t)ac,
123                 authzid_conn_cmp, authzid_conn_dup );
124         ldap_pvt_thread_mutex_unlock( &authzid_mutex );
125
126         return rc;
127 }
128
129 static int
130 authzid_conn_remove( Connection *c )
131 {
132         authzid_conn_t *ac, *tmp;
133
134         ldap_pvt_thread_mutex_lock( &authzid_mutex );
135         ac = authzid_conn_find( c );
136         if ( !ac ) {
137                 ldap_pvt_thread_mutex_unlock( &authzid_mutex );
138                 return -1;
139         }
140         tmp = avl_delete( &authzid_tree, (caddr_t)ac, authzid_conn_cmp );
141         ldap_pvt_thread_mutex_unlock( &authzid_mutex );
142
143         assert( tmp == ac );
144         SLAP_FREE( ac );
145
146         return 0;
147 }
148
149 static int
150 authzid_response(
151         Operation *op,
152         SlapReply *rs )
153 {
154         LDAPControl **ctrls;
155         struct berval edn = BER_BVNULL;
156         ber_len_t len = 0;
157         int n = 0;
158
159         assert( rs->sr_tag = LDAP_RES_BIND );
160
161         if ( rs->sr_err == LDAP_SASL_BIND_IN_PROGRESS ) {
162                 authzid_conn_t *ac = op->o_controls[ authzid_cid ];
163                 if ( ac ) {
164                         authzid_conn_release( ac );
165                 } else {
166                         (void)authzid_conn_insert( op->o_conn, op->o_ctrlflag[ authzid_cid ] );
167                 }
168                 return SLAP_CB_CONTINUE;
169         }
170
171         (void)authzid_conn_remove( op->o_conn );
172
173         if ( rs->sr_err != LDAP_SUCCESS ) {
174                 return SLAP_CB_CONTINUE;
175         }
176
177         if ( !BER_BVISEMPTY( &op->orb_edn ) ) {
178                 edn = op->orb_edn;
179         } else if ( !BER_BVISEMPTY( &op->o_conn->c_dn ) ) {
180                 edn = op->o_conn->c_dn;
181         }
182
183         if ( !BER_BVISEMPTY( &edn ) ) {
184                 len = STRLENOF("dn:") + edn.bv_len;
185         }
186
187         /* save original controls in sc_private;
188          * will be restored by sc_cleanup
189          */
190         if ( rs->sr_ctrls != NULL ) {
191                 op->o_callback->sc_private = rs->sr_ctrls;
192                 for ( ; rs->sr_ctrls[n] != NULL; n++ )
193                         ;
194         }
195
196         ctrls = op->o_tmpalloc( sizeof( LDAPControl * )*( n + 2 ), op->o_tmpmemctx );
197         n = 0;
198         if ( rs->sr_ctrls ) {
199                 for ( ; rs->sr_ctrls[n] != NULL; n++ ) {
200                         ctrls[n] = rs->sr_ctrls[n];
201                 }
202         }
203
204         /* anonymous: "", otherwise "dn:<dn>" */
205         ctrls[n] = op->o_tmpalloc( sizeof( LDAPControl ) + len + 1, op->o_tmpmemctx );
206         ctrls[n]->ldctl_oid = LDAP_CONTROL_AUTHZID_RESPONSE;
207         ctrls[n]->ldctl_iscritical = 0;
208         ctrls[n]->ldctl_value.bv_len = len;
209         ctrls[n]->ldctl_value.bv_val = (char *)&ctrls[n][1];
210         if ( len ) {
211                 char *ptr;
212
213                 ptr = lutil_strcopy( ctrls[n]->ldctl_value.bv_val, "dn:" );
214                 ptr = lutil_strncopy( ptr, edn.bv_val, edn.bv_len );
215         }
216         ctrls[n]->ldctl_value.bv_val[len] = '\0';
217         ctrls[n + 1] = NULL;
218
219         rs->sr_ctrls = ctrls;
220
221         return SLAP_CB_CONTINUE;
222 }
223
224 static int
225 authzid_cleanup(
226         Operation *op,
227         SlapReply *rs )
228 {
229         if ( rs->sr_ctrls ) {
230                 LDAPControl *ctrl;
231
232                 /* if ours, cleanup */
233                 ctrl = ldap_control_find( LDAP_CONTROL_AUTHZID_RESPONSE, rs->sr_ctrls, NULL );
234                 if ( ctrl ) {
235                         
236                         op->o_tmpfree( rs->sr_ctrls, op->o_tmpmemctx );
237                 }
238
239                 if ( op->o_callback->sc_private != NULL ) {
240                         rs->sr_ctrls = (LDAPControl **)op->o_callback->sc_private;
241                         op->o_callback->sc_private = NULL;
242                 }
243         }
244
245         op->o_tmpfree( op->o_callback, op->o_tmpmemctx );
246         op->o_callback = NULL;
247
248         return SLAP_CB_CONTINUE;
249 }
250
251 static int
252 authzid_op_bind(
253         Operation *op,
254         SlapReply *rs )
255 {
256         slap_callback *sc;
257
258         if ( op->o_ctrlflag[ authzid_cid ] <= SLAP_CONTROL_IGNORED ) {
259                 authzid_conn_t *ac = authzid_conn_get( op->o_conn );
260                 if ( ac ) {
261                         op->o_ctrlflag[ authzid_cid ] = ac->authzid_flag;
262                         op->o_controls[ authzid_cid] = ac;
263                 }
264         }
265
266         if ( op->o_ctrlflag[ authzid_cid ] > SLAP_CONTROL_IGNORED ) {
267                 sc = op->o_callback;
268                 op->o_callback = op->o_tmpalloc( sizeof( slap_callback ), op->o_tmpmemctx );
269                 op->o_callback->sc_response = authzid_response;
270                 op->o_callback->sc_cleanup = authzid_cleanup;
271                 op->o_callback->sc_private = NULL;
272                 op->o_callback->sc_next = sc;
273         }
274
275         return SLAP_CB_CONTINUE;
276 }
277
278 static int
279 parse_authzid_ctrl(
280         Operation       *op,
281         SlapReply       *rs,
282         LDAPControl     *ctrl )
283 {
284         if ( op->o_ctrlflag[ authzid_cid ] != SLAP_CONTROL_NONE ) {
285                 rs->sr_text = "authzid control specified multiple times";
286                 return LDAP_PROTOCOL_ERROR;
287         }
288
289         if ( !BER_BVISNULL( &ctrl->ldctl_value ) ) {
290                 rs->sr_text = "authzid control value not absent";
291                 return LDAP_PROTOCOL_ERROR;
292         }
293
294         /* drop ongoing requests */
295         (void)authzid_conn_remove( op->o_conn );
296
297         op->o_ctrlflag[ authzid_cid ] = ctrl->ldctl_iscritical ?  SLAP_CONTROL_CRITICAL : SLAP_CONTROL_NONCRITICAL;
298
299         return LDAP_SUCCESS;
300 }
301
302 static int authzid_cnt;
303
304 static int
305 authzid_db_init( BackendDB *be, ConfigReply *cr)
306 {
307         if ( authzid_cnt++ == 0 ) {
308                 int rc;
309
310                 rc = register_supported_control( LDAP_CONTROL_AUTHZID_REQUEST,
311                         SLAP_CTRL_GLOBAL|SLAP_CTRL_BIND|SLAP_CTRL_HIDE, NULL,
312                         parse_authzid_ctrl, &authzid_cid );
313                 if ( rc != LDAP_SUCCESS ) {
314                         Debug( LDAP_DEBUG_ANY,
315                                 "authzid_initialize: Failed to register control '%s' (%d)\n",
316                                 LDAP_CONTROL_AUTHZID_REQUEST, rc, 0 );
317                         return rc;
318                 }
319         }
320
321         return LDAP_SUCCESS;
322 }
323
324 static int
325 authzid_db_destroy( BackendDB *be, ConfigReply *cr )
326 {
327         assert( authzid_cnt > 0 );
328
329 #ifdef SLAP_CONFIG_DELETE
330         overlay_unregister_control( be, LDAP_CONTROL_AUTHZID_REQUEST );
331 #endif /* SLAP_CONFIG_DELETE */
332
333         if ( --authzid_cnt == 0 ) {
334                 unregister_supported_control( LDAP_CONTROL_AUTHZID_REQUEST );
335         }
336
337         return 0;
338 }
339
340 static int
341 authzid_initialize( void )
342 {
343         ldap_pvt_thread_mutex_init( &authzid_mutex );
344
345         authzid.on_bi.bi_type = "authzid";
346
347         authzid.on_bi.bi_db_init = authzid_db_init;
348         authzid.on_bi.bi_db_destroy = authzid_db_destroy;
349         authzid.on_bi.bi_op_bind = authzid_op_bind;
350
351         return overlay_register( &authzid );
352 }
353
354 int
355 init_module( int argc, char *argv[] )
356 {
357         return authzid_initialize();
358 }
359