static int agmt_dn_cmp(Object *ro, const void *arg) { Repl_Agmt *ra; Slapi_DN *sdn = (Slapi_DN *)arg; ra = object_get_data(ro); return(slapi_sdn_compare(sdn, agmt_get_dn_byref(ra))); }
int slapi_sdn_isparent( const Slapi_DN *parent, const Slapi_DN *child ) { Slapi_DN child_parent; slapi_sdn_get_ndn( child ); slapi_sdn_init( &child_parent ); dnParent( (struct berval *)&child->ndn, &child_parent.ndn ); return ( slapi_sdn_compare( parent, &child_parent ) == 0 ); }
int slapi_sdn_isgrandparent( const Slapi_DN *parent, const Slapi_DN *child ) { Slapi_DN child_grandparent; slapi_sdn_get_ndn( child ); slapi_sdn_init( &child_grandparent ); dnParent( (struct berval *)&child->ndn, &child_grandparent.ndn ); if ( child_grandparent.ndn.bv_len == 0 ) { return 0; } dnParent( &child_grandparent.ndn, &child_grandparent.ndn ); return ( slapi_sdn_compare( parent, &child_grandparent ) == 0 ); }
int slapi_sdn_scope_test( const Slapi_DN *dn, const Slapi_DN *base, int scope ) { int rc; switch ( scope ) { case LDAP_SCOPE_BASE: rc = ( slapi_sdn_compare( dn, base ) == 0 ); break; case LDAP_SCOPE_ONELEVEL: rc = slapi_sdn_isparent( base, dn ); break; case LDAP_SCOPE_SUBTREE: rc = slapi_sdn_issuffix( dn, base ); break; default: rc = 0; break; } return rc; }
Object* agmtlist_get_next_agreement_for_replica (Replica *r, Object *prev) { const Slapi_DN *replica_root; Slapi_DN *agmt_root; Object *obj; Repl_Agmt *agmt; if (r == NULL) { /* ONREPL - log error */ return NULL; } replica_root = replica_get_root(r); if (prev) obj = objset_next_obj(agmt_set, prev); else obj = objset_first_obj(agmt_set); while (obj) { agmt = (Repl_Agmt*)object_get_data (obj); PR_ASSERT (agmt); agmt_root = agmt_get_replarea(agmt); PR_ASSERT (agmt_root); if (slapi_sdn_compare (replica_root, agmt_root) == 0) { slapi_sdn_free (&agmt_root); return obj; } slapi_sdn_free (&agmt_root); obj = objset_next_obj(agmt_set, obj); } return NULL; }
static int _ger_g_permission_granted ( Slapi_PBlock *pb, Slapi_Entry *e, const char *subjectdn, char **errbuf ) { char *proxydn = NULL; Slapi_DN *requestor_sdn, *entry_sdn; char *errtext = NULL; int isroot; int rc; /* * Theorically, we should check if the entry has "g" * permission granted to the requestor. If granted, * allows the effective rights on that entry and its * attributes within the entry to be returned for * ANY subject. * * "G" permission granting has not been implemented yet, * the current release assumes that "g" permission be * granted to root and owner of any entry. */ /* * The requestor may be either the bind dn or a proxy dn */ if ((proxyauth_get_dn( pb, &proxydn, &errtext ) == LDAP_SUCCESS) && ( proxydn != NULL )) { requestor_sdn = slapi_sdn_new_dn_passin ( proxydn ); } else { slapi_ch_free_string(&proxydn); /* this could still have been set - free it */ requestor_sdn = &(pb->pb_op->o_sdn); } if ( slapi_sdn_get_dn (requestor_sdn) == NULL ) { slapi_log_err(SLAPI_LOG_ACL, plugin_name, "_ger_g_permission_granted - Anonymous has no g permission\n" ); rc = LDAP_INSUFFICIENT_ACCESS; goto bailout; } isroot = slapi_dn_isroot ( slapi_sdn_get_dn (requestor_sdn) ); if ( isroot ) { /* Root has "g" permission on any entry */ rc = LDAP_SUCCESS; goto bailout; } entry_sdn = slapi_entry_get_sdn ( e ); if ( entry_sdn == NULL || slapi_sdn_get_dn (entry_sdn) == NULL ) { rc = LDAP_SUCCESS; goto bailout; } if ( slapi_sdn_compare ( requestor_sdn, entry_sdn ) == 0 ) { /* Owner has "g" permission on his own entry */ rc = LDAP_SUCCESS; goto bailout; } /* if the requestor and the subject user are identical, let's grant it */ if ( strcasecmp ( slapi_sdn_get_ndn(requestor_sdn), subjectdn ) == 0) { /* Requestor should see his own permission rights on any entry */ rc = LDAP_SUCCESS; goto bailout; } aclutil_str_append ( errbuf, "get-effective-rights: requestor has no g permission on the entry" ); slapi_log_err(SLAPI_LOG_ACL, plugin_name, "_ger_g_permission_granted - %s\n", *errbuf); rc = LDAP_INSUFFICIENT_ACCESS; bailout: if ( proxydn ) { /* The ownership of proxydn has passed to requestor_sdn */ slapi_sdn_free ( &requestor_sdn ); } return rc; }
/* This function is called to process operation that come over external connections */ void do_modrdn( Slapi_PBlock *pb ) { Slapi_Operation *operation; BerElement *ber; char *rawdn = NULL, *rawnewsuperior = NULL; const char *dn = NULL, *newsuperior = NULL; char *newrdn = NULL; int err = 0, deloldrdn = 0; ber_len_t len = 0; char *newdn = NULL; char *parent = NULL; Slapi_DN sdn; Slapi_DN snewdn; Slapi_DN *snewsuperior = NULL; LDAPDebug( LDAP_DEBUG_TRACE, "do_modrdn\n", 0, 0, 0 ); /* count the modrdn request */ slapi_counter_increment(g_get_global_snmp_vars()->ops_tbl.dsModifyRDNOps); slapi_pblock_get( pb, SLAPI_OPERATION, &operation); ber = operation->o_ber; slapi_sdn_init(&sdn); slapi_sdn_init(&snewdn); /* * Parse the modrdn request. It looks like this: * * ModifyRDNRequest := SEQUENCE { * entry DistinguishedName, * newrdn RelativeDistinguishedName, * deleteoldrdn BOOLEAN, * newSuperior [0] LDAPDN OPTIONAL -- v3 only * } */ if (ber_scanf(ber, "{aab", &rawdn, &newrdn, &deloldrdn) == LBER_ERROR) { LDAPDebug( LDAP_DEBUG_ANY, "ber_scanf failed (op=ModRDN; params=DN,newRDN,deleteOldRDN)\n", 0, 0, 0 ); op_shared_log_error_access (pb, "MODRDN", "???", "decoding error"); send_ldap_result( pb, LDAP_PROTOCOL_ERROR, NULL, "unable to decode DN, newRDN, or deleteOldRDN parameters", 0, NULL ); goto free_and_return; } if ( ber_peek_tag( ber, &len ) == LDAP_TAG_NEWSUPERIOR ) { /* This "len" is not used... */ if ( pb->pb_conn->c_ldapversion < LDAP_VERSION3 ) { LDAPDebug( LDAP_DEBUG_ANY, "got newSuperior in LDAPv2 modrdn op\n", 0, 0, 0 ); op_shared_log_error_access (pb, "MODRDN", rawdn?rawdn:"", "decoding error"); send_ldap_result( pb, LDAP_PROTOCOL_ERROR, NULL, "received newSuperior in LDAPv2 modrdn", 0, NULL ); slapi_ch_free_string( &rawdn ); slapi_ch_free_string( &newrdn ); goto free_and_return; } if ( ber_scanf( ber, "a", &rawnewsuperior ) == LBER_ERROR ) { LDAPDebug( LDAP_DEBUG_ANY, "ber_scanf failed (op=ModRDN; params=newSuperior)\n", 0, 0, 0 ); op_shared_log_error_access (pb, "MODRDN", rawdn, "decoding error"); send_ldap_result( pb, LDAP_PROTOCOL_ERROR, NULL, "unable to decode newSuperior parameter", 0, NULL ); slapi_ch_free_string( &rawdn ); slapi_ch_free_string( &newrdn ); goto free_and_return; } } /* Check if we should be performing strict validation. */ if (config_get_dn_validate_strict()) { /* check that the dn is formatted correctly */ err = slapi_dn_syntax_check(pb, rawdn, 1); if (err) { /* syntax check failed */ op_shared_log_error_access(pb, "MODRDN", rawdn?rawdn:"", "strict: invalid dn"); send_ldap_result(pb, LDAP_INVALID_DN_SYNTAX, NULL, "invalid dn", 0, NULL); slapi_ch_free_string( &rawdn ); slapi_ch_free_string( &newrdn ); slapi_ch_free_string( &rawnewsuperior ); goto free_and_return; } /* check that the new rdn is formatted correctly */ err = slapi_dn_syntax_check(pb, newrdn, 1); if (err) { /* syntax check failed */ op_shared_log_error_access(pb, "MODRDN", newrdn?newrdn:"", "strict: invalid new rdn"); send_ldap_result(pb, LDAP_INVALID_DN_SYNTAX, NULL, "invalid new rdn", 0, NULL); slapi_ch_free_string( &rawdn ); slapi_ch_free_string( &newrdn ); slapi_ch_free_string( &rawnewsuperior ); goto free_and_return; } } slapi_sdn_init_dn_passin(&sdn, rawdn); dn = slapi_sdn_get_dn(&sdn); if (rawdn && (strlen(rawdn) > 0) && (NULL == dn)) { /* normalization failed */ op_shared_log_error_access(pb, "MODRDN", rawdn, "invalid dn"); send_ldap_result(pb, LDAP_INVALID_DN_SYNTAX, NULL, "invalid dn", 0, NULL); slapi_ch_free_string( &newrdn ); slapi_ch_free_string( &rawnewsuperior ); goto free_and_return; } if (rawnewsuperior) { if (config_get_dn_validate_strict()) { /* check that the dn is formatted correctly */ err = slapi_dn_syntax_check(pb, rawnewsuperior, 1); if (err) { /* syntax check failed */ op_shared_log_error_access(pb, "MODRDN", rawnewsuperior, "strict: invalid new superior"); send_ldap_result(pb, LDAP_INVALID_DN_SYNTAX, NULL, "invalid new superior", 0, NULL); slapi_ch_free_string( &rawnewsuperior ); goto free_and_return; } } snewsuperior = slapi_sdn_new_dn_passin(rawnewsuperior); newsuperior = slapi_sdn_get_dn(snewsuperior); } /* * If newsuperior is myself or my descendent, the modrdn should fail. * Note: need to check the case newrdn is given, and newsuperior * uses the newrdn, as well. */ parent = slapi_dn_parent(slapi_sdn_get_ndn(&sdn)); newdn = slapi_ch_smprintf("%s,%s", newrdn, parent); /* slapi_sdn_init_normdn_passin expects normalized but NOT * decapitalized dn */ slapi_sdn_init_dn_passin(&snewdn, newdn); if (0 == slapi_sdn_compare(&sdn, snewsuperior) || 0 == slapi_sdn_compare(&snewdn, snewsuperior)) { op_shared_log_error_access(pb, "MODRDN", newsuperior, "new superior is identical to the entry dn"); send_ldap_result(pb, LDAP_UNWILLING_TO_PERFORM, NULL, "new superior is identical to the entry dn", 0, NULL); goto free_and_return; } if (slapi_sdn_issuffix(snewsuperior, &sdn) || slapi_sdn_issuffix(snewsuperior, &snewdn)) { /* E.g., * newsuperior: ou=sub,ou=people,dc=example,dc=com * dn: ou=people,dc=example,dc=com */ op_shared_log_error_access(pb, "MODRDN", newsuperior, "new superior is descendent of the entry"); send_ldap_result(pb, LDAP_UNWILLING_TO_PERFORM, NULL, "new superior is descendent of the entry", 0, NULL); goto free_and_return; } /* * in LDAPv3 there can be optional control extensions on * the end of an LDAPMessage. we need to read them in and * pass them to the backend. */ if ( (err = get_ldapmessage_controls( pb, ber, NULL )) != 0 ) { op_shared_log_error_access (pb, "MODRDN", dn, "failed to decode LDAP controls"); send_ldap_result( pb, err, NULL, NULL, 0, NULL ); goto free_and_return; } LDAPDebug( LDAP_DEBUG_ARGS, "do_modrdn: dn (%s) newrdn (%s) deloldrdn (%d)\n", dn, newrdn, deloldrdn ); slapi_pblock_set( pb, SLAPI_REQUESTOR_ISROOT, &pb->pb_op->o_isroot ); /* dn, newrdn and newsuperior are all normalized */ slapi_pblock_set( pb, SLAPI_ORIGINAL_TARGET, (void *)slapi_sdn_get_udn(&sdn) ); slapi_pblock_set( pb, SLAPI_MODRDN_TARGET_SDN, &sdn ); slapi_pblock_set( pb, SLAPI_MODRDN_NEWRDN, (void *)newrdn ); slapi_pblock_set( pb, SLAPI_MODRDN_NEWSUPERIOR_SDN, (void *)snewsuperior ); slapi_pblock_set( pb, SLAPI_MODRDN_DELOLDRDN, &deloldrdn ); op_shared_rename(pb, 0 /* do not pass in ownership of string arguments */ ); free_and_return: slapi_sdn_done(&sdn); slapi_ch_free_string(&newrdn); slapi_sdn_free(&snewsuperior); slapi_sdn_done(&snewdn); slapi_ch_free_string(&parent); return; }
/* * 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; }
/* * Check if we are modifying the config, or changing the shared config entry */ int memberof_shared_config_validate(Slapi_PBlock *pb) { Slapi_Entry *e = 0; Slapi_Entry *resulting_e = 0; Slapi_Entry *config_entry = NULL; Slapi_DN *sdn = NULL; Slapi_DN *config_sdn = NULL; Slapi_Mods *smods = 0; Slapi_Mod *smod = NULL, *nextmod = NULL; LDAPMod **mods = NULL; char returntext[SLAPI_DSE_RETURNTEXT_SIZE]; char *configarea_dn = NULL; int ret = SLAPI_PLUGIN_SUCCESS; slapi_pblock_get(pb, SLAPI_TARGET_SDN, &sdn); if (slapi_sdn_compare(sdn, memberof_get_plugin_area()) == 0 || slapi_sdn_compare(sdn, memberof_get_config_area()) == 0) { slapi_pblock_get(pb, SLAPI_ENTRY_PRE_OP, &e); if(e){ /* * Create a copy of the entry and apply the * mods to create the resulting entry. */ slapi_pblock_get(pb, SLAPI_MODIFY_MODS, &mods); smods = slapi_mods_new(); slapi_mods_init_byref(smods, mods); resulting_e = slapi_entry_dup(e); if (mods && (slapi_entry_apply_mods(resulting_e, mods) != LDAP_SUCCESS)) { /* we don't care about this, the update is invalid and will be caught later */ goto bail; } if (slapi_sdn_compare(sdn, memberof_get_plugin_area())){ /* * This entry is a plugin config area entry, validate it. */ if( SLAPI_DSE_CALLBACK_ERROR == memberof_validate_config (pb, NULL, resulting_e, &ret, returntext,0)) { ret = LDAP_UNWILLING_TO_PERFORM; } } else { /* * This is the memberOf plugin entry, check if we are adding/replacing the * plugin config area. */ nextmod = slapi_mod_new(); for (smod = slapi_mods_get_first_smod(smods, nextmod); smod != NULL; smod = slapi_mods_get_next_smod(smods, nextmod) ) { if ( PL_strcasecmp(SLAPI_PLUGIN_SHARED_CONFIG_AREA, slapi_mod_get_type(smod)) == 0 ) { /* * Okay, we are modifying the plugin config area, we only care about * adds and replaces. */ if(SLAPI_IS_MOD_REPLACE(slapi_mod_get_operation(smod)) || SLAPI_IS_MOD_ADD(slapi_mod_get_operation(smod))) { struct berval *bv = NULL; int rc = 0; bv = slapi_mod_get_first_value(smod); configarea_dn = slapi_ch_strdup(bv->bv_val); if(configarea_dn){ /* Check the DN syntax */ rc = slapi_dn_syntax_check(pb, configarea_dn, 1); if (rc) { /* syntax check failed */ PR_snprintf(returntext, SLAPI_DSE_RETURNTEXT_SIZE, "%s does not contain a valid DN (%s)", SLAPI_PLUGIN_SHARED_CONFIG_AREA, configarea_dn); ret = LDAP_UNWILLING_TO_PERFORM; goto bail; } /* Check if the plugin config area entry exists */ if((config_sdn = slapi_sdn_new_dn_byval(configarea_dn))){ rc = slapi_search_internal_get_entry(config_sdn, NULL, &config_entry, memberof_get_plugin_id()); if(config_entry){ int err = 0; /* * Validate the settings from the new config area. */ if ( memberof_validate_config(pb, NULL, config_entry, &err, returntext,0) == SLAPI_DSE_CALLBACK_ERROR ) { ret = LDAP_UNWILLING_TO_PERFORM; goto bail; } } else { /* The config area does not exist */ PR_snprintf(returntext, SLAPI_DSE_RETURNTEXT_SIZE, "Unable to locate shared config entry (%s) error %d", slapi_sdn_get_dn(memberof_get_config_area()), rc); ret = LDAP_UNWILLING_TO_PERFORM; goto bail; } } } slapi_ch_free_string(&configarea_dn); slapi_sdn_free(&config_sdn); } } } } } else { PR_snprintf(returntext, SLAPI_DSE_RETURNTEXT_SIZE,"Unable to locate shared config entry (%s)", slapi_sdn_get_dn(memberof_get_config_area())); ret = LDAP_UNWILLING_TO_PERFORM; } } bail: if (ret){ slapi_pblock_set(pb, SLAPI_RESULT_CODE, &ret); slapi_pblock_set(pb, SLAPI_PB_RESULT_TEXT, returntext); slapi_log_err(SLAPI_LOG_ERR, MEMBEROF_PLUGIN_SUBSYSTEM, "memberof_shared_config_validate - %s/n", returntext); } slapi_sdn_free(&config_sdn); if(nextmod) slapi_mod_free(&nextmod); slapi_mods_free(&smods); slapi_entry_free(resulting_e); slapi_entry_free(config_entry); slapi_ch_free_string(&configarea_dn); return ret; }
/* * memberof_validate_config() * * Validate the pending changes in the e entry. */ int memberof_validate_config (Slapi_PBlock *pb, Slapi_Entry* entryBefore, Slapi_Entry* e, int *returncode, char *returntext, void *arg) { Slapi_Attr *memberof_attr = NULL; Slapi_Attr *group_attr = NULL; Slapi_DN *config_sdn = NULL; Slapi_DN **include_dn = NULL; Slapi_DN **exclude_dn = NULL; char *syntaxoid = NULL; char *config_dn = NULL; char *skip_nested = NULL; char *auto_add_oc = NULL; char **entry_scopes = NULL; char **entry_exclude_scopes = NULL; int not_dn_syntax = 0; int num_vals = 0; *returncode = LDAP_UNWILLING_TO_PERFORM; /* be pessimistic */ /* Make sure both the group attr and the memberOf attr * config atributes are supplied. We don't care about &attr * here, but slapi_entry_attr_find() requires us to pass it. */ if (!slapi_entry_attr_find(e, MEMBEROF_GROUP_ATTR, &group_attr) && !slapi_entry_attr_find(e, MEMBEROF_ATTR, &memberof_attr)) { Slapi_Attr *test_attr = NULL; Slapi_Value *value = NULL; int hint = 0; /* Loop through each group attribute to see if the syntax is correct. */ hint = slapi_attr_first_value(group_attr, &value); while (value && (not_dn_syntax == 0)) { /* We need to create an attribute to find the syntax. */ test_attr = slapi_attr_new(); slapi_attr_init(test_attr, slapi_value_get_string(value)); /* Get the syntax OID and see if it's the Distinguished Name or * Name and Optional UID syntax. */ slapi_attr_get_syntax_oid_copy(test_attr, &syntaxoid ); not_dn_syntax = strcmp(syntaxoid, DN_SYNTAX_OID) & strcmp(syntaxoid, NAME_OPT_UID_SYNTAX_OID); slapi_ch_free_string(&syntaxoid); /* Print an error if the current attribute is not using the Distinguished * Name syntax, otherwise get the next group attribute. */ if (not_dn_syntax) { PR_snprintf(returntext, SLAPI_DSE_RETURNTEXT_SIZE, "The %s configuration attribute must be set to " "an attribute defined to use either the Distinguished " "Name or Name and Optional UID syntax. (illegal value: %s)", slapi_value_get_string(value), MEMBEROF_GROUP_ATTR); } else { hint = slapi_attr_next_value(group_attr, hint, &value); } /* Free the group attribute. */ slapi_attr_free(&test_attr); } if (not_dn_syntax == 0) { /* Check the syntax of the memberof attribute. */ slapi_attr_first_value(memberof_attr, &value); test_attr = slapi_attr_new(); slapi_attr_init(test_attr, slapi_value_get_string(value)); slapi_attr_get_syntax_oid_copy(test_attr, &syntaxoid ); not_dn_syntax = strcmp(syntaxoid, DN_SYNTAX_OID); slapi_ch_free_string(&syntaxoid); slapi_attr_free(&test_attr); if (not_dn_syntax) { PR_snprintf(returntext, SLAPI_DSE_RETURNTEXT_SIZE, "The %s configuration attribute must be set to " "an attribute defined to use the Distinguished " "Name syntax. (illegal value: %s)", slapi_value_get_string(value), MEMBEROF_ATTR); goto done; } else { *returncode = LDAP_SUCCESS; } } } else { PR_snprintf(returntext, SLAPI_DSE_RETURNTEXT_SIZE, "The %s and %s configuration attributes must be provided", MEMBEROF_GROUP_ATTR, MEMBEROF_ATTR); goto done; } if ((skip_nested = slapi_entry_attr_get_charptr(e, MEMBEROF_SKIP_NESTED_ATTR))){ if(strcasecmp(skip_nested, "on") != 0 && strcasecmp(skip_nested, "off") != 0){ PR_snprintf(returntext, SLAPI_DSE_RETURNTEXT_SIZE, "The %s configuration attribute must be set to " "\"on\" or \"off\". (illegal value: %s)", MEMBEROF_SKIP_NESTED_ATTR, skip_nested); goto done; } } if ((auto_add_oc = slapi_entry_attr_get_charptr(e, MEMBEROF_AUTO_ADD_OC))){ char *sup = NULL; /* Check if the objectclass exists by looking for its superior oc */ if((sup = slapi_schema_get_superior_name(auto_add_oc)) == NULL){ PR_snprintf(returntext, SLAPI_DSE_RETURNTEXT_SIZE, "The %s configuration attribute must be set to " "to an existing objectclass (unknown: %s)", MEMBEROF_AUTO_ADD_OC, auto_add_oc); *returncode = LDAP_UNWILLING_TO_PERFORM; goto done; } else { slapi_ch_free_string(&sup); } } if ((config_dn = slapi_entry_attr_get_charptr(e, SLAPI_PLUGIN_SHARED_CONFIG_AREA))){ /* Now check the shared config attribute, validate it now */ Slapi_Entry *e = NULL; int rc = 0; rc = slapi_dn_syntax_check(pb, config_dn, 1); if (rc) { /* syntax check failed */ slapi_log_err(SLAPI_LOG_ERR, MEMBEROF_PLUGIN_SUBSYSTEM, "memberof_validate_config - " "%s does not contain a valid DN (%s)\n", SLAPI_PLUGIN_SHARED_CONFIG_AREA, config_dn); *returncode = LDAP_INVALID_DN_SYNTAX; goto done; } config_sdn = slapi_sdn_new_dn_byval(config_dn); slapi_search_internal_get_entry(config_sdn, NULL, &e, memberof_get_plugin_id()); if(e){ slapi_entry_free(e); *returncode = LDAP_SUCCESS; } else { /* config area does not exist! */ PR_snprintf(returntext, SLAPI_DSE_RETURNTEXT_SIZE, "The %s configuration attribute points to an entry that " "can not be found. (%s)", SLAPI_PLUGIN_SHARED_CONFIG_AREA, config_dn); *returncode = LDAP_UNWILLING_TO_PERFORM; } } /* * Check the entry scopes */ entry_scopes = slapi_entry_attr_get_charray_ext(e, MEMBEROF_ENTRY_SCOPE_ATTR, &num_vals); if(entry_scopes){ int i = 0; /* Validate the syntax before we create our DN array */ for (i = 0;i < num_vals; i++){ if(slapi_dn_syntax_check(pb, entry_scopes[i], 1)){ /* invalid dn syntax */ PR_snprintf(returntext, SLAPI_DSE_RETURNTEXT_SIZE, "%s: Invalid DN (%s) for include suffix.", MEMBEROF_PLUGIN_SUBSYSTEM, entry_scopes[i]); slapi_ch_array_free(entry_scopes); entry_scopes = NULL; theConfig.entryScopeCount = 0; *returncode = LDAP_UNWILLING_TO_PERFORM; goto done; } } /* Now create our SDN array for conflict checking */ include_dn = (Slapi_DN **)slapi_ch_calloc(sizeof(Slapi_DN *), num_vals+1); for (i = 0;i < num_vals; i++){ include_dn[i] = slapi_sdn_new_dn_passin(entry_scopes[i]); } } /* * Check and process the entry exclude scopes */ entry_exclude_scopes = slapi_entry_attr_get_charray_ext(e, MEMBEROF_ENTRY_SCOPE_EXCLUDE_SUBTREE, &num_vals); if(entry_exclude_scopes){ int i = 0; /* Validate the syntax before we create our DN array */ for (i = 0;i < num_vals; i++){ if(slapi_dn_syntax_check(pb, entry_exclude_scopes[i], 1)){ /* invalid dn syntax */ PR_snprintf(returntext, SLAPI_DSE_RETURNTEXT_SIZE, "%s: Invalid DN (%s) for exclude suffix.", MEMBEROF_PLUGIN_SUBSYSTEM, entry_exclude_scopes[i]); slapi_ch_array_free(entry_exclude_scopes); entry_exclude_scopes = NULL; *returncode = LDAP_UNWILLING_TO_PERFORM; goto done; } } /* Now create our SDN array for conflict checking */ exclude_dn = (Slapi_DN **)slapi_ch_calloc(sizeof(Slapi_DN *),num_vals+1); for (i = 0;i < num_vals; i++){ exclude_dn[i] = slapi_sdn_new_dn_passin(entry_exclude_scopes[i]); } } /* * Need to do conflict checking */ if(include_dn && exclude_dn){ /* * Make sure we haven't mixed the same suffix, and there are no * conflicts between the includes and excludes */ int i = 0; while(include_dn[i]){ int x = 0; while(exclude_dn[x]){ if(slapi_sdn_compare(include_dn[i], exclude_dn[x] ) == 0) { /* we have a conflict */ PR_snprintf(returntext, SLAPI_DSE_RETURNTEXT_SIZE, "%s: include suffix (%s) is also listed as an exclude suffix list", MEMBEROF_PLUGIN_SUBSYSTEM, slapi_sdn_get_dn(include_dn[i])); *returncode = LDAP_UNWILLING_TO_PERFORM; goto done; } x++; } i++; } /* Check for parent/child conflicts */ i = 0; while(include_dn[i]){ int x = 0; while(exclude_dn[x]){ if(slapi_sdn_issuffix(include_dn[i], exclude_dn[x])) { /* we have a conflict */ PR_snprintf(returntext, SLAPI_DSE_RETURNTEXT_SIZE, "%s: include suffix (%s) is a child of the exclude suffix(%s)", MEMBEROF_PLUGIN_SUBSYSTEM, slapi_sdn_get_dn(include_dn[i]), slapi_sdn_get_dn(exclude_dn[i])); *returncode = LDAP_UNWILLING_TO_PERFORM; goto done; } x++; } i++; } } done: memberof_free_scope(exclude_dn, &num_vals); memberof_free_scope(include_dn, &num_vals); slapi_ch_free((void**)&entry_scopes); slapi_ch_free((void**)&entry_exclude_scopes); slapi_sdn_free(&config_sdn); slapi_ch_free_string(&config_dn); slapi_ch_free_string(&skip_nested); slapi_ch_free_string(&auto_add_oc); if (*returncode != LDAP_SUCCESS) { return SLAPI_DSE_CALLBACK_ERROR; } else { return SLAPI_DSE_CALLBACK_OK; } }
static int updatedn_compare_dns(const void *d1, const void *d2) { return (0 == slapi_sdn_compare((const Slapi_DN *)d1, (const Slapi_DN *)d2)); }
static int search_one_berval(Slapi_DN *baseDN, const char *attrName, const struct berval *value, const char *requiredObjectClass, Slapi_DN *target) { int result; char *filter; Slapi_PBlock *spb; result = LDAP_SUCCESS; /* If no value, can't possibly be a conflict */ if ( (struct berval *)NULL == value ) return result; filter = 0; spb = 0; BEGIN int err; int sres; Slapi_Entry **entries; static char *attrs[] = { "1.1", 0 }; /* Create the filter - this needs to be freed */ filter = create_filter(attrName, value, requiredObjectClass); #ifdef DEBUG slapi_log_error(SLAPI_LOG_PLUGIN, plugin_name, "SEARCH filter=%s\n", filter); #endif /* Perform the search using the new internal API */ spb = slapi_pblock_new(); if (!spb) { result = uid_op_error(2); break; } slapi_search_internal_set_pb_ext(spb, baseDN, LDAP_SCOPE_SUBTREE, filter, attrs, 0 /* attrs only */, NULL, NULL, plugin_identity, 0 /* actions */); slapi_search_internal_pb(spb); err = slapi_pblock_get(spb, SLAPI_PLUGIN_INTOP_RESULT, &sres); if (err) { result = uid_op_error(3); break; } /* Allow search to report that there is nothing in the subtree */ if (sres == LDAP_NO_SUCH_OBJECT) break; /* Other errors are bad */ if (sres) { result = uid_op_error(3); break; } err = slapi_pblock_get(spb, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES, &entries); if (err) { result = uid_op_error(4); break; } /* * Look at entries returned. Any entry found must be the * target entry or the constraint fails. */ for(;*entries;entries++) { #ifdef DEBUG slapi_log_error(SLAPI_LOG_PLUGIN, plugin_name, "SEARCH entry dn=%s\n", slapi_entry_get_dn(*entries)); #endif /* * It is a Constraint Violation if any entry is found, unless * the entry is the target entry (if any). */ if (!target || slapi_sdn_compare(slapi_entry_get_sdn(*entries), target) != 0) { result = LDAP_CONSTRAINT_VIOLATION; break; } } #ifdef DEBUG slapi_log_error(SLAPI_LOG_PLUGIN, plugin_name, "SEARCH complete result=%d\n", result); #endif END /* Clean-up */ if (spb) { slapi_free_search_results_internal(spb); slapi_pblock_destroy(spb); } slapi_ch_free((void**)&filter); return result; }
/* * Return 0 for OK, -1 for Error, >0 for action code * Action Code Bit 0: Fetch existing entry. * Action Code Bit 1: Fetch parent entry. */ int urp_modrdn_operation( Slapi_PBlock *pb ) { slapi_operation_parameters *op_params = NULL; Slapi_Entry *parent_entry; Slapi_Entry *new_parent_entry; Slapi_DN *newsuperior = NULL; Slapi_DN *parentdn = NULL; const Slapi_Entry *target_entry; Slapi_Entry *existing_entry; const CSN *target_entry_dncsn; CSN *opcsn= NULL; char *op_uniqueid = NULL; const char *existing_uniqueid = NULL; const Slapi_DN *target_sdn; const Slapi_DN *existing_sdn; char *newrdn; char sessionid[REPL_SESSION_ID_SIZE]; int r; int op_result= 0; int rc= 0; /* OK */ int del_old_replconflict_attr = 0; if ( slapi_op_abandoned(pb) ) { return rc; } slapi_pblock_get (pb, SLAPI_MODRDN_TARGET_ENTRY, &target_entry); if(target_entry==NULL) { /* An entry can't be found for the Unique Identifier */ op_result= LDAP_NO_SUCH_OBJECT; slapi_pblock_set(pb, SLAPI_RESULT_CODE, &op_result); rc= -1; /* No entry to modrdn */ PROFILE_POINT; /* ModRDN Conflict; Entry does not Exist; Discard ModRDN */ goto bailout; } get_repl_session_id (pb, sessionid, &opcsn); target_entry_dncsn = entry_get_dncsn (target_entry); if ( csn_compare (target_entry_dncsn, opcsn) >= 0 ) { /* * The Operation CSN is not newer than the DN CSN. * Either we're beaten by another ModRDN or we've applied the op. */ /* op_result= LDAP_SUCCESS; */ /* * 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 */ slapi_log_error(slapi_log_urp, sessionid, "urp_modrdn (%s): operation CSN is newer than the DN CSN.\n", slapi_entry_get_dn_const(target_entry)); op_result= LDAP_UNWILLING_TO_PERFORM; slapi_pblock_set(pb, SLAPI_RESULT_CODE, &op_result); rc = SLAPI_PLUGIN_NOOP; /* Ignore the modrdn */ PROFILE_POINT; /* ModRDN Conflict; Entry with Target DN Exists; OPCSN is not newer. */ goto bailout; } /* The DN CSN is older than the Operation CSN. Apply the operation */ target_sdn = slapi_entry_get_sdn_const (target_entry); /* newrdn is no need to be case-ignored (get_rdn_plus_uniqueid) */ slapi_pblock_get(pb, SLAPI_MODRDN_NEWRDN, &newrdn); slapi_pblock_get(pb, SLAPI_TARGET_UNIQUEID, &op_uniqueid); slapi_pblock_get(pb, SLAPI_MODRDN_PARENT_ENTRY, &parent_entry); slapi_pblock_get(pb, SLAPI_MODRDN_NEWPARENT_ENTRY, &new_parent_entry); slapi_pblock_get(pb, SLAPI_MODRDN_NEWSUPERIOR_SDN, &newsuperior); if ( is_tombstone_entry (target_entry) ) { /* * It is a non-trivial task to rename a tombstone. * This op has been ignored so far by * setting SLAPI_RESULT_CODE to LDAP_NO_SUCH_OBJECT * and rc to -1. */ /* Turn the tombstone to glue before rename it */ /* op_result = tombstone_to_glue (pb, sessionid, target_entry, slapi_entry_get_sdn (target_entry), "renameTombstone", opcsn); */ op_result = LDAP_NO_SUCH_OBJECT; slapi_pblock_set(pb, SLAPI_RESULT_CODE, &op_result); if (op_result == 0) { /* * Remember to turn this entry back to tombstone in post op. * We'll just borrow an obsolete pblock type here. */ slapi_pblock_set (pb, SLAPI_URP_TOMBSTONE_UNIQUEID, slapi_ch_strdup(op_uniqueid)); rc= slapi_setbit_int(rc,SLAPI_RTN_BIT_FETCH_TARGET_ENTRY); rc = 0; } else { slapi_log_error(slapi_log_urp, sessionid, "urp_modrdn (%s): target entry is a tombstone.\n", slapi_entry_get_dn_const(target_entry)); rc = SLAPI_PLUGIN_NOOP; /* Ignore the modrdn */ } PROFILE_POINT; /* ModRDN Conflict; Entry with Target DN Exists; OPCSN is not newer. */ goto bailout; } slapi_pblock_get(pb, SLAPI_MODRDN_EXISTING_ENTRY, &existing_entry); if(existing_entry!=NULL) { /* * An entry with the target DN already exists. * The smaller dncsn wins. The loser changes its RDN to * uniqueid+baserdn, and adds operational attribute * ATTR_NSDS5_REPLCONFLIC */ existing_uniqueid = slapi_entry_get_uniqueid (existing_entry); existing_sdn = slapi_entry_get_sdn_const ( existing_entry); /* * It used to dismiss the operation if the existing entry is * the same as the target one. * But renaming the RDN with the one which only cases are different, * cn=ABC --> cn=Abc, this case matches. We should go forward the op. */ if (strcmp(op_uniqueid, existing_uniqueid) == 0) { op_result= LDAP_SUCCESS; slapi_pblock_set(pb, SLAPI_RESULT_CODE, &op_result); rc = 0; /* Don't ignore the op */ PROFILE_POINT; /* ModRDN Replay */ goto bailout; } r= csn_compare ( entry_get_dncsn (existing_entry), opcsn); if (r == 0) { /* * The CSN of the Operation and the Entry DN are the same * but the uniqueids are not. * There might be two replicas with the same ReplicaID. */ slapi_log_error(slapi_log_urp, sessionid, "urp_modrdn: Duplicated CSN for different uniqueids [%s][%s]", existing_uniqueid, op_uniqueid); op_result= LDAP_OPERATIONS_ERROR; slapi_pblock_set(pb, SLAPI_RESULT_CODE, &op_result); rc = SLAPI_PLUGIN_NOOP; /* Ignore this Operation */ PROFILE_POINT; /* ModRDN Conflict; Duplicated CSN for Different Entries */ goto bailout; } if(r<0) { /* The target entry is a loser */ char *newrdn_with_uniqueid; newrdn_with_uniqueid= get_rdn_plus_uniqueid (sessionid, newrdn, op_uniqueid); if(newrdn_with_uniqueid==NULL) { op_result= LDAP_OPERATIONS_ERROR; slapi_pblock_set(pb, SLAPI_RESULT_CODE, &op_result); rc= -1; /* Ignore this Operation */ PROFILE_POINT; /* ModRDN Conflict; Entry with Target DN Exists; Unique ID already in RDN - Change to Lost and Found entry */ goto bailout; } mod_namingconflict_attr (op_uniqueid, target_sdn, existing_sdn, opcsn); slapi_pblock_set(pb, SLAPI_MODRDN_NEWRDN, newrdn_with_uniqueid); slapi_log_error(slapi_log_urp, sessionid, "urp_modrdn: Naming conflict MODRDN. Rename target entry to %s\n", newrdn_with_uniqueid ); rc= slapi_setbit_int(rc,SLAPI_RTN_BIT_FETCH_EXISTING_DN_ENTRY); PROFILE_POINT; /* ModRDN Conflict; Entry with Target DN Exists; Rename Operation Entry */ goto bailout; } if ( r>0 ) { /* The existing entry is a loser */ int resolve = urp_annotate_dn (sessionid, existing_entry, opcsn, "MODRDN"); if(!resolve) { op_result= LDAP_OPERATIONS_ERROR; slapi_pblock_set(pb, SLAPI_RESULT_CODE, &op_result); rc= -1; /* Abort this Operation */ goto bailout; } rc= slapi_setbit_int(rc,SLAPI_RTN_BIT_FETCH_EXISTING_DN_ENTRY); rc= slapi_setbit_int(rc,SLAPI_RTN_BIT_FETCH_NEWPARENT_ENTRY); if (LDAP_NO_SUCH_OBJECT == resolve) { /* This means that existing_dn_entry did not really exist!!! * This indicates that a get_copy_of_entry -> dn2entry returned * an entry (existing_dn_entry) that was already removed from the ldbm. * This is bad, because it indicates a dn cache or DB corruption. * However, as far as the conflict is concerned, this error is harmless: * if the existing_dn_entry did not exist in the first place, there was no * conflict!! Return 0 for success to break the ldbm_back_modrdn loop * and get out of this inexistent conflict resolution ASAP. */ rc = 0; } /* Set flag to remove possible old naming conflict */ del_old_replconflict_attr = 1; PROFILE_POINT; /* ModRDN Conflict; Entry with Target DN Exists; Rename Entry with Target DN */ goto bailout; } } else { /* * No entry with the target DN exists. */ /* Set flag to remove possible old naming conflict */ del_old_replconflict_attr = 1; if(new_parent_entry!=NULL) { /* The new superior entry exists */ rc= 0; /* OK, Apply the ModRDN */ PROFILE_POINT; /* ModRDN Conflict; OK */ goto bailout; } /* The new superior entry doesn't exist */ slapi_pblock_get(pb, SLAPI_MODRDN_NEWSUPERIOR_SDN, &newsuperior); if(newsuperior == NULL) { /* (new_parent_entry==NULL && newsuperiordn==NULL) * This is ok - SLAPI_MODRDN_NEWPARENT_ENTRY will * only be set if SLAPI_MODRDN_NEWSUPERIOR_SDN was * suplied by the client. If it wasn't, we're just * changing the RDN of the entry. In that case, * if the entry exists, its parent won't change * when it's renamed, and therefore we can assume * its parent exists. */ rc=0; PROFILE_POINT; /* ModRDN OK */ goto bailout; } if((0 == slapi_sdn_compare(slapi_entry_get_sdn(parent_entry), newsuperior)) || is_suffix_dn (pb, newsuperior, &parentdn) ) { /* * The new superior is the same as the current one, or * this entry is a suffix whose parent can be absent. */ rc= 0; /* OK, Move the entry */ PROFILE_POINT; /* ModRDN Conflict; Absent Target Parent; Create Suffix Entry */ goto bailout; } /* * This entry is not a suffix entry, so the parent entry should exist. * (This shouldn't happen in a ds5 server) */ slapi_pblock_get ( pb, SLAPI_OPERATION_PARAMETERS, &op_params ); op_result = create_glue_entry (pb, sessionid, newsuperior, op_params->p.p_modrdn.modrdn_newsuperior_address.uniqueid, opcsn); if (LDAP_SUCCESS != op_result) { /* * FATAL ERROR * We should probably just abort the rename * this will cause replication divergence requiring * admin intercession */ slapi_log_error( SLAPI_LOG_FATAL, sessionid, "urp_modrdn: Parent %s couldn't be found, nor recreated as a glue entry\n", slapi_sdn_get_dn(newsuperior) ); op_result= LDAP_OPERATIONS_ERROR; slapi_pblock_set(pb, SLAPI_RESULT_CODE, &op_result); rc = SLAPI_PLUGIN_FAILURE; /* Ignore this Operation */ PROFILE_POINT; goto bailout; } /* The backend add code should now search for the parent again. */ rc= slapi_setbit_int(rc,SLAPI_RTN_BIT_FETCH_NEWPARENT_ENTRY); PROFILE_POINT; /* ModRDN Conflict; Absent Target Parent - Change to Lost and Found entry */ goto bailout; } bailout: if ( del_old_replconflict_attr && rc == 0 ) { del_replconflict_attr (target_entry, opcsn, 0); } if ( parentdn ) slapi_sdn_free(&parentdn); return rc; }