diff options
author | cvsadm <cvsadm> | 2005-01-21 00:44:34 +0000 |
---|---|---|
committer | cvsadm <cvsadm> | 2005-01-21 00:44:34 +0000 |
commit | b2093e3016027d6b5cf06b3f91f30769bfc099e2 (patch) | |
tree | cf58939393a9032182c4fbc4441164a9456e82f8 /ldap/servers/plugins/acl/acl_ext.c | |
download | ds-ldapserver7x.tar.gz ds-ldapserver7x.tar.xz ds-ldapserver7x.zip |
Moving NSCP Directory Server from DirectoryBranch to TRUNK, initial drop. (foxworth)ldapserver7x
Diffstat (limited to 'ldap/servers/plugins/acl/acl_ext.c')
-rw-r--r-- | ldap/servers/plugins/acl/acl_ext.c | 968 |
1 files changed, 968 insertions, 0 deletions
diff --git a/ldap/servers/plugins/acl/acl_ext.c b/ldap/servers/plugins/acl/acl_ext.c new file mode 100644 index 00000000..28a9ce18 --- /dev/null +++ b/ldap/servers/plugins/acl/acl_ext.c @@ -0,0 +1,968 @@ +/** BEGIN COPYRIGHT BLOCK + * Copyright 2001 Sun Microsystems, Inc. + * Portions copyright 1999, 2001-2003 Netscape Communications Corporation. + * All rights reserved. + * END COPYRIGHT BLOCK **/ +#include "acl.h" + +static void acl__done_aclpb ( struct acl_pblock *aclpb ); +static void acl__dump_stats ( struct acl_pblock *aclpb , const char *block_type); +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 char * acl__get_aclpb_type ( Acl_PBlock *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; + + /* 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 && aclpb->aclpb_authorization_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"); + return NULL; + } + + 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"); + return NULL; + } + 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"); + return NULL; + } + 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"); + return NULL; + } + 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"); + return NULL; + } + + /* + * 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"); + return NULL; + } + /* + * 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; + +} + +/* 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; + unsigned long op_type; + + + 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; + } + /* 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; + char *ds_attr_userdn=NULL; /* for finding userdn for freeing */ + 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; + + } + + /* acl__dump_stats ( aclpb, acl__get_aclpb_type(aclpb)); */ + + /* 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, 0 ); + 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, 0,0 ); + + 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; + +} + +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) +{ + int 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:%d 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"); +} +/****************************************************************************/ +/* E N D */ +/****************************************************************************/ + |