/* * This routine sets up a "context" for evaluation of access control * on a given entry for an anonymous user. * It just factors out the scope and targetfilter info into a list * of indices of the global anom profile list, that apply to this * entry, and stores them in the aclpb. * It's use relies on the way that access control is checked in the mailine search * code in the core server, namely: check filter, check entry, then check each * attribute. So, we call this in acl_access_allowed() before calling * aclanom_match_profile()--therafter, aclanom_match_profile() uses the * context to evaluate access to the entry and attributes. * * If there are no anom profiles, or the anom profiles get cancelled * due to complex anon acis, then that's OK, aclanom_match_profile() * returns -1 and the mainline acl code kicks in. * * The lifetime of this context info is the time it takes to check * access control for all parts of this entry (filter, entry, attributes). * So, if for an example an entry changes and a given anom profile entry * no longer applies, we will not notice until the next round of access * control checking on the entry--this is acceptable. * * The gain on doing this factoring in the following type of search * was approx 6%: * anon bind, 20 threads, exact match, ~20 attributes returned, * (searchrate & DirectoryMark). * */ void aclanom_get_suffix_info(Slapi_Entry *e, struct acl_pblock *aclpb ) { int i; char *ndn = NULL; Slapi_DN *e_sdn; const char *aci_ndn; struct scoped_entry_anominfo *s_e_anominfo = &aclpb->aclpb_scoped_entry_anominfo; ANOM_LOCK_READ (); s_e_anominfo->anom_e_nummatched=0; ndn = slapi_entry_get_ndn ( e ) ; e_sdn= slapi_entry_get_sdn ( e ) ; for (i=acl_anom_profile->anom_numacls-1; i >= 0; i-- ) { aci_ndn = slapi_sdn_get_ndn (acl_anom_profile->anom_targetinfo[i].anom_target); if (!slapi_sdn_issuffix(e_sdn,acl_anom_profile->anom_targetinfo[i].anom_target) || (!slapi_is_rootdse(ndn) && slapi_is_rootdse(aci_ndn))) continue; if ( acl_anom_profile->anom_targetinfo[i].anom_filter ) { if ( slapi_vattr_filter_test( aclpb->aclpb_pblock, e, acl_anom_profile->anom_targetinfo[i].anom_filter, 0 /*don't do acess chk*/) != 0) continue; } s_e_anominfo->anom_e_targetInfo[s_e_anominfo->anom_e_nummatched]=i; s_e_anominfo->anom_e_nummatched++; } ANOM_UNLOCK_READ (); }
/* * Invoked when the task instance is added by the client (step 5 of the comment) * Get the necessary attributes from the task entry, and spawns a thread to do * the task. */ static int task_sampletask_add(Slapi_PBlock *pb, Slapi_Entry *e, Slapi_Entry *eAfter, int *returncode, char *returntext, void *arg) { PRThread *thread = NULL; const char *cn; int rv = SLAPI_DSE_CALLBACK_OK; Slapi_PBlock *mypb = NULL; Slapi_Task *task = NULL; const char *myarg; *returncode = LDAP_SUCCESS; if ((cn = fetch_attr(e, "cn", NULL)) == NULL) { *returncode = LDAP_OBJECT_CLASS_VIOLATION; rv = SLAPI_DSE_CALLBACK_ERROR; goto out; } /* get arg(s) */ if ((myarg = fetch_attr(e, "myarg", NULL)) == NULL) { *returncode = LDAP_OBJECT_CLASS_VIOLATION; rv = SLAPI_DSE_CALLBACK_ERROR; goto out; } /* allocate new task now */ task = slapi_new_task(slapi_entry_get_ndn(e)); if (task == NULL) { slapi_log_err(SLAPI_LOG_ERR, "sampletask", "unable to allocate new task!\n"); *returncode = LDAP_OPERATIONS_ERROR; rv = SLAPI_DSE_CALLBACK_ERROR; goto out; } /* set a destructor that will clean up myarg for us when the task is complete */ slapi_task_set_destructor_fn(task, task_sampletask_destructor); /* Stash our argument in the task for use by the task thread */ slapi_task_set_data(task, slapi_ch_strdup(myarg)); /* start the sample task as a separate thread */ thread = PR_CreateThread(PR_USER_THREAD, task_sampletask_thread, (void *)task, PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD, PR_UNJOINABLE_THREAD, SLAPD_DEFAULT_THREAD_STACKSIZE); if (thread == NULL) { slapi_log_err(SLAPI_LOG_ERR, "sampletask", "unable to create sample task thread!\n"); *returncode = LDAP_OPERATIONS_ERROR; rv = SLAPI_DSE_CALLBACK_ERROR; slapi_task_finish(task, *returncode); } else { /* thread successful */ rv = SLAPI_DSE_CALLBACK_OK; } out: return rv; }
static int acl_default_access ( Slapi_PBlock *pb , Slapi_Entry *e, int access) { int isRoot, rootdse, accessCheckDisabled; int rc; slapi_pblock_get ( pb, SLAPI_REQUESTOR_ISROOT, &isRoot); if ( isRoot ) return LDAP_SUCCESS; rc = slapi_pblock_get ( pb, SLAPI_PLUGIN_DB_NO_ACL, &accessCheckDisabled ); if ( rc != -1 && accessCheckDisabled ) return LDAP_SUCCESS; rootdse = slapi_is_rootdse ( slapi_entry_get_ndn ( e ) ); if ( rootdse && (access & (SLAPI_ACL_READ | SLAPI_ACL_SEARCH) ) ) return LDAP_SUCCESS; return LDAP_INSUFFICIENT_ACCESS; }
/* * Callers should have already allocated *gerstr to hold at least * "entryLevelRights: adnvxxx\n". */ unsigned long _ger_get_entry_rights ( Slapi_PBlock *gerpb, Slapi_Entry *e, const char *subjectndn, char **gerstr, size_t *gerstrsize, size_t *gerstrcap, char **errbuf ) { unsigned long entryrights = 0; Slapi_RDN *rdn = NULL; char *rdntype = NULL; char *rdnvalue = NULL; _append_gerstr(gerstr, gerstrsize, gerstrcap, "entryLevelRights: ", NULL); slapi_log_err(SLAPI_LOG_ACL, plugin_name, "_ger_get_entry_rights - SLAPI_ACL_READ\n" ); if (acl_access_allowed(gerpb, e, "*", NULL, SLAPI_ACL_READ) == LDAP_SUCCESS) { /* v - view e */ entryrights |= SLAPI_ACL_READ; _append_gerstr(gerstr, gerstrsize, gerstrcap, "v", NULL); } slapi_log_err(SLAPI_LOG_ACL, plugin_name, "_ger_get_entry_rights - SLAPI_ACL_ADD\n" ); if (acl_access_allowed(gerpb, e, NULL, NULL, SLAPI_ACL_ADD) == LDAP_SUCCESS) { /* a - add child entry below e */ entryrights |= SLAPI_ACL_ADD; _append_gerstr(gerstr, gerstrsize, gerstrcap, "a", NULL); } slapi_log_err(SLAPI_LOG_ACL, plugin_name, "_ger_get_entry_rights - SLAPI_ACL_DELETE\n" ); if (acl_access_allowed(gerpb, e, NULL, NULL, SLAPI_ACL_DELETE) == LDAP_SUCCESS) { /* d - delete e */ entryrights |= SLAPI_ACL_DELETE; _append_gerstr(gerstr, gerstrsize, gerstrcap, "d", NULL); } if (config_get_moddn_aci()) { /* The server enforces the new MODDN aci right. * So the status 'n' is set if this right is granted. * Opposed to the legacy mode where this flag is set if * WRITE was granted on rdn attrbibute */ if (acl_access_allowed(gerpb, e, NULL, NULL, SLAPI_ACL_MODDN) == LDAP_SUCCESS) { slapi_log_err(SLAPI_LOG_ACL, plugin_name, "_ger_get_entry_rights - SLAPI_ACL_MODDN %s\n", slapi_entry_get_ndn(e)); /* n - rename e */ entryrights |= SLAPI_ACL_MODDN; _append_gerstr(gerstr, gerstrsize, gerstrcap, "n", NULL); } } else { /* * Some limitation/simplification applied here: * - The modrdn right requires the rights to delete the old rdn and * the new one. However we have no knowledge of what the new rdn * is going to be. * - In multi-valued RDN case, we check the right on * the first rdn type only for now. */ rdn = slapi_rdn_new_dn(slapi_entry_get_ndn(e)); slapi_rdn_get_first(rdn, &rdntype, &rdnvalue); if (NULL != rdntype) { slapi_log_err(SLAPI_LOG_ACL, plugin_name, "_ger_get_entry_rights - SLAPI_ACL_WRITE_DEL & _ADD %s\n", rdntype); if (acl_access_allowed(gerpb, e, rdntype, NULL, ACLPB_SLAPI_ACL_WRITE_DEL) == LDAP_SUCCESS && acl_access_allowed(gerpb, e, rdntype, NULL, ACLPB_SLAPI_ACL_WRITE_ADD) == LDAP_SUCCESS) { /* n - rename e */ entryrights |= SLAPI_ACL_WRITE; _append_gerstr(gerstr, gerstrsize, gerstrcap, "n", NULL); } } slapi_rdn_free(&rdn); } if ( entryrights == 0 ) { _append_gerstr(gerstr, gerstrsize, gerstrcap, "none", NULL); } _append_gerstr(gerstr, gerstrsize, gerstrcap, "\n", NULL); return entryrights; }
int acl_get_effective_rights ( Slapi_PBlock *pb, Slapi_Entry *e, /* target entry */ char **attrs, /* Attribute of the entry */ struct berval *val, /* value of attr. NOT USED */ int access, /* requested access rights */ char **errbuf ) { Slapi_PBlock *gerpb = NULL; void *aclcb = NULL; char *subjectndn = NULL; char *gerstr = NULL; size_t gerstrsize = 0; size_t gerstrcap = 0; int iscritical = 0; /* critical may be missing or false http://tools.ietf.org/html/draft-ietf-ldapext-acl-model-08 */ int rc = LDAP_SUCCESS; *errbuf = NULL; if (NULL == e) /* create a template entry from SLAPI_SEARCH_GERATTRS */ { rc = _ger_generate_template_entry ( pb ); slapi_pblock_get ( pb, SLAPI_SEARCH_RESULT_ENTRY, &e ); if ( rc != LDAP_SUCCESS || NULL == e ) { goto bailout; } } /* * Get the subject */ rc = _ger_parse_control (pb, &subjectndn, &iscritical, errbuf ); if ( rc != LDAP_SUCCESS ) { goto bailout; } /* * The requestor should have g permission on the entry * to get the effective rights. */ rc = _ger_g_permission_granted (pb, e, subjectndn, errbuf); if ( rc != LDAP_SUCCESS ) { goto bailout; } /* * Construct a new pb */ rc = _ger_new_gerpb ( pb, e, subjectndn, &gerpb, &aclcb, errbuf ); if ( rc != LDAP_SUCCESS ) { goto bailout; } /* Get entry level effective rights */ _ger_get_entry_rights ( gerpb, e, subjectndn, &gerstr, &gerstrsize, &gerstrcap, errbuf ); /* * Attribute level effective rights may not be NULL * even if entry level's is. */ _ger_get_attrs_rights ( gerpb, e, subjectndn, attrs, &gerstr, &gerstrsize, &gerstrcap, errbuf ); bailout: /* * Now construct the response control */ _ger_set_response_control ( pb, iscritical, rc ); if ( rc != LDAP_SUCCESS ) { gerstr = slapi_ch_smprintf("entryLevelRights: %d\nattributeLevelRights: *:%d", rc, rc ); } slapi_log_err(SLAPI_LOG_ACLSUMMARY, plugin_name, "###### Effective Rights on Entry (%s) for Subject (%s) ######\n", e?slapi_entry_get_ndn(e):"null", subjectndn?subjectndn:"null"); slapi_log_err(SLAPI_LOG_ACLSUMMARY, plugin_name, "%s\n", gerstr); /* Restore pb */ _ger_release_gerpb ( &gerpb, &aclcb, pb ); /* * General plugin uses SLAPI_RESULT_TEXT for error text. Here * SLAPI_PB_RESULT_TEXT is exclusively shared with add, dse and schema. * slapi_pblock_set() will free any previous data, and * pblock_done() will free SLAPI_PB_RESULT_TEXT. */ slapi_pblock_set (pb, SLAPI_PB_RESULT_TEXT, gerstr); if ( !iscritical ) { /* * If return code is not LDAP_SUCCESS, the server would * abort sending the data of the entry to the client. */ rc = LDAP_SUCCESS; } slapi_ch_free ( (void **) &subjectndn ); slapi_ch_free ( (void **) &gerstr ); return rc; }
/* Given an entry, provide the account policy in effect for that entry. Returns non-0 if function fails. If account policy comes back NULL, it's not an error; the entry is simply not covered by a policy. */ int get_acctpolicy( Slapi_PBlock *pb, Slapi_Entry *target_entry, void *plugin_id, acctPolicy **policy ) { Slapi_DN *sdn = NULL; Slapi_Entry *policy_entry = NULL; Slapi_Attr *attr; Slapi_Value *sval = NULL; int ldrc; char *attr_name; char *policy_dn = NULL; acctPluginCfg *cfg; int rc = 0; if( policy == NULL ) { /* Bad parameter */ return( -1 ); } *policy = NULL; config_rd_lock(); cfg = get_config(); /* Return success and NULL policy */ policy_dn = get_attr_string_val( target_entry, cfg->spec_attr_name ); if( policy_dn == NULL ) { slapi_log_err(SLAPI_LOG_PLUGIN, PLUGIN_NAME, "get_acctpolicy - \"%s\" is not governed by an account inactivity " "policy subentry\n", slapi_entry_get_ndn( target_entry ) ); if (cfg->inactivitylimit != ULONG_MAX) { goto dopolicy; } slapi_log_err(SLAPI_LOG_PLUGIN, PLUGIN_NAME, "get_acctpolicy - \"%s\" is not governed by an account inactivity " "global policy\n", slapi_entry_get_ndn( target_entry ) ); config_unlock(); return rc; } sdn = slapi_sdn_new_dn_byref( policy_dn ); ldrc = slapi_search_internal_get_entry( sdn, NULL, &policy_entry, plugin_id ); slapi_sdn_free( &sdn ); /* There should be a policy but it can't be retrieved; fatal error */ if( policy_entry == NULL ) { if( ldrc != LDAP_NO_SUCH_OBJECT ) { slapi_log_err(SLAPI_LOG_ERR, PLUGIN_NAME, "get_acctpolicy - Error retrieving policy entry \"%s\": %d\n", policy_dn, ldrc ); } else { slapi_log_err(SLAPI_LOG_PLUGIN, PLUGIN_NAME, "get_acctpolicy - Policy entry \"%s\" is missing: %d\n", policy_dn, ldrc ); } rc = -1; goto done; } dopolicy: *policy = (acctPolicy *)slapi_ch_calloc( 1, sizeof( acctPolicy ) ); if ( !policy_entry ) { /* global policy */ (*policy)->inactivitylimit = cfg->inactivitylimit; goto done; } for( slapi_entry_first_attr( policy_entry, &attr ); attr != NULL; slapi_entry_next_attr( policy_entry, attr, &attr ) ) { slapi_attr_get_type(attr, &attr_name); if( !strcasecmp( attr_name, cfg->limit_attr_name ) ) { if( slapi_attr_first_value( attr, &sval ) == 0 ) { (*policy)->inactivitylimit = slapi_value_get_ulong( sval ); } } } done: config_unlock(); slapi_ch_free_string( &policy_dn ); slapi_entry_free( policy_entry ); return( rc ); }
int sidgen_task_add(Slapi_PBlock *pb, Slapi_Entry *e, Slapi_Entry *eAfter, int *returncode, char *returntext, void *arg) { int ret = SLAPI_DSE_CALLBACK_ERROR; const char *str; struct worker_ctx *worker_ctx = NULL; char *endptr; Slapi_Task *task = NULL; *returncode = LDAP_OPERATIONS_ERROR; returntext[0] = '\0'; worker_ctx = (struct worker_ctx *) slapi_ch_calloc(1, sizeof(struct worker_ctx)); if (worker_ctx == NULL) { LOG_FATAL("slapi_ch_malloc failed!\n"); *returncode = LDAP_OPERATIONS_ERROR; ret = SLAPI_DSE_CALLBACK_ERROR; goto done; } worker_ctx->plugin_id = global_sidgen_plugin_id; str = fetch_attr(e, "delay", NULL); if (str != NULL) { errno = 0; worker_ctx->delay = strtol(str, &endptr, 10); if (errno != 0 || worker_ctx->delay < 0) { LOG_FATAL("invalid delay [%s]!\n", str); *returncode = LDAP_CONSTRAINT_VIOLATION; ret = SLAPI_DSE_CALLBACK_ERROR; goto done; } } LOG("delay is [%li].\n", worker_ctx->delay); str = fetch_attr(e, "nsslapd-basedn", NULL); if (str == NULL) { LOG_FATAL("Missing nsslapd-basedn!\n"); *returncode = LDAP_CONSTRAINT_VIOLATION; ret = SLAPI_DSE_CALLBACK_ERROR; goto done; } worker_ctx->base_dn = slapi_ch_strdup(str); if (worker_ctx->base_dn == NULL) { LOG_FATAL("Failed to copy base DN.\n"); *returncode = LDAP_OPERATIONS_ERROR; ret = ENOMEM; goto done; } ret = get_dom_sid(worker_ctx->plugin_id, worker_ctx->base_dn, &worker_ctx->dom_sid); if (ret != 0) { LOG_FATAL("Cannot find domain SID.\n"); goto done; } ret = get_ranges(worker_ctx->plugin_id, worker_ctx->base_dn, &worker_ctx->ranges); if (ret != 0) { LOG_FATAL("Cannot find ranges.\n"); goto done; } task = slapi_new_task(slapi_entry_get_ndn(e)); if (task == NULL) { LOG_FATAL("unable to allocate new task!\n"); *returncode = LDAP_OPERATIONS_ERROR; ret = SLAPI_DSE_CALLBACK_ERROR; goto done; } slapi_task_set_destructor_fn(task, sidgen_task_destructor); slapi_task_set_data(task, worker_ctx); ret = pthread_create(&worker_ctx->tid, NULL, sidgen_task_thread, task); if (ret != 0) { LOG_FATAL("unable to create sidgen task thread!\n"); *returncode = LDAP_OPERATIONS_ERROR; ret = SLAPI_DSE_CALLBACK_ERROR; slapi_task_finish(task, *returncode); goto done; } ret = SLAPI_DSE_CALLBACK_OK; *returncode = LDAP_SUCCESS; done: if (ret != SLAPI_DSE_CALLBACK_OK) { slapi_ch_free((void **) &worker_ctx->base_dn); slapi_ch_free((void **) &worker_ctx); } return ret; }
/* Apply the pending changes in the e entry to our config struct. validate must have already been called */ static int pam_passthru_apply_config (Slapi_Entry* e) { int rc = PAM_PASSTHRU_SUCCESS; char **excludes = NULL; char **includes = NULL; char *new_service = NULL; char *pam_ident_attr = NULL; char *map_method = NULL; char *dn = NULL; PRBool fallback; PRBool secure; Pam_PassthruConfig *entry = NULL; PRCList *list; Slapi_Attr *a = NULL; char *filter_str = NULL; int inserted = 0; pam_ident_attr = slapi_entry_attr_get_charptr(e, PAMPT_PAM_IDENT_ATTR); map_method = slapi_entry_attr_get_charptr(e, PAMPT_MAP_METHOD_ATTR); new_service = slapi_entry_attr_get_charptr(e, PAMPT_SERVICE_ATTR); excludes = slapi_entry_attr_get_charray(e, PAMPT_EXCLUDES_ATTR); includes = slapi_entry_attr_get_charray(e, PAMPT_INCLUDES_ATTR); fallback = slapi_entry_attr_get_bool(e, PAMPT_FALLBACK_ATTR); filter_str = slapi_entry_attr_get_charptr(e, PAMPT_FILTER_ATTR); /* Require SSL/TLS if the secure attr is not specified. We * need to check if the attribute is present to make this * determiniation. */ if (slapi_entry_attr_find(e, PAMPT_SECURE_ATTR, &a) == 0) { secure = slapi_entry_attr_get_bool(e, PAMPT_SECURE_ATTR); } else { secure = PR_TRUE; } /* Allocate a config struct. */ entry = (Pam_PassthruConfig *) slapi_ch_calloc(1, sizeof(Pam_PassthruConfig)); if (NULL == entry) { rc = PAM_PASSTHRU_FAILURE; goto bail; } /* use the RDN method to derive the PAM identity by default*/ entry->pamptconfig_map_method1 = PAMPT_MAP_METHOD_RDN; entry->pamptconfig_map_method2 = PAMPT_MAP_METHOD_NONE; entry->pamptconfig_map_method3 = PAMPT_MAP_METHOD_NONE; /* Fill in the struct. */ dn = slapi_entry_get_ndn(e); if (dn) { entry->dn = slapi_ch_strdup(dn); } entry->pamptconfig_fallback = fallback; entry->pamptconfig_secure = secure; if (!entry->pamptconfig_service || (new_service && PL_strcmp(entry->pamptconfig_service, new_service))) { slapi_ch_free_string(&entry->pamptconfig_service); entry->pamptconfig_service = new_service; new_service = NULL; /* config now owns memory */ } /* get the list of excluded suffixes */ pam_ptconfig_free_suffixes(entry->pamptconfig_excludes); entry->pamptconfig_excludes = pam_ptconfig_add_suffixes(excludes); /* get the list of included suffixes */ pam_ptconfig_free_suffixes(entry->pamptconfig_includes); entry->pamptconfig_includes = pam_ptconfig_add_suffixes(includes); if (!entry->pamptconfig_pam_ident_attr || (pam_ident_attr && PL_strcmp(entry->pamptconfig_pam_ident_attr, pam_ident_attr))) { slapi_ch_free_string(&entry->pamptconfig_pam_ident_attr); entry->pamptconfig_pam_ident_attr = pam_ident_attr; pam_ident_attr = NULL; /* config now owns memory */ } if (map_method) { parse_map_method(map_method, &entry->pamptconfig_map_method1, &entry->pamptconfig_map_method2, &entry->pamptconfig_map_method3, NULL); } if (filter_str) { entry->filter_str = filter_str; filter_str = NULL; /* config now owns memory */ entry->slapi_filter = slapi_str2filter(entry->filter_str); } /* Add config to list. We just store at the tail. */ if (!PR_CLIST_IS_EMPTY(pam_passthru_global_config)) { list = PR_LIST_HEAD(pam_passthru_global_config); while (list != pam_passthru_global_config) { list = PR_NEXT_LINK(list); if (pam_passthru_global_config == list) { /* add to tail */ PR_INSERT_BEFORE(&(entry->list), list); slapi_log_err(SLAPI_LOG_CONFIG, PAM_PASSTHRU_PLUGIN_SUBSYSTEM, "pam_passthru_apply_config - store [%s] at tail\n", entry->dn); inserted = 1; break; } } } else { /* first entry */ PR_INSERT_LINK(&(entry->list), pam_passthru_global_config); slapi_log_err(SLAPI_LOG_CONFIG, PAM_PASSTHRU_PLUGIN_SUBSYSTEM, "pam_passthru_apply_config - store [%s] at head \n", entry->dn); inserted = 1; } bail: if(!inserted){ pam_passthru_free_config_entry(&entry); } slapi_ch_free_string(&new_service); slapi_ch_free_string(&map_method); slapi_ch_free_string(&pam_ident_attr); slapi_ch_free_string(&filter_str); slapi_ch_array_free(excludes); slapi_ch_array_free(includes); return rc; }
/* * Read and load configuration. Validation will also * be performed unless skip_validate is set to non-0. * Returns PAM_PASSTHRU_SUCCESS if all is well. */ int pam_passthru_load_config(int skip_validate) { int status = PAM_PASSTHRU_SUCCESS; int result; int i; int alternate = 0; Slapi_PBlock *search_pb; Slapi_Entry **entries = NULL; slapi_log_err(SLAPI_LOG_TRACE, PAM_PASSTHRU_PLUGIN_SUBSYSTEM, "=> pam_passthru_load_config\n"); pam_passthru_write_lock(); pam_passthru_delete_config(); search_pb = slapi_pblock_new(); /* Find all entries in the active config area. */ slapi_search_internal_set_pb(search_pb, slapi_sdn_get_ndn(pam_passthru_get_config_area()), LDAP_SCOPE_SUBTREE, "objectclass=*", NULL, 0, NULL, NULL, pam_passthruauth_get_plugin_identity(), 0); slapi_search_internal_pb(search_pb); slapi_pblock_get(search_pb, SLAPI_PLUGIN_INTOP_RESULT, &result); if (LDAP_SUCCESS != result) { status = PAM_PASSTHRU_FAILURE; goto cleanup; } slapi_pblock_get(search_pb, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES, &entries); if (NULL == entries || NULL == entries[0]) { status = PAM_PASSTHRU_FAILURE; goto cleanup; } /* Check if we are using an alternate config area. We do this here * so we don't have to check each every time in the loop below. */ if (slapi_sdn_compare(pam_passthru_get_config_area(), pam_passthruauth_get_plugin_sdn()) != 0) { alternate = 1; } /* Validate and apply config if valid. If skip_validate is set, we skip * validation and just apply the config. This should only be done if the * configuration has already been validated. */ for (i = 0; (entries[i] != NULL); i++) { /* If this is the alternate config container, skip it since * we don't consider it to be an actual config entry. */ if (alternate && (slapi_sdn_compare(pam_passthru_get_config_area(), slapi_entry_get_sdn(entries[i])) == 0)) { continue; } if (skip_validate || (PAM_PASSTHRU_SUCCESS == pam_passthru_validate_config(entries[i], NULL))) { if (PAM_PASSTHRU_FAILURE == pam_passthru_apply_config(entries[i])) { slapi_log_err(SLAPI_LOG_ERR, PAM_PASSTHRU_PLUGIN_SUBSYSTEM, "pam_passthru_load_config - Unable to apply config " "for entry \"%s\"\n", slapi_entry_get_ndn(entries[i])); } } else { slapi_log_err(SLAPI_LOG_ERR, PAM_PASSTHRU_PLUGIN_SUBSYSTEM, "pam_passthru_load_config - Skipping invalid config " "entry \"%s\"\n", slapi_entry_get_ndn(entries[i])); } } cleanup: slapi_free_search_results_internal(search_pb); slapi_pblock_destroy(search_pb); pam_passthru_unlock(); slapi_log_err(SLAPI_LOG_TRACE, PAM_PASSTHRU_PLUGIN_SUBSYSTEM, "<= pam_passthru_load_config\n"); return status; }
/* * Return 0 for OK, * -1 for Ignore or Error depending on SLAPI_RESULT_CODE, * >0 for action code * Action Code Bit 0: Fetch existing entry. * Action Code Bit 1: Fetch parent entry. * The function is called as a be pre-op on consumers. */ int urp_add_operation( Slapi_PBlock *pb ) { Slapi_Entry *existing_uniqueid_entry; Slapi_Entry *existing_dn_entry; Slapi_Entry *addentry; const char *adduniqueid; CSN *opcsn; const char *basedn; char sessionid[REPL_SESSION_ID_SIZE]; int r; int op_result= 0; int rc= 0; /* OK */ Slapi_DN *sdn = NULL; if ( slapi_op_abandoned(pb) ) { return rc; } get_repl_session_id (pb, sessionid, &opcsn); slapi_pblock_get( pb, SLAPI_ADD_EXISTING_UNIQUEID_ENTRY, &existing_uniqueid_entry ); if (existing_uniqueid_entry!=NULL) { /* * An entry with this uniqueid already exists. * - It could be a replay of the same Add, or * - It could be a UUID generation collision, or */ /* * This operation won't be replayed. That is, this CSN won't update * the max csn in RUV. The CSN is left uncommitted in RUV unless an * error is set to op_result. Just to get rid of this CSN from RUV, * setting an error to op_result */ /* op_result = LDAP_SUCCESS; */ slapi_log_error(slapi_log_urp, sessionid, "urp_add (%s): an entry with this uniqueid already exists.\n", slapi_entry_get_dn_const(existing_uniqueid_entry)); op_result= LDAP_UNWILLING_TO_PERFORM; slapi_pblock_set(pb, SLAPI_RESULT_CODE, &op_result); rc = SLAPI_PLUGIN_NOOP; /* Ignore this Operation */ PROFILE_POINT; /* Add Conflict; UniqueID Exists; Ignore */ goto bailout; } slapi_pblock_get( pb, SLAPI_ADD_ENTRY, &addentry ); slapi_pblock_get( pb, SLAPI_ADD_EXISTING_DN_ENTRY, &existing_dn_entry ); if (existing_dn_entry==NULL) /* The target DN does not exist */ { /* Check for parent entry... this could be an orphan. */ Slapi_Entry *parententry; slapi_pblock_get( pb, SLAPI_ADD_PARENT_ENTRY, &parententry ); rc = urp_add_resolve_parententry (pb, sessionid, addentry, parententry, opcsn); PROFILE_POINT; /* Add Entry */ goto bailout; } /* * Naming conflict: an entry with the target DN already exists. * Compare the DistinguishedNameCSN of the existing entry * and the OperationCSN. The smaller CSN wins. The loser changes * its RDN to uniqueid+baserdn, and adds operational attribute * ATTR_NSDS5_REPLCONFLIC. */ basedn = slapi_entry_get_ndn (addentry); adduniqueid = slapi_entry_get_uniqueid (addentry); r = csn_compare (entry_get_dncsn(existing_dn_entry), opcsn); if (r<0) { /* Entry to be added is a loser */ char *newdn= get_dn_plus_uniqueid (sessionid, basedn, adduniqueid); if(newdn==NULL) { op_result= LDAP_OPERATIONS_ERROR; slapi_pblock_set(pb, SLAPI_RESULT_CODE, &op_result); rc = SLAPI_PLUGIN_NOOP; /* Abort this Operation */ slapi_log_error(slapi_log_urp, sessionid, "urp_add (%s): Add conflict; Unique ID (%s) already in RDN\n", basedn, adduniqueid); PROFILE_POINT; /* Add Conflict; Entry Exists; Unique ID already in RDN - Abort this update. */ } else { /* Add the nsds5ReplConflict attribute in the mods */ Slapi_Attr *attr = NULL; Slapi_Value **vals = NULL; Slapi_RDN *rdn; char buf[BUFSIZ]; PR_snprintf(buf, BUFSIZ, "%s %s", REASON_ANNOTATE_DN, basedn); if (slapi_entry_attr_find (addentry, ATTR_NSDS5_REPLCONFLICT, &attr) == 0) { /* ATTR_NSDS5_REPLCONFLICT exists */ slapi_log_error(SLAPI_LOG_FATAL, sessionid, "urp_add: New entry has nsds5ReplConflict already\n"); vals = attr_get_present_values (attr); /* this returns a pointer to the contents */ } if ( vals == NULL || *vals == NULL ) { /* Add new attribute */ slapi_entry_add_string (addentry, ATTR_NSDS5_REPLCONFLICT, buf); } else { /* * Replace old attribute. We don't worry about the index * change here since the entry is yet to be added. */ slapi_value_set_string (*vals, buf); } /* slapi_pblock_get(pb, SLAPI_ADD_TARGET, &dn); */ slapi_pblock_get(pb, SLAPI_ADD_TARGET_SDN, &sdn); slapi_sdn_free(&sdn); slapi_entry_set_normdn(addentry, newdn); /* dn: passin */ sdn = slapi_sdn_dup(slapi_entry_get_sdn_const(addentry)); slapi_pblock_set(pb, SLAPI_ADD_TARGET_SDN, sdn); rdn = slapi_rdn_new_sdn ( slapi_entry_get_sdn_const(addentry) ); slapi_log_error (slapi_log_urp, sessionid, "urp_add: Naming conflict ADD. Add %s instead\n", slapi_rdn_get_rdn(rdn)); slapi_rdn_free(&rdn); rc= slapi_setbit_int(rc,SLAPI_RTN_BIT_FETCH_EXISTING_DN_ENTRY); PROFILE_POINT; /* Add Conflict; Entry Exists; Rename Operation Entry */ } } else if(r>0) { /* Existing entry is a loser */ if (!urp_annotate_dn(sessionid, existing_dn_entry, opcsn, "ADD")) { op_result= LDAP_OPERATIONS_ERROR; slapi_pblock_set(pb, SLAPI_RESULT_CODE, &op_result); slapi_log_error(slapi_log_urp, sessionid, "urp_add (%s): Entry to be added is a loser; " "urp_annotate_dn failed.\n", basedn); rc = SLAPI_PLUGIN_NOOP; /* Ignore this Operation */ } else { /* The backend add code should now search for the existing entry again. */ rc= slapi_setbit_int(rc,SLAPI_RTN_BIT_FETCH_EXISTING_DN_ENTRY); rc= slapi_setbit_int(rc,SLAPI_RTN_BIT_FETCH_PARENT_ENTRY); } PROFILE_POINT; /* Add Conflict; Entry Exists; Rename Existing Entry */ } else /* r==0 */ { /* The CSN of the Operation and the Entry DN are the same. * This could only happen if: * a) There are two replicas with the same ReplicaID. * b) We've seen the Operation before. * Let's go with (b) and ignore the little bastard. */ /* * This operation won't be replayed. That is, this CSN won't update * the max csn in RUV. The CSN is left uncommitted in RUV unless an * error is set to op_result. Just to get rid of this CSN from RUV, * setting an error to op_result */ /* op_result = LDAP_SUCCESS; */ slapi_log_error(slapi_log_urp, sessionid, "urp_add (%s): The CSN of the Operation and the Entry DN are the same.", slapi_entry_get_dn_const(existing_dn_entry)); op_result= LDAP_UNWILLING_TO_PERFORM; slapi_pblock_set(pb, SLAPI_RESULT_CODE, &op_result); rc = SLAPI_PLUGIN_NOOP; /* Ignore this Operation */ PROFILE_POINT; /* Add Conflict; Entry Exists; Same CSN */ } bailout: return rc; }
/* * Function Implementations */ int linked_attrs_fixup_task_add(Slapi_PBlock *pb, Slapi_Entry *e, Slapi_Entry *eAfter, int *returncode, char *returntext, void *arg) { PRThread *thread = NULL; int rv = SLAPI_DSE_CALLBACK_OK; task_data *mytaskdata = NULL; Slapi_Task *task = NULL; const char *linkdn = NULL; char *bind_dn; *returncode = LDAP_SUCCESS; /* make sure the plugin is not closed */ if(!linked_attrs_is_started()){ *returncode = LDAP_OPERATIONS_ERROR; rv = SLAPI_DSE_CALLBACK_ERROR; goto out; } /* get arg(s) */ linkdn = fetch_attr(e, "linkdn", 0); /* setup our task data */ slapi_pblock_get(pb, SLAPI_REQUESTOR_DN, &bind_dn); mytaskdata = (task_data*)slapi_ch_calloc(1, sizeof(task_data)); if (mytaskdata == NULL) { *returncode = LDAP_OPERATIONS_ERROR; rv = SLAPI_DSE_CALLBACK_ERROR; goto out; } if (linkdn) { mytaskdata->linkdn = slapi_dn_normalize(slapi_ch_strdup(linkdn)); } mytaskdata->bind_dn = slapi_ch_strdup(bind_dn); /* allocate new task now */ task = slapi_new_task(slapi_entry_get_ndn(e)); /* register our destructor for cleaning up our private data */ slapi_task_set_destructor_fn(task, linked_attrs_fixup_task_destructor); /* Stash a pointer to our data in the task */ slapi_task_set_data(task, mytaskdata); /* start the sample task as a separate thread */ thread = PR_CreateThread(PR_USER_THREAD, linked_attrs_fixup_task_thread, (void *)task, PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD, PR_UNJOINABLE_THREAD, SLAPD_DEFAULT_THREAD_STACKSIZE); if (thread == NULL) { slapi_log_error( SLAPI_LOG_FATAL, LINK_PLUGIN_SUBSYSTEM, "unable to create task thread!\n"); *returncode = LDAP_OPERATIONS_ERROR; rv = SLAPI_DSE_CALLBACK_ERROR; slapi_task_finish(task, *returncode); } else { rv = SLAPI_DSE_CALLBACK_OK; } out: return rv; }
/* * aclanom_match_profile * Look at the anonymous profile and see if we can use it or not. * * * Inputs: * Slapi_Pblock - The Pblock * Slapi_Entry *e - The entry for which we are asking permission. * char *attr - Attribute name * int access - access type * * Return: * LDAP_SUCCESS ( 0 ) - acess is allowed. * LDAP_INSUFFICIENT_ACCESS (50 ) - access denied. * -1 - didn't match the targets * * Assumptions: * The caller of this module has to make sure that the client is * an anonymous client. */ int aclanom_match_profile (Slapi_PBlock *pb, struct acl_pblock *aclpb, Slapi_Entry *e, char *attr, int access ) { struct anom_profile *a_profile; int result, i, k; char **destArray; int tmatched = 0; int loglevel; struct scoped_entry_anominfo *s_e_anominfo = &aclpb->aclpb_scoped_entry_anominfo; loglevel = slapi_is_loglevel_set(SLAPI_LOG_ACL) ? SLAPI_LOG_ACL : SLAPI_LOG_ACLSUMMARY; /* WE are only interested for READ/SEARCH */ if ( !(access & ( SLAPI_ACL_SEARCH | SLAPI_ACL_READ)) ) return -1; /* If we are here means, the client is doing a anonymous read/search */ if ((a_profile = acl_anom_profile) == NULL ) { return -1; } ANOM_LOCK_READ (); /* Check the signature first */ if ( a_profile->anom_signature != acl_get_aclsignature () ) { /* Need to regenrate the signature. * Need a WRITE lock to generate the anom profile - * which is obtained in acl__gen_anom_user_profile (). Since * I don't have upgrade lock -- I have to do this way. */ ANOM_UNLOCK_READ (); aclanom_gen_anomProfile (DO_TAKE_ACLCACHE_READLOCK); aclanom_get_suffix_info(e, aclpb ); ANOM_LOCK_READ (); } /* doing this early saves use a malloc/free/normalize cost */ if ( !a_profile->anom_numacls ) { ANOM_UNLOCK_READ (); return -1; } result = LDAP_INSUFFICIENT_ACCESS; for ( k=0; k<s_e_anominfo->anom_e_nummatched; k++ ) { short matched = 0; short j = 0; i = s_e_anominfo->anom_e_targetInfo[k]; /* Check for right */ if ( !(a_profile->anom_targetinfo[i].anom_access & access) ) continue; /* * XXX rbyrne Don't really understand the role of this * but not causing any obvious bugs...get back to it. */ tmatched++; if ( attr == NULL ) { result = LDAP_SUCCESS; break; } destArray = a_profile->anom_targetinfo[i].anom_targetAttrs; while ( destArray[j] ) { if ( strcasecmp ( destArray[j], "*") == 0 || slapi_attr_type_cmp ( attr, destArray[j], 1 ) == 0 ) { matched = 1; break; } j++; } if ( a_profile->anom_targetinfo[i].anom_type & ACI_TARGET_ATTR_NOT ) result = matched ? LDAP_INSUFFICIENT_ACCESS : LDAP_SUCCESS; else result = matched ? LDAP_SUCCESS : LDAP_INSUFFICIENT_ACCESS; if ( result == LDAP_SUCCESS ) break; } /* for */ if ( slapi_is_loglevel_set(loglevel) ) { char *ndn = NULL; Slapi_Operation *op = NULL; PRUint64 o_connid = 0xffffffffffffffff; /* no op */ int o_opid = -1; /* no op */ ndn = slapi_entry_get_ndn ( e ) ; slapi_pblock_get(pb, SLAPI_OPERATION, &op); if (op) { o_connid = op->o_connid; o_opid = op->o_opid; } if ( result == LDAP_SUCCESS) { const char *aci_ndn; aci_ndn = slapi_sdn_get_ndn (acl_anom_profile->anom_targetinfo[i].anom_target); if (access & SLAPI_ACL_MODDN) { slapi_log_err(loglevel, plugin_name, "aclanom_match_profile - conn=%" NSPRIu64 " op=%d: Allow access on entry(%s).attr(%s) (from %s) to anonymous: acidn=\"%s\"\n", o_connid, o_opid, ndn, attr ? attr:"NULL", aclpb->aclpb_moddn_source_sdn ? slapi_sdn_get_dn(aclpb->aclpb_moddn_source_sdn) : "NULL", aci_ndn); } else { slapi_log_err(loglevel, plugin_name, "aclanom_match_profile - conn=%" NSPRIu64 " op=%d: Allow access on entry(%s).attr(%s) to anonymous: acidn=\"%s\"\n", o_connid, o_opid, ndn, attr ? attr:"NULL", aci_ndn); } } else { if (access & SLAPI_ACL_MODDN) { slapi_log_err(loglevel, plugin_name, "aclanom_match_profile - conn=%" NSPRIu64 " op=%d: Deny access on entry(%s).attr(%s) (from %s) to anonymous\n", o_connid, o_opid, ndn, attr ? attr:"NULL" , aclpb->aclpb_moddn_source_sdn ? slapi_sdn_get_dn(aclpb->aclpb_moddn_source_sdn) : "NULL"); } else { slapi_log_err(loglevel, plugin_name, "aclanom_match_profile - conn=%" NSPRIu64 " op=%d: Deny access on entry(%s).attr(%s) to anonymous\n", o_connid, o_opid, ndn, attr ? attr:"NULL" ); } } } ANOM_UNLOCK_READ (); if ( tmatched == 0) return -1; else return result; }