generate_combinations(a1, a2, a3, a4, c1, c2, c3, c4)
1. if a1 + a2 + a3 + a4 = 3 then print (a1, a2, a3, a4)
2. else then
3. if c1 > 0 then generate_combinations(a1+1, a2, a3, a4, c1-1, c2, c3, c4)
4. if c2 > 0 then generate_combinations(a1, a2+1, a3, a4, c1, c2-1, c3, c4)
5. if c3 > 0 then generate_combinations(a1, a2, a3+1, a4, c1, c2, c3-1, c4)
6. if c4 > 0 then generate_combinations(a1, a2, a3, a4+1, c1, c2, c3, c4-1)
Or something like that. That won't catch duplicates, though... I suppose you could add some more logic to filter those out, though. Maybe post-processing?
Some clarification: this works by keeping counts of (1) the balls in your hand and (2) the balls in the bag. It ensures that hand+bag=original for every color. Call it with an initially empty hand and it will print every way you can have three balls in your hand.
If you really want to make sure that the algorithm only gives unique ones (rather than using this in conjunction with an algorithm to remove duplicates from a list), you can make sure that you don't add any e.g. red balls to your hand if you have already added any higher-order balls (i.e., if a2 > 0 and a1 = 0, then you don't need to add any red).