int slapi_sdn_issuffix( const Slapi_DN *sdn, const Slapi_DN *suffix_sdn ) { slapi_sdn_get_ndn( sdn ); slapi_sdn_get_ndn( suffix_sdn ); return dnIsSuffix( &sdn->ndn, &suffix_sdn->ndn ); }
/* if vs is given, delete only those values - otherwise, delete all values */ void replica_updatedn_list_delete(ReplicaUpdateDNList list, const Slapi_ValueSet *vs) { PLHashTable *hash = list; if (!vs || slapi_valueset_count(vs) == 0) { /* just delete everything */ PL_HashTableEnumerateEntries(hash, replica_destroy_hash_entry, NULL); } else { Slapi_ValueSet *vs_nc = (Slapi_ValueSet *)vs; /* cast away const */ Slapi_Value *val = NULL; int index = 0; for (index = slapi_valueset_first_value(vs_nc, &val); val; index = slapi_valueset_next_value(vs_nc, index, &val)) { Slapi_DN *dn = slapi_sdn_new_dn_byval(slapi_value_get_string(val)); /* locate object */ Slapi_DN *deldn = (Slapi_DN *)PL_HashTableLookup(hash, slapi_sdn_get_ndn(dn)); if (deldn == NULL) { slapi_log_err(SLAPI_LOG_REPL, repl_plugin_name, "replica_updatedn_list_delete -" "Update DN with value (%s) is not in the update DN list.\n", slapi_sdn_get_ndn(dn)); } else { /* remove from hash */ PL_HashTableRemove(hash, slapi_sdn_get_ndn(dn)); /* free the pointer */ slapi_sdn_free(&deldn); } /* free the temp dn */ slapi_sdn_free(&dn); } } return; }
int slapi_sdn_compare( const Slapi_DN *sdn1, const Slapi_DN *sdn2 ) { int match = -1; slapi_sdn_get_ndn( sdn1 ); slapi_sdn_get_ndn( sdn2 ); dnMatch( &match, 0, slap_schema.si_syn_distinguishedName, NULL, (struct berval *)&sdn1->ndn, (void *)&sdn2->ndn ); return match; }
/* * 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 (); }
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 ); }
/* * This is called on a master when a replication agreement is * destroyed. Any cookie allocated when the agreement was initialized * should be free'd here. */ static void test_repl_session_plugin_destroy_cb(void *cookie, const Slapi_DN *repl_subtree) { slapi_log_err(SLAPI_LOG_DEBUG, test_repl_session_plugin_name, "test_repl_session_plugin_destroy_cb() called for suffix \"%s\".\n", slapi_sdn_get_ndn(repl_subtree)); /* free cookie */ slapi_ch_free_string((char **)&cookie); return; }
void slapi_sdn_get_backend_parent( const Slapi_DN *sdn, Slapi_DN *sdn_parent, const Slapi_Backend *backend ) { slapi_sdn_get_ndn( sdn ); if ( backend == NULL || be_issuffix( (Slapi_Backend *)backend, (struct berval *)&sdn->ndn ) == 0 ) { slapi_sdn_get_parent( sdn, sdn_parent ); } }
/* * lookup instance names by suffix. * if isexact == 0: returns instances including ones that associates with * its sub suffixes. * e.g., suffix: "o=<suffix>" is given, these are returned: * suffixes: o=<suffix>, ou=<ou>,o=<suffix>, ... * instances: inst of "o=<suffix>", * inst of "ou=<ou>,o=<suffix>", * ... * if isexact != 0: returns an instance that associates with the given suffix * e.g., suffix: "o=<suffix>" is given, these are returned: * suffixes: "o=<suffix>" * instances: inst of "o=<suffix>" * Note: if suffixes */ int slapi_lookup_instance_name_by_suffix(char *suffix, char ***suffixes, char ***instances, int isexact) { Slapi_Backend *be = NULL; struct suffixlist *list; char *cookie = NULL; const char *thisdn; int thisdnlen; int suffixlen; int count; int i; int rval = -1; if (instances == NULL) return rval; PR_ASSERT(suffix); rval = 0; suffixlen = strlen(suffix); cookie = NULL; be = slapi_get_first_backend (&cookie); while (be) { if (NULL == be->be_suffixlist) { be = (backend *)slapi_get_next_backend (cookie); continue; } count = slapi_counter_get_value(be->be_suffixcounter); list = be->be_suffixlist; for (i = 0; list && i < count; i++) { thisdn = slapi_sdn_get_ndn(list->be_suffix); thisdnlen = slapi_sdn_get_ndn_len(list->be_suffix); if (isexact?suffixlen!=thisdnlen:suffixlen>thisdnlen){ list = list->next; continue; } if (isexact?(!slapi_UTF8CASECMP(suffix, (char *)thisdn)): (!slapi_UTF8CASECMP(suffix, (char *)thisdn+thisdnlen-suffixlen))) { charray_add(instances, slapi_ch_strdup(be->be_name)); if (suffixes) charray_add(suffixes, slapi_ch_strdup(thisdn)); } list = list->next; } be = (backend *)slapi_get_next_backend (cookie); } slapi_ch_free((void **)&cookie); return rval; }
Slapi_ValueSet * replica_updatedn_list_get_members(Slapi_DN *dn) { static char* const filter_groups = "(|(objectclass=groupOfNames)(objectclass=groupOfUniqueNames)(objectclass=groupOfURLs))"; static char* const type_member = "member"; static char* const type_uniquemember = "uniquemember"; static char* const type_memberURL = "memberURL"; int rval; char *attrs[4]; Slapi_PBlock *mpb = slapi_pblock_new (); Slapi_ValueSet *members = slapi_valueset_new(); attrs[0] = type_member; attrs[1] = type_uniquemember; attrs[2] = type_memberURL; attrs[3] = NULL; slapi_search_internal_set_pb ( mpb, slapi_sdn_get_ndn(dn), LDAP_SCOPE_BASE, filter_groups, &attrs[0], 0, NULL /* controls */, NULL /* uniqueid */, repl_get_plugin_identity (PLUGIN_MULTIMASTER_REPLICATION), 0); slapi_search_internal_pb(mpb); slapi_pblock_get(mpb, SLAPI_PLUGIN_INTOP_RESULT, &rval); if (rval == LDAP_SUCCESS) { Slapi_Entry **ep; slapi_pblock_get(mpb, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES, &ep); if ((ep != NULL) && (ep[0] != NULL)) { Slapi_Attr *attr = NULL; Slapi_Attr *nextAttr = NULL; Slapi_ValueSet *vs = NULL; char *attrType; slapi_entry_first_attr ( ep[0], &attr); while (attr) { slapi_attr_get_type ( attr, &attrType ); if ((strcasecmp (attrType, type_member) == 0) || (strcasecmp (attrType, type_uniquemember) == 0 )) { slapi_attr_get_valueset(attr, &vs); slapi_valueset_join_attr_valueset(attr, members, vs); slapi_valueset_free(vs); } else if (strcasecmp (attrType, type_memberURL) == 0) { /* not yet supported */ } slapi_entry_next_attr ( ep[0], attr, &nextAttr ); attr = nextAttr; } } } slapi_free_search_results_internal(mpb); slapi_pblock_destroy (mpb); return(members); }
static char * derive_from_bind_entry(Slapi_PBlock *pb, const Slapi_DN *bindsdn, MyStrBuf *pam_id, char *map_ident_attr, int *locked) { Slapi_Entry *entry = NULL; char *attrs[] = { NULL, NULL }; attrs[0] = map_ident_attr; int rc = slapi_search_internal_get_entry((Slapi_DN *)bindsdn, attrs, &entry, pam_passthruauth_get_plugin_identity()); if (rc != LDAP_SUCCESS) { slapi_log_error(SLAPI_LOG_FATAL, PAM_PASSTHRU_PLUGIN_SUBSYSTEM, "Could not find BIND dn %s (error %d - %s)\n", slapi_sdn_get_ndn(bindsdn), rc, ldap_err2string(rc)); init_my_str_buf(pam_id, NULL); } else if (NULL == entry) { slapi_log_error(SLAPI_LOG_FATAL, PAM_PASSTHRU_PLUGIN_SUBSYSTEM, "Could not find entry for BIND dn %s\n", slapi_sdn_get_ndn(bindsdn)); init_my_str_buf(pam_id, NULL); } else if (slapi_check_account_lock( pb, entry, 0, 0, 0 ) == 1) { slapi_log_error(SLAPI_LOG_FATAL, PAM_PASSTHRU_PLUGIN_SUBSYSTEM, "Account %s inactivated.\n", slapi_sdn_get_ndn(bindsdn)); init_my_str_buf(pam_id, NULL); *locked = 1; } else { char *val = slapi_entry_attr_get_charptr(entry, map_ident_attr); init_my_str_buf(pam_id, val); slapi_ch_free_string(&val); } slapi_entry_free(entry); return pam_id->str; }
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 ); }
PRBool replica_updatedn_list_ismember(ReplicaUpdateDNList list, const Slapi_DN *dn) { PLHashTable *hash = list; PRBool ret = PR_FALSE; const char *ndn = slapi_sdn_get_ndn(dn); /* Bug 605169 - null ndn would cause core dump */ if ( ndn ) { if ((uintptr_t)PL_HashTableLookupConst(hash, ndn)) ret = PR_TRUE; else ret = PR_FALSE; } return ret; }
/* * This is called on a master when a replication agreement is * initialized at startup. A cookie can be allocated at this * time which is passed to other callbacks on the master side. */ static void * test_repl_session_plugin_agmt_init_cb(const Slapi_DN *repl_subtree) { char *cookie = NULL; slapi_log_err(SLAPI_LOG_DEBUG, test_repl_session_plugin_name, "test_repl_session_plugin_init_cb() called for suffix \"%s\".\n", slapi_sdn_get_ndn(repl_subtree)); /* allocate a string and set as the cookie */ cookie = slapi_ch_smprintf("cookie test"); slapi_log_err(SLAPI_LOG_DEBUG, test_repl_session_plugin_name, "test_repl_session_plugin_init_cb(): Setting cookie: \"%s\".\n", cookie); return cookie; }
/* * This is called on a master when it receives a reply to a * start replication extop that we sent to a replica. Any * extra data sent by a replication session callback on the * replica will be set here as the data parameter. The data_guid * should be checked first to ensure that the sending side is * using the same replication session plug-in before making any * assumptions about the contents of the data parameter. You * should not free data_guid or data. The replication plug-in * will take care of freeing this memory. * * Returning non-0 will abort the replication session. This * results in the master going into incremental backoff mode. */ static int test_repl_session_plugin_post_acquire_cb(void *cookie, const Slapi_DN *repl_subtree, int is_total, const char *data_guid, const struct berval *data) { int rc = 0; slapi_log_err(SLAPI_LOG_DEBUG, test_repl_session_plugin_name, "test_repl_session_plugin_post_acquire_cb() called for suffix \"%s\", " "is_total: \"%s\" cookie: \"%s\".\n", slapi_sdn_get_ndn(repl_subtree), is_total ? "TRUE" : "FALSE", cookie ? (char *)cookie : "NULL"); /* log any extra data that was sent from the replica */ if (data_guid && data) { slapi_log_err(SLAPI_LOG_DEBUG, test_repl_session_plugin_name, "test_repl_session_plugin_post_acquire_cb() received data: guid: \"%s\" data: \"%s\".\n", data_guid, data->bv_val); } return rc; }
/* * add a list of dns to the ReplicaUpdateDNList. * The dn could be the dn of a group, so get the entry * and check the objectclass. If it is a static or dynamic group * generate the list of member dns and recursively call * replica_updatedn_list_add(). * The dn of the group is added to the list, so it will detect * potential circular group definitions */ void replica_updatedn_list_add_ext(ReplicaUpdateDNList list, const Slapi_ValueSet *vs, int group_update) { PLHashTable *hash = list; Slapi_ValueSet *vs_nc = (Slapi_ValueSet *)vs; /* cast away const */ Slapi_Value *val = NULL; int index = 0; PR_ASSERT(list && vs); for (index = slapi_valueset_first_value(vs_nc, &val); val; index = slapi_valueset_next_value(vs_nc, index, &val)) { Slapi_DN *dn = slapi_sdn_new_dn_byval(slapi_value_get_string(val)); const char *ndn = slapi_sdn_get_ndn(dn); /* make sure that the name is unique */ if (PL_HashTableLookup(hash, ndn) != NULL) { slapi_log_err(SLAPI_LOG_REPL, repl_plugin_name, "replica_updatedn_list_add - " "Update DN with value (%s) already in the update DN list\n", ndn); slapi_sdn_free(&dn); } else { Slapi_ValueSet *members = NULL; PL_HashTableAdd(hash, ndn, dn); /* add it, even if it is a group dn, this will * prevent problems with circular group definitions * then check if it has mor members to add */ if (group_update) { members = replica_updatedn_list_get_members(dn); if (members) { replica_updatedn_list_add_ext(list, members, 1); /* free members */ slapi_valueset_free(members); } } } } return; }
/* * This is called on a master when we are about to acquire a * replica. This callback can allocate some extra data to * be sent to the replica in the start replication request. * This memory will be free'd by the replication plug-in * after it is sent. A guid string must be set that is to * be used by the receiving side to ensure that the data is * from the same replication session plug-in. * * Returning non-0 will abort the replication session. This * results in the master going into incremental backoff mode. */ static int test_repl_session_plugin_pre_acquire_cb(void *cookie, const Slapi_DN *repl_subtree, int is_total, char **data_guid, struct berval **data) { int rc = 0; slapi_log_err(SLAPI_LOG_DEBUG, test_repl_session_plugin_name, "test_repl_session_plugin_pre_acquire_cb() called for suffix \"%s\", " "is_total: \"%s\", cookie: \"%s\".\n", slapi_sdn_get_ndn(repl_subtree), is_total ? "TRUE" : "FALSE", cookie ? (char *)cookie : "NULL"); /* allocate some data to be sent to the replica */ *data_guid = slapi_ch_smprintf("test-guid"); *data = (struct berval *)slapi_ch_malloc(sizeof(struct berval)); (*data)->bv_val = slapi_ch_smprintf("test-data"); (*data)->bv_len = strlen((*data)->bv_val) + 1; slapi_log_err(SLAPI_LOG_DEBUG, test_repl_session_plugin_name, "test_repl_session_plugin_pre_acquire_cb() sending data: guid: \"%s\" data: \"%s\".\n", *data_guid, (*data)->bv_val); return rc; }
/* * 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; }
/* * update multiple attribute values per _do_modify */ static int _update_all_per_mod(Slapi_DN *entrySDN, /* DN of the searched entry */ Slapi_Attr *attr, /* referred attribute */ char *attrName, Slapi_DN *origDN, /* original DN that was modified */ char *newRDN, /* new RDN from modrdn */ const char *newsuperior, /* new superior from modrdn */ Slapi_PBlock *mod_pb) { Slapi_Mods *smods = NULL; char *newDN = NULL; char **dnParts = NULL; char *sval = NULL; char *newvalue = NULL; char *p = NULL; size_t dnlen = 0; int rc = 0; int nval = 0; slapi_attr_get_numvalues(attr, &nval); if (NULL == newRDN && NULL == newsuperior) { /* in delete mode */ LDAPMod *mods[2]; char *values_del[2]; LDAPMod attribute1; /* delete old dn so set that up */ values_del[0] = (char *)slapi_sdn_get_dn(origDN); values_del[1] = NULL; attribute1.mod_type = attrName; attribute1.mod_op = LDAP_MOD_DELETE; attribute1.mod_values = values_del; mods[0] = &attribute1; /* terminate list of mods. */ mods[1] = NULL; rc = _do_modify(mod_pb, entrySDN, mods); if (rc) { slapi_log_error( SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM, "_update_all_per_mod: entry %s: deleting \"%s: %s\" failed (%d)" "\n", slapi_sdn_get_dn(entrySDN), attrName, slapi_sdn_get_dn(origDN), rc); } } else { /* in modrdn mode */ const char *superior = NULL; int nval = 0; Slapi_Value *v = NULL; if (NULL == origDN) { slapi_log_error(SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM, "_update_all_per_mod: NULL dn was passed\n"); goto bail; } /* need to put together rdn into a dn */ dnParts = slapi_ldap_explode_dn( slapi_sdn_get_dn(origDN), 0 ); if (NULL == dnParts) { slapi_log_error(SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM, "_update_all_per_mod: failed to explode dn %s\n", slapi_sdn_get_dn(origDN)); goto bail; } if (NULL == newRDN) { newRDN = dnParts[0]; } if (newsuperior) { superior = newsuperior; } else { /* do not free superior */ superior = slapi_dn_find_parent(slapi_sdn_get_dn(origDN)); } /* newRDN and superior are already normalized. */ newDN = slapi_ch_smprintf("%s,%s", newRDN, superior); slapi_dn_ignore_case(newDN); /* * Compare the modified dn with the value of * the target attribute of referint to find out * the modified dn is the ancestor (case 2) or * the value itself (case 1). * * E.g., * (case 1) * modrdn: uid=A,ou=B,o=C --> uid=A',ou=B',o=C * (origDN) (newDN) * member: uid=A,ou=B,ou=C --> uid=A',ou=B',ou=C * (sval) (newDN) * * (case 2) * modrdn: ou=B,o=C --> ou=B',o=C * (origDN) (newDN) * member: uid=A,ou=B,ou=C --> uid=A,ou=B',ou=C * (sval) (sval' + newDN) */ slapi_attr_get_numvalues(attr, &nval); smods = slapi_mods_new(); slapi_mods_init(smods, 2 * nval + 1); for (nval = slapi_attr_first_value(attr, &v); nval != -1; nval = slapi_attr_next_value(attr, nval, &v)) { p = NULL; dnlen = 0; /* DN syntax, which should be a string */ sval = slapi_ch_strdup(slapi_value_get_string(v)); rc = slapi_dn_normalize_case_ext(sval, 0, &p, &dnlen); if (rc == 0) { /* sval is passed in; not terminated */ *(p + dnlen) = '\0'; sval = p; } else if (rc > 0) { slapi_ch_free_string(&sval); sval = p; } /* else: (rc < 0) Ignore the DN normalization error for now. */ p = PL_strstr(sval, slapi_sdn_get_ndn(origDN)); if (p == sval) { /* (case 1) */ slapi_mods_add_string(smods, LDAP_MOD_DELETE, attrName, sval); slapi_mods_add_string(smods, LDAP_MOD_ADD, attrName, newDN); } else if (p) { /* (case 2) */ slapi_mods_add_string(smods, LDAP_MOD_DELETE, attrName, sval); *p = '\0'; newvalue = slapi_ch_smprintf("%s%s", sval, newDN); slapi_mods_add_string(smods, LDAP_MOD_ADD, attrName, newvalue); slapi_ch_free_string(&newvalue); } /* else: value does not include the modified DN. Ignore it. */ slapi_ch_free_string(&sval); } rc = _do_modify(mod_pb, entrySDN, slapi_mods_get_ldapmods_byref(smods)); if (rc) { slapi_log_error( SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM, "_update_all_per_mod: entry %s failed (%d)\n", slapi_sdn_get_dn(entrySDN), rc); } /* cleanup memory allocated for dnParts and newDN */ if (dnParts){ slapi_ldap_value_free(dnParts); dnParts = NULL; } slapi_ch_free_string(&newDN); slapi_mods_free(&smods); } bail: 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; }
int slapi_sdn_get_ndn_len( const Slapi_DN *sdn ) { slapi_sdn_get_ndn( sdn ); return sdn->ndn.bv_len; }
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; }
/* * 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; }