/* * searchAllSubtrees - search all subtrees in argv for entries * with a named attribute matching the list of values, by * calling search for each one. * * If 'attr' is NULL, the values are taken from 'values'. * If 'attr' is non-NULL, the values are taken from 'attr'. * * Return: * LDAP_SUCCESS - no matches, or the attribute matches the * target dn. * LDAP_CONSTRAINT_VIOLATION - an entry was found that already * contains the attribute value. * LDAP_OPERATIONS_ERROR - a server failure. */ static int searchAllSubtrees(int argc, char *argv[], const char *attrName, Slapi_Attr *attr, struct berval **values, const char *requiredObjectClass, Slapi_DN *dn) { int result = LDAP_SUCCESS; /* * For each DN in the managed list, do uniqueness checking if * the target DN is a subnode in the tree. */ for(;argc > 0;argc--,argv++) { Slapi_DN *sufdn = slapi_sdn_new_dn_byref(*argv); /* * The DN should already be normalized, so we don't have to * worry about that here. */ if (slapi_sdn_issuffix(dn, sufdn)) { result = search(sufdn, attrName, attr, values, requiredObjectClass, dn); slapi_sdn_free(&sufdn); if (result) break; } else { slapi_sdn_free(&sufdn); } } return result; }
/* * Check if User Private Groups are enabled in given IPA domain * Returns: 0 - UPG are enabled * 1 - UPG are disabled * -1 - some sort of error */ static int ipa_winsync_upg_enabled(const Slapi_DN *ds_subtree) { int ret = -1; int rc; char * dn = NULL; Slapi_Entry *entry = NULL; Slapi_Backend *be; const Slapi_DN *ds_suffix = NULL; Slapi_DN *sdn = NULL; const char *attrs_list[] = {IPA_WINSYNC_UPG_DEF_ATTR, 0}; char * value = NULL; /* find ancestor base DN */ be = slapi_be_select(ds_subtree); ds_suffix = slapi_be_getsuffix(be, 0); if (ds_suffix == NULL) { LOG_FATAL("Invalid DS subtree [%s]\n", slapi_sdn_get_dn(ds_subtree)); goto done; } dn = slapi_ch_smprintf(IPA_WINSYNC_UPG_DEF_DN, slapi_sdn_get_dn(ds_suffix)); if (!dn) { LOG_OOM(); goto done; } sdn = slapi_sdn_new_dn_byref(dn); rc = slapi_search_internal_get_entry(sdn, (char **) attrs_list, &entry, ipa_winsync_get_plugin_identity()); if (rc) { LOG("failed to retrieve UPG definition (%s) with rc %d\n", dn, rc); goto done; } value = slapi_entry_attr_get_charptr(entry, IPA_WINSYNC_UPG_DEF_ATTR); if (!value) { LOG("failed to read %s from UPG definition (%s)\n", IPA_WINSYNC_UPG_DEF_ATTR, dn); goto done; } if (strstr(value, IPA_WINSYNC_UPG_DEF_DISABLED) == NULL) { ret = 0; } else { ret = 1; } done: slapi_ch_free_string(&dn); slapi_sdn_free(&sdn); slapi_ch_free_string(&value); slapi_entry_free(entry); return ret; }
/* Searches the dn in directory, * If found : fills in slapi_entry structure and returns 0 * If NOT found : returns the search result as LDAP_NO_SUCH_OBJECT */ int ipapwd_getEntry(const char *dn, Slapi_Entry **e2, char **attrlist) { Slapi_DN *sdn; int search_result = 0; LOG_TRACE("=>\n"); sdn = slapi_sdn_new_dn_byref(dn); search_result = slapi_search_internal_get_entry(sdn, attrlist, e2, ipapwd_plugin_id); if (search_result != LDAP_SUCCESS) { LOG_TRACE("No such entry-(%s), err (%d)\n", dn, search_result); } slapi_sdn_free(&sdn); LOG_TRACE("<= result: %d\n", search_result); return search_result; }
int ipapwd_gen_checks(Slapi_PBlock *pb, char **errMesg, struct ipapwd_krbcfg **config, int check_flags) { int ret, ssf; int rc = LDAP_SUCCESS; Slapi_Backend *be; const Slapi_DN *psdn; Slapi_DN *sdn; char *dn = NULL; LOG_TRACE("=>\n"); #ifdef LDAP_EXTOP_PASSMOD_CONN_SECURE if (check_flags & IPAPWD_CHECK_CONN_SECURE) { /* Allow password modify on all connections with a Security Strength * Factor (SSF) higher than 1 */ if (slapi_pblock_get(pb, SLAPI_OPERATION_SSF, &ssf) != 0) { LOG("Could not get SSF from connection\n"); *errMesg = "Operation requires a secure connection.\n"; rc = LDAP_OPERATIONS_ERROR; goto done; } if (ssf <= 1) { *errMesg = "Operation requires a secure connection.\n"; rc = LDAP_CONFIDENTIALITY_REQUIRED; goto done; } } #endif if (check_flags & IPAPWD_CHECK_DN) { /* check we have a valid DN in the pblock or just abort */ ret = slapi_pblock_get(pb, SLAPI_TARGET_DN, &dn); if (ret) { LOG("Tried to change password for an invalid DN [%s]\n", dn ? dn : "<NULL>"); *errMesg = "Invalid DN"; rc = LDAP_OPERATIONS_ERROR; goto done; } sdn = slapi_sdn_new_dn_byref(dn); if (!sdn) { LOG_FATAL("Unable to convert dn to sdn %s", dn ? dn : "<NULL>"); *errMesg = "Internal Error"; rc = LDAP_OPERATIONS_ERROR; goto done; } be = slapi_be_select(sdn); slapi_sdn_free(&sdn); psdn = slapi_be_getsuffix(be, 0); if (!psdn) { *errMesg = "Invalid DN"; rc = LDAP_OPERATIONS_ERROR; goto done; } } /* get the kerberos context and master key */ *config = ipapwd_getConfig(); if (NULL == *config) { LOG_FATAL("Error Retrieving Master Key"); *errMesg = "Fatal Internal Error"; rc = LDAP_OPERATIONS_ERROR; } done: 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 sync_read_entry_from_changelog( Slapi_Entry *cl_entry, void *cb_data) { char *uniqueid = NULL; char *chgtype = NULL; char *chgnr = NULL; int chg_req; int prev = 0; int index = 0; unsigned long chgnum = 0; Sync_CallBackData *cb = (Sync_CallBackData *) cb_data; if (cb == NULL) { return(1); } uniqueid = sync_get_attr_value_from_entry (cl_entry, CL_ATTR_UNIQUEID); if (uniqueid == NULL) { slapi_log_err(SLAPI_LOG_ERR, SYNC_PLUGIN_SUBSYSTEM, "sync_read_entry_from_changelog - Retro Changelog does not provide nsuniquedid." "Check RCL plugin configuration.\n" ); return(1); } chgnr = sync_get_attr_value_from_entry (cl_entry, CL_ATTR_CHANGENUMBER); chgnum = sync_number2ulong(chgnr); if (SYNC_INVALID_CHANGENUM == chgnum) { slapi_log_err(SLAPI_LOG_ERR, SYNC_PLUGIN_SUBSYSTEM, "sync_read_entry_from_changelog - Change number provided by Retro Changelog is invalid: %s\n", chgnr); slapi_ch_free_string(&chgnr); slapi_ch_free_string(&uniqueid); return(1); } if (chgnum < cb->change_start) { slapi_log_err(SLAPI_LOG_ERR, SYNC_PLUGIN_SUBSYSTEM, "sync_read_entry_from_changelog - " "Change number provided by Retro Changelog %s is less than the initial number %lu\n", chgnr, cb->change_start); slapi_ch_free_string(&chgnr); slapi_ch_free_string(&uniqueid); return(1); } index = chgnum - cb->change_start; chgtype = sync_get_attr_value_from_entry (cl_entry, CL_ATTR_CHGTYPE); chg_req = sync_str2chgreq(chgtype); switch (chg_req){ case LDAP_REQ_ADD: /* nsuniqueid cannot exist, just add reference */ cb->cb_updates[index].upd_chgtype = LDAP_REQ_ADD; cb->cb_updates[index].upd_uuid = uniqueid; break; case LDAP_REQ_MODIFY: /* check if we have seen this uuid already */ prev = sync_find_ref_by_uuid(cb->cb_updates, index, uniqueid); if (prev == -1) { cb->cb_updates[index].upd_chgtype = LDAP_REQ_MODIFY; cb->cb_updates[index].upd_uuid = uniqueid; } else { /* was add or mod, keep it */ cb->cb_updates[index].upd_uuid = 0; cb->cb_updates[index].upd_chgtype = 0; slapi_ch_free_string(&uniqueid); } break; case LDAP_REQ_MODRDN: { /* if it is a modrdn, we finally need to decide if this will * trigger a present or delete state, keep the info that * the entry was subject to a modrdn */ int new_scope = 0; int old_scope = 0; Slapi_DN *original_dn; char *newsuperior = sync_get_attr_value_from_entry (cl_entry, CL_ATTR_NEWSUPERIOR); char *entrydn = sync_get_attr_value_from_entry (cl_entry, CL_ATTR_ENTRYDN); /* if newsuperior is set we need to checkif the entry has been moved into * or moved out of the scope of the synchronization request */ original_dn = slapi_sdn_new_dn_byref(entrydn); old_scope = sync_is_active_scope(original_dn,cb->orig_pb); slapi_sdn_free(&original_dn); slapi_ch_free_string(&entrydn); if (newsuperior) { Slapi_DN *newbase; newbase = slapi_sdn_new_dn_byref(newsuperior); new_scope = sync_is_active_scope(newbase, cb->orig_pb); slapi_ch_free_string(&newsuperior); slapi_sdn_free(&newbase); } else { /* scope didn't change */ new_scope = old_scope; } prev = sync_find_ref_by_uuid(cb->cb_updates, index, uniqueid); if ( old_scope && new_scope ) { /* nothing changed, it's just a MOD */ if (prev == -1) { cb->cb_updates[index].upd_chgtype = LDAP_REQ_MODIFY; cb->cb_updates[index].upd_uuid = uniqueid; } else { cb->cb_updates[index].upd_uuid = 0; cb->cb_updates[index].upd_chgtype = 0; slapi_ch_free_string(&uniqueid); } } else if ( old_scope ) { /* it was moved out of scope, handle as DEL */ if (prev == -1) { cb->cb_updates[index].upd_chgtype = LDAP_REQ_DELETE; cb->cb_updates[index].upd_uuid = uniqueid; cb->cb_updates[index].upd_e = sync_deleted_entry_from_changelog(cl_entry); } else { cb->cb_updates[prev].upd_chgtype = LDAP_REQ_DELETE; cb->cb_updates[prev].upd_e = sync_deleted_entry_from_changelog(cl_entry); slapi_ch_free_string(&uniqueid); } } else if ( new_scope ) { /* moved into scope, handle as ADD */ cb->cb_updates[index].upd_chgtype = LDAP_REQ_ADD; cb->cb_updates[index].upd_uuid = uniqueid; } else { /* nothing to do */ slapi_ch_free_string(&uniqueid); } slapi_sdn_free(&original_dn); break; } case LDAP_REQ_DELETE: /* check if we have seen this uuid already */ prev = sync_find_ref_by_uuid(cb->cb_updates, index, uniqueid); if (prev == -1) { cb->cb_updates[index].upd_chgtype = LDAP_REQ_DELETE; cb->cb_updates[index].upd_uuid = uniqueid; cb->cb_updates[index].upd_e = sync_deleted_entry_from_changelog(cl_entry); } else { /* if it was added since last cookie state, we * can ignoere it */ if (cb->cb_updates[prev].upd_chgtype == LDAP_REQ_ADD) { slapi_ch_free_string(&(cb->cb_updates[prev].upd_uuid)); cb->cb_updates[prev].upd_uuid = NULL; cb->cb_updates[index].upd_uuid = NULL; } else { /* ignore previous mod */ cb->cb_updates[index].upd_uuid = NULL; cb->cb_updates[prev].upd_chgtype = LDAP_REQ_DELETE; cb->cb_updates[prev].upd_e = sync_deleted_entry_from_changelog(cl_entry); } slapi_ch_free_string(&uniqueid); } break; default: slapi_ch_free_string(&uniqueid); } slapi_ch_free_string(&chgtype); slapi_ch_free_string(&chgnr); return (0); }
/* * Check if there are any persistent searches. If so, * the check to see if the chgtype is one of those the * client is interested in. If so, then check to see if * the entry matches any of the filters the searches. * If so, then enqueue the entry on that persistent search's * ps_entryqueue and signal it to wake up and send the entry. * * Note that if eprev is NULL we assume that the entry's DN * was not changed by the op. that called this function. If * chgnum is 0 it is unknown so we won't ever send it to a * client in the EntryChangeNotification control. */ void ps_service_persistent_searches( Slapi_Entry *e, Slapi_Entry *eprev, ber_int_t chgtype, ber_int_t chgnum ) { LDAPControl *ctrl = NULL; PSearch *ps = NULL; PSEQNode *pe = NULL; int matched = 0; const char *edn; if ( !PS_IS_INITIALIZED()) { return; } if ( NULL == e ) { /* For now, some backends such as the chaining backend do not provide a post-op entry */ return; } PSL_LOCK_READ(); edn = slapi_entry_get_dn_const(e); for ( ps = psearch_list ? psearch_list->pl_head : NULL; NULL != ps; ps = ps->ps_next ) { char *origbase = NULL; Slapi_DN *base = NULL; Slapi_Filter *f; int scope; /* Skip the node that doesn't meet the changetype, * or is unable to use the change in ps_send_results() */ if (( ps->ps_changetypes & chgtype ) == 0 || ps->ps_pblock->pb_op == NULL || slapi_op_abandoned( ps->ps_pblock ) ) { continue; } slapi_log_error(SLAPI_LOG_CONNS, "Persistent Search", "conn=%" NSPRIu64 " op=%d entry %s with chgtype %d " "matches the ps changetype %d\n", ps->ps_pblock->pb_conn->c_connid, ps->ps_pblock->pb_op->o_opid, edn, chgtype, ps->ps_changetypes); slapi_pblock_get( ps->ps_pblock, SLAPI_SEARCH_FILTER, &f ); slapi_pblock_get( ps->ps_pblock, SLAPI_ORIGINAL_TARGET_DN, &origbase ); slapi_pblock_get( ps->ps_pblock, SLAPI_SEARCH_TARGET_SDN, &base ); slapi_pblock_get( ps->ps_pblock, SLAPI_SEARCH_SCOPE, &scope ); if (NULL == base) { base = slapi_sdn_new_dn_byref(origbase); slapi_pblock_set(ps->ps_pblock, SLAPI_SEARCH_TARGET_SDN, base); } /* * See if the entry meets the scope and filter criteria. * We cannot do the acl check here as this thread * would then potentially clash with the ps_send_results() * thread on the aclpb in ps->ps_pblock. * By avoiding the acl check in this thread, and leaving all the acl * checking to the ps_send_results() thread we avoid * the ps_pblock contention problem. * The lesson here is "Do not give multiple threads arbitary access * to the same pblock" this kind of muti-threaded access * to the same pblock must be done carefully--there is currently no * generic satisfactory way to do this. */ if ( slapi_sdn_scope_test( slapi_entry_get_sdn_const(e), base, scope ) && slapi_vattr_filter_test( ps->ps_pblock, e, f, 0 /* verify_access */ ) == 0 ) { PSEQNode *pOldtail; /* The scope and the filter match - enqueue it */ matched++; pe = (PSEQNode *)slapi_ch_calloc( 1, sizeof( PSEQNode )); pe->pe_entry = slapi_entry_dup( e ); if ( ps->ps_send_entchg_controls ) { /* create_entrychange_control() is more * expensive than slapi_dup_control() */ if ( ctrl == NULL ) { int rc; rc = create_entrychange_control( chgtype, chgnum, eprev ? slapi_entry_get_dn_const(eprev) : NULL, &ctrl ); if ( rc != LDAP_SUCCESS ) { LDAPDebug( LDAP_DEBUG_ANY, "ps_service_persistent_searches:" " unable to create EntryChangeNotification control for" " entry \"%s\" -- control won't be sent.\n", slapi_entry_get_dn_const(e), 0, 0 ); } } if ( ctrl ) { pe->pe_ctrls[0] = slapi_dup_control( ctrl ); } } /* Put it on the end of the list for this pers search */ PR_Lock( ps->ps_lock ); pOldtail = ps->ps_eq_tail; ps->ps_eq_tail = pe; if ( NULL == ps->ps_eq_head ) { ps->ps_eq_head = ps->ps_eq_tail; } else { pOldtail->pe_next = ps->ps_eq_tail; } PR_Unlock( ps->ps_lock ); } } PSL_UNLOCK_READ(); /* Were there any matches? */ if ( matched ) { ldap_control_free( ctrl ); /* Turn 'em loose */ ps_wakeup_all(); LDAPDebug( LDAP_DEBUG_TRACE, "ps_service_persistent_searches: enqueued entry " "\"%s\" on %d persistent search lists\n", slapi_entry_get_dn_const(e), matched, 0 ); } else { LDAPDebug( LDAP_DEBUG_TRACE, "ps_service_persistent_searches: entry " "\"%s\" not enqueued on any persistent search lists\n", slapi_entry_get_dn_const(e), 0, 0 ); } }