This is the mail archive of the cygwin@cygwin.com mailing list for the Cygwin project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

FAQ entry for setting up /etc/passwd with both NT domain users andSamba servers under ntsec


I spent a while figuring out the right way to configure Cygwin's
/etc/passwd in the face of CYGWIN=ntsec, domain users, and Samba
servers.  I thought I'd write a quick FAQ entry to save others time.

Let's say you have a Windows domain "DOM" to which all your users
belong.  However, you also have a Samba server, which we'll call
"SAMBA".  Usernames are the same in the domain and on the Samba
server; let's consider user "juser".  Files created on the Windows
machines will be correctly owned by "DOM\juser"; files on the Samba
server will be owned by "SAMBA\juser".  Unfortunately Samba does not
yet handle forwarding user SIDs from the domain, even with "security =
domain", though the documentation says work is ongoing in this area.
Instead it just makes up a SID base when it first initializes itself,
and uses a simple algorithm (2*uid+1000) to generate RIDs from uids.

The older cygwins didn't have to worry about this issue, since they
always mapped all the file ownership on remote shares to the username
of the user who was active.  (This is still the default behavior if
you don't set CYGWIN=ntsec.)  Unfortunately, in this mode you can't
see file owners or permissions, which is a serious limitation.

The question then is, how do we map the "SAMBA\juser" SIDs for cygwin?
If you just do a standard "mkpasswd -d", you will get a password file
that includes uids for all the DOM users, but doesn't include uids for
the SIDs generated by the SAMBA server; files on that server will be
shown as owned by (effectively) random uids with no names.  What's
more, since the uids won't match, programs will tend to get confused
as to whether they're accessible.  For example, if your Unix account
owns a file with 644 permissions, access(file,W_OK) will report
failure (specifically EACCESS, permission denied) if you check it from
cygwin.

At first I just wanted to give names to the uids owning the Samba
server files.  Following Corinna's advice from a while back, I created
a series of /etc/passwd lines by taking the Unix uids, applying the
Samba conversion to get RIDs, then writing out lines with the RID as
the uid and the username as "SAMBA\juser".  This gave real usernames
to the uids, but didn't help with the access problems.  I then decided
the "SAMBA\" prefixes weren't buying me much, and removed them.  At
this point each user had two entries in the Cygwin /etc/passwd, one
for the DOM RID mapping to one UID, and the other for the SAMBA RID
mapping to another UID.  This made the output of "ls -l", etc., look
prettier, since users appeared to own their own files, but the
underlying uids still didn't match for things like access().

Finally I realized that, unlike a normal Unix passwd file, it made
sense for there to be multiple lines with the same name and uid.  In
normal Unix all you do is map from username to uid and back, so lines
like this would be meaningless.  With cygwin there's an extra mapping
from SID to uid, and that's when it helps to have multiple lines.  My
final solution was to write a Perl script that digests the Cygwin
"mkpasswd -d" output to get preferred name->uid mappings, then digests
the Unix passwd file to generate SAMBA+RID->uid mappings that match
the domain uids.  (The Samba SID base is available in the MACHINE.SID
file.)  Combining the initial "mkpasswd -d" output with the output of
this script gives us the final Cygwin /etc/passwd.  Now both
"DOM\juser" and "SAMBA\juser" files are mapped to the same uid and all
the cygwin functionality just works.

This still seems like something of an elaborate workaround,
unfortunately.  Ideally, of course, the Samba server would use the
user's domain SID.  But until that happens, it would be nice if there
was a way to coerce it into using the right SID.  Clearly we can reset
the MACHINE.SID to the domain SID base.  But the RIDs will still be
out of wack; we would need a table mapping uids to RIDs that Samba
could use.  (We can't do it "just" by changing all the Unix uids,
since the domain RIDs can be odd numbers, unlike Samba user RIDs.)

I've appended my version of the perl script I use to do this.  It
should be reasonably easy to customize.

I don't plan on pushing any further on this, but I'd be curious to
hear if anyone has any better strategies they've used in this
situation.

Chris

--
#!/usr/bin/perl

# This script builds a piece of the password file for Cygwin.
# It should be run on a Samba server; it parses the server's /etc/passwd
# and /etc/group and creates matching files in $TARGET_DIR
# suitable for appending to a cygwin /etc/{passwd,group}.
# It requires that the "mkpasswd -d" output be available in $TARGET_DIR.
# We use the SID of the host, from /etc/samba/MACHINE.SID, plus the
# computed ID (1000+uid*2, 1001+gid*2).  However, we map usernames
# that appear in the domain not to that $uid, but to the domain $uid,
# so that Cygwin thinks it's all the same.
#
# Hopefully this will all be unnecessary with a later release of Samba.
# See the discussion of "security = domain" in the Samba-HOWTO-Collection.

$TARGET_DIR = "/i/cygwin";

# Read the Samba server's SID into $sid.
open(SID, "/etc/samba/MACHINE.SID") ||
  die("Can't read /etc/samba/MACHINE.SID: $!\n");
$sid = <SID>;
close(SID);
chomp $sid;
die ("Bad format SID: $sid\n") if ($sid !~ /^S-/);

# Read the "mkpasswd -d" output and create %domuid, %domgid mappings.
open(DOMPASS, "$TARGET_DIR/passwd.domain") ||
  die("Can't read $TARGET_DIR/passwd.domain: $!\n");
while (<DOMPASS>) {
    ($name,$x,$uid,$gid) = split(":");
    $domuid{$name} = $uid;
    $domgid{$name} = $gid;
}
close(DOMPASS);

# Create the Cygwin passwd file piece from the Unix /etc/passwd.
open(PASSWD, "/etc/passwd") ||
  die("Can't read /etc/passwd: $!\n");
open(CYGPASS, ">$TARGET_DIR/passwd") ||
  die("Can't write $TARGET_DIR/passwd: $!\n");
while (<PASSWD>) {
  chomp $_;
  ($name,$x,$uid,$gid,$full,$home,$shell) = split(":");

  # Do any local home directory munging you need here.
  $home =~ s,^/u/,/h/,;
  $home = "/" if ($home !~ /^\/h\//);

  # Compute Samba-style uid/gid.
  $rid = ($uid*2)+1000;
  $uid = $rid;
  $uid = $domuid{$name} if (defined($domuid{$name}));
  $gid = ($gid*2)+1000;
  $gid = $domgid{$name} if (defined($domgid{$name}));

  # Generate appropriate new entry.
  print CYGPASS "$name:x:$uid:$gid:$full,U-RD\\$name,$sid-$rid:$home:$shell\n";
}
close(PASSWD);
close(CYGPASS);

# Create the Cygwin group file piece from the Unix /etc/group.
open(GROUP, "/etc/group") ||
  die("Can't read /etc/group: $!\n");
open(CYGGRP, ">$TARGET_DIR/group") ||
  die("Can't write $TARGET_DIR/group: $!\n");
while (<GROUP>) {
  chomp $_;
  ($name,$x,$gid,$members) = split(":");

  # Compute Samba-style gid.
  $gid = ($gid*2)+1001;

  # Generate appropriate new entry.
  print CYGGRP "$name:$sid-$gid:$gid:\n";
}
close(GROUP);
close(CYGGRP);



--
Unsubscribe info:      http://cygwin.com/ml/#unsubscribe-simple
Bug reporting:         http://cygwin.com/bugs.html
Documentation:         http://cygwin.com/docs.html
FAQ:                   http://cygwin.com/faq/


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]