A Problem with Managed Preferences

In our labs Mac OS X machines bind to a Mac OS X Server for user authentication. But this also affords us the opportunity to control certain aspects of our workstations' behavior en masse as well. And we certainly take advantage of this. The way this works is simple, and, when it works properly, a thing of beauty: Open up Workgroup Manager, create a computer list, add computers to it and then set whatever preferences you want on those systems. Just about anything you can set in System Preferences can be controlled from the server — Login Items, Energy Saver settings, and my personal favorite, Printers, to name just a few. The Open Directory host — your OS X Server — will make sure all the prefs you set in here are managed on the specified machines.

But recently I had a few machines that would simply not allow themselves to be controlled from the server. Binding was working properly, as evidenced by the fact that network logins worked. But any sort of managed preferences would not be sensed by the workstations. This is a perennial problem and historically has had something to do with mcx_cache settings not being reset by the server. But this has gotten much better over the years, to the point where it's not usually an issue. Still I tried everything with regards to cache, and no matter what I did, authentication worked but managed preferences did not. Finally, today I managed to stumble upon the solution.

Turns out there's a little quirk in the Workgroup Manager. Seems if you add the same computer to two different lists, you'll get two separate entries in your OD database — one called "computer" and one called "computer_1." I did this. And then later I deleted the original "computer" entry from the first list, and renamed the "computer_1" entry back to "computer" in the WGM GUI. This is a no-no. And it's what was causing my computer control problems, though there seemed no apparent problem from the standpoint of the standard WGM interface.

Workgroup Manager Preferences: Show Me the Records!
(click image for larger view)

The solution was to enable WGM's "Show 'All Records' tab and inspector" preference, which gives you a much more accurate view of your Open Directory database than does the standard GUI interface. Once the "All Records" tab was enabled I opened it up and looked at the "Computers" list from the pull-down on the right (just below the search field). Lo and behold, there was my "computer_1" record, but no "computer" record. Looks like the server was getting confused as to whether to control "computer" (as set in the GUI) or "computer_1" (as was actually entered in the OD database). So I deleted all references to the machine in the "All Records" inspector, then went back into the GUI and re-added the machine to the appropriate list. Voila! The machine instantly began getting managed preference settings from the server.

So the rules of thumb here are:

  1. Avoid adding the same machine to more than one list. You're not supposed to do it, and it can muck things up.
  2. The "All Records" tab is your friend. Look here for more accurate views than the standard GUI can provide. Edit with care as necessary.

My lesson for the day.

External Network Unification Part 3: Migrating to Joomla

When last we visited this issue I had just gotten the venerable Joomla CMS to authenticate to our LDAP server. I decided to build a replica of our existing CMS, which is based on the Mambo core, and do some testing to see how easy it would be to port to our LDAP-saavy Joomla core. The Joomla site gives instructions for doing this, and frankly it sounded drop-dead simple.

It turns out it is drop-dead simple. The hard part is successfully replicating the existing Mambo site and all its requisite databases and components. To do this, I first copied all the files over to the test server. This is easy of course. Then I had to get the MySQL databases over. This was a bit more challenging. Using the command mysqldump was the way to go, but I encountered numerous errors when attempting this with the standard options. After some research I discovered that I needed to apply the --skip-opt option to the command. My final command looked something like this:

mysqldump --skip-opt -u mambosql -p -B TheDatabase > TheDatabase.bak.sql

I honestly don't remember why the --skip-opt flag was necessary, or even if it was the right approach, only that it seemed to do the trick: the dump completed without errors. So I copied the database over and set everything up on my test server exactly as it was on the original server, putting the Mambo site in the proper web root, and importing the databases on the test system. After some fidgeting — specifically, making sure the Mambo config file was edited to use the new server — I was able to get the test site working. The only problem was (and still is) that the admin pages don't work. No matter what I do, I can 't login and I'm told that my username and password are wrong, though they work on the front end. I suspect a problem with my dump. It's also possible that the admin pages require a different user — one I'm unaware of — than the front-end for access. Since I didn't build the original server, I can't be sure. But whatever.

The next part of this test was to try and port the Mambo install to the Joomla engine with the LDAP hack enabled. This turned out to be fairly straightforward: Install and configure Joomla (v.1.0.8 — later versions do not work with the LDAP hack) to authenticate to LDAP; copy over all the custom Mambo files to the new Joomla site (without overwriting any Joomla stuff); copy the Mambo config file over and edit it for the new site root; trash the "Installation" folder (we won't be needing it); and that was it. My old Mambo site was now running on an LDAP-enabled Joomla engine.

There were some major snags here though. Because I could not get into the admin pages (a problem that persisted even with the new Joomla engine), I could not configure user authentication. I was able to directly access the MySQL database, however, with phpMyAdmin. Here I was able to edit my user account to use LDAP rather than using the password stored in the MySQL database by entering "@LDAP" into the password field. This worked well in fact.

One feature, however — automatic user creation — did not work so well. That is, if a new user logs in — a user that doesn't yet exist in the MySQL database, but does exist on the LDAP server — what the LDAP Hack does is create the new user in the MySQL database with a flag that says, "Get this user's password from the LDAP database." Logging in as a new user on my test Joomla server produced erratic results. I'm assuming that this had something to do with the lack of admin access to the MySQL database.

Still, we've accomplished some things here. For one, we've figured out a method for porting our current Mambo CMS to an LDAP-enabled Joomla engine. Secondly, we've shown, at least in theory, that this system can work with LDAP. The next step will be to try all this out on a copy of our live Mambo CMS on the actual web server. Hopefully, when we do that, access to the admin pages will function normally and the LDAP hack can be configured so that new users are properly added at login. If all goes well, our CMS will be authenticating to LDAP in the next post in this series.

If all goes well.

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.

Publish iCal Calendars on the Internet for Free

Addendum: Aug 21, 2010

I wanted to let folks know that the information in this post is pretty old, and these days there are better options for sharing calendars. Most notably, Google Calendar sharing. The method used in the post you're about to read is a one-way share in which the publishing computer is the only one that can make changes, and all subscribing calendars have read-only access. This is limited, I know, but at the time it was readily available and plenty of functionality for most people who just wanted a free option for calendar sharing from their main machine. Nowadays, though, Google Calendar sharing gives the same level of ease-of-use and true, server-based, two-way calendar syncing, allowing you to edit you calendars from any computer (including iPhones). It truly is superior, and I highly recommend it.

So, if you're still interested in the one-way Box.net method, I leave it up for posterity. Otherwise, Google Calendar sharing is probably the way to go.

Happy calendaring!

Original Post

Ever want to share your iCal calendars on the 'net? Well, I have. Unfortunately, iCal publishing requires a server that runs the WebDAV protocol. Apple's .Mac offers such a service, and .Mac, indeed, uses WebDAV. But .Mac costs money, and I've never seen a compelling enough reason to pay for it. Setting up iCal on a Macintosh server is also fairly easy, but it's an awful lot of trouble to go to and a waste of resources if all you're interested in is sharing your iCal calendars. But today I've discovered an easier — and free — way to do just that.

Box.net offers 1 GB of online file storage for free. The data is accessible via the web, so you can get to it from any connected computer. They have a web interface for accessing you files. On Windows they also have client software that lets you access your data as though it were on a shared volume, right from the Desktop. But on the Mac you can connect to it right from the Finder using the ever-trusty "Connect to Server..." command (or command-k) in the "Go" menu. How is this possible you ask? Because the Mac Finder has WebDAV accessibility built right in. And because box.net shares it's data via the WebDAV protocol.

If you haven't put it together yet, this means you can use your free box.net account to host your iCal calendars. The process would go something like this:

  1. Sign up for a free box.net account. It's easy as pie, and faster than a bat out of hell. Give 'em your email, a password, and you are d-o-n-e, done. (NOTE: Obviously, to share the calendar with others, they'll need the URL and the box.net username and password, so you might want to make sure you set this account up with information you don't mind giving out. Use a second, private account for stuff you want to keep secure.)
  2. To access your box.net account via the Finder, click "Connect to Server..." and type "https://www.box.net/dav" into the URL field of the connection window. (NOTE: Some folks are unable to connect using the "https" protocol. If this fails for you, try it with "http" instead. Either one works for me.) You will be prompted for username (the email you used to register the account) and your box.net password. Enter these and your online data will appear on the Desktop in a volume called "dav" which will be pre-populated with a few default folders.
  3. But to publish your iCal calendar, just open iCal, select the calendar you want to share and choose "Publish" from the "Calendar" pulldown menu.

    (click for larger view)

  4. In the dialog box that follows, name your calendar (or keep the existing name if it suits you), for "Publish on:" select "Private Server," enter "https://www.box.net/dav/Documents" for the "Base URL:" and enter your box.net username and password in the "Login:" and "Password:" fields respectively. (NOTE: Here, too, secure http sometimes fails, so if you have trouble try using "http" instead of "https".)
  5. You might also want to check or uncheck some of the checkboxes at the bottom, depending on your needs.
  6. Finally, hit "Publish" to publish the calendar. You'll see your calendar now sports the "I'm Published" icon just to its right.
  7. To subscribe to this calendar (say, from another computer), choose "Subscribe" in the"Calendar" pull-down menu.
  8. In the URL field enter:

    "http://www.box.net/dav/Documents/YourCalendar.ics"

    (where "YourCalendar" is the name of the calendar you just published).

    (click for larger view)

    Be careful NOT to enter "https" here. Just use the "http" protocol to subscribe. Enter your box.net username and password at the prompt and you'll suddenly find yourself subscribed to your own calendar.

    (click for larger view)

  9. A final note: Updates to the calendar take some time. Hitting refresh too often (like every minute or so) on a subscribed calendar will generate an error. Just wait and let iCal do it's thing and it will keep everthing up to date. No pun intended.

I'm not sure if many people will find this useful. But to me it seems like a good way to share you iCal calendars, either between remote locations (like work and home) or between groups of people, like friends, family or members of an organization. And hey, it's completely free. How cool is that?

UPDATE 1:

A lot of people have written in with great suggestions, alternatives to and variations on this process, including a page for similarly configuring Sunbird. Please read the comments for more useful information.

UPDATE 2:

I have added a note to the publishing instructions in this article regarding the use of "https". In a nutshell, both publishing and subscribing sometimes fail because of problems with secure http. This is something I receive a lot of comments about and I just wanted to clear things up. If you are having trouble either publishing or subscribing, try doing so using "http" instead of "https". While somewhat less secure, it tends to be far more reliable.

Three Platforms, One Server Part 8: A Minor Snafu

So far we've hit only one very minor snag in our migration to a single, unified authentication server for Mac, Windows and Linux. Since Mac and Linux behave so similarly with regards to authentication — in fact, I'd say they're practically identical — and since Windows is so utterly, infuriatingly different, you can expect most of our problems to happen on the Windows side. At this point it should go without saying. This latest snag is no exception.

Today we discovered that applications to be used by network users on Windows machines must be installed by a network user, and this network user must be a domain admin. Put another way, if a Windows application is installed by a local administrator, it will not be fully accessible by users who authenticate via the domain hosted by the Authentication Server. Typical.

The solution is fairly easy, albeit kind of a pain. On each client workstation, you must give the network admin user (i.e., a user whose account exists only on the authentication server) full access to the "C" drive. You heard me: On each computer. Giving full access to a user on Windows requires logging in as a local admin and granting the network user full access rights. Windows then changes the access permissions on every file on the machine, which takes a long-ass time. You heard me: long-ass.

If we had to do this on every machine by hand, I'd be grumpy about it (but I'd do it anyway). Fortunately, we'll be building our Windows boxes from clones, which means we only have to do this once on a master build. the change should propagate via the clones after that. So I'm a pretty happy camper. And we're back on track.

Still, Windows, what the fuck?

And just to be clear on this, I honestly don't know enough about Windows or Active Directory to understand why this is happening. All I know is what we've observed, which is that Windows apps fail to run properly for network users when installed by local users. We tried matching the users and groups we'd had on the old Windows Server, but that did no good. Setting full access locally for a networked user was the only thing we could find that worked. It's very possible, however, that there's a better solution than the one we're using. If anyone can enlighten me, I'm all ears.

Oh, and yes, our network user has full access privileges for the directory domain. Confused? Me too.

More to come...

UPDATE: I found a better solution. A network user can be added to the "Administrators" group via the Users and Groups control panel. Doing so is not particularly intuitive, but it works and saves us the trouble of having to modify permissions on the entire "C" drive.

Windows "Advanced" Users and Groups: By "Advanced" I Think They Mean "Annoying"
(click image for larger view)

It essentially requires logging in as a local Administrator, navigating to the "Advanced" window in Users and Groups, and then adding the user to the "Administrator" group.


Group Properties: Do We Really Need This Window?
(click image for larger view)

Windows doesn't see a network user unless she's logged in, so you have to know how to enter a network user. It should look something like this: DOMAIN\user, where "DOMAIN" is your Active Directory Domain, and "user" is the user name.


Add the User Here: Who'd a Thunk It?
(click image for larger view)

You can find more complete instructions here, which is where I got these images.

Fun stuff.