Exemplo n.º 1
0
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;
}
Exemplo n.º 2
0
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;
}
Exemplo n.º 3
0
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;
}
Exemplo n.º 4
0
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;
}
Exemplo n.º 5
0
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;
}
Exemplo n.º 6
0
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;
}