1 /* authzid.c - RFC 3829 Authzid Control */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
5 * Copyright 2010 The OpenLDAP Foundation.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted only as authorized by the OpenLDAP
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>.
17 * This work was initially developed by Pierangelo Masarati for inclusion
18 * in OpenLDAP Software.
29 #include "ac/string.h"
31 typedef struct authzid_conn_t {
37 static ldap_pvt_thread_mutex_t authzid_mutex;
38 static Avlnode *authzid_tree;
41 authzid_conn_cmp( const void *c1, const void *c2 )
43 const authzid_conn_t *ac1 = (const authzid_conn_t *)c1;
44 const authzid_conn_t *ac2 = (const authzid_conn_t *)c2;
46 return SLAP_PTRCMP( ac1->conn, ac2->conn );
50 authzid_conn_dup( void *c1, void *c2 )
52 authzid_conn_t *ac1 = (authzid_conn_t *)c1;
53 authzid_conn_t *ac2 = (authzid_conn_t *)c2;
55 if ( ac1->conn == ac2->conn ) {
62 static int authzid_cid;
63 static slap_overinst authzid;
65 static authzid_conn_t *
66 authzid_conn_find( Connection *c )
68 authzid_conn_t *ac = NULL, tmp = { 0 };
71 ac = (authzid_conn_t *)avl_find( authzid_tree, (caddr_t)&tmp, authzid_conn_cmp );
72 if ( ac == NULL || ( ac != NULL && ac->refcnt != 0 ) ) {
74 ldap_pvt_thread_mutex_unlock( &authzid_mutex );
83 static authzid_conn_t *
84 authzid_conn_get( Connection *c )
86 authzid_conn_t *ac = NULL;
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 );
98 authzid_conn_release( authzid_conn_t *ac )
100 ldap_pvt_thread_mutex_lock( &authzid_mutex );
102 ldap_pvt_thread_mutex_unlock( &authzid_mutex );
106 authzid_conn_insert( Connection *c, char flag )
111 ldap_pvt_thread_mutex_lock( &authzid_mutex );
112 ac = authzid_conn_find( c );
114 ldap_pvt_thread_mutex_unlock( &authzid_mutex );
118 ac = SLAP_MALLOC( sizeof( authzid_conn_t ) );
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 );
130 authzid_conn_remove( Connection *c )
132 authzid_conn_t *ac, *tmp;
134 ldap_pvt_thread_mutex_lock( &authzid_mutex );
135 ac = authzid_conn_find( c );
137 ldap_pvt_thread_mutex_unlock( &authzid_mutex );
140 tmp = avl_delete( &authzid_tree, (caddr_t)ac, authzid_conn_cmp );
141 ldap_pvt_thread_mutex_unlock( &authzid_mutex );
155 struct berval edn = BER_BVNULL;
159 assert( rs->sr_tag = LDAP_RES_BIND );
161 if ( rs->sr_err == LDAP_SASL_BIND_IN_PROGRESS ) {
162 authzid_conn_t *ac = op->o_controls[ authzid_cid ];
164 authzid_conn_release( ac );
166 (void)authzid_conn_insert( op->o_conn, op->o_ctrlflag[ authzid_cid ] );
168 return SLAP_CB_CONTINUE;
171 (void)authzid_conn_remove( op->o_conn );
173 if ( rs->sr_err != LDAP_SUCCESS ) {
174 return SLAP_CB_CONTINUE;
177 if ( !BER_BVISEMPTY( &op->orb_edn ) ) {
179 } else if ( !BER_BVISEMPTY( &op->o_conn->c_dn ) ) {
180 edn = op->o_conn->c_dn;
183 if ( !BER_BVISEMPTY( &edn ) ) {
184 len = STRLENOF("dn:") + edn.bv_len;
187 /* save original controls in sc_private;
188 * will be restored by sc_cleanup
190 if ( rs->sr_ctrls != NULL ) {
191 op->o_callback->sc_private = rs->sr_ctrls;
192 for ( ; rs->sr_ctrls[n] != NULL; n++ )
196 ctrls = op->o_tmpalloc( sizeof( LDAPControl * )*( n + 2 ), op->o_tmpmemctx );
198 if ( rs->sr_ctrls ) {
199 for ( ; rs->sr_ctrls[n] != NULL; n++ ) {
200 ctrls[n] = rs->sr_ctrls[n];
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];
213 ptr = lutil_strcopy( ctrls[n]->ldctl_value.bv_val, "dn:" );
214 ptr = lutil_strncopy( ptr, edn.bv_val, edn.bv_len );
216 ctrls[n]->ldctl_value.bv_val[len] = '\0';
219 rs->sr_ctrls = ctrls;
221 return SLAP_CB_CONTINUE;
229 if ( rs->sr_ctrls ) {
232 /* if ours, cleanup */
233 ctrl = ldap_control_find( LDAP_CONTROL_AUTHZID_RESPONSE, rs->sr_ctrls, NULL );
236 op->o_tmpfree( rs->sr_ctrls, op->o_tmpmemctx );
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;
245 op->o_tmpfree( op->o_callback, op->o_tmpmemctx );
246 op->o_callback = NULL;
248 return SLAP_CB_CONTINUE;
258 if ( op->o_ctrlflag[ authzid_cid ] <= SLAP_CONTROL_IGNORED ) {
259 authzid_conn_t *ac = authzid_conn_get( op->o_conn );
261 op->o_ctrlflag[ authzid_cid ] = ac->authzid_flag;
262 op->o_controls[ authzid_cid] = ac;
266 if ( op->o_ctrlflag[ authzid_cid ] > SLAP_CONTROL_IGNORED ) {
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;
275 return SLAP_CB_CONTINUE;
284 if ( op->o_ctrlflag[ authzid_cid ] != SLAP_CONTROL_NONE ) {
285 rs->sr_text = "authzid control specified multiple times";
286 return LDAP_PROTOCOL_ERROR;
289 if ( !BER_BVISNULL( &ctrl->ldctl_value ) ) {
290 rs->sr_text = "authzid control value not absent";
291 return LDAP_PROTOCOL_ERROR;
294 /* drop ongoing requests */
295 (void)authzid_conn_remove( op->o_conn );
297 op->o_ctrlflag[ authzid_cid ] = ctrl->ldctl_iscritical ? SLAP_CONTROL_CRITICAL : SLAP_CONTROL_NONCRITICAL;
302 static int authzid_cnt;
305 authzid_db_init( BackendDB *be, ConfigReply *cr)
307 if ( authzid_cnt++ == 0 ) {
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 );
325 authzid_db_destroy( BackendDB *be, ConfigReply *cr )
327 assert( authzid_cnt > 0 );
329 #ifdef SLAP_CONFIG_DELETE
330 overlay_unregister_control( be, LDAP_CONTROL_AUTHZID_REQUEST );
331 #endif /* SLAP_CONFIG_DELETE */
333 if ( --authzid_cnt == 0 ) {
334 unregister_supported_control( LDAP_CONTROL_AUTHZID_REQUEST );
341 authzid_initialize( void )
343 ldap_pvt_thread_mutex_init( &authzid_mutex );
345 authzid.on_bi.bi_type = "authzid";
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;
351 return overlay_register( &authzid );
355 init_module( int argc, char *argv[] )
357 return authzid_initialize();