static int default_mr_filter_match(void *obj, Slapi_Entry *e, Slapi_Attr *attr) { /* returns: 0 filter matched * -1 filter did not match * >0 an LDAP error code */ int rc = -1; struct mr_private* mrpriv = (struct mr_private*)obj; /* In case SLAPI_PLUGIN_OBJECT is not set, mrpriv may be NULL */ if (mrpriv == NULL) return rc; for (; (rc == -1) && (attr != NULL); slapi_entry_next_attr(e, attr, &attr)) { char* type = NULL; if (!slapi_attr_get_type (attr, &type) && type != NULL && !slapi_attr_type_cmp ((const char *)mrpriv->type, type, 2/*match subtypes*/)) { Slapi_Value **vals = attr_get_present_values(attr); #ifdef SUPPORT_MR_SUBSTRING_MATCHING if (mrpriv->ftype == LDAP_FILTER_SUBSTRINGS) { rc = (*mrpriv->match_fn)(pb, mrpriv->initial, mrpriv->any, mrpriv->final, vals); } #endif rc = (*mrpriv->match_fn)(NULL, mrpriv->value, vals, mrpriv->ftype, NULL); }
int ldbm_back_bind( Slapi_PBlock *pb ) { backend *be; ldbm_instance *inst; int method; struct berval *cred; struct ldbminfo *li; struct backentry *e; Slapi_Attr *attr; Slapi_Value **bvals; entry_address *addr; back_txn txn = {NULL}; /* get parameters */ slapi_pblock_get( pb, SLAPI_BACKEND, &be ); slapi_pblock_get( pb, SLAPI_PLUGIN_PRIVATE, &li ); slapi_pblock_get( pb, SLAPI_TARGET_ADDRESS, &addr ); slapi_pblock_get( pb, SLAPI_BIND_METHOD, &method ); slapi_pblock_get( pb, SLAPI_BIND_CREDENTIALS, &cred ); slapi_pblock_get( pb, SLAPI_TXN, &txn.back_txn_txn ); if ( !txn.back_txn_txn ) { dblayer_txn_init( li, &txn ); slapi_pblock_set( pb, SLAPI_TXN, txn.back_txn_txn ); } inst = (ldbm_instance *) be->be_instance_info; /* always allow noauth simple binds (front end will send the result) */ if ( method == LDAP_AUTH_SIMPLE && cred->bv_len == 0 ) { return( SLAPI_BIND_ANONYMOUS ); } /* * find the target entry. find_entry() takes care of referrals * and sending errors if the entry does not exist. */ if (( e = find_entry( pb, be, addr, &txn )) == NULL ) { return( SLAPI_BIND_FAIL ); } switch ( method ) { case LDAP_AUTH_SIMPLE: { Slapi_Value cv; if ( slapi_entry_attr_find( e->ep_entry, "userpassword", &attr ) != 0 ) { #if defined( XP_WIN32 ) if( WindowsAuthentication( e, cred ) == LDAPWA_Success ) { break; } #endif slapi_send_ldap_result( pb, LDAP_INAPPROPRIATE_AUTH, NULL, NULL, 0, NULL ); CACHE_RETURN( &inst->inst_cache, &e ); return( SLAPI_BIND_FAIL ); } bvals= attr_get_present_values(attr); slapi_value_init_berval(&cv,cred); if ( slapi_pw_find_sv( bvals, &cv ) != 0 ) { #if defined( XP_WIN32 ) /* One last try - attempt Windows authentication, if the user has a Windows account. */ if( WindowsAuthentication( e, cred ) == LDAPWA_Success ) { break; } #endif slapi_send_ldap_result( pb, LDAP_INVALID_CREDENTIALS, NULL, NULL, 0, NULL ); CACHE_RETURN( &inst->inst_cache, &e ); value_done(&cv); return( SLAPI_BIND_FAIL ); } value_done(&cv); } break; default: slapi_send_ldap_result( pb, LDAP_STRONG_AUTH_NOT_SUPPORTED, NULL, "auth method not supported", 0, NULL ); CACHE_RETURN( &inst->inst_cache, &e ); return( SLAPI_BIND_FAIL ); } CACHE_RETURN( &inst->inst_cache, &e ); /* success: front end will send result */ return( SLAPI_BIND_SUCCESS ); }
/* Code shared between regular and internal add operation */ static void op_shared_add (Slapi_PBlock *pb) { Slapi_Operation *operation; Slapi_Entry *e, *pse; Slapi_Backend *be = NULL; int err; int internal_op, repl_op, legacy_op, lastmod; char *pwdtype = NULL; Slapi_Attr *attr = NULL; Slapi_Entry *referral; char errorbuf[SLAPI_DSE_RETURNTEXT_SIZE]; struct slapdplugin *p = NULL; char *proxydn = NULL; char *proxystr = NULL; int proxy_err = LDAP_SUCCESS; char *errtext = NULL; Slapi_DN *sdn = NULL; passwdPolicy *pwpolicy; slapi_pblock_get (pb, SLAPI_OPERATION, &operation); slapi_pblock_get (pb, SLAPI_ADD_ENTRY, &e); slapi_pblock_get (pb, SLAPI_IS_REPLICATED_OPERATION, &repl_op); slapi_pblock_get (pb, SLAPI_IS_LEGACY_REPLICATED_OPERATION, &legacy_op); internal_op= operation_is_flag_set(operation, OP_FLAG_INTERNAL); pwpolicy = new_passwdPolicy(pb, slapi_entry_get_dn(e)); /* target spec is used to decide which plugins are applicable for the operation */ operation_set_target_spec (operation, slapi_entry_get_sdn (e)); if ((err = slapi_entry_add_rdn_values(e)) != LDAP_SUCCESS) { send_ldap_result(pb, err, NULL, "failed to add RDN values", 0, NULL); goto done; } /* get the proxy auth dn if the proxy auth control is present */ proxy_err = proxyauth_get_dn(pb, &proxydn, &errtext); if (operation_is_flag_set(operation,OP_FLAG_ACTION_LOG_ACCESS)) { if (proxydn) { proxystr = slapi_ch_smprintf(" authzid=\"%s\"", proxydn); } if ( !internal_op ) { slapi_log_access(LDAP_DEBUG_STATS, "conn=%" NSPRIu64 " op=%d ADD dn=\"%s\"%s\n", pb->pb_conn->c_connid, operation->o_opid, slapi_entry_get_dn_const(e), proxystr ? proxystr : ""); } else { slapi_log_access(LDAP_DEBUG_ARGS, "conn=%s op=%d ADD dn=\"%s\"\n", LOG_INTERNAL_OP_CON_ID, LOG_INTERNAL_OP_OP_ID, slapi_entry_get_dn_const(e)); } } /* If we encountered an error parsing the proxy control, return an error * to the client. We do this here to ensure that we log the operation first. */ if (proxy_err != LDAP_SUCCESS) { send_ldap_result(pb, proxy_err, NULL, errtext, 0, NULL); goto done; } /* * We could be serving multiple database backends. Select the * appropriate one. */ if ((err = slapi_mapping_tree_select(pb, &be, &referral, errorbuf, sizeof(errorbuf))) != LDAP_SUCCESS) { send_ldap_result(pb, err, NULL, errorbuf, 0, NULL); be = NULL; goto done; } if (referral) { int managedsait; slapi_pblock_get(pb, SLAPI_MANAGEDSAIT, &managedsait); if (managedsait) { send_ldap_result(pb, LDAP_UNWILLING_TO_PERFORM, NULL, "cannot update referral", 0, NULL); slapi_entry_free(referral); goto done; } slapi_pblock_set(pb, SLAPI_TARGET_SDN, (void*)operation_get_target_spec (operation)); send_referrals_from_entry(pb,referral); slapi_entry_free(referral); goto done; } if (!slapi_be_is_flag_set(be,SLAPI_BE_FLAG_REMOTE_DATA)) { Slapi_Value **unhashed_password_vals = NULL; Slapi_Value **present_values = NULL; /* Setting unhashed password to the entry extension. */ if (repl_op) { /* replicated add ==> get unhashed pw from entry, if any. * set it to the extension */ slapi_entry_attr_find(e, PSEUDO_ATTR_UNHASHEDUSERPASSWORD, &attr); if (attr) { present_values = attr_get_present_values(attr); valuearray_add_valuearray(&unhashed_password_vals, present_values, 0); #if !defined(USE_OLD_UNHASHED) /* and remove it from the entry. */ slapi_entry_attr_delete(e, PSEUDO_ATTR_UNHASHEDUSERPASSWORD); #endif } } else { /* ordinary add ==> * get unhashed pw from userpassword before encrypting it */ /* look for user password attribute */ slapi_entry_attr_find(e, SLAPI_USERPWD_ATTR, &attr); if (attr) { Slapi_Value **vals = NULL; /* Set the backend in the pblock. * The slapi_access_allowed function * needs this set to work properly. */ slapi_pblock_set(pb, SLAPI_BACKEND, slapi_be_select(slapi_entry_get_sdn_const(e))); /* Check ACI before checking password syntax */ if ((err = slapi_access_allowed(pb, e, SLAPI_USERPWD_ATTR, NULL, SLAPI_ACL_ADD)) != LDAP_SUCCESS) { send_ldap_result(pb, err, NULL, "Insufficient 'add' privilege to the " "'userPassword' attribute", 0, NULL); goto done; } /* * Check password syntax, unless this is a pwd admin/rootDN */ present_values = attr_get_present_values(attr); if (!pw_is_pwp_admin(pb, pwpolicy) && check_pw_syntax(pb, slapi_entry_get_sdn_const(e), present_values, NULL, e, 0) != 0) { /* error result is sent from check_pw_syntax */ goto done; } /* pw syntax is valid */ valuearray_add_valuearray(&unhashed_password_vals, present_values, 0); valuearray_add_valuearray(&vals, present_values, 0); pw_encodevals_ext(pb, slapi_entry_get_sdn (e), vals); add_password_attrs(pb, operation, e); slapi_entry_attr_replace_sv(e, SLAPI_USERPWD_ATTR, vals); valuearray_free(&vals); #if defined(USE_OLD_UNHASHED) /* Add the unhashed password pseudo-attribute to the entry */ pwdtype = slapi_attr_syntax_normalize(PSEUDO_ATTR_UNHASHEDUSERPASSWORD); slapi_entry_add_values_sv(e, pwdtype, unhashed_password_vals); #endif } } if (unhashed_password_vals && (SLAPD_UNHASHED_PW_OFF != config_get_unhashed_pw_switch())) { /* unhashed_password_vals is consumed if successful. */ err = slapi_pw_set_entry_ext(e, unhashed_password_vals, SLAPI_EXT_SET_ADD); if (err) { valuearray_free(&unhashed_password_vals); } } #if defined(THISISTEST) { /* test code to retrieve an unhashed pw from the entry extention & * PSEUDO_ATTR_UNHASHEDUSERPASSWORD attribute */ char *test_str = slapi_get_first_clear_text_pw(e); if (test_str) { slapi_log_err(SLAPI_LOG_ERR, "Value from extension: %s\n", test_str); slapi_ch_free_string(&test_str); } #if defined(USE_OLD_UNHASHED) test_str = slapi_entry_attr_get_charptr(e, PSEUDO_ATTR_UNHASHEDUSERPASSWORD); if (test_str) { slapi_log_err(SLAPI_LOG_ERR, "Value from attr: %s\n", test_str); slapi_ch_free_string(&test_str); } #endif /* USE_OLD_UNHASHED */ } #endif /* THISISTEST */ /* look for multiple backend local credentials or replication local credentials */ for ( p = get_plugin_list(PLUGIN_LIST_REVER_PWD_STORAGE_SCHEME); p != NULL && !repl_op; p = p->plg_next ) { char *L_attr = NULL; int i=0; /* Get the appropriate decoding function */ for ( L_attr = p->plg_argv[i]; i<p->plg_argc; L_attr = p->plg_argv[++i]) { /* look for multiple backend local credentials or replication local credentials */ char *L_normalized = slapi_attr_syntax_normalize(L_attr); slapi_entry_attr_find(e, L_normalized, &attr); if (attr) { Slapi_Value **present_values = NULL; Slapi_Value **vals = NULL; present_values= attr_get_present_values(attr); valuearray_add_valuearray(&vals, present_values, 0); pw_rever_encode(vals, L_normalized); slapi_entry_attr_replace_sv(e, L_normalized, vals); valuearray_free(&vals); } if (L_normalized) slapi_ch_free ((void**)&L_normalized); } } } slapi_pblock_set(pb, SLAPI_BACKEND, be); if (!repl_op) { /* can get lastmod only after backend is selected */ slapi_pblock_get(pb, SLAPI_BE_LASTMOD, &lastmod); if (lastmod && add_created_attrs(pb, e) != 0) { send_ldap_result(pb, LDAP_UNWILLING_TO_PERFORM, NULL, "cannot insert computed attributes", 0, NULL); goto done; } /* expand objectClass values to reflect the inheritance hierarchy */ slapi_schema_expand_objectclasses( e ); } /* uniqueid needs to be generated for entries added during legacy replication */ if (legacy_op){ if (add_uniqueid(e) != UID_SUCCESS) { send_ldap_result(pb, LDAP_UNWILLING_TO_PERFORM, NULL, "cannot insert computed attributes", 0, NULL); goto done; } } /* * call the pre-add plugins. if they succeed, call * the backend add function. then call the post-add * plugins. */ sdn = slapi_sdn_dup(slapi_entry_get_sdn_const(e)); slapi_pblock_set(pb, SLAPI_ADD_TARGET_SDN, (void *)sdn); if (plugin_call_plugins(pb, internal_op ? SLAPI_PLUGIN_INTERNAL_PRE_ADD_FN : SLAPI_PLUGIN_PRE_ADD_FN) == SLAPI_PLUGIN_SUCCESS) { int rc; Slapi_Entry *ec; Slapi_DN *add_target_sdn = NULL; Slapi_Entry *save_e = NULL; slapi_pblock_set(pb, SLAPI_PLUGIN, be->be_database); set_db_default_result_handlers(pb); /* because be_add frees the entry */ ec = slapi_entry_dup(e); add_target_sdn = slapi_sdn_dup(slapi_entry_get_sdn_const(ec)); slapi_pblock_get(pb, SLAPI_ADD_TARGET_SDN, &sdn); slapi_sdn_free(&sdn); slapi_pblock_set(pb, SLAPI_ADD_TARGET_SDN, add_target_sdn); if (be->be_add != NULL) { rc = (*be->be_add)(pb); /* backend may change this if errors and not consumed */ slapi_pblock_get(pb, SLAPI_ADD_ENTRY, &save_e); slapi_pblock_set(pb, SLAPI_ADD_ENTRY, ec); if (rc == 0) { /* acl is not enabled for internal operations */ /* don't update aci store for remote acis */ if ((!internal_op) && (!slapi_be_is_flag_set(be,SLAPI_BE_FLAG_REMOTE_DATA))) { plugin_call_acl_mods_update (pb, SLAPI_OPERATION_ADD); } if (operation_is_flag_set(operation,OP_FLAG_ACTION_LOG_AUDIT)) { write_audit_log_entry(pb); /* Record the operation in the audit log */ } slapi_pblock_get(pb, SLAPI_ENTRY_POST_OP, &pse); do_ps_service(pse, NULL, LDAP_CHANGETYPE_ADD, 0); /* * If be_add succeeded, then e is consumed except the resurrect case. * If it is resurrect, the corresponding tombstone entry is resurrected * and put into the cache. * Otherwise, we set e to NULL to prevent freeing it ourselves. */ if (operation_is_flag_set(operation,OP_FLAG_RESURECT_ENTRY) && save_e) { e = save_e; } else { e = NULL; } } else { /* PR_ASSERT(!save_e); save_e is supposed to be freed in the backend. */ e = save_e; if (rc == SLAPI_FAIL_DISKFULL) { operation_out_of_disk_space(); goto done; } /* If the disk is full we don't want to make it worse ... */ if (operation_is_flag_set(operation,OP_FLAG_ACTION_LOG_AUDIT)) { write_auditfail_log_entry(pb); /* Record the operation in the audit log */ } } } else { send_ldap_result(pb, LDAP_UNWILLING_TO_PERFORM, NULL, "Function not implemented", 0, NULL); } slapi_pblock_set(pb, SLAPI_PLUGIN_OPRETURN, &rc); plugin_call_plugins(pb, internal_op ? SLAPI_PLUGIN_INTERNAL_POST_ADD_FN : SLAPI_PLUGIN_POST_ADD_FN); slapi_entry_free(ec); } slapi_pblock_get(pb, SLAPI_ADD_TARGET_SDN, &sdn); slapi_sdn_free(&sdn); done: if (be) slapi_be_Unlock(be); slapi_pblock_get(pb, SLAPI_ENTRY_POST_OP, &pse); slapi_entry_free(pse); slapi_ch_free((void **)&operation->o_params.p.p_add.parentuniqueid); slapi_entry_free(e); slapi_pblock_set(pb, SLAPI_ADD_ENTRY, NULL); slapi_ch_free((void**)&pwdtype); slapi_ch_free_string(&proxydn); slapi_ch_free_string(&proxystr); }
/* * 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; }