Sandbox and ACLs or: Why I Want to French Kiss Mikey-San

So I recently had a freelance project that involved my first experience with, among other things, Access Control Lists (which we will, from here on out, refer to as ACLs, 'cause I'm not typing that shit a hundred more times today). Briefly, ACLs allow more fine-grained control over file and folder permissions by defining multiple rules for multiple groups and/or users for any given object. ACLs are exceptionally cool. But they're also incredibly complex.

For my freelance project I was assigned the odious task of setting up a share on a Mac server, and this share would be readable by all, but its contents would not, unless explicitly allowed, be readable by members of a particular group. Let me try to clarify this, 'cause it took me a few days to get my head around it: Essentially we had three groups, which we'll refer to as Artists, Producers and Freelancers. Artists and Producers needed full access to everything on the share (which we'll call Share), and Freelancers needed read access. Freelancers, however, needed to be denied access to all subfolders of Share, including newly created folders. Later, if a member of Freelancers needed access, someone from one of the other groups would grant them access to the folder in question on Share.

Complicated? You betcha! Impossible? Surprisingly, no. Though, if you try to do this with Apple's Workgroup Manager (which we'll just call WGM) you'll never be able to. The key lies with two concepts: rule ordering and inheritance. See, ACLs are ordered lists, and the first rule in the list wins. Additionally, "deny" rules always trump "allow" rules, with one crucial exception: explicit allow rules trump inherited deny rules. This was the magic that made our little scenario work. I did not see any mention of this in the Mac OS X Server documentation (though it's entirely possible I missed it). And I certainly did not see any way to reorder rules in the WGM application, inherited or not. Rather than from Apple, I got all my info on rule ordering and precedence from my new best-est pal in the whole wide universe, mikey-san of sightless and born.

Enter: Sandbox.

Sandbox is a cool, free, little utility whose sole purpose in life is to enable ACL management on non-server versions of Mac OS X. It even has some pretty informative documentation. Amazingly, however, Sandbox gives you way more and better control over your ACLs than Mac OS X Server's WGM app, particularly with regards to rule ordering. With Sandbox, you can explicitly set a rule as "inherited," and you can explicitly set the order of rules. You can't do either of these things in WGM, which is quite infuriating considering how important ordering is in ACLs.

Like the Command-Line: This is How it Looks in Sandbox

(click for larger view)

So, using Sandbox, I created a rule for Share that gave full access to Share for Artists and Producers, and that forced inheritance of these permissions to any subfolders of Share (so Share and its subfolders are always accessible to Artists and Producers). Then I created an "allow" rule which granted Freelancers read permissions on Share, but which did not propagate those permissions to subsequent subfolders (so Share is readable by Freelancers, but none of its subfolders are — if this rule is not propagated, which it's not, there is no rule on subfolders, and POSIX permissions take over, granting "world," and thus Freelancers, read access to subfolders of Share, so we need a deny rule next). Finally, I created a "deny" rule for Freelancers that disallowed them access to Share and any of its subfolders. This rule is inherited and occurs before the "allow" rule (so denial of access is propagated to subfolders of Share, essentially acting like a umask, but does not apply to the actual Share folder). The key here is that, in order for this deny rule to not override the allow rule, it must be inherited (remember, explicit "allow" rules trump inherited "deny" rules), and, once it has been set to "inherited," it must occur before the deny rule. Neither of these astonishing feats can be accomplished with WGM. Both can with Sandbox.

That "Deny" is Out of Order: Here's How it Looks in WGM

(click for larger view)

And that is why I want to French kiss mikey-san. Whoever he is.

UPDATE:

All the above was done on a test machine. (Thanks be to the joys of education work that actually allows me to build test servers!) Putting this plan into practice was one more, extra, added layer of tricky. You see, the share on which we wanted to set this up was already in use by the client. Yup, it was already populated with all manner of data, none of which had any ACLs applied.

The final nail in this coffin was to propagate the ACLs in WGM. But this had to be done such that all subfolders and files had the inherited properties we wanted, but the top-level "Share" had it's original properties. Remember: our top-level Share should be readable by Freelancers, but it's descendants should not, so the top-level permissions are different from all the subfolders and files. Had we simply propagated our "Share" permissions through the entire tree, Freelancers would have read-access to everything, and this was verboten. The trick was to remove the "allow:read" rule from "Share" and then propagate permissions. After the propagation was finished (about 10-15 minutes later — it was a large amount of data) we reapplied the "allow:read" rule to "Share" and all seems cool.

This may seem like an obvious solution, but I wanted to make a note of it as ACLs — at least complex ones like these — seem to befuddle even the most logical minds, and certainly mine. So for thoroughness' sake, there you have it.