int fe_op_delete( Operation *op, SlapReply *rs ) { struct berval pdn = BER_BVNULL; BackendDB *op_be, *bd = op->o_bd; /* * We could be serving multiple database backends. Select the * appropriate one, or send a referral to our "referral server" * if we don't hold it. */ op->o_bd = select_backend( &op->o_req_ndn, 1 ); if ( op->o_bd == NULL ) { op->o_bd = bd; rs->sr_ref = referral_rewrite( default_referral, NULL, &op->o_req_dn, LDAP_SCOPE_DEFAULT ); if (!rs->sr_ref) rs->sr_ref = default_referral; if ( rs->sr_ref != NULL ) { rs->sr_err = LDAP_REFERRAL; send_ldap_result( op, rs ); if (rs->sr_ref != default_referral) ber_bvarray_free( rs->sr_ref ); } else { send_ldap_error( op, rs, LDAP_UNWILLING_TO_PERFORM, "no global superior knowledge" ); } goto cleanup; } /* If we've got a glued backend, check the real backend */ op_be = op->o_bd; if ( SLAP_GLUE_INSTANCE( op->o_bd )) { op->o_bd = select_backend( &op->o_req_ndn, 0 ); } /* check restrictions */ if( backend_check_restrictions( op, rs, NULL ) != LDAP_SUCCESS ) { send_ldap_result( op, rs ); goto cleanup; } /* check for referrals */ if( backend_check_referrals( op, rs ) != LDAP_SUCCESS ) { goto cleanup; } /* * do the delete if 1 && (2 || 3) * 1) there is a delete function implemented in this backend; * 2) this backend is master for what it holds; * 3) it's a replica and the dn supplied is the update_ndn. */ if ( op->o_bd->be_delete ) { /* do the update here */ int repl_user = be_isupdate( op ); if ( !SLAP_SINGLE_SHADOW(op->o_bd) || repl_user ) { struct berval org_req_dn = BER_BVNULL; struct berval org_req_ndn = BER_BVNULL; struct berval org_dn = BER_BVNULL; struct berval org_ndn = BER_BVNULL; int org_managedsait; op->o_bd = op_be; op->o_bd->be_delete( op, rs ); org_req_dn = op->o_req_dn; org_req_ndn = op->o_req_ndn; org_dn = op->o_dn; org_ndn = op->o_ndn; org_managedsait = get_manageDSAit( op ); op->o_dn = op->o_bd->be_rootdn; op->o_ndn = op->o_bd->be_rootndn; op->o_managedsait = SLAP_CONTROL_NONCRITICAL; while ( rs->sr_err == LDAP_SUCCESS && op->o_delete_glue_parent ) { op->o_delete_glue_parent = 0; if ( !be_issuffix( op->o_bd, &op->o_req_ndn )) { slap_callback cb = { NULL, NULL, NULL, NULL }; cb.sc_response = slap_null_cb; dnParent( &op->o_req_ndn, &pdn ); op->o_req_dn = pdn; op->o_req_ndn = pdn; op->o_callback = &cb; op->o_bd->be_delete( op, rs ); } else { break; } } op->o_managedsait = org_managedsait; op->o_dn = org_dn; op->o_ndn = org_ndn; op->o_req_dn = org_req_dn; op->o_req_ndn = org_req_ndn; op->o_delete_glue_parent = 0; } else { BerVarray defref = op->o_bd->be_update_refs ? op->o_bd->be_update_refs : default_referral; if ( defref != NULL ) { rs->sr_ref = referral_rewrite( defref, NULL, &op->o_req_dn, LDAP_SCOPE_DEFAULT ); if (!rs->sr_ref) rs->sr_ref = defref; rs->sr_err = LDAP_REFERRAL; send_ldap_result( op, rs ); if (rs->sr_ref != defref) ber_bvarray_free( rs->sr_ref ); } else { send_ldap_error( op, rs, LDAP_UNWILLING_TO_PERFORM, "shadow context; no update referral" ); } } } else { send_ldap_error( op, rs, LDAP_UNWILLING_TO_PERFORM, "operation not supported within namingContext" ); } cleanup:; op->o_bd = bd; return rs->sr_err; }
int fe_op_modify( Operation *op, SlapReply *rs ) { BackendDB *op_be, *bd = op->o_bd; char textbuf[ SLAP_TEXT_BUFLEN ]; size_t textlen = sizeof( textbuf ); if ( BER_BVISEMPTY( &op->o_req_ndn ) ) { Debug( LDAP_DEBUG_ANY, "%s do_modify: root dse!\n", op->o_log_prefix ); send_ldap_error( op, rs, LDAP_UNWILLING_TO_PERFORM, "modify upon the root DSE not supported" ); goto cleanup; } else if ( bvmatch( &op->o_req_ndn, &frontendDB->be_schemandn ) ) { Debug( LDAP_DEBUG_ANY, "%s do_modify: subschema subentry!\n", op->o_log_prefix ); send_ldap_error( op, rs, LDAP_UNWILLING_TO_PERFORM, "modification of subschema subentry not supported" ); goto cleanup; } /* * We could be serving multiple database backends. Select the * appropriate one, or send a referral to our "referral server" * if we don't hold it. */ op->o_bd = select_backend( &op->o_req_ndn, 1 ); if ( op->o_bd == NULL ) { op->o_bd = bd; rs->sr_ref = referral_rewrite( default_referral, NULL, &op->o_req_dn, LDAP_SCOPE_DEFAULT ); if ( !rs->sr_ref ) { rs->sr_ref = default_referral; } if ( rs->sr_ref != NULL ) { rs->sr_err = LDAP_REFERRAL; send_ldap_result( op, rs ); if ( rs->sr_ref != default_referral ) { ber_bvarray_free( rs->sr_ref ); } } else { send_ldap_error( op, rs, LDAP_UNWILLING_TO_PERFORM, "no global superior knowledge" ); } goto cleanup; } /* If we've got a glued backend, check the real backend */ op_be = op->o_bd; if ( SLAP_GLUE_INSTANCE( op->o_bd )) { op->o_bd = select_backend( &op->o_req_ndn, 0 ); } /* check restrictions */ if ( backend_check_restrictions( op, rs, NULL ) != LDAP_SUCCESS ) { send_ldap_result( op, rs ); goto cleanup; } /* check for referrals */ if ( backend_check_referrals( op, rs ) != LDAP_SUCCESS ) { goto cleanup; } rs->sr_err = slap_mods_obsolete_check( op, op->orm_modlist, &rs->sr_text, textbuf, textlen ); if ( rs->sr_err != LDAP_SUCCESS ) { send_ldap_result( op, rs ); goto cleanup; } /* check for modify/increment support */ if ( op->orm_increment && !SLAP_INCREMENT( op->o_bd ) ) { send_ldap_error( op, rs, LDAP_UNWILLING_TO_PERFORM, "modify/increment not supported in context" ); goto cleanup; } /* * do the modify if 1 && (2 || 3) * 1) there is a modify function implemented in this backend; * 2) this backend is master for what it holds; * 3) it's a replica and the dn supplied is the update_ndn. */ if ( op->o_bd->bd_info->bi_op_modify ) { /* do the update here */ int repl_user = be_isupdate( op ); /* * Multimaster slapd does not have to check for replicator dn * because it accepts each modify request */ if ( !SLAP_SINGLE_SHADOW(op->o_bd) || repl_user ) { int update = !BER_BVISEMPTY( &op->o_bd->be_update_ndn ); op->o_bd = op_be; if ( !update ) { rs->sr_err = slap_mods_no_user_mod_check( op, op->orm_modlist, &rs->sr_text, textbuf, textlen ); if ( rs->sr_err != LDAP_SUCCESS ) { send_ldap_result( op, rs ); goto cleanup; } } slap_biglock_call_be( op_modify, op, rs ); } else { /* send a referral */ BerVarray defref = op->o_bd->be_update_refs ? op->o_bd->be_update_refs : default_referral; if ( defref != NULL ) { rs->sr_ref = referral_rewrite( defref, NULL, &op->o_req_dn, LDAP_SCOPE_DEFAULT ); if ( rs->sr_ref == NULL ) { /* FIXME: must duplicate, because * overlays may muck with it */ rs->sr_ref = defref; } rs->sr_err = LDAP_REFERRAL; send_ldap_result( op, rs ); if ( rs->sr_ref != defref ) { ber_bvarray_free( rs->sr_ref ); } } else { send_ldap_error( op, rs, LDAP_UNWILLING_TO_PERFORM, "shadow context; no update referral" ); } } } else { send_ldap_error( op, rs, LDAP_UNWILLING_TO_PERFORM, "operation not supported within namingContext" ); } cleanup:; op->o_bd = bd; return rs->sr_err; }
int fe_op_compare( Operation *op, SlapReply *rs ) { Entry *entry = NULL; AttributeAssertion *ava = op->orc_ava; BackendDB *bd = op->o_bd; if( strcasecmp( op->o_req_ndn.bv_val, LDAP_ROOT_DSE ) == 0 ) { if( backend_check_restrictions( op, rs, NULL ) != LDAP_SUCCESS ) { send_ldap_result( op, rs ); goto cleanup; } rs->sr_err = root_dse_info( op->o_conn, &entry, &rs->sr_text ); if( rs->sr_err != LDAP_SUCCESS ) { send_ldap_result( op, rs ); goto cleanup; } } else if ( bvmatch( &op->o_req_ndn, &frontendDB->be_schemandn ) ) { if( backend_check_restrictions( op, rs, NULL ) != LDAP_SUCCESS ) { send_ldap_result( op, rs ); rs->sr_err = 0; goto cleanup; } rs->sr_err = schema_info( &entry, &rs->sr_text ); if( rs->sr_err != LDAP_SUCCESS ) { send_ldap_result( op, rs ); rs->sr_err = 0; goto cleanup; } } if( entry ) { rs->sr_err = slap_compare_entry( op, entry, ava ); entry_free( entry ); send_ldap_result( op, rs ); if( rs->sr_err == LDAP_COMPARE_TRUE || rs->sr_err == LDAP_COMPARE_FALSE ) { rs->sr_err = LDAP_SUCCESS; } goto cleanup; } /* * We could be serving multiple database backends. Select the * appropriate one, or send a referral to our "referral server" * if we don't hold it. */ op->o_bd = select_backend( &op->o_req_ndn, 0 ); if ( op->o_bd == NULL ) { rs->sr_ref = referral_rewrite( default_referral, NULL, &op->o_req_dn, LDAP_SCOPE_DEFAULT ); rs->sr_err = LDAP_REFERRAL; if (!rs->sr_ref) rs->sr_ref = default_referral; op->o_bd = bd; send_ldap_result( op, rs ); if (rs->sr_ref != default_referral) ber_bvarray_free( rs->sr_ref ); rs->sr_err = 0; goto cleanup; } /* check restrictions */ if( backend_check_restrictions( op, rs, NULL ) != LDAP_SUCCESS ) { send_ldap_result( op, rs ); goto cleanup; } /* check for referrals */ if( backend_check_referrals( op, rs ) != LDAP_SUCCESS ) { goto cleanup; } if ( SLAP_SHADOW(op->o_bd) && get_dontUseCopy(op) ) { /* don't use shadow copy */ send_ldap_error( op, rs, LDAP_UNWILLING_TO_PERFORM, "copy not used" ); } else if ( ava->aa_desc == slap_schema.si_ad_entryDN ) { send_ldap_error( op, rs, LDAP_UNWILLING_TO_PERFORM, "entryDN compare not supported" ); } else if ( ava->aa_desc == slap_schema.si_ad_subschemaSubentry ) { send_ldap_error( op, rs, LDAP_UNWILLING_TO_PERFORM, "subschemaSubentry compare not supported" ); #ifndef SLAP_COMPARE_IN_FRONTEND } else if ( ava->aa_desc == slap_schema.si_ad_hasSubordinates && op->o_bd->be_has_subordinates ) { int rc, hasSubordinates = LDAP_SUCCESS; rc = be_entry_get_rw( op, &op->o_req_ndn, NULL, NULL, 0, &entry ); if ( rc == 0 && entry ) { if ( ! access_allowed( op, entry, ava->aa_desc, &ava->aa_value, ACL_COMPARE, NULL ) ) { rc = rs->sr_err = LDAP_INSUFFICIENT_ACCESS; } else { rc = rs->sr_err = op->o_bd->be_has_subordinates( op, entry, &hasSubordinates ); be_entry_release_r( op, entry ); } } if ( rc == 0 ) { int asserted; asserted = bvmatch( &ava->aa_value, &slap_true_bv ) ? LDAP_COMPARE_TRUE : LDAP_COMPARE_FALSE; if ( hasSubordinates == asserted ) { rs->sr_err = LDAP_COMPARE_TRUE; } else { rs->sr_err = LDAP_COMPARE_FALSE; } } else { /* return error only if "disclose" * is granted on the object */ if ( backend_access( op, NULL, &op->o_req_ndn, slap_schema.si_ad_entry, NULL, ACL_DISCLOSE, NULL ) == LDAP_INSUFFICIENT_ACCESS ) { rs->sr_err = LDAP_NO_SUCH_OBJECT; } } send_ldap_result( op, rs ); if ( rc == 0 ) { rs->sr_err = LDAP_SUCCESS; } } else if ( op->o_bd->be_compare ) { rs->sr_err = op->o_bd->be_compare( op, rs ); #endif /* ! SLAP_COMPARE_IN_FRONTEND */ } else { rs->sr_err = SLAP_CB_CONTINUE; } if ( rs->sr_err == SLAP_CB_CONTINUE ) { /* do our best to compare that AVA * * NOTE: this code is used only * if SLAP_COMPARE_IN_FRONTEND * is #define'd (it's not by default) * or if op->o_bd->be_compare is NULL. * * FIXME: one potential issue is that * if SLAP_COMPARE_IN_FRONTEND overlays * are not executed for compare. */ BerVarray vals = NULL; int rc = LDAP_OTHER; rs->sr_err = backend_attribute( op, NULL, &op->o_req_ndn, ava->aa_desc, &vals, ACL_COMPARE ); switch ( rs->sr_err ) { default: /* return error only if "disclose" * is granted on the object */ if ( backend_access( op, NULL, &op->o_req_ndn, slap_schema.si_ad_entry, NULL, ACL_DISCLOSE, NULL ) == LDAP_INSUFFICIENT_ACCESS ) { rs->sr_err = LDAP_NO_SUCH_OBJECT; } break; case LDAP_SUCCESS: if ( value_find_ex( op->oq_compare.rs_ava->aa_desc, SLAP_MR_ATTRIBUTE_VALUE_NORMALIZED_MATCH | SLAP_MR_ASSERTED_VALUE_NORMALIZED_MATCH, vals, &ava->aa_value, op->o_tmpmemctx ) == 0 ) { rs->sr_err = LDAP_COMPARE_TRUE; break; } else { rs->sr_err = LDAP_COMPARE_FALSE; } rc = LDAP_SUCCESS; break; } send_ldap_result( op, rs ); if ( rc == 0 ) { rs->sr_err = LDAP_SUCCESS; } if ( vals ) { ber_bvarray_free_x( vals, op->o_tmpmemctx ); } } cleanup:; op->o_bd = bd; return rs->sr_err; }
int fe_op_modrdn( Operation *op, SlapReply *rs ) { struct berval dest_ndn = BER_BVNULL, dest_pndn, pdn = BER_BVNULL; BackendDB *op_be, *bd = op->o_bd; ber_slen_t diff; if( op->o_req_ndn.bv_len == 0 ) { Debug( LDAP_DEBUG_ANY, "%s do_modrdn: root dse!\n", op->o_log_prefix, 0, 0 ); send_ldap_error( op, rs, LDAP_UNWILLING_TO_PERFORM, "cannot rename the root DSE" ); goto cleanup; } else if ( bvmatch( &op->o_req_ndn, &frontendDB->be_schemandn ) ) { Debug( LDAP_DEBUG_ANY, "%s do_modrdn: subschema subentry: %s (%ld)\n", op->o_log_prefix, frontendDB->be_schemandn.bv_val, (long)frontendDB->be_schemandn.bv_len ); send_ldap_error( op, rs, LDAP_UNWILLING_TO_PERFORM, "cannot rename subschema subentry" ); goto cleanup; } if( op->orr_nnewSup ) { dest_pndn = *op->orr_nnewSup; } else { dnParent( &op->o_req_ndn, &dest_pndn ); } build_new_dn( &dest_ndn, &dest_pndn, &op->orr_nnewrdn, op->o_tmpmemctx ); diff = (ber_slen_t) dest_ndn.bv_len - (ber_slen_t) op->o_req_ndn.bv_len; if ( diff > 0 ? dnIsSuffix( &dest_ndn, &op->o_req_ndn ) : diff < 0 && dnIsSuffix( &op->o_req_ndn, &dest_ndn ) ) { send_ldap_error( op, rs, LDAP_UNWILLING_TO_PERFORM, diff > 0 ? "cannot place an entry below itself" : "cannot place an entry above itself" ); goto cleanup; } /* * We could be serving multiple database backends. Select the * appropriate one, or send a referral to our "referral server" * if we don't hold it. */ op->o_bd = select_backend( &op->o_req_ndn, 1 ); if ( op->o_bd == NULL ) { op->o_bd = bd; rs->sr_ref = referral_rewrite( default_referral, NULL, &op->o_req_dn, LDAP_SCOPE_DEFAULT ); if (!rs->sr_ref) rs->sr_ref = default_referral; if ( rs->sr_ref != NULL ) { rs->sr_err = LDAP_REFERRAL; send_ldap_result( op, rs ); if (rs->sr_ref != default_referral) ber_bvarray_free( rs->sr_ref ); } else { send_ldap_error( op, rs, LDAP_UNWILLING_TO_PERFORM, "no global superior knowledge" ); } goto cleanup; } /* If we've got a glued backend, check the real backend */ op_be = op->o_bd; if ( SLAP_GLUE_INSTANCE( op->o_bd )) { op->o_bd = select_backend( &op->o_req_ndn, 0 ); } /* check restrictions */ if( backend_check_restrictions( op, rs, NULL ) != LDAP_SUCCESS ) { send_ldap_result( op, rs ); goto cleanup; } /* check for referrals */ if ( backend_check_referrals( op, rs ) != LDAP_SUCCESS ) { goto cleanup; } /* check that destination DN is in the same backend as source DN */ if ( select_backend( &dest_ndn, 0 ) != op->o_bd ) { send_ldap_error( op, rs, LDAP_AFFECTS_MULTIPLE_DSAS, "cannot rename between DSAs" ); goto cleanup; } /* * do the modrdn if 1 && (2 || 3) * 1) there is a modrdn function implemented in this backend; * 2) this backend is master for what it holds; * 3) it's a replica and the dn supplied is the update_ndn. */ if ( op->o_bd->be_modrdn ) { /* do the update here */ int repl_user = be_isupdate( op ); if ( !SLAP_SINGLE_SHADOW(op->o_bd) || repl_user ) { op->o_bd = op_be; op->o_bd->be_modrdn( op, rs ); if ( op->o_bd->be_delete ) { struct berval org_req_dn = BER_BVNULL; struct berval org_req_ndn = BER_BVNULL; struct berval org_dn = BER_BVNULL; struct berval org_ndn = BER_BVNULL; int org_managedsait; org_req_dn = op->o_req_dn; org_req_ndn = op->o_req_ndn; org_dn = op->o_dn; org_ndn = op->o_ndn; org_managedsait = get_manageDSAit( op ); op->o_dn = op->o_bd->be_rootdn; op->o_ndn = op->o_bd->be_rootndn; op->o_managedsait = SLAP_CONTROL_NONCRITICAL; while ( rs->sr_err == LDAP_SUCCESS && op->o_delete_glue_parent ) { op->o_delete_glue_parent = 0; if ( !be_issuffix( op->o_bd, &op->o_req_ndn )) { slap_callback cb = { NULL }; cb.sc_response = slap_null_cb; dnParent( &op->o_req_ndn, &pdn ); op->o_req_dn = pdn; op->o_req_ndn = pdn; op->o_callback = &cb; op->o_bd->be_delete( op, rs ); } else { break; } } op->o_managedsait = org_managedsait; op->o_dn = org_dn; op->o_ndn = org_ndn; op->o_req_dn = org_req_dn; op->o_req_ndn = org_req_ndn; op->o_delete_glue_parent = 0; } } else { BerVarray defref = op->o_bd->be_update_refs ? op->o_bd->be_update_refs : default_referral; if ( defref != NULL ) { rs->sr_ref = referral_rewrite( defref, NULL, &op->o_req_dn, LDAP_SCOPE_DEFAULT ); if (!rs->sr_ref) rs->sr_ref = defref; rs->sr_err = LDAP_REFERRAL; send_ldap_result( op, rs ); if (rs->sr_ref != defref) ber_bvarray_free( rs->sr_ref ); } else { send_ldap_error( op, rs, LDAP_UNWILLING_TO_PERFORM, "shadow context; no update referral" ); } } } else { send_ldap_error( op, rs, LDAP_UNWILLING_TO_PERFORM, "operation not supported within namingContext" ); } cleanup:; if ( dest_ndn.bv_val != NULL ) ber_memfree_x( dest_ndn.bv_val, op->o_tmpmemctx ); op->o_bd = bd; return rs->sr_err; }
int fe_op_search( Operation *op, SlapReply *rs ) { BackendDB *bd = op->o_bd; if ( op->ors_scope == LDAP_SCOPE_BASE ) { Entry *entry = NULL; if ( BER_BVISEMPTY( &op->o_req_ndn ) ) { #ifdef LDAP_CONNECTIONLESS /* Ignore LDAPv2 CLDAP Root DSE queries */ if (op->o_protocol == LDAP_VERSION2 && op->o_conn->c_is_udp) { goto return_results; } #endif /* check restrictions */ if( backend_check_restrictions( op, rs, NULL ) != LDAP_SUCCESS ) { send_ldap_result( op, rs ); goto return_results; } rs->sr_err = root_dse_info( op->o_conn, &entry, &rs->sr_text ); } else if ( bvmatch( &op->o_req_ndn, &frontendDB->be_schemandn ) ) { /* check restrictions */ if( backend_check_restrictions( op, rs, NULL ) != LDAP_SUCCESS ) { send_ldap_result( op, rs ); goto return_results; } rs->sr_err = schema_info( &entry, &rs->sr_text ); } if( rs->sr_err != LDAP_SUCCESS ) { send_ldap_result( op, rs ); goto return_results; } else if ( entry != NULL ) { rs->sr_err = test_filter( op, entry, op->ors_filter ); if( rs->sr_err == LDAP_COMPARE_TRUE ) { /* note: we set no limits because either * no limit is specified, or at least 1 * is specified, and we're going to return * at most one entry */ op->ors_slimit = SLAP_NO_LIMIT; op->ors_tlimit = SLAP_NO_LIMIT; rs->sr_entry = entry; rs->sr_attrs = op->ors_attrs; rs->sr_operational_attrs = NULL; rs->sr_flags = 0; send_search_entry( op, rs ); rs->sr_entry = NULL; rs->sr_operational_attrs = NULL; } entry_free( entry ); rs->sr_err = LDAP_SUCCESS; send_ldap_result( op, rs ); goto return_results; } } if( BER_BVISEMPTY( &op->o_req_ndn ) && !BER_BVISEMPTY( &default_search_nbase ) ) { slap_sl_free( op->o_req_dn.bv_val, op->o_tmpmemctx ); slap_sl_free( op->o_req_ndn.bv_val, op->o_tmpmemctx ); ber_dupbv_x( &op->o_req_dn, &default_search_base, op->o_tmpmemctx ); ber_dupbv_x( &op->o_req_ndn, &default_search_nbase, op->o_tmpmemctx ); } /* * We could be serving multiple database backends. Select the * appropriate one, or send a referral to our "referral server" * if we don't hold it. */ op->o_bd = select_backend( &op->o_req_ndn, 1 ); if ( op->o_bd == NULL ) { rs->sr_ref = referral_rewrite( default_referral, NULL, &op->o_req_dn, op->ors_scope ); if (!rs->sr_ref) rs->sr_ref = default_referral; rs->sr_err = LDAP_REFERRAL; op->o_bd = bd; send_ldap_result( op, rs ); if (rs->sr_ref != default_referral) ber_bvarray_free( rs->sr_ref ); rs->sr_ref = NULL; goto return_results; } /* check restrictions */ if( backend_check_restrictions( op, rs, NULL ) != LDAP_SUCCESS ) { send_ldap_result( op, rs ); goto return_results; } /* check for referrals */ if( backend_check_referrals( op, rs ) != LDAP_SUCCESS ) { goto return_results; } if ( SLAP_SHADOW(op->o_bd) && get_dontUseCopy(op) ) { /* don't use shadow copy */ BerVarray defref = op->o_bd->be_update_refs ? op->o_bd->be_update_refs : default_referral; if( defref != NULL ) { rs->sr_ref = referral_rewrite( defref, NULL, &op->o_req_dn, op->ors_scope ); if( !rs->sr_ref) rs->sr_ref = defref; rs->sr_err = LDAP_REFERRAL; send_ldap_result( op, rs ); if (rs->sr_ref != defref) ber_bvarray_free( rs->sr_ref ); } else { send_ldap_error( op, rs, LDAP_UNWILLING_TO_PERFORM, "copy not used; no referral information available" ); } } else if ( op->o_bd->be_search ) { if ( limits_check( op, rs ) == 0 ) { /* actually do the search and send the result(s) */ (op->o_bd->be_search)( op, rs ); } /* else limits_check() sends error */ } else { send_ldap_error( op, rs, LDAP_UNWILLING_TO_PERFORM, "operation not supported within namingContext" ); } return_results:; op->o_bd = bd; return rs->sr_err; }
int passwd_extop( Operation *op, SlapReply *rs ) { struct berval id = {0, NULL}, hash, *rsp = NULL; req_pwdexop_s *qpw = &op->oq_pwdexop; req_extended_s qext = op->oq_extended; Modifications *ml; slap_callback cb = { NULL, slap_null_cb, NULL, NULL }; int i, nhash; char **hashes, idNul = 0; int rc; BackendDB *op_be; int freenewpw = 0; struct berval dn = BER_BVNULL, ndn = BER_BVNULL; slap_biglock_t *bl = NULL; assert( ber_bvcmp( &slap_EXOP_MODIFY_PASSWD, &op->ore_reqoid ) == 0 ); if( op->o_dn.bv_len == 0 ) { Statslog( LDAP_DEBUG_STATS, "%s PASSMOD\n", op->o_log_prefix ); rs->sr_text = "only authenticated users may change passwords"; return LDAP_STRONG_AUTH_REQUIRED; } qpw->rs_old.bv_len = 0; qpw->rs_old.bv_val = NULL; qpw->rs_new.bv_len = 0; qpw->rs_new.bv_val = NULL; qpw->rs_mods = NULL; qpw->rs_modtail = NULL; rs->sr_err = slap_passwd_parse( op->ore_reqdata, &id, &qpw->rs_old, &qpw->rs_new, &rs->sr_text ); if ( !BER_BVISNULL( &id )) { idNul = id.bv_val[id.bv_len]; id.bv_val[id.bv_len] = '\0'; } if ( rs->sr_err == LDAP_SUCCESS && !BER_BVISEMPTY( &id ) ) { Statslog( LDAP_DEBUG_STATS, "%s PASSMOD id=\"%s\"%s%s\n", op->o_log_prefix, id.bv_val, qpw->rs_old.bv_val ? " old" : "", qpw->rs_new.bv_val ? " new" : "" ); } else { Statslog( LDAP_DEBUG_STATS, "%s PASSMOD%s%s\n", op->o_log_prefix, qpw->rs_old.bv_val ? " old" : "", qpw->rs_new.bv_val ? " new" : "" ); } if ( rs->sr_err != LDAP_SUCCESS ) { if ( !BER_BVISNULL( &id )) id.bv_val[id.bv_len] = idNul; return rs->sr_err; } if ( !BER_BVISEMPTY( &id ) ) { rs->sr_err = dnPrettyNormal( NULL, &id, &dn, &ndn, op->o_tmpmemctx ); id.bv_val[id.bv_len] = idNul; if ( rs->sr_err != LDAP_SUCCESS ) { rs->sr_text = "Invalid DN"; rc = rs->sr_err; goto error_return; } op->o_req_dn = dn; op->o_req_ndn = ndn; op->o_bd = select_backend( &op->o_req_ndn, 1 ); } else { ber_dupbv_x( &dn, &op->o_dn, op->o_tmpmemctx ); ber_dupbv_x( &ndn, &op->o_ndn, op->o_tmpmemctx ); op->o_req_dn = dn; op->o_req_ndn = ndn; ldap_pvt_thread_mutex_lock( &op->o_conn->c_mutex ); op->o_bd = op->o_conn->c_authz_backend; ldap_pvt_thread_mutex_unlock( &op->o_conn->c_mutex ); } if( op->o_bd == NULL ) { if ( qpw->rs_old.bv_val != NULL ) { rs->sr_text = "unwilling to verify old password"; rc = LDAP_UNWILLING_TO_PERFORM; goto error_return; } #ifdef HAVE_CYRUS_SASL rc = slap_sasl_setpass( op, rs ); #else rs->sr_text = "no authz backend"; rc = LDAP_OTHER; #endif goto error_return; } if ( op->o_req_ndn.bv_len == 0 ) { rs->sr_text = "no password is associated with the Root DSE"; rc = LDAP_UNWILLING_TO_PERFORM; goto error_return; } /* If we've got a glued backend, check the real backend */ op_be = op->o_bd; if ( SLAP_GLUE_INSTANCE( op->o_bd )) { op->o_bd = select_backend( &op->o_req_ndn, 0 ); } bl = slap_biglock_get(op->o_bd); slap_biglock_acquire(bl); if (backend_check_restrictions( op, rs, (struct berval *)&slap_EXOP_MODIFY_PASSWD ) != LDAP_SUCCESS) { rc = rs->sr_err; goto error_return; } /* check for referrals */ if ( backend_check_referrals( op, rs ) != LDAP_SUCCESS ) { rc = rs->sr_err; goto error_return; } /* This does not apply to multi-master case */ if(!( !SLAP_SINGLE_SHADOW( op->o_bd ) || be_isupdate( op ))) { /* we SHOULD return a referral in this case */ BerVarray defref = op->o_bd->be_update_refs ? op->o_bd->be_update_refs : default_referral; if( defref != NULL ) { rs->sr_ref = referral_rewrite( defref, NULL, NULL, LDAP_SCOPE_DEFAULT ); if ( ! rs->sr_ref ) ber_bvarray_dup_x( &rs->sr_ref, defref, NULL ); rs->sr_flags |= REP_REF_MUSTBEFREED; rc = LDAP_REFERRAL; goto error_return; } rs->sr_text = "shadow context; no update referral"; rc = LDAP_UNWILLING_TO_PERFORM; goto error_return; } /* generate a new password if none was provided */ if ( qpw->rs_new.bv_len == 0 ) { slap_passwd_generate( &qpw->rs_new ); if ( qpw->rs_new.bv_len ) { rsp = slap_passwd_return( &qpw->rs_new ); freenewpw = 1; } } if ( qpw->rs_new.bv_len == 0 ) { rs->sr_text = "password generation failed"; rc = LDAP_OTHER; goto error_return; } op->o_bd = op_be; /* Give the backend a chance to handle this itself */ if ( op->o_bd->be_extended ) { rs->sr_err = op->o_bd->be_extended( op, rs ); if ( rs->sr_err != LDAP_UNWILLING_TO_PERFORM && rs->sr_err != SLAP_CB_CONTINUE ) { rc = rs->sr_err; if ( rsp ) { rs->sr_rspdata = rsp; rsp = NULL; } goto error_return; } } /* The backend didn't handle it, so try it here */ if( op->o_bd && !op->o_bd->bd_info->bi_op_modify ) { rs->sr_text = "operation not supported for current user"; rc = LDAP_UNWILLING_TO_PERFORM; goto error_return; } if ( qpw->rs_old.bv_val != NULL ) { Entry *e = NULL; rc = be_entry_get_rw( op, &op->o_req_ndn, NULL, slap_schema.si_ad_userPassword, 0, &e ); if ( rc == LDAP_SUCCESS && e ) { Attribute *a = attr_find( e->e_attrs, slap_schema.si_ad_userPassword ); if ( a ) rc = slap_passwd_check( op, e, a, &qpw->rs_old, &rs->sr_text ); else rc = 1; be_entry_release_r( op, e ); if ( rc == LDAP_SUCCESS ) goto old_good; } rs->sr_text = "unwilling to verify old password"; rc = LDAP_UNWILLING_TO_PERFORM; goto error_return; } old_good: ml = ch_malloc( sizeof(Modifications) ); if ( !qpw->rs_modtail ) qpw->rs_modtail = &ml->sml_next; if ( default_passwd_hash ) { for ( nhash = 0; default_passwd_hash[nhash]; nhash++ ); hashes = default_passwd_hash; } else { nhash = 1; hashes = (char **)defhash; } ml->sml_numvals = nhash; ml->sml_values = ch_malloc( (nhash+1)*sizeof(struct berval) ); for ( i=0; hashes[i]; i++ ) { slap_passwd_hash_type( &qpw->rs_new, &hash, hashes[i], &rs->sr_text ); if ( hash.bv_len == 0 ) { if ( !rs->sr_text ) { rs->sr_text = "password hash failed"; } break; } ml->sml_values[i] = hash; } ml->sml_values[i].bv_val = NULL; ml->sml_nvalues = NULL; ml->sml_desc = slap_schema.si_ad_userPassword; ml->sml_type = ml->sml_desc->ad_cname; ml->sml_op = LDAP_MOD_REPLACE; ml->sml_flags = 0; ml->sml_next = qpw->rs_mods; qpw->rs_mods = ml; if ( hashes[i] ) { rs->sr_err = LDAP_OTHER; } else { slap_callback *sc = op->o_callback; op->o_tag = LDAP_REQ_MODIFY; op->o_callback = &cb; op->orm_modlist = qpw->rs_mods; op->orm_no_opattrs = 0; cb.sc_private = qpw; /* let Modify know this was pwdMod, * if it cares... */ rs->sr_err = op->o_bd->bd_info->bi_op_modify( op, rs ); /* be_modify() might have shuffled modifications */ qpw->rs_mods = op->orm_modlist; if ( rs->sr_err == LDAP_SUCCESS ) { rs->sr_rspdata = rsp; } else if ( rsp ) { ber_bvfree( rsp ); rsp = NULL; } op->o_tag = LDAP_REQ_EXTENDED; op->o_callback = sc; } rc = rs->sr_err; op->oq_extended = qext; error_return:; slap_biglock_release(bl); if ( qpw->rs_mods ) { slap_mods_free( qpw->rs_mods, 1 ); } if ( freenewpw ) { free( qpw->rs_new.bv_val ); } if ( !BER_BVISNULL( &dn ) ) { op->o_tmpfree( dn.bv_val, op->o_tmpmemctx ); BER_BVZERO( &op->o_req_dn ); } if ( !BER_BVISNULL( &ndn ) ) { op->o_tmpfree( ndn.bv_val, op->o_tmpmemctx ); BER_BVZERO( &op->o_req_ndn ); } return rc; }