builtin product options like un-publishing, deleting and showbuybutton=false, can categorize the product as "unsellable" but not to the extent that you want to behave(as it will be filtered out).
One trick you can use is, say product B is the free product required for product A
Setup product B as:
1. make a copy of product B's xml package,
product.simpleproduct.xml.config -> product.simpleproduct_nobuy.xml.config
2. open the copied file and remove the call to the AddToCartForm extension functions.
C#/VB.NET Code:
<xsl:value-of select="aspdnsf:AddtoCartForm(ProductID, VariantID, 1)" disable-output-escaping="yes"/>
3. use the _nobuy xmlpackage for product B and zero-out the price.
Setup Product A as having product B as a required product.
This would make product B behave as "unsellable" by not having a buy button option when the user views it's product page, but without having the system filter it out.