Thursday, February 22, 2007

Fixing Cygwin's user groups

Cygwin is a great tool for running a Linux-like environment under Windows. Overall, I'm very pleased with it, though you should be aware of a limitation in how Cygwin handles user groups.

Under Windows, Linux, or just about any other operating system that has the concept of user accounts, a user can belong to one or more groups. The problem is that except for the current user, Cygwin only returns a specific user's primary group.

Running "groups", "id -Gn", or "id -Gn {user}" under a real Linux installation all return the same result - a list of all groups the user belongs to. Unfortunately, under Cygwin, passing in a username (even for the current user) will only return the user's primary group.

Why is this an issue?

For example, I sometimes setup a workstation to run OpenSSH under Cygwin. The SSH daemon's config file allows for securing SSH access by user ("AllowUsers"), or much better, by groups ("AllowGroups"). The benefits of managing users by groups are well known (though I'm still looking for a better link to cite. For now, see Wikipedia's entry on Role-Based Access Control.) However, due to this issue, OpenSSH's "AllowGroups" fails to function under Cygwin.

Unfortunately, Cygwin lacks any of the typical bug reporting/tracking tools, such as Bugzilla. However, the Cygwin mailing lists track this issue back to March 2000. I made my first inquiry to the list in February 2006.

The "solution":

Finally, in January 2007, one of the primary Cygwin developers finally posted an answer, though I still hesitate to call it a complete solution. Basically, though Cygwin delegates to the underlying OS to handle passwords and most of the security in general, it doesn't try very hard for working with user groups.

Basically, mkgroup should be run with the -u flag (which should generally be output to /etc/group). The help for "-u" is "print user list in gr_mem field". In short, Cygwin doesn't ask the OS for the user's groups, but just reads them as text from /etc/group.

This still has 2 notable issues:

  1. If group membership is changed within Windows, Cygwin won't recognize it until /etc/group is updated, which generally has to be done manually.
  2. "mkgroup -u" appears to have a bug. It always includes the Windows' usernames, even if renamed in /etc/passwd for Cygwin-purposes (e.g. removing spaces). I.E., "John Smith" is recognized by Cygwin as "jsmith" per /etc/passwd, but "mkgroup -u" still outputs "John Smith" into /etc/group.

Some technical details:

The groups and id commands both appear to fail in this manner through their call to the getugroups function. I would suspect that OpenSSH and other applications may link to this function directly, which also causes them to fail in this manner. "groups" is just a shell script that calls "id -Gn", so nothing needs to be changed here.

The source code impacting this problem appears to be limited to the "cygwin" and "coreutils" packages.

I've found the source for "id" in /usr/src/coreutils-6.7/src/id.c. On line ~263, it checks to see if a username is supplied. If not, it calls getgroups(…), which appears to work as expected. If a username is supplied, it calls getugroups(…), passing the username and gid. I've never seen this return properly.

I found /usr/src/coreutils-6.7/lib/getugroups.c. It calls setgrent() to place the next call to getgrent() to the beginning of the group list, then proceeds to call getgrent(). As I've debugged this, I've not been able to get getgrent() to return anything but null. I've not tracked down the implementation of the getgrent() and related functions, but based on the feedback I received above (see "The solution", above), this must be where the /etc/groups file is being read rather than using the Windows API.

Final notes:

Unfortunately, that's it for now. I'd consider writing some sort of a scheduled task to update /etc/group on at least a daily basis. Keep in mind that some additional work would have to be done to account for the #2 issue above...

Some additional resources:


Anonymous said...

Nice catch. We had been dealing with this for ages and actually put the blame on subversion.

Anonymous said...

Well this is clear text at last.
Installed cygwin for the first time yesterday evening and was playing with it. first i found a group none (xp home standalone where i run it on) and then would like to have all groups of a user there but now have to find out how to get windows users in xp home into groups and if i even can... creat groups) but the documentation in cygwin is hard to follow. This however is clear and another hurdle is taken again. Thanx!