summaryrefslogtreecommitdiffstats
path: root/ldap/servers/plugins/acl/aclinit.c
diff options
context:
space:
mode:
Diffstat (limited to 'ldap/servers/plugins/acl/aclinit.c')
-rw-r--r--ldap/servers/plugins/acl/aclinit.c537
1 files changed, 537 insertions, 0 deletions
diff --git a/ldap/servers/plugins/acl/aclinit.c b/ldap/servers/plugins/acl/aclinit.c
new file mode 100644
index 00000000..21e54337
--- /dev/null
+++ b/ldap/servers/plugins/acl/aclinit.c
@@ -0,0 +1,537 @@
+/** 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 int __aclinit__RegisterLases(void);
+static int __aclinit__RegisterAttributes(void);
+static int __aclinit_handler(Slapi_Entry *e, void *callback_data);
+
+/***************************************************************************
+*
+* aclinit_main()
+* Main routine which is called at the server boot up time.
+*
+* 1) Reads all the ACI entries from the database and creates
+* the ACL list.
+* 2) Registers all the LASes and the GetAttrs supported by the DS.
+* 3) Generates anonymous profiles.
+* 4) Registers proxy control
+* 5) Creates aclpb pool
+*
+* Input:
+* None.
+*
+* Returns:
+* 0 -- no error
+* 1 -- Error
+*
+* Error Handling:
+* If any error found during the ACL generation, error is logged.
+*
+**************************************************************************/
+static int acl_initialized = 0;
+int
+aclinit_main()
+{
+ char *cookie = NULL;
+ Slapi_PBlock *pb;
+ int rv;
+ Slapi_DN *sdn;
+ void *node;
+
+ if (acl_initialized) {
+ /* There is no need to do anything more */
+ return 0;
+ }
+
+ /* Initialize the LIBACCESS ACL library */
+ if (ACL_Init() != 0) {
+ slapi_log_error(SLAPI_LOG_FATAL, plugin_name,
+ "ACL Library Initialization failed\n",0,0,0);
+ return 1;
+ }
+
+ /* register all the LASes supported by the DS */
+ if (ACL_ERR == __aclinit__RegisterLases()) {
+ /* Error is already logged */
+ return 1;
+ }
+
+ /* Register all the Attrs */
+ if (ACL_ERR == __aclinit__RegisterAttributes()) {
+ /* Error is already logged */
+ return 1;
+ }
+
+ /*
+ * Register to get backend state changes so we can add/remove
+ * acis from backends that come up and go down.
+ */
+
+ slapi_register_backend_state_change((void *) NULL, acl_be_state_change_fnc);
+
+
+ /* register the extensions */
+ /* ONREPL Moved to the acl_init function because extensions
+ need to be registered before any operations are issued
+ if ( 0 != acl_init_ext() ) {
+ slapi_log_error ( SLAPI_LOG_FATAL, plugin_name,
+ "Unable to initialize the extensions\n");
+ return 1;
+ } */
+
+ /* create the mutex array */
+ if ( 0 != aclext_alloc_lockarray ( ) ) {
+ slapi_log_error ( SLAPI_LOG_FATAL, plugin_name,
+ "Unable to create the mutext array\n");
+ return 1;
+ }
+
+ /* Allocate the pool */
+ if ( 0 != acl_create_aclpb_pool () ) {
+ slapi_log_error ( SLAPI_LOG_FATAL, plugin_name,
+ "Unable to create the acl private pool\n");
+ return 1;
+ }
+
+ /*
+ * Now read all the ACLs from all the backends and put it
+ * in a list
+ */
+ /* initialize the ACLLIST sub-system */
+ if ( 0 != (rv = acllist_init ( ))) {
+ slapi_log_error ( SLAPI_LOG_FATAL, plugin_name,
+ "Unable to initialize the plugin:%d\n", rv );
+ return 1;
+ }
+
+ /* Initialize the anonymous profile i.e., generate it */
+ rv = aclanom_init ();
+
+ pb = slapi_pblock_new();
+
+ /*
+ * search for the aci_attr_type attributes of all entries.
+ *
+ * slapi_get_fist_suffix() and slapi_get_next_suffix() do not return the
+ * rootdse entry so we search for acis in there explicitly here.
+ */
+
+ sdn = slapi_sdn_new_dn_byval("");
+ slapi_log_error ( SLAPI_LOG_ACL, plugin_name,
+ "Searching for all acis(scope base) at suffix ''\n");
+ aclinit_search_and_update_aci ( 0, /* thisbeonly */
+ sdn, /* base */
+ NULL, /* be name*/
+ LDAP_SCOPE_BASE, ACL_ADD_ACIS,
+ DO_TAKE_ACLCACHE_WRITELOCK);
+ slapi_sdn_free(&sdn);
+
+ sdn = slapi_get_first_suffix( &node, 1 );
+ while (sdn)
+ {
+ slapi_log_error ( SLAPI_LOG_ACL, plugin_name,
+ "Searching for all acis(scope subtree) at suffix '%s'\n",
+ slapi_sdn_get_dn(sdn) );
+ aclinit_search_and_update_aci ( 0, /* thisbeonly */
+ sdn, /* base */
+ NULL, /* be name*/
+ LDAP_SCOPE_SUBTREE, ACL_ADD_ACIS,
+ DO_TAKE_ACLCACHE_WRITELOCK);
+ sdn = slapi_get_next_suffix( &node, 1 );
+ }
+
+ /* Initialize it. */
+ acl_initialized = 1;
+
+ /* generate the signatures */
+ acl_set_aclsignature ( aclutil_gen_signature ( 100 ) );
+
+ /* Initialize the user-group cache */
+ rv = aclgroup_init ( );
+
+ aclanom_gen_anomProfile (DO_TAKE_ACLCACHE_READLOCK);
+
+ /* Register both of the proxied authorization controls (version 1 and 2) */
+ slapi_register_supported_control( LDAP_CONTROL_PROXYAUTH,
+ SLAPI_OPERATION_SEARCH | SLAPI_OPERATION_COMPARE
+ | SLAPI_OPERATION_ADD | SLAPI_OPERATION_DELETE
+ | SLAPI_OPERATION_MODIFY | SLAPI_OPERATION_MODDN
+ | SLAPI_OPERATION_EXTENDED );
+ slapi_register_supported_control( LDAP_CONTROL_PROXIEDAUTH,
+ SLAPI_OPERATION_SEARCH | SLAPI_OPERATION_COMPARE
+ | SLAPI_OPERATION_ADD | SLAPI_OPERATION_DELETE
+ | SLAPI_OPERATION_MODIFY | SLAPI_OPERATION_MODDN
+ | SLAPI_OPERATION_EXTENDED );
+
+ slapi_pblock_destroy ( pb );
+ return 0;
+}
+/*
+ * This routine is the one that scans for acis and either adds them
+ * to the internal cache (op==ACL_ADD_ACIS) or deletes them
+ * (op==ACL_REMOVE_ACIS).
+ *
+ * If thisbeonly is 0 the search
+ * is conducted on the base with the specifed scope and be_name is ignored.
+ * This is used at startup time where we iterate over all suffixes, searching
+ * for all the acis in the DIT to load the ACL cache.
+ *
+ * If thisbeonly is 1 then then a be_name must be specified.
+ * In this case we will search in that backend ONLY.
+ * This is used in the case where a backend is turned on and off--in this
+ * case we only want to add/remove the acis in that particular backend and
+ * not for example in any backends below that one.
+*/
+
+int
+aclinit_search_and_update_aci ( int thisbeonly, const Slapi_DN *base,
+ char *be_name, int scope, int op,
+ acl_lock_flag_t lock_flag )
+{
+ char *attrs[2] = { "aci", NULL };
+ /* Tell __aclinit_handler whether it's an add or a delete */
+ int any_error = op;
+ Slapi_PBlock *aPb;
+ LDAPControl **ctrls=NULL;
+ int retval;
+ struct berval *bval;
+ aclinit_handler_callback_data_t call_back_data;
+
+ PR_ASSERT( lock_flag == DONT_TAKE_ACLCACHE_WRITELOCK ||
+ lock_flag == DO_TAKE_ACLCACHE_WRITELOCK);
+
+ if ( thisbeonly && be_name == NULL) {
+ slapi_log_error ( SLAPI_LOG_FATAL, plugin_name,
+ "Error: This be_name must be specified.\n", 0, 0, 0);
+ return -1;
+ }
+
+
+ /*
+ * We need to explicitly request (objectclass=ldapsubentry)
+ * in order to get all the subentry acis too.
+ * Note that subentries can be added under subentries (although its not
+ * recommended) so that
+ * there may be non-trivial acis under a subentry.
+ */
+
+ /* Use new search internal API */
+ /* and never retrieve aci from a remote server */
+ aPb = slapi_pblock_new ();
+
+ /*
+ * Set up the control to say "Only get acis from this Backend--
+ * there may be more backends under this one.
+ */
+
+ if ( thisbeonly ) {
+
+ bval = (struct berval *)slapi_ch_malloc(sizeof(struct berval));
+ bval->bv_len = strlen(be_name) + 1;
+ bval->bv_val = slapi_ch_strdup(be_name);
+
+ ctrls = (LDAPControl **)slapi_ch_calloc( 2, sizeof(LDAPControl *));
+ ctrls[0] = NULL;
+ ctrls[1] = NULL;
+
+ retval = slapi_build_control_from_berval(
+ MTN_CONTROL_USE_ONE_BACKEND_OID,
+ bval,
+ 1 /* is critical */,
+ ctrls);
+
+ }
+
+ slapi_search_internal_set_pb ( aPb,
+ slapi_sdn_get_dn(base),
+ scope,
+ "(|(aci=*)(objectclass=ldapsubentry))",
+ attrs,
+ 0 /* attrsonly */,
+ ctrls /* controls: SLAPI_ARGCONTROLS */,
+ NULL /* uniqueid */,
+ aclplugin_get_identity (ACL_PLUGIN_IDENTITY),
+ SLAPI_OP_FLAG_NEVER_CHAIN /* actions : get local aci only */);
+
+ if (thisbeonly) {
+ slapi_pblock_set(aPb, SLAPI_REQCONTROLS, ctrls);
+ }
+
+ call_back_data.op = op;
+ call_back_data.retCode = 0;
+ call_back_data.lock_flag = lock_flag;
+
+ slapi_search_internal_callback_pb(aPb,
+ &call_back_data /* callback_data */,
+ NULL/* result_callback */,
+ __aclinit_handler,
+ NULL /* referral_callback */);
+
+ if (thisbeonly) {
+ slapi_ch_free((void **)&bval);
+ }
+
+ /*
+ * This frees the control oid, the bv_val and the control itself and the
+ * ctrls array mem by caling ldap_controls_free()--so we
+ * don't need to do it ourselves.
+ */
+ slapi_pblock_destroy (aPb);
+
+ return call_back_data.retCode;
+
+}
+
+/***************************************************************************
+*
+* __aclinit_handler
+*
+* For each entry, finds if there is any ACL in thet entry. If there is
+* then the ACL is processed and stored in the ACL LIST.
+*
+*
+* Input:
+*
+*
+* Returns:
+* None.
+*
+* Error Handling:
+* If any error found during the ACL generation, the ACL is
+* logged. Also, set in the callback_data so that caller can act upon it.
+*
+**************************************************************************/
+static int
+__aclinit_handler ( Slapi_Entry *e, void *callback_data)
+{
+ Slapi_Attr *attr;
+ aclinit_handler_callback_data_t *call_back_data =
+ (aclinit_handler_callback_data_t*)callback_data;
+ Slapi_DN *e_sdn;
+ int rv;
+ Slapi_Value *sval=NULL;
+
+ call_back_data->retCode = 0; /* assume success--if there's an error we overwrite it */
+ if (e != NULL) {
+
+ e_sdn = slapi_entry_get_sdn ( e );
+
+ /*
+ * Take the write lock around all the mods--so that
+ * other operations will see the acicache either before the whole mod
+ * or after but not, as it was before, during the mod.
+ * This is in line with the LDAP concept of the operation
+ * on the whole entry being the atomic unit.
+ *
+ */
+
+ if ( call_back_data->op == ACL_ADD_ACIS ) {
+ slapi_log_error ( SLAPI_LOG_ACL, plugin_name,
+ "Adding acis for entry '%s'\n", slapi_sdn_get_dn(e_sdn));
+ slapi_entry_attr_find ( e, aci_attr_type, &attr );
+
+ if ( attr ) {
+
+ const struct berval *attrValue;
+
+ int i;
+ if ( call_back_data->lock_flag == DO_TAKE_ACLCACHE_WRITELOCK) {
+ acllist_acicache_WRITE_LOCK();
+ }
+ i= slapi_attr_first_value ( attr, &sval );
+ while(i != -1) {
+ attrValue = slapi_value_get_berval(sval);
+
+ if ( 0 != (rv=acllist_insert_aci_needsLock (e_sdn, attrValue))) {
+ aclutil_print_err(rv, e_sdn, attrValue, NULL);
+
+ /* We got an error; Log it and then march along */
+ slapi_log_error ( SLAPI_LOG_FATAL, plugin_name,
+ "Error: This (%s) ACL will not be considered for evaluation"
+ " because of syntax errors.\n",
+ attrValue->bv_val ? attrValue->bv_val: "NULL", 0, 0);
+ call_back_data->retCode = rv;
+ }
+ i= slapi_attr_next_value( attr, i, &sval );
+ }/* while */
+ if ( call_back_data->lock_flag == DO_TAKE_ACLCACHE_WRITELOCK) {
+ acllist_acicache_WRITE_UNLOCK();
+ }
+ }
+ } else if (call_back_data->op == ACL_REMOVE_ACIS) {
+
+ /* Here we are deleting the acis. */
+ slapi_log_error ( SLAPI_LOG_ACL, plugin_name, "Removing acis\n");
+ if ( call_back_data->lock_flag == DO_TAKE_ACLCACHE_WRITELOCK) {
+ acllist_acicache_WRITE_LOCK();
+ }
+ if ( 0 != (rv=acllist_remove_aci_needsLock(e_sdn, NULL))) {
+ aclutil_print_err(rv, e_sdn, NULL, NULL);
+
+ /* We got an error; Log it and then march along */
+ slapi_log_error ( SLAPI_LOG_FATAL, plugin_name,
+ "Error: ACls not deleted from %s\n",
+ e_sdn, 0, 0);
+ call_back_data->retCode = rv;
+ }
+ if ( call_back_data->lock_flag == DO_TAKE_ACLCACHE_WRITELOCK) {
+ acllist_acicache_WRITE_UNLOCK();
+ }
+ }
+
+ }
+
+ /*
+ * If we get here it's success.
+ * The call_back_data->error is the error code that counts as it's the
+ * one that the original caller will see--this routine is called off a callbacl.
+ */
+
+ return ACL_FALSE; /* "local" error code--it's 0 */
+}
+/***************************************************************************
+*
+* __acl__RegisterAttributes
+*
+* Register all the attributes supported by the DS.
+*
+* Input:
+* None.
+*
+* Returns:
+* ACL_OK - No error
+* ACL_ERR - in case of errror
+*
+* Error Handling:
+* None.
+*
+**************************************************************************/
+static int
+__aclinit__RegisterAttributes(void)
+{
+
+ ACLMethod_t methodinfo;
+ NSErr_t errp;
+ int rv;
+
+ memset (&errp, 0, sizeof(NSErr_t));
+
+ rv = ACL_MethodRegister(&errp, DS_METHOD, &methodinfo);
+ if (rv < 0) {
+ acl_print_acllib_err(&errp, NULL);
+ slapi_log_error(SLAPI_LOG_FATAL, plugin_name,
+ "Unable to Register the methods\n", 0,0,0);
+ return ACL_ERR;
+ }
+ rv = ACL_MethodSetDefault (&errp, methodinfo);
+ if (rv < 0) {
+ acl_print_acllib_err(&errp, NULL);
+ slapi_log_error(SLAPI_LOG_FATAL, plugin_name,
+ "Unable to Set the default method\n", 0,0,0);
+ return ACL_ERR;
+ }
+ rv = ACL_AttrGetterRegister(&errp, ACL_ATTR_IP, DS_LASIpGetter,
+ methodinfo, ACL_DBTYPE_ANY, ACL_AT_FRONT, NULL);
+ if (rv < 0) {
+ acl_print_acllib_err(&errp, NULL);
+ slapi_log_error(SLAPI_LOG_FATAL, plugin_name,
+ "Unable to Register Attr ip\n", 0,0,0);
+ return ACL_ERR;
+ }
+ rv = ACL_AttrGetterRegister(&errp, ACL_ATTR_DNS, DS_LASDnsGetter,
+ methodinfo, ACL_DBTYPE_ANY, ACL_AT_FRONT, NULL);
+ if (rv < 0) {
+ acl_print_acllib_err(&errp, NULL);
+ slapi_log_error(SLAPI_LOG_FATAL, plugin_name,
+ "Unable to Register Attr dns\n", 0,0,0);
+ return ACL_ERR;
+ }
+ return ACL_OK;
+}
+
+/***************************************************************************
+*
+* __acl__RegisterLases
+* Register all the LASes supported by the DS.
+*
+* The DS doesnot support user/group. We have defined our own LAS
+* so that we can display/print an error when the LAS is invoked.
+* Input:
+* None.
+*
+* Returns:
+* ACL_OK - No error
+* ACL_ERR - in case of errror
+*
+* Error Handling:
+* None.
+*
+**************************************************************************/
+static int
+__aclinit__RegisterLases(void)
+{
+
+ if (ACL_LasRegister(NULL, DS_LAS_USER, (LASEvalFunc_t) DS_LASUserEval,
+ (LASFlushFunc_t) NULL) < 0) {
+ slapi_log_error (SLAPI_LOG_FATAL, plugin_name,
+ "Unable to register USER Las\n",0,0,0);
+ return ACL_ERR;
+ }
+ if (ACL_LasRegister(NULL, DS_LAS_GROUP, (LASEvalFunc_t) DS_LASGroupEval,
+ (LASFlushFunc_t) NULL) < 0) {
+ slapi_log_error (SLAPI_LOG_FATAL, plugin_name,
+ "Unable to register GROUP Las\n",0,0,0);
+ return ACL_ERR;
+ }
+ if (ACL_LasRegister(NULL, DS_LAS_GROUPDN, (LASEvalFunc_t)DS_LASGroupDnEval,
+ (LASFlushFunc_t)NULL) < 0) {
+ slapi_log_error (SLAPI_LOG_FATAL, plugin_name,
+ "Unable to register GROUPDN Las\n",0,0,0);
+ return ACL_ERR;
+ }
+ if (ACL_LasRegister(NULL, DS_LAS_ROLEDN, (LASEvalFunc_t)DS_LASRoleDnEval,
+ (LASFlushFunc_t)NULL) < 0) {
+ slapi_log_error (SLAPI_LOG_FATAL, plugin_name,
+ "Unable to register ROLEDN Las\n",0,0,0);
+ return ACL_ERR;
+ }
+ if (ACL_LasRegister(NULL, DS_LAS_USERDN, (LASEvalFunc_t)DS_LASUserDnEval,
+ (LASFlushFunc_t)NULL) < 0) {
+ slapi_log_error (SLAPI_LOG_FATAL, plugin_name,
+ "Unable to register USERDN Las\n",0,0,0);
+ return ACL_ERR;
+ }
+ if (ACL_LasRegister(NULL, DS_LAS_USERDNATTR,
+ (LASEvalFunc_t)DS_LASUserDnAttrEval,
+ (LASFlushFunc_t)NULL) < 0) {
+ slapi_log_error (SLAPI_LOG_FATAL, plugin_name,
+ "Unable to register USERDNATTR Las\n",0,0,0);
+ return ACL_ERR;
+ }
+ if (ACL_LasRegister(NULL, DS_LAS_AUTHMETHOD,
+ (LASEvalFunc_t)DS_LASAuthMethodEval,
+ (LASFlushFunc_t)NULL) < 0) {
+ slapi_log_error (SLAPI_LOG_FATAL, plugin_name,
+ "Unable to register CLIENTAUTHTYPE Las\n",0,0,0);
+ return ACL_ERR;
+ }
+ if (ACL_LasRegister(NULL, DS_LAS_GROUPDNATTR,
+ (LASEvalFunc_t)DS_LASGroupDnAttrEval,
+ (LASFlushFunc_t)NULL) < 0) {
+ slapi_log_error (SLAPI_LOG_FATAL, plugin_name,
+ "Unable to register GROUPDNATTR Las\n",0,0,0);
+ return ACL_ERR;
+ }
+ if (ACL_LasRegister(NULL, DS_LAS_USERATTR,
+ (LASEvalFunc_t)DS_LASUserAttrEval,
+ (LASFlushFunc_t)NULL) < 0) {
+ slapi_log_error (SLAPI_LOG_FATAL, plugin_name,
+ "Unable to register USERATTR Las\n",0,0,0);
+ return ACL_ERR;
+ }
+ return ACL_OK;
+}