/** BEGIN COPYRIGHT BLOCK * This Program is free software; you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by the Free Software * Foundation; version 2 of the License. * * This Program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along with * this Program; if not, write to the Free Software Foundation, Inc., 59 Temple * Place, Suite 330, Boston, MA 02111-1307 USA. * * In addition, as a special exception, Red Hat, Inc. gives You the additional * right to link the code of this Program with code not covered under the GNU * General Public License ("Non-GPL Code") and to distribute linked combinations * including the two, subject to the limitations in this paragraph. Non-GPL Code * permitted under this exception must only link to the code of this Program * through those well defined interfaces identified in the file named EXCEPTION * found in the source code files (the "Approved Interfaces"). The files of * Non-GPL Code may instantiate templates or use macros or inline functions from * the Approved Interfaces without causing the resulting work to be covered by * the GNU General Public License. Only Red Hat, Inc. may make changes or * additions to the list of Approved Interfaces. You must obey the GNU General * Public License in all respects for all of the Program code and other code used * in conjunction with the Program except the Non-GPL Code covered by this * exception. If you modify this file, you may extend this exception to your * version of the file, but you are not obligated to do so. If you do not wish to * provide this exception without modification, you must delete this exception * statement from your version and license this file solely under the GPL without * exception. * * * Copyright (C) 2001 Sun Microsystems, Inc. Used by permission. * Copyright (C) 2005 Red Hat, Inc. * All rights reserved. * END COPYRIGHT BLOCK **/ #ifdef HAVE_CONFIG_H # include #endif #include "acl.h" static void acl__done_aclpb ( struct acl_pblock *aclpb ); #ifdef FOR_DEBUGGING static void acl__dump_stats ( struct acl_pblock *aclpb , const char *block_type); static char * acl__get_aclpb_type ( Acl_PBlock *aclpb ); #endif static Acl_PBlock * acl__get_aclpb_from_pool ( ); static int acl__put_aclpb_back_to_pool ( Acl_PBlock *aclpb ); static Acl_PBlock * acl__malloc_aclpb ( ); static PRLock *aclext_get_lock (); struct acl_pbqueue { Acl_PBlock *aclq_free; Acl_PBlock *aclq_busy; short aclq_nfree; short aclq_nbusy; PRLock *aclq_lock; }; typedef struct acl_pbqueue Acl_PBqueue; static Acl_PBqueue *aclQueue; /* structure with information for each extension */ typedef struct acl_ext { char *object_name; /* name of the object extended */ int object_type; /* handle to the extended object */ int handle; /* extension handle */ } acl_ext; static acl_ext acl_ext_list [ACL_EXT_ALL]; /* * EXTENSION INITIALIZATION, CONSTRUCTION, & DESTRUCTION * */ int acl_init_ext () { int rc; acl_ext_list[ACL_EXT_OPERATION].object_name = SLAPI_EXT_OPERATION; rc = slapi_register_object_extension(plugin_name, SLAPI_EXT_OPERATION, acl_operation_ext_constructor, acl_operation_ext_destructor, &acl_ext_list[ACL_EXT_OPERATION].object_type, &acl_ext_list[ACL_EXT_OPERATION].handle); if ( rc != 0 ) return rc; acl_ext_list[ACL_EXT_CONNECTION].object_name = SLAPI_EXT_CONNECTION; rc = slapi_register_object_extension(plugin_name, SLAPI_EXT_CONNECTION, acl_conn_ext_constructor, acl_conn_ext_destructor, &acl_ext_list[ACL_EXT_CONNECTION].object_type, &acl_ext_list[ACL_EXT_CONNECTION].handle); return rc; } /* Interface to get the extensions */ void * acl_get_ext (ext_type type, void *object) { struct acl_ext ext; void *data; if ( type >= ACL_EXT_ALL ) { slapi_log_error ( SLAPI_LOG_ACL, plugin_name, "Invalid extension type:%d\n", type ); return NULL; } /* find the requested extension */ ext = acl_ext_list [type]; data = slapi_get_object_extension(ext.object_type, object, ext.handle); return data; } void acl_set_ext (ext_type type, void *object, void *data) { if ( type >= 0 && type < ACL_EXT_ALL ) { struct acl_ext ext = acl_ext_list [type]; slapi_set_object_extension ( ext.object_type, object, ext.handle, data ); } } /**************************************************************************** * Global lock array so that private extension between connection and operation * co-exist * ******************************************************************************/ struct ext_lockArray { PRLock **lockArray; int numlocks; }; static struct ext_lockArray extLockArray; /* PKBxxx: make this a configurable. Start with 2 * maxThreads */ #define ACLEXT_MAX_LOCKS 40 int aclext_alloc_lockarray ( ) { int i; PRLock *lock; extLockArray.lockArray = (PRLock **) slapi_ch_calloc ( ACLEXT_MAX_LOCKS, sizeof ( PRLock *) ); for ( i =0; i < ACLEXT_MAX_LOCKS; i++) { if (NULL == (lock = PR_NewLock()) ) { slapi_log_error( SLAPI_LOG_FATAL, plugin_name, "Unable to allocate locks used for private extension\n"); return 1; } extLockArray.lockArray[i] = lock; } extLockArray.numlocks = ACLEXT_MAX_LOCKS; return 0; } static PRUint32 slot_id =0; static PRLock * aclext_get_lock () { PRUint16 slot = slot_id % ACLEXT_MAX_LOCKS; slot_id++; return ( extLockArray.lockArray[slot] ); } /****************************************************************************/ /* CONNECTION EXTENSION SPECIFIC */ /****************************************************************************/ void * acl_conn_ext_constructor ( void *object, void *parent ) { struct acl_cblock *ext = NULL; ext = (struct acl_cblock * ) slapi_ch_calloc (1, sizeof (struct acl_cblock ) ); if (( ext->aclcb_lock = aclext_get_lock () ) == NULL ) { slapi_log_error( SLAPI_LOG_FATAL, plugin_name, "Unable to get Read/Write lock for CONNECTION extension\n"); slapi_ch_free ( (void **) &ext ); return NULL; } ext->aclcb_sdn = slapi_sdn_new (); /* store the signatures */ ext->aclcb_aclsignature = acl_get_aclsignature(); ext->aclcb_state = -1; return ext; } void acl_conn_ext_destructor ( void *ext, void *object, void *parent ) { struct acl_cblock *aclcb = ext; PRLock *shared_lock; if ( NULL == aclcb ) return; PR_Lock ( aclcb->aclcb_lock ); shared_lock = aclcb->aclcb_lock; acl_clean_aclEval_context ( &aclcb->aclcb_eval_context, 0 /* clean*/ ); slapi_sdn_free ( &aclcb->aclcb_sdn ); aclcb->aclcb_lock = NULL; slapi_ch_free ( (void **) &aclcb ); PR_Unlock ( shared_lock ); } /****************************************************************************/ /* OPERATION EXTENSION SPECIFIC */ /****************************************************************************/ void * acl_operation_ext_constructor ( void *object, void *parent ) { Acl_PBlock *aclpb = NULL; TNF_PROBE_0_DEBUG(acl_operation_ext_constructor_start ,"ACL",""); /* This means internal operations */ if ( NULL == parent) { TNF_PROBE_1_DEBUG(acl_operation_ext_constructor_end ,"ACL","", tnf_string,internal_op,""); return NULL; } aclpb = acl__get_aclpb_from_pool(); if ( NULL == aclpb ) { slapi_log_error ( SLAPI_LOG_FATAL, plugin_name, "Operation extension allocation Failed\n"); } TNF_PROBE_0_DEBUG(acl_operation_ext_constructor_end ,"ACL",""); return aclpb; } void acl_operation_ext_destructor ( void *ext, void *object, void *parent ) { struct acl_cblock *aclcb = NULL; struct acl_pblock *aclpb = NULL; TNF_PROBE_0_DEBUG(acl_operation_ext_destructor_start ,"ACL",""); if ( (NULL == parent ) || (NULL == ext)) { TNF_PROBE_1_DEBUG(acl_operation_ext_destructor_end ,"ACL","", tnf_string,internal_op,""); return; } aclpb = (Acl_PBlock *) ext; if ( (NULL == aclpb) || (NULL == aclpb->aclpb_pblock) || (!(aclpb->aclpb_state & ACLPB_INITIALIZED))) goto clean_aclpb; if ( NULL == aclpb->aclpb_authorization_sdn ) { slapi_log_error (SLAPI_LOG_FATAL, plugin_name, "NULL aclcb_autorization_sdn\n"); goto clean_aclpb; } /* get the connection extension */ aclcb = (struct acl_cblock *) acl_get_ext ( ACL_EXT_CONNECTION, parent ); /* We are about to get out of this connection. Move all the ** cached information to the acl private block which hangs ** from the connection struct. */ if ( aclcb && aclcb->aclcb_lock && ( (aclpb->aclpb_state & ACLPB_UPD_ACLCB_CACHE ) || (aclpb->aclpb_state & ACLPB_INCR_ACLCB_CACHE ) ) ) { aclEvalContext *c_evalContext; int attr_only = 0; PRLock *shared_lock = aclcb->aclcb_lock; if (aclcb->aclcb_lock ) PR_Lock ( shared_lock ); else { goto clean_aclpb; } if ( !aclcb->aclcb_lock ) { slapi_log_error (SLAPI_LOG_FATAL, plugin_name, "aclcb lock released! aclcb cache can't be refreshed\n"); PR_Unlock ( shared_lock ); goto clean_aclpb; } /* We need to refresh the aclcb cache */ if ( aclpb->aclpb_state & ACLPB_UPD_ACLCB_CACHE ) acl_clean_aclEval_context ( &aclcb->aclcb_eval_context, 0 /* clean*/ ); if ( aclpb->aclpb_prev_entryEval_context.acle_numof_attrs ) { c_evalContext = &aclpb->aclpb_prev_entryEval_context; } else { c_evalContext = &aclpb->aclpb_curr_entryEval_context; } if (( aclpb->aclpb_state & ACLPB_INCR_ACLCB_CACHE ) && ! ( aclpb->aclpb_state & ACLPB_UPD_ACLCB_CACHE )) attr_only = 1; acl_copyEval_context ( NULL, c_evalContext, &aclcb->aclcb_eval_context, attr_only ); aclcb->aclcb_aclsignature = aclpb->aclpb_signature; if ( aclcb->aclcb_sdn && (0 != slapi_sdn_compare ( aclcb->aclcb_sdn, aclpb->aclpb_authorization_sdn ) ) ) { slapi_sdn_set_ndn_byval( aclcb->aclcb_sdn, slapi_sdn_get_ndn ( aclpb->aclpb_authorization_sdn ) ); } aclcb->aclcb_state = 0; aclcb->aclcb_state |= ACLCB_HAS_CACHED_EVALCONTEXT; PR_Unlock ( shared_lock ); } clean_aclpb: if ( aclpb ) { if ( aclpb->aclpb_proxy ) { TNF_PROBE_0_DEBUG(acl_proxy_aclpbdoneback_start ,"ACL",""); acl__done_aclpb( aclpb->aclpb_proxy ); /* Put back to the Pool */ acl__put_aclpb_back_to_pool ( aclpb->aclpb_proxy ); aclpb->aclpb_proxy = NULL; TNF_PROBE_0_DEBUG(acl_proxy_aclpbdoneback_end ,"ACL",""); } TNF_PROBE_0_DEBUG(acl_aclpbdoneback_start ,"ACL",""); acl__done_aclpb( aclpb); acl__put_aclpb_back_to_pool ( aclpb ); TNF_PROBE_0_DEBUG(acl_aclpbdoneback_end ,"ACL",""); } TNF_PROBE_0_DEBUG(acl_operation_ext_destructor_end ,"ACL",""); } /****************************************************************************/ /* FUNCTIONS TO MANAGE THE ACLPB POOL */ /****************************************************************************/ /* * Get the right acl pblock */ struct acl_pblock * acl_get_aclpb ( Slapi_PBlock *pb, int type ) { Acl_PBlock *aclpb = NULL; void *op = NULL; slapi_pblock_get ( pb, SLAPI_OPERATION, &op ); aclpb = (Acl_PBlock *) acl_get_ext ( ACL_EXT_OPERATION, op ); if (NULL == aclpb ) return NULL; if ( type == ACLPB_BINDDN_PBLOCK ) return aclpb; else if ( type == ACLPB_PROXYDN_PBLOCK ) return aclpb->aclpb_proxy; else slapi_log_error ( SLAPI_LOG_FATAL, plugin_name, "acl_get_aclpb: Invalid aclpb type %d\n", type ); return NULL; } /* * Create a new proxy acl pblock * */ struct acl_pblock * acl_new_proxy_aclpb( Slapi_PBlock *pb ) { void *op; Acl_PBlock *aclpb = NULL; Acl_PBlock *proxy_aclpb = NULL; slapi_pblock_get ( pb, SLAPI_OPERATION, &op ); aclpb = (Acl_PBlock *) acl_get_ext ( ACL_EXT_OPERATION, op ); if (NULL == aclpb ) return NULL; proxy_aclpb = acl__get_aclpb_from_pool(); if (NULL == proxy_aclpb) return NULL; proxy_aclpb->aclpb_type = ACLPB_TYPE_PROXY; aclpb->aclpb_proxy = proxy_aclpb; return proxy_aclpb; } static int acl__handle_config_entry (Slapi_Entry *e, void *callback_data ) { *(int * )callback_data = slapi_entry_attr_get_int( e, "nsslapd-threadnumber"); return 0; } /* * Create a pool of acl pblock. Created during the ACL plugin * initialization. */ int acl_create_aclpb_pool () { Acl_PBlock *aclpb; Acl_PBlock *prev_aclpb; Acl_PBlock *first_aclpb; int i; int maxThreads= 0; slapi_search_internal_callback( "cn=config", LDAP_SCOPE_BASE, "(objectclass=*)", NULL, 0 /* attrsonly */, &maxThreads/* callback_data */, NULL /* controls */, NULL /* result_callback */, acl__handle_config_entry, NULL /* referral_callback */); /* Create a pool pf aclpb */ maxThreads = 2 * maxThreads; aclQueue = ( Acl_PBqueue *) slapi_ch_calloc ( 1, sizeof (Acl_PBqueue) ); aclQueue->aclq_lock = PR_NewLock(); if ( NULL == aclQueue->aclq_lock ) { /* ERROR */ return 1; } prev_aclpb = NULL; first_aclpb = NULL; for ( i = 0; i < maxThreads; i++ ) { aclpb = acl__malloc_aclpb (); if ( 0 == i) first_aclpb = aclpb; aclpb->aclpb_prev = prev_aclpb; if ( prev_aclpb ) prev_aclpb->aclpb_next = aclpb; prev_aclpb = aclpb; } /* Since this is the begining, everybody is in free list */ aclQueue->aclq_free = first_aclpb; aclQueue->aclq_nfree = maxThreads; return 0; } /* * Get a FREE acl pblock from the pool. * */ static Acl_PBlock * acl__get_aclpb_from_pool ( ) { Acl_PBlock *aclpb = NULL; Acl_PBlock *t_aclpb = NULL; PR_Lock (aclQueue->aclq_lock ); /* Get the first aclpb from the FREE List */ aclpb = aclQueue->aclq_free; if ( aclpb ) { t_aclpb = aclpb->aclpb_next; if ( t_aclpb ) t_aclpb->aclpb_prev = NULL; aclQueue->aclq_free = t_aclpb; /* make the this an orphon */ aclpb->aclpb_prev = aclpb->aclpb_next = NULL; aclQueue->aclq_nfree--; } else { slapi_log_error ( SLAPI_LOG_ACL, plugin_name, "Unable to find a free aclpb\n"); aclpb = acl__malloc_aclpb (); } /* Now move it to the FRONT of busy list */ t_aclpb = aclQueue->aclq_busy; aclpb->aclpb_next = t_aclpb; if ( t_aclpb ) t_aclpb->aclpb_prev = aclpb; aclQueue->aclq_busy = aclpb; aclQueue->aclq_nbusy++; PR_Unlock (aclQueue->aclq_lock ); return aclpb; } /* * Put the acl pblock into the FREE pool. * */ static int acl__put_aclpb_back_to_pool ( Acl_PBlock *aclpb ) { Acl_PBlock *p_aclpb, *n_aclpb; PR_Lock (aclQueue->aclq_lock ); /* Remove it from the busy list */ n_aclpb = aclpb->aclpb_next; p_aclpb = aclpb->aclpb_prev; if ( p_aclpb ) { p_aclpb->aclpb_next = n_aclpb; if ( n_aclpb ) n_aclpb->aclpb_prev = p_aclpb; } else { aclQueue->aclq_busy = n_aclpb; if ( n_aclpb ) n_aclpb->aclpb_prev = NULL; } aclQueue->aclq_nbusy--; /* Put back to the FREE list */ aclpb->aclpb_prev = NULL; n_aclpb = aclQueue->aclq_free; aclpb->aclpb_next = n_aclpb; if ( n_aclpb ) n_aclpb->aclpb_prev = aclpb; aclQueue->aclq_free = aclpb; aclQueue->aclq_nfree++; PR_Unlock (aclQueue->aclq_lock ); return 0; } /* * Allocate the basic acl pb * */ static Acl_PBlock * acl__malloc_aclpb ( ) { Acl_PBlock *aclpb = NULL; aclpb = ( Acl_PBlock *) slapi_ch_calloc ( 1, sizeof ( Acl_PBlock) ); /* Now set the propert we need for ACL evaluations */ if ((aclpb->aclpb_proplist = PListNew(NULL)) == NULL) { slapi_log_error (SLAPI_LOG_FATAL, plugin_name, "Unable to allocate the aclprop PList\n"); goto error; } if (PListInitProp(aclpb->aclpb_proplist, 0, DS_PROP_ACLPB, aclpb, 0) < 0) { slapi_log_error(SLAPI_LOG_FATAL, plugin_name, "Unable to set the ACL PBLOCK in the Plist\n"); goto error; } if (PListInitProp(aclpb->aclpb_proplist, 0, DS_ATTR_USERDN, aclpb, 0) < 0) { slapi_log_error(SLAPI_LOG_FATAL, plugin_name, "Unable to set the USER DN in the Plist\n"); goto error; } if (PListInitProp(aclpb->aclpb_proplist, 0, DS_ATTR_AUTHTYPE, aclpb, 0) < 0) { slapi_log_error(SLAPI_LOG_FATAL, plugin_name, "Unable to set the AUTH TYPE in the Plist\n"); goto error; } if (PListInitProp(aclpb->aclpb_proplist, 0, DS_ATTR_ENTRY, aclpb, 0) < 0) { slapi_log_error(SLAPI_LOG_FATAL, plugin_name, "Unable to set the ENTRY TYPE in the Plist\n"); goto error; } if (PListInitProp(aclpb->aclpb_proplist, 0, DS_ATTR_SSF, aclpb, 0) < 0) { slapi_log_error(SLAPI_LOG_FATAL, plugin_name, "Unable to set the SSF in the Plist\n"); goto error; } /* * ACL_ATTR_IP and ACL_ATTR_DNS are initialized lazily in the * IpGetter and DnsGetter functions. * They are removed from the aclpb property list at acl__aclpb_done() * time. */ /* allocate the acleval struct */ aclpb->aclpb_acleval = (ACLEvalHandle_t *) ACL_EvalNew(NULL, NULL); if (aclpb->aclpb_acleval == NULL) { slapi_log_error(SLAPI_LOG_FATAL, plugin_name, "Unable to allocate the acleval block\n"); goto error; } /* * This is a libaccess routine. * Need to setup subject and resource property information */ ACL_EvalSetSubject(NULL, aclpb->aclpb_acleval, aclpb->aclpb_proplist); /* allocate some space for attr name */ aclpb->aclpb_Evalattr = (char *) slapi_ch_malloc (ACLPB_MAX_ATTR_LEN); aclpb->aclpb_deny_handles = (aci_t **) slapi_ch_calloc (1, ACLPB_INCR_LIST_HANDLES * sizeof (aci_t *)); aclpb->aclpb_allow_handles = (aci_t **) slapi_ch_calloc (1, ACLPB_INCR_LIST_HANDLES * sizeof (aci_t *)); aclpb->aclpb_deny_handles_size = ACLPB_INCR_LIST_HANDLES; aclpb->aclpb_allow_handles_size = ACLPB_INCR_LIST_HANDLES; /* allocate the array for bases */ aclpb->aclpb_grpsearchbase = (char **) slapi_ch_malloc (ACLPB_INCR_BASES * sizeof(char *)); aclpb->aclpb_grpsearchbase_size = ACLPB_INCR_BASES; aclpb->aclpb_numof_bases = 0; /* Make sure aclpb_search_base is initialized to NULL..tested elsewhere! */ aclpb->aclpb_search_base = NULL; aclpb->aclpb_authorization_sdn = slapi_sdn_new (); aclpb->aclpb_curr_entry_sdn = slapi_sdn_new(); aclpb->aclpb_aclContainer = acllist_get_aciContainer_new (); /* hash table to store macro matched values from targets */ aclpb->aclpb_macro_ht = acl_ht_new(); return aclpb; error: if (aclpb->aclpb_acleval) ACL_EvalDestroy(NULL, NULL, aclpb->aclpb_acleval); if (aclpb->aclpb_proplist) PListDestroy(aclpb->aclpb_proplist); slapi_ch_free((void**)&aclpb); return NULL; } /* Initializes the aclpb */ void acl_init_aclpb ( Slapi_PBlock *pb , Acl_PBlock *aclpb, const char *dn, int copy_from_aclcb) { struct acl_cblock *aclcb = NULL; char *authType; void *conn; int op_type; intptr_t ssf = 0; if ( NULL == aclpb ) { slapi_log_error ( SLAPI_LOG_FATAL, plugin_name, "acl_init_aclpb:No ACLPB\n"); return; } /* See if we have initialized already */ if (aclpb->aclpb_state & ACLPB_INITIALIZED) return; slapi_pblock_get ( pb, SLAPI_OPERATION_TYPE, &op_type ); if ( op_type == SLAPI_OPERATION_BIND || op_type == SLAPI_OPERATION_UNBIND ) return; /* We indicate the initialize here becuase, if something goes wrong, it's cleaned up ** properly. */ aclpb->aclpb_state = ACLPB_INITIALIZED; /* We make an anonymous user a non null dn which is empty */ if (dn && *dn != '\0' ) slapi_sdn_set_ndn_byval ( aclpb->aclpb_authorization_sdn, dn ); else slapi_sdn_set_ndn_byval ( aclpb->aclpb_authorization_sdn, "" ); /* reset scoped entry cache to be empty */ aclpb->aclpb_scoped_entry_anominfo.anom_e_nummatched = 0; if (PListAssignValue(aclpb->aclpb_proplist, DS_ATTR_USERDN, slapi_sdn_get_ndn(aclpb->aclpb_authorization_sdn), 0) < 0) { slapi_log_error(SLAPI_LOG_FATAL, plugin_name, "Unable to set the USER DN in the Plist\n"); return; } slapi_pblock_get ( pb, SLAPI_OPERATION_AUTHTYPE, &authType ); if (PListAssignValue(aclpb->aclpb_proplist, DS_ATTR_AUTHTYPE, authType, 0) < 0) { slapi_log_error(SLAPI_LOG_FATAL, plugin_name, "Unable to set the AUTH TYPE in the Plist\n"); return; } slapi_pblock_get ( pb, SLAPI_OPERATION_SSF, &ssf); if (PListAssignValue(aclpb->aclpb_proplist, DS_ATTR_SSF, (const void *)ssf, 0) < 0) { slapi_log_error(SLAPI_LOG_FATAL, plugin_name, "Unable to set the SSF in the Plist\n"); return; } /* PKBxxx: We should be getting it from the OP struct */ slapi_pblock_get ( pb, SLAPI_CONN_CERT, &aclpb->aclpb_clientcert ); /* See if the we have already a cached info about user's group */ aclg_init_userGroup ( aclpb, dn, 0 /* get lock */ ); slapi_pblock_get( pb, SLAPI_BE_MAXNESTLEVEL, &aclpb->aclpb_max_nesting_level ); slapi_pblock_get( pb, SLAPI_SEARCH_SIZELIMIT, &aclpb->aclpb_max_member_sizelimit ); if ( aclpb->aclpb_max_member_sizelimit == 0 ) { aclpb->aclpb_max_member_sizelimit = SLAPD_DEFAULT_LOOKTHROUGHLIMIT; } slapi_pblock_get( pb, SLAPI_OPERATION_TYPE, &aclpb->aclpb_optype ); aclpb->aclpb_signature = acl_get_aclsignature(); aclpb->aclpb_last_cache_result = 0; aclpb->aclpb_pblock = pb; PR_ASSERT ( aclpb->aclpb_pblock != NULL ); /* get the connection */ slapi_pblock_get ( pb, SLAPI_CONNECTION, &conn); aclcb = (struct acl_cblock *) acl_get_ext ( ACL_EXT_CONNECTION, conn ); if (NULL == aclcb || NULL == aclcb->aclcb_lock) { /* This could happen if the client is dead and we are in ** process of abondoning this operation */ slapi_log_error( SLAPI_LOG_ACL, plugin_name, "No CONNECTION extension\n"); } else if ( aclcb->aclcb_state == -1 ) { /* indicate that we need to update the cache */ aclpb->aclpb_state |= ACLPB_UPD_ACLCB_CACHE; aclcb->aclcb_state = 0; /* Nore this is ACLCB and not ACLPB */ } else if ( copy_from_aclcb ){ char *cdn; Slapi_DN *c_sdn; /* client SDN */ /* check if the operation is abandoned or not.*/ if ( slapi_op_abandoned ( pb ) ) { return; } slapi_pblock_get ( pb, SLAPI_CONN_DN, &cdn ); /* We *must* free cdn! */ c_sdn = slapi_sdn_new_dn_passin( cdn ); PR_Lock ( aclcb->aclcb_lock ); /* * since PR_Lock is taken, * we can mark the connection extension ok to be destroyed. */ if ( (aclcb->aclcb_aclsignature != acl_get_aclsignature()) || ( (NULL == cdn) && aclcb->aclcb_sdn ) || (cdn && (NULL == aclcb->aclcb_sdn )) || (cdn && aclcb->aclcb_sdn && ( 0 != slapi_sdn_compare ( c_sdn, aclcb->aclcb_sdn ) ))) { /* cleanup the aclcb cache */ acl_clean_aclEval_context ( &aclcb->aclcb_eval_context, 0 /*clean*/ ); aclcb->aclcb_state = 0; aclcb->aclcb_aclsignature = 0; slapi_sdn_done ( aclcb->aclcb_sdn ); } slapi_sdn_free ( &c_sdn ); /* COPY the cached information from ACLCB --> ACLPB */ if ( aclcb->aclcb_state & ACLCB_HAS_CACHED_EVALCONTEXT) { acl_copyEval_context ( aclpb, &aclcb->aclcb_eval_context , &aclpb->aclpb_prev_opEval_context, 0 ); aclpb->aclpb_state |= ACLPB_HAS_ACLCB_EVALCONTEXT; } PR_Unlock ( aclcb->aclcb_lock ); } } /* Cleans up the aclpb */ static void acl__done_aclpb ( struct acl_pblock *aclpb ) { int i; int dump_aclpb_info = 0; int rc=-1; char *tmp_ptr=NULL; /* ** First, let's do some sanity checks to see if we have everything what ** it should be. */ /* Nothing needs to be cleaned up in this case */ if (!(aclpb->aclpb_state & ACLPB_INITIALIZED)) return; /* Check the state */ if (aclpb->aclpb_state & ~ACLPB_STATE_ALL) { slapi_log_error( SLAPI_LOG_FATAL, plugin_name, "The aclpb.state value (%d) is incorrect. Exceeded the limit (%d)\n", aclpb->aclpb_state, ACLPB_STATE_ALL); dump_aclpb_info = 1; } #ifdef FOR_DEBUGGING acl__dump_stats ( aclpb, acl__get_aclpb_type(aclpb)); #endif /* reset the usergroup cache */ aclg_reset_userGroup ( aclpb ); if ( aclpb->aclpb_res_type & ~ACLPB_RESTYPE_ALL ) { slapi_log_error( SLAPI_LOG_FATAL, plugin_name, "The aclpb res_type value (%d) has exceeded. Limit is (%d)\n", aclpb->aclpb_res_type, ACLPB_RESTYPE_ALL ); dump_aclpb_info = 1; } if ( dump_aclpb_info ) { const char *ndn; slapi_log_error ( SLAPI_LOG_FATAL, plugin_name, "ACLPB value is:%p\n", aclpb ); ndn = slapi_sdn_get_ndn ( aclpb->aclpb_curr_entry_sdn ); slapi_log_error ( SLAPI_LOG_FATAL, plugin_name, "curr_entry:%p num_entries:%d curr_dn:%p\n", aclpb->aclpb_curr_entry ? (char *) aclpb->aclpb_curr_entry : "NULL", aclpb->aclpb_num_entries, ndn ? ndn : "NULL"); slapi_log_error ( SLAPI_LOG_FATAL, plugin_name, "Last attr:%p, Plist:%p acleval: %p\n", aclpb->aclpb_Evalattr ? aclpb->aclpb_Evalattr : "NULL", aclpb->aclpb_proplist ? (char *) aclpb->aclpb_proplist : "NULL", aclpb->aclpb_acleval ? (char *) aclpb->aclpb_acleval : "NULL" ); } /* Now Free the contents or clean it */ slapi_sdn_done ( aclpb->aclpb_curr_entry_sdn ); if (aclpb->aclpb_Evalattr) aclpb->aclpb_Evalattr[0] = '\0'; /* deallocate the contents of the base array */ for (i=0; i < aclpb->aclpb_numof_bases; i++) { if (aclpb->aclpb_grpsearchbase[i]) slapi_ch_free ( (void **)&aclpb->aclpb_grpsearchbase[i] ); } aclpb->aclpb_numof_bases = 0; acl_clean_aclEval_context ( &aclpb->aclpb_prev_opEval_context, 0 /*claen*/ ); acl_clean_aclEval_context ( &aclpb->aclpb_prev_entryEval_context, 0 /*clean*/ ); acl_clean_aclEval_context ( &aclpb->aclpb_curr_entryEval_context, 0/*clean*/ ); if ( aclpb->aclpb_client_entry ) slapi_entry_free ( aclpb->aclpb_client_entry ); aclpb->aclpb_client_entry = NULL; slapi_sdn_done ( aclpb->aclpb_authorization_sdn ); aclpb->aclpb_pblock = NULL; if ( aclpb->aclpb_search_base ) slapi_ch_free ( (void **) &aclpb->aclpb_search_base ); for ( i=0; i < aclpb->aclpb_num_deny_handles; i++ ) aclpb->aclpb_deny_handles[i] = NULL; aclpb->aclpb_num_deny_handles = 0; for ( i=0; i < aclpb->aclpb_num_allow_handles; i++ ) aclpb->aclpb_allow_handles[i] = NULL; aclpb->aclpb_num_allow_handles = 0; /* clear results cache */ memset((char*)aclpb->aclpb_cache_result, 0, sizeof(struct result_cache)*aclpb->aclpb_last_cache_result); aclpb->aclpb_last_cache_result = 0; aclpb->aclpb_handles_index[0] = -1; aclpb->aclpb_base_handles_index[0] = -1; aclpb->aclpb_stat_acllist_scanned = 0; aclpb->aclpb_stat_aclres_matched = 0; aclpb->aclpb_stat_total_entries = 0; aclpb->aclpb_stat_anom_list_scanned = 0; aclpb->aclpb_stat_num_copycontext = 0; aclpb->aclpb_stat_num_copy_attrs = 0; aclpb->aclpb_stat_num_tmatched_acls = 0; aclpb->aclpb_clientcert = NULL; aclpb->aclpb_proxy = NULL; acllist_done_aciContainer ( aclpb->aclpb_aclContainer ); /* * Here, decide which things need to be freed/removed/whatever from the * aclpb_proplist. */ /* * The DS_ATTR_DNS property contains the name of the client machine. * * The value pointed to by this property is stored in the pblock--it * points to the SLAPI_CLIENT_DNS object. So, that memory will * be freed elsewhere. * * It's removed here from the aclpb_proplist as it would be an error to * allow it to persist in the aclpb which is an operation time thing. * If we leave it here the next time this aclpb gets used, the DnsGetter * is not called by LASDnsEval/ACL_GetAttribute() as it thinks the * ACL_ATTR_DNS has already been initialized. * */ if ((rc = PListFindValue(aclpb->aclpb_proplist, ACL_ATTR_DNS, (void **)&tmp_ptr, NULL)) > 0) { PListDeleteProp(aclpb->aclpb_proplist, rc, NULL); } /* * Remove the DS_ATTR_IP property from the property list. * The value of this property is just the property pointer * (an unsigned long) so that gets freed too when we delete the * property. * It's removed here from the aclpb_proplist as it would be an error to * allow it to persist in the aclpb which is an operation time thing. * If we leave it here the next time this aclpb gets used, the DnsGetter * is not called by LASIpEval/ACL_GetAttribute() as it thinks the * ACL_ATTR_IP has already been initialized. */ if ((rc = PListFindValue(aclpb->aclpb_proplist, ACL_ATTR_IP, (void **)&tmp_ptr, NULL)) > 0) { PListDeleteProp(aclpb->aclpb_proplist, rc, NULL); } /* * The DS_ATTR_USERDN value comes from aclpb_authorization_sdn. * This memory * is freed above using aclpb_authorization_sdn so we don't need to free it here * before overwriting the old value. */ PListAssignValue(aclpb->aclpb_proplist, DS_ATTR_USERDN, NULL, 0); /* * The DS_ATTR_AUTHTYPE value is a pointer into the pblock, so * we do not need to free that memory before overwriting the value. */ PListAssignValue(aclpb->aclpb_proplist, DS_ATTR_AUTHTYPE, NULL, 0); /* * DO NOT overwrite the aclpb pointer--it is initialized at malloc_aclpb * time and is kept within the aclpb. * * PListAssignValue(aclpb->aclpb_proplist, DS_PROP_ACLPB, NULL, 0); */ /* * The DS_ATTR_ENTRY value was a pointer to the entry being evaluated * by the ACL code. That entry comes from outside the context of * the acl code and so is dealt with out there. Ergo, here we can just * lose the pointer to that entry. */ PListAssignValue(aclpb->aclpb_proplist, DS_ATTR_ENTRY, NULL, 0); aclpb->aclpb_signature = 0; /* reset scoped entry cache to be empty */ aclpb->aclpb_scoped_entry_anominfo.anom_e_nummatched = 0; /* Free up any of the string values left in the macro ht and remove * the entries.*/ acl_ht_free_all_entries_and_values(aclpb->aclpb_macro_ht); /* Finally, set it to the no use state */ aclpb->aclpb_state = 0; } #ifdef FOR_DEBUGGING static char * acl__get_aclpb_type ( Acl_PBlock *aclpb ) { if (aclpb->aclpb_state & ACLPB_TYPE_PROXY) return ACLPB_TYPE_PROXY_STR; return ACLPB_TYPE_MAIN_STR; } static void acl__dump_stats ( struct acl_pblock *aclpb , const char *block_type) { PRUint64 connid = 0; int opid = 0; Slapi_PBlock *pb = NULL; pb = aclpb->aclpb_pblock; if ( pb ) { slapi_pblock_get ( pb, SLAPI_CONN_ID, &connid ); slapi_pblock_get ( pb, SLAPI_OPERATION_ID, &opid ); } /* DUMP STAT INFO */ slapi_log_error( SLAPI_LOG_ACL, plugin_name, "**** ACL OPERATION STAT BEGIN ( aclpb:%p Block type: %s): Conn:%" PRIu64 " Operation:%d *******\n", aclpb, block_type, connid, opid ); slapi_log_error( SLAPI_LOG_ACL, plugin_name, "\tNumber of entries scanned: %d\n", aclpb->aclpb_stat_total_entries); slapi_log_error( SLAPI_LOG_ACL, plugin_name, "\tNumber of times ACL List scanned: %d\n", aclpb->aclpb_stat_acllist_scanned); slapi_log_error( SLAPI_LOG_ACL, plugin_name, "\tNumber of ACLs with target matched:%d\n", aclpb->aclpb_stat_num_tmatched_acls); slapi_log_error( SLAPI_LOG_ACL, plugin_name, "\tNumber of times acl resource matched:%d\n", aclpb->aclpb_stat_aclres_matched); slapi_log_error( SLAPI_LOG_ACL, plugin_name, "\tNumber of times ANOM list scanned:%d\n", aclpb->aclpb_stat_anom_list_scanned); slapi_log_error( SLAPI_LOG_ACL, plugin_name, "\tNumber of times Context was copied:%d\n", aclpb->aclpb_stat_num_copycontext); slapi_log_error( SLAPI_LOG_ACL, plugin_name, "\tNumber of times Attrs was copied:%d\n", aclpb->aclpb_stat_num_copy_attrs); slapi_log_error( SLAPI_LOG_ACL, plugin_name, " **** ACL OPERATION STAT END *******\n"); } #endif /****************************************************************************/ /* E N D */ /****************************************************************************/