1 /* authzid.c - RFC 3829 Authzid Control */
3 /* This work is part of OpenLDAP Software <http://www.openldap.org/>.
5 * Copyright 2010-2011 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.
24 * must be instantiated as a global overlay
32 #include "ac/string.h"
34 typedef struct authzid_conn_t {
40 static ldap_pvt_thread_mutex_t authzid_mutex;
41 static Avlnode *authzid_tree;
44 authzid_conn_cmp( const void *c1, const void *c2 )
46 const authzid_conn_t *ac1 = (const authzid_conn_t *)c1;
47 const authzid_conn_t *ac2 = (const authzid_conn_t *)c2;
49 return SLAP_PTRCMP( ac1->conn, ac2->conn );
53 authzid_conn_dup( void *c1, void *c2 )
55 authzid_conn_t *ac1 = (authzid_conn_t *)c1;
56 authzid_conn_t *ac2 = (authzid_conn_t *)c2;
58 if ( ac1->conn == ac2->conn ) {
65 static int authzid_cid;
66 static slap_overinst authzid;
68 static authzid_conn_t *
69 authzid_conn_find( Connection *c )
71 authzid_conn_t *ac = NULL, tmp = { 0 };
74 ac = (authzid_conn_t *)avl_find( authzid_tree, (caddr_t)&tmp, authzid_conn_cmp );
75 if ( ac == NULL || ( ac != NULL && ac->refcnt != 0 ) ) {
77 ldap_pvt_thread_mutex_unlock( &authzid_mutex );
86 static authzid_conn_t *
87 authzid_conn_get( Connection *c )
89 authzid_conn_t *ac = NULL;
91 ldap_pvt_thread_mutex_lock( &authzid_mutex );
92 ac = authzid_conn_find( c );
93 if ( ac && ac->refcnt ) ac = NULL;
94 if ( ac ) ac->refcnt++;
95 ldap_pvt_thread_mutex_unlock( &authzid_mutex );
101 authzid_conn_release( authzid_conn_t *ac )
103 ldap_pvt_thread_mutex_lock( &authzid_mutex );
105 ldap_pvt_thread_mutex_unlock( &authzid_mutex );
109 authzid_conn_insert( Connection *c, char flag )
114 ldap_pvt_thread_mutex_lock( &authzid_mutex );
115 ac = authzid_conn_find( c );
117 ldap_pvt_thread_mutex_unlock( &authzid_mutex );
121 ac = SLAP_MALLOC( sizeof( authzid_conn_t ) );
124 ac->authzid_flag = flag;
125 rc = avl_insert( &authzid_tree, (caddr_t)ac,
126 authzid_conn_cmp, authzid_conn_dup );
127 ldap_pvt_thread_mutex_unlock( &authzid_mutex );
133 authzid_conn_remove( Connection *c )
135 authzid_conn_t *ac, *tmp;
137 ldap_pvt_thread_mutex_lock( &authzid_mutex );
138 ac = authzid_conn_find( c );
140 ldap_pvt_thread_mutex_unlock( &authzid_mutex );
143 tmp = avl_delete( &authzid_tree, (caddr_t)ac, authzid_conn_cmp );
144 ldap_pvt_thread_mutex_unlock( &authzid_mutex );
158 struct berval edn = BER_BVNULL;
162 assert( rs->sr_tag = LDAP_RES_BIND );
164 if ( rs->sr_err == LDAP_SASL_BIND_IN_PROGRESS ) {
165 authzid_conn_t *ac = op->o_controls[ authzid_cid ];
167 authzid_conn_release( ac );
169 (void)authzid_conn_insert( op->o_conn, op->o_ctrlflag[ authzid_cid ] );
171 return SLAP_CB_CONTINUE;
174 (void)authzid_conn_remove( op->o_conn );
176 if ( rs->sr_err != LDAP_SUCCESS ) {
177 return SLAP_CB_CONTINUE;
180 if ( !BER_BVISEMPTY( &op->orb_edn ) ) {
183 } else if ( !BER_BVISEMPTY( &op->o_conn->c_dn ) ) {
184 edn = op->o_conn->c_dn;
187 if ( !BER_BVISEMPTY( &edn ) ) {
188 ber_tag_t save_tag = op->o_tag;
189 struct berval save_dn = op->o_dn;
190 struct berval save_ndn = op->o_ndn;
193 /* pretend it's an extop without data,
194 * so it is treated as a generic write
196 op->o_tag = LDAP_REQ_EXTENDED;
199 rc = backend_check_restrictions( op, rs, NULL );
200 op->o_tag = save_tag;
202 op->o_ndn = save_ndn;
203 if ( rc != LDAP_SUCCESS ) {
204 rs->sr_err = LDAP_CONFIDENTIALITY_REQUIRED;
205 return SLAP_CB_CONTINUE;
208 len = STRLENOF("dn:") + edn.bv_len;
211 /* save original controls in sc_private;
212 * will be restored by sc_cleanup
214 if ( rs->sr_ctrls != NULL ) {
215 op->o_callback->sc_private = rs->sr_ctrls;
216 for ( ; rs->sr_ctrls[n] != NULL; n++ )
220 ctrls = op->o_tmpalloc( sizeof( LDAPControl * )*( n + 2 ), op->o_tmpmemctx );
222 if ( rs->sr_ctrls ) {
223 for ( ; rs->sr_ctrls[n] != NULL; n++ ) {
224 ctrls[n] = rs->sr_ctrls[n];
228 /* anonymous: "", otherwise "dn:<dn>" */
229 ctrls[n] = op->o_tmpalloc( sizeof( LDAPControl ) + len + 1, op->o_tmpmemctx );
230 ctrls[n]->ldctl_oid = LDAP_CONTROL_AUTHZID_RESPONSE;
231 ctrls[n]->ldctl_iscritical = 0;
232 ctrls[n]->ldctl_value.bv_len = len;
233 ctrls[n]->ldctl_value.bv_val = (char *)&ctrls[n][1];
237 ptr = lutil_strcopy( ctrls[n]->ldctl_value.bv_val, "dn:" );
238 ptr = lutil_strncopy( ptr, edn.bv_val, edn.bv_len );
240 ctrls[n]->ldctl_value.bv_val[len] = '\0';
243 rs->sr_ctrls = ctrls;
245 return SLAP_CB_CONTINUE;
253 if ( rs->sr_ctrls ) {
256 /* if ours, cleanup */
257 ctrl = ldap_control_find( LDAP_CONTROL_AUTHZID_RESPONSE, rs->sr_ctrls, NULL );
259 op->o_tmpfree( rs->sr_ctrls, op->o_tmpmemctx );
263 if ( op->o_callback->sc_private != NULL ) {
264 rs->sr_ctrls = (LDAPControl **)op->o_callback->sc_private;
265 op->o_callback->sc_private = NULL;
269 op->o_tmpfree( op->o_callback, op->o_tmpmemctx );
270 op->o_callback = NULL;
272 return SLAP_CB_CONTINUE;
282 if ( op->o_ctrlflag[ authzid_cid ] <= SLAP_CONTROL_IGNORED ) {
283 authzid_conn_t *ac = authzid_conn_get( op->o_conn );
285 op->o_ctrlflag[ authzid_cid ] = ac->authzid_flag;
286 op->o_controls[ authzid_cid] = ac;
290 if ( op->o_ctrlflag[ authzid_cid ] > SLAP_CONTROL_IGNORED ) {
292 op->o_callback = op->o_tmpalloc( sizeof( slap_callback ), op->o_tmpmemctx );
293 op->o_callback->sc_response = authzid_response;
294 op->o_callback->sc_cleanup = authzid_cleanup;
295 op->o_callback->sc_private = NULL;
296 op->o_callback->sc_next = sc;
299 return SLAP_CB_CONTINUE;
308 if ( op->o_ctrlflag[ authzid_cid ] != SLAP_CONTROL_NONE ) {
309 rs->sr_text = "authzid control specified multiple times";
310 return LDAP_PROTOCOL_ERROR;
313 if ( !BER_BVISNULL( &ctrl->ldctl_value ) ) {
314 rs->sr_text = "authzid control value not absent";
315 return LDAP_PROTOCOL_ERROR;
318 /* drop ongoing requests */
319 (void)authzid_conn_remove( op->o_conn );
321 op->o_ctrlflag[ authzid_cid ] = ctrl->ldctl_iscritical ? SLAP_CONTROL_CRITICAL : SLAP_CONTROL_NONCRITICAL;
327 authzid_db_init( BackendDB *be, ConfigReply *cr )
329 if ( !SLAP_ISGLOBALOVERLAY( be ) ) {
330 /* do not allow slapo-ppolicy to be global by now (ITS#5858) */
332 snprintf( cr->msg, sizeof(cr->msg),
333 "slapo-authzid must be global" );
334 Debug( LDAP_DEBUG_ANY, "%s\n", cr->msg, 0, 0 );
341 rc = register_supported_control( LDAP_CONTROL_AUTHZID_REQUEST,
342 SLAP_CTRL_GLOBAL|SLAP_CTRL_BIND|SLAP_CTRL_HIDE, NULL,
343 parse_authzid_ctrl, &authzid_cid );
344 if ( rc != LDAP_SUCCESS ) {
345 Debug( LDAP_DEBUG_ANY,
346 "authzid_initialize: Failed to register control '%s' (%d)\n",
347 LDAP_CONTROL_AUTHZID_REQUEST, rc, 0 );
355 * Almost pointless, by now, since this overlay needs to be global,
356 * and global overlays deletion is not supported yet.
359 authzid_db_destroy( BackendDB *be, ConfigReply *cr )
361 #ifdef SLAP_CONFIG_DELETE
362 overlay_unregister_control( be, LDAP_CONTROL_AUTHZID_REQUEST );
363 #endif /* SLAP_CONFIG_DELETE */
365 unregister_supported_control( LDAP_CONTROL_AUTHZID_REQUEST );
371 authzid_initialize( void )
373 ldap_pvt_thread_mutex_init( &authzid_mutex );
375 authzid.on_bi.bi_type = "authzid";
377 authzid.on_bi.bi_db_init = authzid_db_init;
378 authzid.on_bi.bi_db_destroy = authzid_db_destroy;
379 authzid.on_bi.bi_op_bind = authzid_op_bind;
381 return overlay_register( &authzid );
385 init_module( int argc, char *argv[] )
387 return authzid_initialize();