OSDN Git Service

* fhandler.cc (fhandler_base::fhaccess): Accommodate interface changes
authorcorinna <corinna>
Fri, 20 Jul 2007 14:29:43 +0000 (14:29 +0000)
committercorinna <corinna>
Fri, 20 Jul 2007 14:29:43 +0000 (14:29 +0000)
of access control functions throughout.
* fhandler_disk_file.cc: Ditto.
* fhandler_registry.cc: Ditto.
* sec_acl.cc: Drop unnecessary includes.
(setacl): Take path_conv instead of file name as parameter.
Accommodate interface changes of access control functions.
(getacl): Ditto.
* sec_auth.cc: New file, taking over all authentication related
functions from security.cc.
* sec_helper.cc: Drop unnecessary includes.
* security.cc: Ditto.  Move all authentication related functions to
sec_auth.cc.
(ALL_SECURITY_INFORMATION): New define.  Use throughout.
(set_file_sd): New function, replacing read_sd and the file related
part of get_nt_object_security.
(get_reg_sd): Rename from get_reg_security.  Drop type parameter.
(get_reg_attribute): New function, replacing the registry related part
of get_nt_object_security.
(get_file_attribute): Take path_conv instead of file name as parameter.
Use new get_file_sd call.
(set_file_attribute): Ditto plus new set_file_sd.  Drop unnecessary
implementation without uid/gid parameters.
(check_file_access): Take path_conv instead of file name as parameter.
Use new get_file_sd call.
(check_registry_access): Use new get_reg_sd call.
* security.h: Accommodate above interface changes.

winsup/cygwin/ChangeLog
winsup/cygwin/Makefile.in
winsup/cygwin/fhandler.cc
winsup/cygwin/fhandler_disk_file.cc
winsup/cygwin/fhandler_registry.cc
winsup/cygwin/sec_acl.cc
winsup/cygwin/sec_auth.cc [new file with mode: 0644]
winsup/cygwin/sec_helper.cc
winsup/cygwin/security.cc
winsup/cygwin/security.h

index 47f009c..72cf45c 100644 (file)
@@ -1,3 +1,36 @@
+2007-07-20  Corinna Vinschen  <corinna@vinschen.de>
+
+       * Makefile.in (DLL_OFILES): Add sec_auth.o.
+
+
+       * fhandler.cc (fhandler_base::fhaccess): Accommodate interface changes
+       of access control functions throughout.
+       * fhandler_disk_file.cc: Ditto.
+       * fhandler_registry.cc: Ditto.
+       * sec_acl.cc: Drop unnecessary includes.
+       (setacl): Take path_conv instead of file name as parameter.
+       Accommodate interface changes of access control functions.
+       (getacl): Ditto.
+       * sec_auth.cc: New file, taking over all authentication related
+       functions from security.cc.
+       * sec_helper.cc: Drop unnecessary includes.
+       * security.cc: Ditto.  Move all authentication related functions to
+       sec_auth.cc.
+       (ALL_SECURITY_INFORMATION): New define.  Use throughout.
+       (set_file_sd): New function, replacing read_sd and the file related
+       part of get_nt_object_security.
+       (get_reg_sd): Rename from get_reg_security.  Drop type parameter.
+       (get_reg_attribute): New function, replacing the registry related part
+       of get_nt_object_security.
+       (get_file_attribute): Take path_conv instead of file name as parameter.
+       Use new get_file_sd call.
+       (set_file_attribute): Ditto plus new set_file_sd.  Drop unnecessary
+       implementation without uid/gid parameters.
+       (check_file_access): Take path_conv instead of file name as parameter.
+       Use new get_file_sd call.
+       (check_registry_access): Use new get_reg_sd call.
+       * security.h: Accommodate above interface changes.
+
 2007-07-19  Corinna Vinschen  <corinna@vinschen.de>
 
        * security.cc (set_nt_attribute): Remove.
index eb0c858..5251ff9 100644 (file)
@@ -139,12 +139,12 @@ DLL_OFILES:=assert.o autoload.o bsdlib.o ctype.o cxx.o cygheap.o cygthread.o \
        minires.o miscfuncs.o mktemp.o mmap.o msg.o net.o netdb.o nftw.o \
        passwd.o path.o pinfo.o pipe.o poll.o posix_ipc.o pthread.o random.o \
        regcomp.o regerror.o regexec.o regfree.o registry.o resource.o rexec.o \
-       rcmd.o scandir.o sched.o sec_acl.o sec_helper.o security.o select.o \
-       sem.o shared.o shm.o sigfe.o signal.o sigproc.o smallprint.o spawn.o \
-       strace.o strptime.o strsep.o strsig.o sync.o syscalls.o sysconf.o \
-       syslog.o termios.o thread.o timelocal.o timer.o times.o tty.o uinfo.o \
-       uname.o v8_regexp.o v8_regerror.o v8_regsub.o wait.o wincap.o window.o \
-       winf.o xsique.o \
+       rcmd.o scandir.o sched.o sec_acl.o sec_auth.o sec_helper.o security.o \
+       select.o sem.o shared.o shm.o sigfe.o signal.o sigproc.o smallprint.o \
+       spawn.o strace.o strptime.o strsep.o strsig.o sync.o syscalls.o \
+       sysconf.o syslog.o termios.o thread.o timelocal.o timer.o times.o \
+       tty.o uinfo.o uname.o v8_regexp.o v8_regerror.o v8_regsub.o wait.o \
+       wincap.o window.o winf.o xsique.o \
        $(EXTRA_DLL_OFILES) $(EXTRA_OFILES) $(MALLOC_OFILES) $(MT_SAFE_OBJECTS)
 
 GMON_OFILES:=gmon.o mcount.o profil.o
index 960b375..0ee0bbb 100644 (file)
@@ -374,7 +374,7 @@ fhandler_base::fhaccess (int flags)
     goto eaccess_done;
   else if (has_acls () && allow_ntsec)
     {
-      res = check_file_access (get_win32_name (), flags);
+      res = check_file_access (pc, flags);
       goto done;
     }
   else if (get_device () == FH_REGISTRY && allow_ntsec && open (O_RDONLY, 0)
index 5d37d04..59fcb44 100644 (file)
@@ -433,17 +433,15 @@ fhandler_base::fstat_helper (struct __stat64 *buf,
       buf->st_size = pc.get_symlink_length ();
       /* symlinks are everything for everyone! */
       buf->st_mode = S_IFLNK | S_IRWXU | S_IRWXG | S_IRWXO;
-      get_file_attribute (pc.has_acls (), get_io_handle (), get_win32_name (),
-                         NULL, &buf->st_uid, &buf->st_gid);
+      get_file_attribute (get_io_handle (), pc, NULL,
+                         &buf->st_uid, &buf->st_gid);
       goto done;
     }
   else if (pc.issocket ())
     buf->st_mode = S_IFSOCK;
 
-  if (!get_file_attribute (pc.has_acls (),
-                          is_fs_special () ? NULL: get_io_handle (),
-                          get_win32_name (), &buf->st_mode,
-                          &buf->st_uid, &buf->st_gid))
+  if (!get_file_attribute (is_fs_special () ? NULL: get_io_handle (), pc,
+                          &buf->st_mode, &buf->st_uid, &buf->st_gid))
     {
       /* If read-only attribute is set, modify ntsec return value */
       if (::has_attribute (dwFileAttributes, FILE_ATTRIBUTE_READONLY)
@@ -660,7 +658,7 @@ fhandler_disk_file::fchmod (mode_t mode)
     {
       if (pc.isdir ())
        mode |= S_IFDIR;
-      if (!set_file_attribute (pc.has_acls (), get_io_handle (), pc,
+      if (!set_file_attribute (get_io_handle (), pc,
                               ILLEGAL_UID, ILLEGAL_GID, mode)
          && allow_ntsec)
        res = 0;
@@ -706,7 +704,7 @@ fhandler_disk_file::fchown (__uid32_t uid, __gid32_t gid)
   mode_t attrib = 0;
   if (pc.isdir ())
     attrib |= S_IFDIR;
-  int res = get_file_attribute (pc.has_acls (), get_io_handle (), pc, &attrib);
+  int res = get_file_attribute (get_io_handle (), pc, &attrib, NULL, NULL);
   if (!res)
     {
       /* Typical Windows default ACLs can contain permissions for one
@@ -718,8 +716,7 @@ fhandler_disk_file::fchown (__uid32_t uid, __gid32_t gid)
         world to read the symlink and only the new owner to change it. */
       if (pc.issymlink ())
        attrib = S_IFLNK | STD_RBITS | STD_WBITS;
-      res = set_file_attribute (pc.has_acls (), get_io_handle (), pc,
-                               uid, gid, attrib);
+      res = set_file_attribute (get_io_handle (), pc, uid, gid, attrib);
     }
   if (oret)
     close ();
@@ -808,10 +805,10 @@ fhandler_disk_file::facl (int cmd, int nentries, __aclent32_t *aclbufp)
            if (!aclbufp)
              set_errno(EFAULT);
            else
-             res = getacl (get_io_handle (), pc, pc, nentries, aclbufp);
+             res = getacl (get_io_handle (), pc, nentries, aclbufp);
            break;
          case GETACLCNT:
-           res = getacl (get_io_handle (), pc, pc, 0, NULL);
+           res = getacl (get_io_handle (), pc, 0, NULL);
            break;
          default:
            set_errno (EINVAL);
index 62cd8f4..23d88c8 100644 (file)
@@ -269,9 +269,7 @@ fhandler_registry::fstat (struct __stat64 *buf)
                }
              __uid32_t uid;
              __gid32_t gid;
-             if (get_object_attribute
-                 ((HANDLE) hKey, SE_REGISTRY_KEY, &buf->st_mode, &uid,
-                  &gid) == 0)
+             if (get_reg_attribute (hKey, &buf->st_mode, &uid, &gid) == 0)
                {
                  buf->st_uid = uid;
                  buf->st_gid = gid;
index 87c6428..54d443b 100644 (file)
@@ -11,17 +11,9 @@ Cygwin license.  Please consult the file "CYGWIN_LICENSE" for
 details. */
 
 #include "winsup.h"
-#include <grp.h>
-#include <pwd.h>
-#include <unistd.h>
 #include <stdlib.h>
-#include <limits.h>
-#include <sys/types.h>
-#include <sys/stat.h>
 #include <sys/acl.h>
 #include <ctype.h>
-#include <wingdi.h>
-#include <winuser.h>
 #include "cygerrno.h"
 #include "security.h"
 #include "path.h"
@@ -44,17 +36,13 @@ searchace (__aclent32_t *aclp, int nentries, int type, __uid32_t id = ILLEGAL_UI
 }
 
 int
-setacl (HANDLE handle, const char *file, int nentries, __aclent32_t *aclbufp,
+setacl (HANDLE handle, path_conv &pc, int nentries, __aclent32_t *aclbufp,
        bool &writable)
 {
   security_descriptor sd_ret;
 
-  if ((!handle || get_nt_object_security (handle, SE_FILE_OBJECT, sd_ret))
-      && read_sd (file, sd_ret) <= 0)
-    {
-      debug_printf ("read_sd %E");
-      return -1;
-    }
+  if (get_file_sd (handle, pc, sd_ret))
+    return -1;
 
   BOOL dummy;
 
@@ -227,7 +215,7 @@ setacl (HANDLE handle, const char *file, int nentries, __aclent32_t *aclbufp,
       return -1;
     }
   debug_printf ("Created SD-Size: %d", sd_ret.size ());
-  return write_sd (handle, file, sd_ret);
+  return set_file_sd (handle, pc, sd_ret);
 }
 
 /* Temporary access denied bits */
@@ -262,17 +250,12 @@ getace (__aclent32_t &acl, int type, int id, DWORD win_ace_mask,
 }
 
 int
-getacl (HANDLE handle, const char *file, DWORD attr, int nentries,
-       __aclent32_t *aclbufp)
+getacl (HANDLE handle, path_conv &pc, int nentries, __aclent32_t *aclbufp)
 {
   security_descriptor sd;
 
-  if ((!handle || get_nt_object_security (handle, SE_FILE_OBJECT, sd))
-      && read_sd (file, sd) <= 0)
-    {
-      debug_printf ("read_sd %E");
-      return -1;
-    }
+  if (get_file_sd (handle, pc, sd))
+    return -1;
 
   cygpsid owner_sid;
   cygpsid group_sid;
@@ -372,7 +355,7 @@ getacl (HANDLE handle, const char *file, DWORD attr, int nentries,
                getace (lacl[pos], type, id, ace->Mask, ace->Header.AceType);
            }
          if ((ace->Header.AceFlags & SUB_CONTAINERS_AND_OBJECTS_INHERIT)
-             && (attr & FILE_ATTRIBUTE_DIRECTORY))
+             && pc.isdir ())
            {
              if (type == USER_OBJ)
                type = USER;
@@ -408,7 +391,7 @@ getacl (HANDLE handle, const char *file, DWORD attr, int nentries,
       aclbufp[i].a_perm &= ~(DENY_R | DENY_W | DENY_X);
     aclsort32 (pos, 0, aclbufp);
   }
-  syscall_printf ("%d = getacl (%s)", pos, file);
+  syscall_printf ("%d = getacl (%s)", pos, pc.get_win32 ());
   return pos;
 }
 
diff --git a/winsup/cygwin/sec_auth.cc b/winsup/cygwin/sec_auth.cc
new file mode 100644 (file)
index 0000000..7cf2cb4
--- /dev/null
@@ -0,0 +1,1119 @@
+/* sec_auth.cc: NT authentication functions
+
+   Copyright 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
+   2006, 2007 Red Hat, Inc.
+
+This file is part of Cygwin.
+
+This software is a copyrighted work licensed under the terms of the
+Cygwin license.  Please consult the file "CYGWIN_LICENSE" for
+details. */
+
+#include "winsup.h"
+#include <stdlib.h>
+#include <wininet.h>
+#include <ntsecapi.h>
+#include <dsgetdc.h>
+#include "cygerrno.h"
+#include "security.h"
+#include "path.h"
+#include "fhandler.h"
+#include "dtable.h"
+#include "pinfo.h"
+#include "cygheap.h"
+#include "ntdll.h"
+#include "lm.h"
+#include "pwdgrp.h"
+#include "cyglsa.h"
+#include <cygwin/version.h>
+
+extern "C" void
+cygwin_set_impersonation_token (const HANDLE hToken)
+{
+  debug_printf ("set_impersonation_token (%d)", hToken);
+  cygheap->user.external_token = hToken == INVALID_HANDLE_VALUE ? NO_IMPERSONATION : hToken;
+}
+
+void
+extract_nt_dom_user (const struct passwd *pw, char *domain, char *user)
+{
+  char *d, *u, *c;
+
+  domain[0] = 0;
+  strlcpy (user, pw->pw_name, UNLEN + 1);
+  debug_printf ("pw_gecos %x (%s)", pw->pw_gecos, pw->pw_gecos);
+
+  if ((d = strstr (pw->pw_gecos, "U-")) != NULL &&
+      (d == pw->pw_gecos || d[-1] == ','))
+    {
+      c = strechr (d + 2, ',');
+      if ((u = strechr (d + 2, '\\')) >= c)
+       u = d + 1;
+      else if (u - d <= INTERNET_MAX_HOST_NAME_LENGTH + 2)
+       strlcpy (domain, d + 2, u - d - 1);
+      if (c - u <= UNLEN + 1)
+       strlcpy (user, u + 1, c - u);
+    }
+  if (domain[0])
+    return;
+
+  cygsid psid;
+  DWORD ulen = UNLEN + 1;
+  DWORD dlen = INTERNET_MAX_HOST_NAME_LENGTH + 1;
+  SID_NAME_USE use;
+  if (psid.getfrompw (pw))
+    LookupAccountSid (NULL, psid, user, &ulen, domain, &dlen, &use);
+}
+
+extern "C" HANDLE
+cygwin_logon_user (const struct passwd *pw, const char *password)
+{
+  if (!pw)
+    {
+      set_errno (EINVAL);
+      return INVALID_HANDLE_VALUE;
+    }
+
+  char nt_domain[INTERNET_MAX_HOST_NAME_LENGTH + 1];
+  char nt_user[UNLEN + 1];
+  HANDLE hToken;
+
+  extract_nt_dom_user (pw, nt_domain, nt_user);
+  debug_printf ("LogonUserA (%s, %s, %s, ...)", nt_user, nt_domain, password);
+  /* CV 2005-06-08: LogonUser should run under the primary process token,
+     otherwise it returns with ERROR_ACCESS_DENIED on W2K. Don't ask me why. */
+  RevertToSelf ();
+  if (!LogonUserA (nt_user, *nt_domain ? nt_domain : NULL, (char *) password,
+                  LOGON32_LOGON_INTERACTIVE,
+                  LOGON32_PROVIDER_DEFAULT,
+                  &hToken))
+    {
+      __seterrno ();
+      hToken = INVALID_HANDLE_VALUE;
+    }
+  else if (!SetHandleInformation (hToken,
+                                 HANDLE_FLAG_INHERIT,
+                                 HANDLE_FLAG_INHERIT))
+    {
+      __seterrno ();
+      CloseHandle (hToken);
+      hToken = INVALID_HANDLE_VALUE;
+    }
+  cygheap->user.reimpersonate ();
+  debug_printf ("%d = logon_user(%s,...)", hToken, pw->pw_name);
+  return hToken;
+}
+
+static void
+str2lsa (LSA_STRING &tgt, const char *srcstr)
+{
+  tgt.Length = strlen (srcstr);
+  tgt.MaximumLength = tgt.Length + 1;
+  tgt.Buffer = (PCHAR) srcstr;
+}
+
+static void
+str2buf2lsa (LSA_STRING &tgt, char *buf, const char *srcstr)
+{
+  tgt.Length = strlen (srcstr);
+  tgt.MaximumLength = tgt.Length + 1;
+  tgt.Buffer = (PCHAR) buf;
+  memcpy (buf, srcstr, tgt.MaximumLength);
+}
+
+/* The dimension of buf is assumed to be at least strlen(srcstr) + 1,
+   The result will be shorter if the input has multibyte chars */
+void
+str2buf2uni (UNICODE_STRING &tgt, WCHAR *buf, const char *srcstr)
+{
+  tgt.Buffer = (PWCHAR) buf;
+  tgt.MaximumLength = (strlen (srcstr) + 1) * sizeof (WCHAR);
+  tgt.Length = sys_mbstowcs (buf, srcstr, tgt.MaximumLength / sizeof (WCHAR))
+              * sizeof (WCHAR);
+  if (tgt.Length)
+    tgt.Length -= sizeof (WCHAR);
+}
+
+void
+str2uni_cat (UNICODE_STRING &tgt, const char *srcstr)
+{
+  int len = sys_mbstowcs (tgt.Buffer + tgt.Length / sizeof (WCHAR), srcstr,
+                         (tgt.MaximumLength - tgt.Length) / sizeof (WCHAR));
+  if (len)
+    tgt.Length += (len - 1) * sizeof (WCHAR);
+  else
+    tgt.Length = tgt.MaximumLength = 0;
+}
+
+static LSA_HANDLE
+open_local_policy ()
+{
+  LSA_OBJECT_ATTRIBUTES oa = { 0, 0, 0, 0, 0, 0 };
+  LSA_HANDLE lsa = INVALID_HANDLE_VALUE;
+
+  NTSTATUS ret = LsaOpenPolicy (NULL, &oa, POLICY_EXECUTE, &lsa);
+  if (ret != STATUS_SUCCESS)
+    __seterrno_from_win_error (LsaNtStatusToWinError (ret));
+  return lsa;
+}
+
+static void
+close_local_policy (LSA_HANDLE &lsa)
+{
+  if (lsa != INVALID_HANDLE_VALUE)
+    LsaClose (lsa);
+  lsa = INVALID_HANDLE_VALUE;
+}
+
+/* CV, 2006-07-06: Missing in w32api. */
+extern "C" DWORD WINAPI DsGetDcNameA (LPCSTR, LPCSTR, GUID *, LPCSTR, ULONG,
+                                     PDOMAIN_CONTROLLER_INFOA *);
+#define DS_FORCE_REDISCOVERY   1
+
+bool
+get_logon_server (const char *domain, char *server, WCHAR *wserver,
+                 bool rediscovery)
+{
+  DWORD dret;
+  PDOMAIN_CONTROLLER_INFOA pci;
+  WCHAR *buf;
+  DWORD size = INTERNET_MAX_HOST_NAME_LENGTH + 1;
+  WCHAR wdomain[size];
+
+  /* Empty domain is interpreted as local system */
+  if ((GetComputerName (server + 2, &size)) &&
+      (strcasematch (domain, server + 2) || !domain[0]))
+    {
+      server[0] = server[1] = '\\';
+      if (wserver)
+       sys_mbstowcs (wserver, server, INTERNET_MAX_HOST_NAME_LENGTH + 1);
+      return true;
+    }
+
+  /* Try to get any available domain controller for this domain */
+  dret = DsGetDcNameA (NULL, domain, NULL, NULL,
+                      rediscovery ? DS_FORCE_REDISCOVERY : 0, &pci);
+  if (dret == ERROR_SUCCESS)
+    {
+      strcpy (server, pci->DomainControllerName);
+      sys_mbstowcs (wserver, server, INTERNET_MAX_HOST_NAME_LENGTH + 1);
+      NetApiBufferFree (pci);
+      debug_printf ("DC: rediscovery: %d, server: %s", rediscovery, server);
+      return true;
+    }
+  else if (dret == ERROR_PROC_NOT_FOUND)
+    {
+      /* NT4 w/o DSClient */
+      sys_mbstowcs (wdomain, domain, INTERNET_MAX_HOST_NAME_LENGTH + 1);
+      if (rediscovery)
+       dret = NetGetAnyDCName (NULL, wdomain, (LPBYTE *) &buf);
+      else
+       dret = NetGetDCName (NULL, wdomain, (LPBYTE *) &buf);
+      if (dret == NERR_Success)
+       {
+         sys_wcstombs (server, INTERNET_MAX_HOST_NAME_LENGTH + 1, buf);
+         if (wserver)
+           for (WCHAR *ptr1 = buf; (*wserver++ = *ptr1++);)
+             ;
+         NetApiBufferFree (buf);
+         debug_printf ("NT: rediscovery: %d, server: %s", rediscovery, server);
+         return true;
+       }
+    }
+  __seterrno_from_win_error (dret);
+  return false;
+}
+
+static bool
+get_user_groups (WCHAR *wlogonserver, cygsidlist &grp_list, char *user,
+                char *domain)
+{
+  char dgroup[INTERNET_MAX_HOST_NAME_LENGTH + GNLEN + 2];
+  WCHAR wuser[UNLEN + 1];
+  sys_mbstowcs (wuser, user, UNLEN + 1);
+  LPGROUP_USERS_INFO_0 buf;
+  DWORD cnt, tot, len;
+  NET_API_STATUS ret;
+
+  /* Look only on logonserver */
+  ret = NetUserGetGroups (wlogonserver, wuser, 0, (LPBYTE *) &buf,
+                         MAX_PREFERRED_LENGTH, &cnt, &tot);
+  if (ret)
+    {
+      __seterrno_from_win_error (ret);
+      /* It's no error when the user name can't be found. */
+      return ret == NERR_UserNotFound;
+    }
+
+  len = strlen (domain);
+  strcpy (dgroup, domain);
+  dgroup[len++] = '\\';
+
+  for (DWORD i = 0; i < cnt; ++i)
+    {
+      cygsid gsid;
+      DWORD glen = MAX_SID_LEN;
+      char domain[INTERNET_MAX_HOST_NAME_LENGTH + 1];
+      DWORD dlen = sizeof (domain);
+      SID_NAME_USE use = SidTypeInvalid;
+
+      sys_wcstombs (dgroup + len, GNLEN + 1, buf[i].grui0_name);
+      if (!LookupAccountName (NULL, dgroup, gsid, &glen, domain, &dlen, &use))
+       debug_printf ("LookupAccountName(%s), %E", dgroup);
+      else if (legal_sid_type (use))
+       grp_list += gsid;
+      else
+       debug_printf ("Global group %s invalid. Domain: %s Use: %d",
+                     dgroup, domain, use);
+    }
+
+  NetApiBufferFree (buf);
+  return true;
+}
+
+static bool
+is_group_member (WCHAR *wgroup, PSID pusersid, cygsidlist &grp_list)
+{
+  LPLOCALGROUP_MEMBERS_INFO_1 buf;
+  DWORD cnt, tot;
+  NET_API_STATUS ret;
+
+  /* Members can be users or global groups */
+  ret = NetLocalGroupGetMembers (NULL, wgroup, 1, (LPBYTE *) &buf,
+                                MAX_PREFERRED_LENGTH, &cnt, &tot, NULL);
+  if (ret)
+    return false;
+
+  bool retval = true;
+  for (DWORD bidx = 0; bidx < cnt; ++bidx)
+    if (EqualSid (pusersid, buf[bidx].lgrmi1_sid))
+      goto done;
+    else
+      {
+       /* The extra test for the group being a global group or a well-known
+          group is necessary, since apparently also aliases (for instance
+          Administrators or Users) can be members of local groups, even
+          though MSDN states otherwise.  The GUI refuses to put aliases into
+          local groups, but the CLI interface allows it.  However, a normal
+          logon token does not contain groups, in which the user is only
+          indirectly a member by being a member of an alias in this group.
+          So we also should not put them into the token group list.
+          Note: Allowing those groups in our group list renders external
+          tokens invalid, so that it becomes impossible to logon with
+          password and valid logon token. */
+       for (int glidx = 0; glidx < grp_list.count (); ++glidx)
+         if ((buf[bidx].lgrmi1_sidusage == SidTypeGroup
+              || buf[bidx].lgrmi1_sidusage == SidTypeWellKnownGroup)
+             && EqualSid (grp_list.sids[glidx], buf[bidx].lgrmi1_sid))
+           goto done;
+      }
+
+  retval = false;
+ done:
+  NetApiBufferFree (buf);
+  return retval;
+}
+
+static bool
+get_user_local_groups (cygsidlist &grp_list, PSID pusersid)
+{
+  LPLOCALGROUP_INFO_0 buf;
+  DWORD cnt, tot;
+  NET_API_STATUS ret;
+
+  ret = NetLocalGroupEnum (NULL, 0, (LPBYTE *) &buf,
+                          MAX_PREFERRED_LENGTH, &cnt, &tot, NULL);
+  if (ret)
+    {
+      __seterrno_from_win_error (ret);
+      return false;
+    }
+
+  char bgroup[INTERNET_MAX_HOST_NAME_LENGTH + GNLEN + 2];
+  char lgroup[INTERNET_MAX_HOST_NAME_LENGTH + GNLEN + 2];
+  DWORD blen, llen;
+  SID_NAME_USE use;
+
+  blen = llen = INTERNET_MAX_HOST_NAME_LENGTH + 1;
+  if (!LookupAccountSid (NULL, well_known_admins_sid, lgroup, &llen, bgroup, &blen, &use)
+      || !GetComputerNameA (lgroup, &(llen = INTERNET_MAX_HOST_NAME_LENGTH + 1)))
+    {
+      __seterrno ();
+      return false;
+    }
+  bgroup[blen++] = lgroup[llen++] = '\\';
+
+  for (DWORD i = 0; i < cnt; ++i)
+    if (is_group_member (buf[i].lgrpi0_name, pusersid, grp_list))
+      {
+       cygsid gsid;
+       DWORD glen = MAX_SID_LEN;
+       char domain[INTERNET_MAX_HOST_NAME_LENGTH + 1];
+       DWORD dlen = sizeof (domain);
+
+       use = SidTypeInvalid;
+       sys_wcstombs (bgroup + blen, GNLEN + 1, buf[i].lgrpi0_name);
+       if (!LookupAccountName (NULL, bgroup, gsid, &glen, domain, &dlen, &use))
+         {
+           if (GetLastError () != ERROR_NONE_MAPPED)
+             debug_printf ("LookupAccountName(%s), %E", bgroup);
+           strcpy (lgroup + llen, bgroup + blen);
+           if (!LookupAccountName (NULL, lgroup, gsid, &glen,
+                                   domain, &dlen, &use))
+             debug_printf ("LookupAccountName(%s), %E", lgroup);
+         }
+       if (!legal_sid_type (use))
+         debug_printf ("Rejecting local %s. use: %d", bgroup + blen, use);
+       grp_list *= gsid;
+      }
+  NetApiBufferFree (buf);
+  return true;
+}
+
+static bool
+sid_in_token_groups (PTOKEN_GROUPS grps, cygpsid sid)
+{
+  if (!grps)
+    return false;
+  for (DWORD i = 0; i < grps->GroupCount; ++i)
+    if (sid == grps->Groups[i].Sid)
+      return true;
+  return false;
+}
+
+static void
+get_unix_group_sidlist (struct passwd *pw, cygsidlist &grp_list)
+{
+  struct __group32 *gr;
+  cygsid gsid;
+
+  for (int gidx = 0; (gr = internal_getgrent (gidx)); ++gidx)
+    {
+      if (gr->gr_gid == (__gid32_t) pw->pw_gid)
+       goto found;
+      else if (gr->gr_mem)
+       for (int gi = 0; gr->gr_mem[gi]; ++gi)
+         if (strcasematch (pw->pw_name, gr->gr_mem[gi]))
+           goto found;
+      continue;
+    found:
+      if (gsid.getfromgr (gr))
+       grp_list += gsid;
+
+    }
+}
+
+static void
+get_token_group_sidlist (cygsidlist &grp_list, PTOKEN_GROUPS my_grps,
+                        LUID auth_luid, int &auth_pos)
+{
+  auth_pos = -1;
+  if (my_grps)
+    {
+      grp_list += well_known_local_sid;
+      if (sid_in_token_groups (my_grps, well_known_dialup_sid))
+       grp_list *= well_known_dialup_sid;
+      if (sid_in_token_groups (my_grps, well_known_network_sid))
+       grp_list *= well_known_network_sid;
+      if (sid_in_token_groups (my_grps, well_known_batch_sid))
+       grp_list *= well_known_batch_sid;
+      grp_list *= well_known_interactive_sid;
+      if (sid_in_token_groups (my_grps, well_known_service_sid))
+       grp_list *= well_known_service_sid;
+      if (sid_in_token_groups (my_grps, well_known_this_org_sid))
+       grp_list *= well_known_this_org_sid;
+    }
+  else
+    {
+      grp_list += well_known_local_sid;
+      grp_list *= well_known_interactive_sid;
+    }
+  if (get_ll (auth_luid) != 999LL) /* != SYSTEM_LUID */
+    {
+      for (DWORD i = 0; i < my_grps->GroupCount; ++i)
+       if (my_grps->Groups[i].Attributes & SE_GROUP_LOGON_ID)
+         {
+           grp_list += my_grps->Groups[i].Sid;
+           auth_pos = grp_list.count () - 1;
+           break;
+         }
+    }
+}
+
+bool
+get_server_groups (cygsidlist &grp_list, PSID usersid, struct passwd *pw)
+{
+  char user[UNLEN + 1];
+  char domain[INTERNET_MAX_HOST_NAME_LENGTH + 1];
+  WCHAR wserver[INTERNET_MAX_HOST_NAME_LENGTH + 3];
+  char server[INTERNET_MAX_HOST_NAME_LENGTH + 3];
+
+  if (well_known_system_sid == usersid)
+    {
+      grp_list *= well_known_admins_sid;
+      get_unix_group_sidlist (pw, grp_list);
+      return true;
+    }
+
+  grp_list *= well_known_world_sid;
+  grp_list *= well_known_authenticated_users_sid;
+  extract_nt_dom_user (pw, domain, user);
+  if (get_logon_server (domain, server, wserver, false)
+      && !get_user_groups (wserver, grp_list, user, domain)
+      && get_logon_server (domain, server, wserver, true))
+    get_user_groups (wserver, grp_list, user, domain);
+  if (get_user_local_groups (grp_list, usersid))
+    {
+      get_unix_group_sidlist (pw, grp_list);
+      return true;
+    }
+  return false;
+}
+
+static bool
+get_initgroups_sidlist (cygsidlist &grp_list,
+                       PSID usersid, PSID pgrpsid, struct passwd *pw,
+                       PTOKEN_GROUPS my_grps, LUID auth_luid, int &auth_pos)
+{
+  grp_list *= well_known_world_sid;
+  grp_list *= well_known_authenticated_users_sid;
+  if (well_known_system_sid == usersid)
+    auth_pos = -1;
+  else
+    get_token_group_sidlist (grp_list, my_grps, auth_luid, auth_pos);
+  if (!get_server_groups (grp_list, usersid, pw))
+    return false;
+
+  /* special_pgrp true if pgrpsid is not in normal groups */
+  grp_list += pgrpsid;
+  return true;
+}
+
+static void
+get_setgroups_sidlist (cygsidlist &tmp_list, PSID usersid, struct passwd *pw,
+                      PTOKEN_GROUPS my_grps, user_groups &groups,
+                      LUID auth_luid, int &auth_pos)
+{
+  tmp_list *= well_known_world_sid;
+  tmp_list *= well_known_authenticated_users_sid;
+  get_token_group_sidlist (tmp_list, my_grps, auth_luid, auth_pos);
+  get_server_groups (tmp_list, usersid, pw);
+  for (int gidx = 0; gidx < groups.sgsids.count (); gidx++)
+    tmp_list += groups.sgsids.sids[gidx];
+  tmp_list += groups.pgsid;
+}
+
+static ULONG sys_privs[] = {
+  SE_CREATE_TOKEN_PRIVILEGE,
+  SE_ASSIGNPRIMARYTOKEN_PRIVILEGE,             
+  SE_LOCK_MEMORY_PRIVILEGE,            
+  SE_INCREASE_QUOTA_PRIVILEGE,         
+  SE_TCB_PRIVILEGE,            
+  SE_SECURITY_PRIVILEGE,               
+  SE_TAKE_OWNERSHIP_PRIVILEGE,         
+  SE_LOAD_DRIVER_PRIVILEGE,            
+  SE_SYSTEM_PROFILE_PRIVILEGE,         /* Vista ONLY */
+  SE_SYSTEMTIME_PRIVILEGE,             
+  SE_PROF_SINGLE_PROCESS_PRIVILEGE,            
+  SE_INC_BASE_PRIORITY_PRIVILEGE,              
+  SE_CREATE_PAGEFILE_PRIVILEGE,                
+  SE_CREATE_PERMANENT_PRIVILEGE,               
+  SE_BACKUP_PRIVILEGE,         
+  SE_RESTORE_PRIVILEGE,                
+  SE_SHUTDOWN_PRIVILEGE,               
+  SE_DEBUG_PRIVILEGE,          
+  SE_AUDIT_PRIVILEGE,          
+  SE_SYSTEM_ENVIRONMENT_PRIVILEGE,             
+  SE_CHANGE_NOTIFY_PRIVILEGE,          
+  SE_UNDOCK_PRIVILEGE,
+  SE_MANAGE_VOLUME_PRIVILEGE,
+  SE_IMPERSONATE_PRIVILEGE,
+  SE_CREATE_GLOBAL_PRIVILEGE,
+  SE_INCREASE_WORKING_SET_PRIVILEGE,
+  SE_TIME_ZONE_PRIVILEGE,
+  SE_CREATE_SYMBOLIC_LINK_PRIVILEGE
+};
+
+#define SYSTEM_PRIVILEGES_COUNT (sizeof sys_privs / sizeof *sys_privs)
+
+static PTOKEN_PRIVILEGES
+get_system_priv_list (size_t &size)
+{
+  ULONG max_idx = 0;
+  while (max_idx < SYSTEM_PRIVILEGES_COUNT
+        && sys_privs[max_idx] != wincap.max_sys_priv ())
+    ++max_idx;
+  if (max_idx >= SYSTEM_PRIVILEGES_COUNT)
+    api_fatal ("Coding error: wincap privilege %u doesn't exist in sys_privs",
+              wincap.max_sys_priv ());
+  size = sizeof (ULONG) + (max_idx + 1) * sizeof (LUID_AND_ATTRIBUTES);
+  PTOKEN_PRIVILEGES privs = (PTOKEN_PRIVILEGES) malloc (size);
+  if (!privs)
+    {
+      debug_printf ("malloc (system_privs) failed.");
+      return NULL;
+    }
+  privs->PrivilegeCount = 0;
+  for (ULONG i = 0; i <= max_idx; ++i)
+    {
+      privs->Privileges[privs->PrivilegeCount].Luid.HighPart = 0L;
+      privs->Privileges[privs->PrivilegeCount].Luid.LowPart = sys_privs[i];
+      privs->Privileges[privs->PrivilegeCount].Attributes =
+       SE_PRIVILEGE_ENABLED | SE_PRIVILEGE_ENABLED_BY_DEFAULT;
+      ++privs->PrivilegeCount;
+    }
+  return privs;
+}
+
+static PTOKEN_PRIVILEGES
+get_priv_list (LSA_HANDLE lsa, cygsid &usersid, cygsidlist &grp_list,
+              size_t &size)
+{
+  PLSA_UNICODE_STRING privstrs;
+  ULONG cnt;
+  PTOKEN_PRIVILEGES privs = NULL;
+  NTSTATUS ret;
+  char buf[INTERNET_MAX_HOST_NAME_LENGTH + 1];
+
+  if (usersid == well_known_system_sid)
+    return get_system_priv_list (size);
+
+  for (int grp = -1; grp < grp_list.count (); ++grp)
+    {
+      if (grp == -1)
+       {
+         if ((ret = LsaEnumerateAccountRights (lsa, usersid, &privstrs,
+                                               &cnt)) != STATUS_SUCCESS)
+           continue;
+       }
+      else if ((ret = LsaEnumerateAccountRights (lsa, grp_list.sids[grp],
+                                                &privstrs, &cnt))
+              != STATUS_SUCCESS)
+       continue;
+      for (ULONG i = 0; i < cnt; ++i)
+       {
+         LUID priv;
+         PTOKEN_PRIVILEGES tmp;
+         DWORD tmp_count;
+
+         sys_wcstombs (buf, sizeof (buf),
+                       privstrs[i].Buffer, privstrs[i].Length / 2);
+         if (!privilege_luid (buf, &priv))
+           continue;
+
+         if (privs)
+           {
+             DWORD pcnt = privs->PrivilegeCount;
+             LUID_AND_ATTRIBUTES *p = privs->Privileges;
+             for (; pcnt > 0; --pcnt, ++p)
+               if (priv.HighPart == p->Luid.HighPart
+                   && priv.LowPart == p->Luid.LowPart)
+                 goto next_account_right;
+           }
+
+         tmp_count = privs ? privs->PrivilegeCount : 0;
+         size = sizeof (DWORD)
+                + (tmp_count + 1) * sizeof (LUID_AND_ATTRIBUTES);
+         tmp = (PTOKEN_PRIVILEGES) realloc (privs, size);
+         if (!tmp)
+           {
+             if (privs)
+               free (privs);
+             LsaFreeMemory (privstrs);
+             debug_printf ("realloc (privs) failed.");
+             return NULL;
+           }
+         tmp->PrivilegeCount = tmp_count;
+         privs = tmp;
+         privs->Privileges[privs->PrivilegeCount].Luid = priv;
+         privs->Privileges[privs->PrivilegeCount].Attributes =
+           SE_PRIVILEGE_ENABLED | SE_PRIVILEGE_ENABLED_BY_DEFAULT;
+         ++privs->PrivilegeCount;
+
+       next_account_right:
+         ;
+       }
+      LsaFreeMemory (privstrs);
+    }
+  return privs;
+}
+
+/* Accept a token if
+   - the requested usersid matches the TokenUser and
+   - if setgroups has been called:
+       the token groups that are listed in /etc/group match the union of
+       the requested primary and supplementary groups in gsids.
+   - else the (unknown) implicitly requested supplementary groups and those
+       in the token are the groups associated with the usersid. We assume
+       they match and verify only the primary groups.
+       The requested primary group must appear in the token.
+       The primary group in the token is a group associated with the usersid,
+       except if the token is internal and the group is in the token SD
+       (see create_token). In that latter case that group must match the
+       requested primary group.  */
+bool
+verify_token (HANDLE token, cygsid &usersid, user_groups &groups, bool *pintern)
+{
+  DWORD size;
+  bool intern = false;
+
+  if (pintern)
+    {
+      TOKEN_SOURCE ts;
+      if (!GetTokenInformation (token, TokenSource,
+                               &ts, sizeof ts, &size))
+       debug_printf ("GetTokenInformation(), %E");
+      else
+       *pintern = intern = !memcmp (ts.SourceName, "Cygwin.1", 8);
+    }
+  /* Verify usersid */
+  cygsid tok_usersid = NO_SID;
+  if (!GetTokenInformation (token, TokenUser,
+                           &tok_usersid, sizeof tok_usersid, &size))
+    debug_printf ("GetTokenInformation(), %E");
+  if (usersid != tok_usersid)
+    return false;
+
+  /* For an internal token, if setgroups was not called and if the sd group
+     is not well_known_null_sid, it must match pgrpsid */
+  if (intern && !groups.issetgroups ())
+    {
+      const DWORD sd_buf_siz = MAX_SID_LEN + sizeof (SECURITY_DESCRIPTOR);
+      PSECURITY_DESCRIPTOR sd_buf = (PSECURITY_DESCRIPTOR) alloca (sd_buf_siz);
+      cygpsid gsid (NO_SID);
+      if (!GetKernelObjectSecurity (token, GROUP_SECURITY_INFORMATION,
+                                   sd_buf, sd_buf_siz, &size))
+       debug_printf ("GetKernelObjectSecurity(), %E");
+      else if (!GetSecurityDescriptorGroup (sd_buf, (PSID *) &gsid,
+                                           (BOOL *) &size))
+       debug_printf ("GetSecurityDescriptorGroup(), %E");
+      if (well_known_null_sid != gsid)
+       return gsid == groups.pgsid;
+    }
+
+  PTOKEN_GROUPS my_grps;
+  bool sawpg = false, ret = false;
+
+  if (!GetTokenInformation (token, TokenGroups, NULL, 0, &size) &&
+      GetLastError () != ERROR_INSUFFICIENT_BUFFER)
+    debug_printf ("GetTokenInformation(token, TokenGroups), %E");
+  else if (!(my_grps = (PTOKEN_GROUPS) alloca (size)))
+    debug_printf ("alloca (my_grps) failed.");
+  else if (!GetTokenInformation (token, TokenGroups, my_grps, size, &size))
+    debug_printf ("GetTokenInformation(my_token, TokenGroups), %E");
+  else
+    {
+      if (groups.issetgroups ()) /* setgroups was called */
+       {
+         cygsid gsid;
+         struct __group32 *gr;
+         bool saw[groups.sgsids.count ()];
+         memset (saw, 0, sizeof(saw));
+
+         /* token groups found in /etc/group match the user.gsids ? */
+         for (int gidx = 0; (gr = internal_getgrent (gidx)); ++gidx)
+           if (gsid.getfromgr (gr) && sid_in_token_groups (my_grps, gsid))
+             {
+               int pos = groups.sgsids.position (gsid);
+               if (pos >= 0)
+                 saw[pos] = true;
+               else if (groups.pgsid == gsid)
+                 sawpg = true;
+               else if (gsid != well_known_world_sid
+                        && gsid != usersid)
+                 goto done;
+             }
+         /* user.sgsids groups must be in the token */
+         for (int gidx = 0; gidx < groups.sgsids.count (); gidx++)
+           if (!saw[gidx] && !sid_in_token_groups (my_grps, groups.sgsids.sids[gidx]))
+             goto done;
+       }
+      /* The primary group must be in the token */
+      ret = sawpg
+       || sid_in_token_groups (my_grps, groups.pgsid)
+       || groups.pgsid == usersid;
+    }
+done:
+  return ret;
+}
+
+HANDLE
+create_token (cygsid &usersid, user_groups &new_groups, struct passwd *pw)
+{
+  NTSTATUS ret;
+  LSA_HANDLE lsa = INVALID_HANDLE_VALUE;
+
+  cygsidlist tmp_gsids (cygsidlist_auto, 12);
+
+  SECURITY_QUALITY_OF_SERVICE sqos =
+    { sizeof sqos, SecurityImpersonation, SECURITY_STATIC_TRACKING, FALSE };
+  OBJECT_ATTRIBUTES oa = { sizeof oa, 0, 0, 0, 0, &sqos };
+  LUID auth_luid = SYSTEM_LUID;
+  LARGE_INTEGER exp = { QuadPart:INT64_MAX };
+
+  TOKEN_USER user;
+  PTOKEN_GROUPS new_tok_gsids = NULL;
+  PTOKEN_PRIVILEGES privs = NULL;
+  TOKEN_OWNER owner;
+  TOKEN_PRIMARY_GROUP pgrp;
+  TOKEN_DEFAULT_DACL dacl = {};
+  TOKEN_SOURCE source;
+  TOKEN_STATISTICS stats;
+  memcpy (source.SourceName, "Cygwin.1", 8);
+  source.SourceIdentifier.HighPart = 0;
+  source.SourceIdentifier.LowPart = 0x0101;
+
+  HANDLE token = INVALID_HANDLE_VALUE;
+  HANDLE primary_token = INVALID_HANDLE_VALUE;
+
+  PTOKEN_GROUPS my_tok_gsids = NULL;
+  DWORD size;
+  size_t psize = 0;
+
+  /* SE_CREATE_TOKEN_NAME privilege needed to call NtCreateToken. */
+  push_self_privilege (SE_CREATE_TOKEN_PRIVILEGE, true);
+
+  /* Open policy object. */
+  if ((lsa = open_local_policy ()) == INVALID_HANDLE_VALUE)
+    goto out;
+
+  /* User, owner, primary group. */
+  user.User.Sid = usersid;
+  user.User.Attributes = 0;
+  owner.Owner = usersid;
+
+  /* Retrieve authentication id and group list from own process. */
+  if (hProcToken)
+    {
+      /* Switching user context to SYSTEM doesn't inherit the authentication
+        id of the user account running current process. */
+      if (usersid != well_known_system_sid)
+       if (!GetTokenInformation (hProcToken, TokenStatistics,
+                                 &stats, sizeof stats, &size))
+         debug_printf
+           ("GetTokenInformation(hProcToken, TokenStatistics), %E");
+       else
+         auth_luid = stats.AuthenticationId;
+
+      /* Retrieving current processes group list to be able to inherit
+        some important well known group sids. */
+      if (!GetTokenInformation (hProcToken, TokenGroups, NULL, 0, &size)
+         && GetLastError () != ERROR_INSUFFICIENT_BUFFER)
+       debug_printf ("GetTokenInformation(hProcToken, TokenGroups), %E");
+      else if (!(my_tok_gsids = (PTOKEN_GROUPS) malloc (size)))
+       debug_printf ("malloc (my_tok_gsids) failed.");
+      else if (!GetTokenInformation (hProcToken, TokenGroups, my_tok_gsids,
+                                    size, &size))
+       {
+         debug_printf ("GetTokenInformation(hProcToken, TokenGroups), %E");
+         free (my_tok_gsids);
+         my_tok_gsids = NULL;
+       }
+    }
+
+  /* Create list of groups, the user is member in. */
+  int auth_pos;
+  if (new_groups.issetgroups ())
+    get_setgroups_sidlist (tmp_gsids, usersid, pw, my_tok_gsids, new_groups,
+                          auth_luid, auth_pos);
+  else if (!get_initgroups_sidlist (tmp_gsids, usersid, new_groups.pgsid, pw,
+                                   my_tok_gsids, auth_luid, auth_pos))
+    goto out;
+
+  /* Primary group. */
+  pgrp.PrimaryGroup = new_groups.pgsid;
+
+  /* Create a TOKEN_GROUPS list from the above retrieved list of sids. */
+  new_tok_gsids = (PTOKEN_GROUPS)
+                 alloca (sizeof (DWORD) + tmp_gsids.count ()
+                                          * sizeof (SID_AND_ATTRIBUTES));
+  new_tok_gsids->GroupCount = tmp_gsids.count ();
+  for (DWORD i = 0; i < new_tok_gsids->GroupCount; ++i)
+    {
+      new_tok_gsids->Groups[i].Sid = tmp_gsids.sids[i];
+      new_tok_gsids->Groups[i].Attributes = SE_GROUP_MANDATORY
+                                           | SE_GROUP_ENABLED_BY_DEFAULT
+                                           | SE_GROUP_ENABLED;
+    }
+  if (auth_pos >= 0)
+    new_tok_gsids->Groups[auth_pos].Attributes |= SE_GROUP_LOGON_ID;
+  /* Retrieve list of privileges of that user. */
+  if (!(privs = get_priv_list (lsa, usersid, tmp_gsids, psize)))
+    goto out;
+
+  /* Let's be heroic... */
+  ret = NtCreateToken (&token, TOKEN_ALL_ACCESS, &oa, TokenImpersonation,
+                      &auth_luid, &exp, &user, new_tok_gsids, privs, &owner,
+                      &pgrp, &dacl, &source);
+  if (ret)
+    __seterrno_from_nt_status (ret);
+  else if (GetLastError () == ERROR_PROC_NOT_FOUND)
+    {
+      __seterrno ();
+      debug_printf ("Loading NtCreateToken failed.");
+    }
+  else
+    {
+      /* Convert to primary token. */
+      if (!DuplicateTokenEx (token, MAXIMUM_ALLOWED, &sec_none,
+                            SecurityImpersonation, TokenPrimary,
+                            &primary_token))
+       {
+         __seterrno ();
+         debug_printf ("DuplicateTokenEx %E");
+       }
+    }
+
+out:
+  pop_self_privilege ();
+  if (token != INVALID_HANDLE_VALUE)
+    CloseHandle (token);
+  if (privs)
+    free (privs);
+  if (my_tok_gsids)
+    free (my_tok_gsids);
+  close_local_policy (lsa);
+
+  debug_printf ("0x%x = create_token ()", primary_token);
+  return primary_token;
+}
+
+HANDLE
+lsaauth (cygsid &usersid, user_groups &new_groups, struct passwd *pw)
+{
+  cygsidlist tmp_gsids (cygsidlist_auto, 12);
+  cygpsid pgrpsid;
+  LSA_STRING name;
+  HANDLE lsa_hdl = NULL, lsa = INVALID_HANDLE_VALUE;
+  LSA_OPERATIONAL_MODE sec_mode;
+  NTSTATUS ret, ret2;
+  ULONG package_id, size;
+  LUID auth_luid = SYSTEM_LUID;
+  struct {
+    LSA_STRING str;
+    CHAR buf[16];
+  } origin;
+  cyglsa_t *authinf = NULL;
+  ULONG authinf_size;
+  TOKEN_SOURCE ts;
+  PCYG_TOKEN_GROUPS gsids = NULL;
+  PTOKEN_PRIVILEGES privs = NULL;
+  PACL dacl = NULL;
+  PVOID profile = NULL;
+  LUID luid;
+  QUOTA_LIMITS quota;
+  size_t psize = 0, gsize = 0, dsize = 0;
+  OFFSET offset, sids_offset;
+  int tmpidx, non_well_known_cnt;
+
+  HANDLE user_token = NULL;
+
+  push_self_privilege (SE_TCB_PRIVILEGE, true);
+
+  /* Register as logon process. */
+  str2lsa (name, "Cygwin");
+  SetLastError (0);
+  ret = LsaRegisterLogonProcess (&name, &lsa_hdl, &sec_mode);
+  if (ret != STATUS_SUCCESS)
+    {
+      debug_printf ("LsaRegisterLogonProcess: %p", ret);
+      __seterrno_from_win_error (LsaNtStatusToWinError (ret));
+      goto out;
+    }
+  else if (GetLastError () == ERROR_PROC_NOT_FOUND)
+    {
+      debug_printf ("Couldn't load Secur32.dll");
+      goto out;
+    }
+  /* Get handle to our own LSA package. */
+  str2lsa (name, CYG_LSA_PKGNAME);
+  ret = LsaLookupAuthenticationPackage (lsa_hdl, &name, &package_id);
+  if (ret != STATUS_SUCCESS)
+    {
+      debug_printf ("LsaLookupAuthenticationPackage: %p", ret);
+      __seterrno_from_win_error (LsaNtStatusToWinError (ret));
+      goto out;
+    }
+
+  /* Open policy object. */
+  if ((lsa = open_local_policy ()) == INVALID_HANDLE_VALUE)
+    goto out;
+
+  /* Create origin. */
+  str2buf2lsa (origin.str, origin.buf, "Cygwin");
+  /* Create token source. */
+  memcpy (ts.SourceName, "Cygwin.1", 8);
+  ts.SourceIdentifier.HighPart = 0;
+  ts.SourceIdentifier.LowPart = 0x0103;
+
+  /* Create list of groups, the user is member in. */
+  int auth_pos;
+  if (new_groups.issetgroups ())
+    get_setgroups_sidlist (tmp_gsids, usersid, pw, NULL, new_groups, auth_luid,
+                          auth_pos);
+  else if (!get_initgroups_sidlist (tmp_gsids, usersid, new_groups.pgsid, pw,
+                                   NULL, auth_luid, auth_pos))
+    goto out;
+  /* The logon SID entry is not generated automatically on Windows 2000
+     and earlier for some reason.  So add fake logon sid here, which is
+     filled with logon id values in the authentication package. */
+  if (wincap.needs_logon_sid_in_sid_list ())
+    tmp_gsids += fake_logon_sid;
+
+  tmp_gsids.debug_print ("tmp_gsids");
+
+  /* Evaluate size of TOKEN_GROUPS list */
+  non_well_known_cnt =  tmp_gsids.non_well_known_count ();
+  gsize = sizeof (DWORD) + non_well_known_cnt * sizeof (SID_AND_ATTRIBUTES);
+  tmpidx = -1;
+  for (int i = 0; i < non_well_known_cnt; ++i)
+    if ((tmpidx = tmp_gsids.next_non_well_known_sid (tmpidx)) >= 0)
+      gsize += GetLengthSid (tmp_gsids.sids[tmpidx]);
+
+  /* Retrieve list of privileges of that user. */
+  if (!(privs = get_priv_list (lsa, usersid, tmp_gsids, psize)))
+    goto out;
+
+  /* Create DefaultDacl. */
+  dsize = sizeof (ACL) + 3 * sizeof (ACCESS_ALLOWED_ACE)
+         + GetLengthSid (usersid)
+         + GetLengthSid (well_known_admins_sid)
+         + GetLengthSid (well_known_system_sid);
+  dacl = (PACL) alloca (dsize);
+  if (!InitializeAcl (dacl, dsize, ACL_REVISION))
+    goto out;
+  if (!AddAccessAllowedAce (dacl, ACL_REVISION, GENERIC_ALL, usersid))
+    goto out;
+  if (!AddAccessAllowedAce (dacl, ACL_REVISION, GENERIC_ALL,
+                           well_known_admins_sid))
+    goto out;
+  if (!AddAccessAllowedAce (dacl, ACL_REVISION, GENERIC_ALL,
+                           well_known_system_sid))
+    goto out;
+
+  /* Evaluate authinf size and allocate authinf. */
+  authinf_size = (authinf->data - (PBYTE) authinf);
+  authinf_size += GetLengthSid (usersid);          /* User SID */
+  authinf_size += gsize;                           /* Groups + Group SIDs */
+  /* When trying to define the admins group as primary group on Vista,
+     LsaLogonUser fails with error STATUS_INVALID_OWNER.  As workaround
+     we define "Local" as primary group here.  First, this adds the otherwise
+     missing "Local" group to the group list and second, seteuid32
+     sets the primary group to the group set in /etc/passwd anyway. */
+  pgrpsid = well_known_local_sid;
+  authinf_size += GetLengthSid (pgrpsid);          /* Primary Group SID */
+
+  authinf_size += psize;                           /* Privileges */
+  authinf_size += 0;                               /* Owner SID */
+  authinf_size += dsize;                           /* Default DACL */
+
+  authinf = (cyglsa_t *) alloca (authinf_size);
+  authinf->inf_size = authinf_size - ((PBYTE) &authinf->inf - (PBYTE) authinf);
+
+  authinf->magic = CYG_LSA_MAGIC;
+
+  extract_nt_dom_user (pw, authinf->domain, authinf->username);
+
+  /* Store stuff in authinf with offset relative to start of "inf" member,
+     instead of using pointers. */
+  offset = authinf->data - (PBYTE) &authinf->inf;
+
+  authinf->inf.ExpirationTime.LowPart = 0xffffffffL;
+  authinf->inf.ExpirationTime.HighPart = 0x7fffffffL;
+  /* User SID */
+  authinf->inf.User.User.Sid = offset;
+  authinf->inf.User.User.Attributes = 0;
+  CopySid (GetLengthSid (usersid), (PSID) ((PBYTE) &authinf->inf + offset),
+          usersid);
+  offset += GetLengthSid (usersid);
+  /* Groups */
+  authinf->inf.Groups = offset;
+  gsids = (PCYG_TOKEN_GROUPS) ((PBYTE) &authinf->inf + offset);
+  sids_offset = offset + sizeof (ULONG) + non_well_known_cnt
+                                         * sizeof (SID_AND_ATTRIBUTES);
+  gsids->GroupCount = non_well_known_cnt;
+  /* Group SIDs */
+  tmpidx = -1;
+  for (int i = 0; i < non_well_known_cnt; ++i)
+    {
+      if ((tmpidx = tmp_gsids.next_non_well_known_sid (tmpidx)) < 0)
+       break;
+      gsids->Groups[i].Sid = sids_offset;
+      gsids->Groups[i].Attributes = SE_GROUP_MANDATORY
+                                   | SE_GROUP_ENABLED_BY_DEFAULT
+                                   | SE_GROUP_ENABLED;
+      /* Mark logon SID as logon SID :) */
+      if (wincap.needs_logon_sid_in_sid_list ()
+         && tmp_gsids.sids[tmpidx] == fake_logon_sid)
+       gsids->Groups[i].Attributes += SE_GROUP_LOGON_ID;
+      CopySid (GetLengthSid (tmp_gsids.sids[tmpidx]),
+              (PSID) ((PBYTE) &authinf->inf + sids_offset),
+              tmp_gsids.sids[tmpidx]);
+      sids_offset += GetLengthSid (tmp_gsids.sids[tmpidx]);
+    }
+  offset += gsize;
+  /* Primary Group SID */
+  authinf->inf.PrimaryGroup.PrimaryGroup = offset;
+  CopySid (GetLengthSid (pgrpsid), (PSID) ((PBYTE) &authinf->inf + offset),
+          pgrpsid);
+  offset += GetLengthSid (pgrpsid);
+  /* Privileges */
+  authinf->inf.Privileges = offset;
+  memcpy ((PBYTE) &authinf->inf + offset, privs, psize);
+  offset += psize;
+  /* Owner */
+  authinf->inf.Owner.Owner = 0;
+  /* Default DACL */
+  authinf->inf.DefaultDacl.DefaultDacl = offset;
+  memcpy ((PBYTE) &authinf->inf + offset, dacl, dsize);
+
+  authinf->checksum = CYGWIN_VERSION_MAGIC (CYGWIN_VERSION_DLL_MAJOR,
+                                           CYGWIN_VERSION_DLL_MINOR);
+  PDWORD csp = (PDWORD) &authinf->username;
+  PDWORD csp_end = (PDWORD) ((PBYTE) authinf + authinf_size);
+  while (csp < csp_end)
+    authinf->checksum += *csp++;
+
+  /* Try to logon... */
+  ret = LsaLogonUser (lsa_hdl, (PLSA_STRING) &origin, Interactive, package_id,
+                     authinf, authinf_size, NULL, &ts, &profile, &size, &luid,
+                     &user_token, &quota, &ret2);
+  if (ret != STATUS_SUCCESS)
+    {
+      debug_printf ("LsaLogonUser: %p", ret);
+      __seterrno_from_win_error (LsaNtStatusToWinError (ret));
+      goto out;
+    }
+  if (profile)
+    LsaFreeReturnBuffer (profile);
+
+  if (wincap.has_mandatory_integrity_control ())
+    {
+      typedef struct _TOKEN_LINKED_TOKEN
+      {
+       HANDLE LinkedToken;
+      } TOKEN_LINKED_TOKEN, *PTOKEN_LINKED_TOKEN;
+#     define TokenLinkedToken ((TOKEN_INFORMATION_CLASS) 19)
+
+      TOKEN_LINKED_TOKEN linked;
+
+      if (GetTokenInformation (user_token, TokenLinkedToken,
+                              (PVOID) &linked, sizeof linked, &size))
+       {
+         debug_printf ("Linked Token: %lu", linked.LinkedToken);
+         if (linked.LinkedToken)
+           user_token = linked.LinkedToken;
+       }
+    }
+
+out:
+  if (privs)
+    free (privs);
+  close_local_policy (lsa);
+  if (lsa_hdl)
+    LsaDeregisterLogonProcess (lsa_hdl);
+  pop_self_privilege ();
+
+  debug_printf ("0x%x = lsaauth ()", user_token);
+  return user_token;
+}
index 4fb6252..7fc9492 100644 (file)
@@ -11,17 +11,8 @@ Cygwin license.  Please consult the file "CYGWIN_LICENSE" for
 details. */
 
 #include "winsup.h"
-#include <grp.h>
-#include <pwd.h>
-#include <unistd.h>
 #include <stdlib.h>
-#include <limits.h>
-#include <sys/stat.h>
 #include <sys/acl.h>
-#include <ctype.h>
-#include <wingdi.h>
-#include <winuser.h>
-#include <wininet.h>
 #include "cygerrno.h"
 #include "security.h"
 #include "path.h"
@@ -29,7 +20,6 @@ details. */
 #include "dtable.h"
 #include "pinfo.h"
 #include "cygheap.h"
-#include "cygtls.h"
 #include "pwdgrp.h"
 #include "ntdll.h"
 
index 5fca3d8..5740446 100644 (file)
@@ -1,4 +1,4 @@
-/* security.cc: NT security functions
+/* security.cc: NT file access control functions
 
    Copyright 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
    2006, 2007 Red Hat, Inc.
@@ -13,22 +13,8 @@ Cygwin license.  Please consult the file "CYGWIN_LICENSE" for
 details. */
 
 #include "winsup.h"
-#include <grp.h>
-#include <pwd.h>
 #include <unistd.h>
 #include <stdlib.h>
-#include <limits.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/acl.h>
-#include <ctype.h>
-#include <winnls.h>
-#include <wingdi.h>
-#include <winuser.h>
-#include <wininet.h>
-#include <ntsecapi.h>
-#include <aclapi.h>
-#include <dsgetdc.h>
 #include "cygerrno.h"
 #include "security.h"
 #include "path.h"
@@ -36,12 +22,12 @@ details. */
 #include "dtable.h"
 #include "pinfo.h"
 #include "cygheap.h"
-#include <ntdef.h>
 #include "ntdll.h"
-#include "lm.h"
 #include "pwdgrp.h"
-#include "cyglsa.h"
-#include <cygwin/version.h>
+
+#define ALL_SECURITY_INFORMATION (DACL_SECURITY_INFORMATION \
+                                 | GROUP_SECURITY_INFORMATION \
+                                 | OWNER_SECURITY_INFORMATION)
 
 /* Set ntsec explicit as default. */
 bool allow_ntsec = true;
@@ -49,1227 +35,97 @@ bool allow_ntsec = true;
    It's defined here because of it's strong relationship to allow_ntsec. */
 bool allow_smbntsec;
 
-extern "C" void
-cygwin_set_impersonation_token (const HANDLE hToken)
-{
-  debug_printf ("set_impersonation_token (%d)", hToken);
-  cygheap->user.external_token = hToken == INVALID_HANDLE_VALUE ? NO_IMPERSONATION : hToken;
-}
-
-void
-extract_nt_dom_user (const struct passwd *pw, char *domain, char *user)
-{
-  char *d, *u, *c;
-
-  domain[0] = 0;
-  strlcpy (user, pw->pw_name, UNLEN + 1);
-  debug_printf ("pw_gecos %x (%s)", pw->pw_gecos, pw->pw_gecos);
-
-  if ((d = strstr (pw->pw_gecos, "U-")) != NULL &&
-      (d == pw->pw_gecos || d[-1] == ','))
-    {
-      c = strechr (d + 2, ',');
-      if ((u = strechr (d + 2, '\\')) >= c)
-       u = d + 1;
-      else if (u - d <= INTERNET_MAX_HOST_NAME_LENGTH + 2)
-       strlcpy (domain, d + 2, u - d - 1);
-      if (c - u <= UNLEN + 1)
-       strlcpy (user, u + 1, c - u);
-    }
-  if (domain[0])
-    return;
-
-  cygsid psid;
-  DWORD ulen = UNLEN + 1;
-  DWORD dlen = INTERNET_MAX_HOST_NAME_LENGTH + 1;
-  SID_NAME_USE use;
-  if (psid.getfrompw (pw))
-    LookupAccountSid (NULL, psid, user, &ulen, domain, &dlen, &use);
-}
-
-extern "C" HANDLE
-cygwin_logon_user (const struct passwd *pw, const char *password)
-{
-  if (!pw)
-    {
-      set_errno (EINVAL);
-      return INVALID_HANDLE_VALUE;
-    }
-
-  char nt_domain[INTERNET_MAX_HOST_NAME_LENGTH + 1];
-  char nt_user[UNLEN + 1];
-  HANDLE hToken;
-
-  extract_nt_dom_user (pw, nt_domain, nt_user);
-  debug_printf ("LogonUserA (%s, %s, %s, ...)", nt_user, nt_domain, password);
-  /* CV 2005-06-08: LogonUser should run under the primary process token,
-     otherwise it returns with ERROR_ACCESS_DENIED on W2K. Don't ask me why. */
-  RevertToSelf ();
-  if (!LogonUserA (nt_user, *nt_domain ? nt_domain : NULL, (char *) password,
-                  LOGON32_LOGON_INTERACTIVE,
-                  LOGON32_PROVIDER_DEFAULT,
-                  &hToken))
-    {
-      __seterrno ();
-      hToken = INVALID_HANDLE_VALUE;
-    }
-  else if (!SetHandleInformation (hToken,
-                                 HANDLE_FLAG_INHERIT,
-                                 HANDLE_FLAG_INHERIT))
-    {
-      __seterrno ();
-      CloseHandle (hToken);
-      hToken = INVALID_HANDLE_VALUE;
-    }
-  cygheap->user.reimpersonate ();
-  debug_printf ("%d = logon_user(%s,...)", hToken, pw->pw_name);
-  return hToken;
-}
-
-static void
-str2lsa (LSA_STRING &tgt, const char *srcstr)
-{
-  tgt.Length = strlen (srcstr);
-  tgt.MaximumLength = tgt.Length + 1;
-  tgt.Buffer = (PCHAR) srcstr;
-}
-
-static void
-str2buf2lsa (LSA_STRING &tgt, char *buf, const char *srcstr)
-{
-  tgt.Length = strlen (srcstr);
-  tgt.MaximumLength = tgt.Length + 1;
-  tgt.Buffer = (PCHAR) buf;
-  memcpy (buf, srcstr, tgt.MaximumLength);
-}
-
-/* The dimension of buf is assumed to be at least strlen(srcstr) + 1,
-   The result will be shorter if the input has multibyte chars */
-void
-str2buf2uni (UNICODE_STRING &tgt, WCHAR *buf, const char *srcstr)
-{
-  tgt.Buffer = (PWCHAR) buf;
-  tgt.MaximumLength = (strlen (srcstr) + 1) * sizeof (WCHAR);
-  tgt.Length = sys_mbstowcs (buf, srcstr, tgt.MaximumLength / sizeof (WCHAR))
-              * sizeof (WCHAR);
-  if (tgt.Length)
-    tgt.Length -= sizeof (WCHAR);
-}
-
-void
-str2uni_cat (UNICODE_STRING &tgt, const char *srcstr)
-{
-  int len = sys_mbstowcs (tgt.Buffer + tgt.Length / sizeof (WCHAR), srcstr,
-                         (tgt.MaximumLength - tgt.Length) / sizeof (WCHAR));
-  if (len)
-    tgt.Length += (len - 1) * sizeof (WCHAR);
-  else
-    tgt.Length = tgt.MaximumLength = 0;
-}
-
-static LSA_HANDLE
-open_local_policy ()
-{
-  LSA_OBJECT_ATTRIBUTES oa = { 0, 0, 0, 0, 0, 0 };
-  LSA_HANDLE lsa = INVALID_HANDLE_VALUE;
-
-  NTSTATUS ret = LsaOpenPolicy (NULL, &oa, POLICY_EXECUTE, &lsa);
-  if (ret != STATUS_SUCCESS)
-    __seterrno_from_win_error (LsaNtStatusToWinError (ret));
-  return lsa;
-}
-
-static void
-close_local_policy (LSA_HANDLE &lsa)
-{
-  if (lsa != INVALID_HANDLE_VALUE)
-    LsaClose (lsa);
-  lsa = INVALID_HANDLE_VALUE;
-}
-
-/* CV, 2006-07-06: Missing in w32api. */
-extern "C" DWORD WINAPI DsGetDcNameA (LPCSTR, LPCSTR, GUID *, LPCSTR, ULONG,
-                                     PDOMAIN_CONTROLLER_INFOA *);
-#define DS_FORCE_REDISCOVERY   1
-
-bool
-get_logon_server (const char *domain, char *server, WCHAR *wserver,
-                 bool rediscovery)
-{
-  DWORD dret;
-  PDOMAIN_CONTROLLER_INFOA pci;
-  WCHAR *buf;
-  DWORD size = INTERNET_MAX_HOST_NAME_LENGTH + 1;
-  WCHAR wdomain[size];
-
-  /* Empty domain is interpreted as local system */
-  if ((GetComputerName (server + 2, &size)) &&
-      (strcasematch (domain, server + 2) || !domain[0]))
-    {
-      server[0] = server[1] = '\\';
-      if (wserver)
-       sys_mbstowcs (wserver, server, INTERNET_MAX_HOST_NAME_LENGTH + 1);
-      return true;
-    }
-
-  /* Try to get any available domain controller for this domain */
-  dret = DsGetDcNameA (NULL, domain, NULL, NULL,
-                      rediscovery ? DS_FORCE_REDISCOVERY : 0, &pci);
-  if (dret == ERROR_SUCCESS)
-    {
-      strcpy (server, pci->DomainControllerName);
-      sys_mbstowcs (wserver, server, INTERNET_MAX_HOST_NAME_LENGTH + 1);
-      NetApiBufferFree (pci);
-      debug_printf ("DC: rediscovery: %d, server: %s", rediscovery, server);
-      return true;
-    }
-  else if (dret == ERROR_PROC_NOT_FOUND)
-    {
-      /* NT4 w/o DSClient */
-      sys_mbstowcs (wdomain, domain, INTERNET_MAX_HOST_NAME_LENGTH + 1);
-      if (rediscovery)
-       dret = NetGetAnyDCName (NULL, wdomain, (LPBYTE *) &buf);
-      else
-       dret = NetGetDCName (NULL, wdomain, (LPBYTE *) &buf);
-      if (dret == NERR_Success)
-       {
-         sys_wcstombs (server, INTERNET_MAX_HOST_NAME_LENGTH + 1, buf);
-         if (wserver)
-           for (WCHAR *ptr1 = buf; (*wserver++ = *ptr1++);)
-             ;
-         NetApiBufferFree (buf);
-         debug_printf ("NT: rediscovery: %d, server: %s", rediscovery, server);
-         return true;
-       }
-    }
-  __seterrno_from_win_error (dret);
-  return false;
-}
-
-static bool
-get_user_groups (WCHAR *wlogonserver, cygsidlist &grp_list, char *user,
-                char *domain)
-{
-  char dgroup[INTERNET_MAX_HOST_NAME_LENGTH + GNLEN + 2];
-  WCHAR wuser[UNLEN + 1];
-  sys_mbstowcs (wuser, user, UNLEN + 1);
-  LPGROUP_USERS_INFO_0 buf;
-  DWORD cnt, tot, len;
-  NET_API_STATUS ret;
-
-  /* Look only on logonserver */
-  ret = NetUserGetGroups (wlogonserver, wuser, 0, (LPBYTE *) &buf,
-                         MAX_PREFERRED_LENGTH, &cnt, &tot);
-  if (ret)
-    {
-      __seterrno_from_win_error (ret);
-      /* It's no error when the user name can't be found. */
-      return ret == NERR_UserNotFound;
-    }
-
-  len = strlen (domain);
-  strcpy (dgroup, domain);
-  dgroup[len++] = '\\';
-
-  for (DWORD i = 0; i < cnt; ++i)
-    {
-      cygsid gsid;
-      DWORD glen = MAX_SID_LEN;
-      char domain[INTERNET_MAX_HOST_NAME_LENGTH + 1];
-      DWORD dlen = sizeof (domain);
-      SID_NAME_USE use = SidTypeInvalid;
-
-      sys_wcstombs (dgroup + len, GNLEN + 1, buf[i].grui0_name);
-      if (!LookupAccountName (NULL, dgroup, gsid, &glen, domain, &dlen, &use))
-       debug_printf ("LookupAccountName(%s), %E", dgroup);
-      else if (legal_sid_type (use))
-       grp_list += gsid;
-      else
-       debug_printf ("Global group %s invalid. Domain: %s Use: %d",
-                     dgroup, domain, use);
-    }
-
-  NetApiBufferFree (buf);
-  return true;
-}
-
-static bool
-is_group_member (WCHAR *wgroup, PSID pusersid, cygsidlist &grp_list)
-{
-  LPLOCALGROUP_MEMBERS_INFO_1 buf;
-  DWORD cnt, tot;
-  NET_API_STATUS ret;
-
-  /* Members can be users or global groups */
-  ret = NetLocalGroupGetMembers (NULL, wgroup, 1, (LPBYTE *) &buf,
-                                MAX_PREFERRED_LENGTH, &cnt, &tot, NULL);
-  if (ret)
-    return false;
-
-  bool retval = true;
-  for (DWORD bidx = 0; bidx < cnt; ++bidx)
-    if (EqualSid (pusersid, buf[bidx].lgrmi1_sid))
-      goto done;
-    else
-      {
-       /* The extra test for the group being a global group or a well-known
-          group is necessary, since apparently also aliases (for instance
-          Administrators or Users) can be members of local groups, even
-          though MSDN states otherwise.  The GUI refuses to put aliases into
-          local groups, but the CLI interface allows it.  However, a normal
-          logon token does not contain groups, in which the user is only
-          indirectly a member by being a member of an alias in this group.
-          So we also should not put them into the token group list.
-          Note: Allowing those groups in our group list renders external
-          tokens invalid, so that it becomes impossible to logon with
-          password and valid logon token. */
-       for (int glidx = 0; glidx < grp_list.count (); ++glidx)
-         if ((buf[bidx].lgrmi1_sidusage == SidTypeGroup
-              || buf[bidx].lgrmi1_sidusage == SidTypeWellKnownGroup)
-             && EqualSid (grp_list.sids[glidx], buf[bidx].lgrmi1_sid))
-           goto done;
-      }
-
-  retval = false;
- done:
-  NetApiBufferFree (buf);
-  return retval;
-}
-
-static bool
-get_user_local_groups (cygsidlist &grp_list, PSID pusersid)
-{
-  LPLOCALGROUP_INFO_0 buf;
-  DWORD cnt, tot;
-  NET_API_STATUS ret;
-
-  ret = NetLocalGroupEnum (NULL, 0, (LPBYTE *) &buf,
-                          MAX_PREFERRED_LENGTH, &cnt, &tot, NULL);
-  if (ret)
-    {
-      __seterrno_from_win_error (ret);
-      return false;
-    }
-
-  char bgroup[INTERNET_MAX_HOST_NAME_LENGTH + GNLEN + 2];
-  char lgroup[INTERNET_MAX_HOST_NAME_LENGTH + GNLEN + 2];
-  DWORD blen, llen;
-  SID_NAME_USE use;
-
-  blen = llen = INTERNET_MAX_HOST_NAME_LENGTH + 1;
-  if (!LookupAccountSid (NULL, well_known_admins_sid, lgroup, &llen, bgroup, &blen, &use)
-      || !GetComputerNameA (lgroup, &(llen = INTERNET_MAX_HOST_NAME_LENGTH + 1)))
-    {
-      __seterrno ();
-      return false;
-    }
-  bgroup[blen++] = lgroup[llen++] = '\\';
-
-  for (DWORD i = 0; i < cnt; ++i)
-    if (is_group_member (buf[i].lgrpi0_name, pusersid, grp_list))
-      {
-       cygsid gsid;
-       DWORD glen = MAX_SID_LEN;
-       char domain[INTERNET_MAX_HOST_NAME_LENGTH + 1];
-       DWORD dlen = sizeof (domain);
-
-       use = SidTypeInvalid;
-       sys_wcstombs (bgroup + blen, GNLEN + 1, buf[i].lgrpi0_name);
-       if (!LookupAccountName (NULL, bgroup, gsid, &glen, domain, &dlen, &use))
-         {
-           if (GetLastError () != ERROR_NONE_MAPPED)
-             debug_printf ("LookupAccountName(%s), %E", bgroup);
-           strcpy (lgroup + llen, bgroup + blen);
-           if (!LookupAccountName (NULL, lgroup, gsid, &glen,
-                                   domain, &dlen, &use))
-             debug_printf ("LookupAccountName(%s), %E", lgroup);
-         }
-       if (!legal_sid_type (use))
-         debug_printf ("Rejecting local %s. use: %d", bgroup + blen, use);
-       grp_list *= gsid;
-      }
-  NetApiBufferFree (buf);
-  return true;
-}
-
-static bool
-sid_in_token_groups (PTOKEN_GROUPS grps, cygpsid sid)
-{
-  if (!grps)
-    return false;
-  for (DWORD i = 0; i < grps->GroupCount; ++i)
-    if (sid == grps->Groups[i].Sid)
-      return true;
-  return false;
-}
-
-#if 0                          /* Unused */
-static BOOL
-get_user_primary_group (WCHAR *wlogonserver, const char *user,
-                       PSID pusersid, cygsid &pgrpsid)
-{
-  LPUSER_INFO_3 buf;
-  WCHAR wuser[UNLEN + 1];
-  NET_API_STATUS ret;
-  BOOL retval = FALSE;
-  UCHAR count = 0;
-
-  if (well_known_system_sid == pusersid)
-    {
-      pgrpsid = well_known_system_sid;
-      return TRUE;
-    }
-
-  sys_mbstowcs (wuser, user, UNLEN + 1);
-  ret = NetUserGetInfo (wlogonserver, wuser, 3, (LPBYTE *) &buf);
-  if (ret)
-    {
-      __seterrno_from_win_error (ret);
-      return FALSE;
-    }
-
-  pgrpsid = pusersid;
-  if (IsValidSid (pgrpsid)
-      && (count = *GetSidSubAuthorityCount (pgrpsid)) > 1)
-    {
-      *GetSidSubAuthority (pgrpsid, count - 1) = buf->usri3_primary_group_id;
-      retval = TRUE;
-    }
-  NetApiBufferFree (buf);
-  return retval;
-}
-#endif
-
-static void
-get_unix_group_sidlist (struct passwd *pw, cygsidlist &grp_list)
-{
-  struct __group32 *gr;
-  cygsid gsid;
-
-  for (int gidx = 0; (gr = internal_getgrent (gidx)); ++gidx)
-    {
-      if (gr->gr_gid == (__gid32_t) pw->pw_gid)
-       goto found;
-      else if (gr->gr_mem)
-       for (int gi = 0; gr->gr_mem[gi]; ++gi)
-         if (strcasematch (pw->pw_name, gr->gr_mem[gi]))
-           goto found;
-      continue;
-    found:
-      if (gsid.getfromgr (gr))
-       grp_list += gsid;
-
-    }
-}
-
-static void
-get_token_group_sidlist (cygsidlist &grp_list, PTOKEN_GROUPS my_grps,
-                        LUID auth_luid, int &auth_pos)
-{
-  auth_pos = -1;
-  if (my_grps)
-    {
-      grp_list += well_known_local_sid;
-      if (sid_in_token_groups (my_grps, well_known_dialup_sid))
-       grp_list *= well_known_dialup_sid;
-      if (sid_in_token_groups (my_grps, well_known_network_sid))
-       grp_list *= well_known_network_sid;
-      if (sid_in_token_groups (my_grps, well_known_batch_sid))
-       grp_list *= well_known_batch_sid;
-      grp_list *= well_known_interactive_sid;
-      if (sid_in_token_groups (my_grps, well_known_service_sid))
-       grp_list *= well_known_service_sid;
-      if (sid_in_token_groups (my_grps, well_known_this_org_sid))
-       grp_list *= well_known_this_org_sid;
-    }
-  else
-    {
-      grp_list += well_known_local_sid;
-      grp_list *= well_known_interactive_sid;
-    }
-  if (get_ll (auth_luid) != 999LL) /* != SYSTEM_LUID */
-    {
-      for (DWORD i = 0; i < my_grps->GroupCount; ++i)
-       if (my_grps->Groups[i].Attributes & SE_GROUP_LOGON_ID)
-         {
-           grp_list += my_grps->Groups[i].Sid;
-           auth_pos = grp_list.count () - 1;
-           break;
-         }
-    }
-}
-
-bool
-get_server_groups (cygsidlist &grp_list, PSID usersid, struct passwd *pw)
-{
-  char user[UNLEN + 1];
-  char domain[INTERNET_MAX_HOST_NAME_LENGTH + 1];
-  WCHAR wserver[INTERNET_MAX_HOST_NAME_LENGTH + 3];
-  char server[INTERNET_MAX_HOST_NAME_LENGTH + 3];
-
-  if (well_known_system_sid == usersid)
-    {
-      grp_list *= well_known_admins_sid;
-      get_unix_group_sidlist (pw, grp_list);
-      return true;
-    }
-
-  grp_list *= well_known_world_sid;
-  grp_list *= well_known_authenticated_users_sid;
-  extract_nt_dom_user (pw, domain, user);
-  if (get_logon_server (domain, server, wserver, false)
-      && !get_user_groups (wserver, grp_list, user, domain)
-      && get_logon_server (domain, server, wserver, true))
-    get_user_groups (wserver, grp_list, user, domain);
-  if (get_user_local_groups (grp_list, usersid))
-    {
-      get_unix_group_sidlist (pw, grp_list);
-      return true;
-    }
-  return false;
-}
-
-static bool
-get_initgroups_sidlist (cygsidlist &grp_list,
-                       PSID usersid, PSID pgrpsid, struct passwd *pw,
-                       PTOKEN_GROUPS my_grps, LUID auth_luid, int &auth_pos)
-{
-  grp_list *= well_known_world_sid;
-  grp_list *= well_known_authenticated_users_sid;
-  if (well_known_system_sid == usersid)
-    auth_pos = -1;
-  else
-    get_token_group_sidlist (grp_list, my_grps, auth_luid, auth_pos);
-  if (!get_server_groups (grp_list, usersid, pw))
-    return false;
-
-  /* special_pgrp true if pgrpsid is not in normal groups */
-  grp_list += pgrpsid;
-  return true;
-}
-
-static void
-get_setgroups_sidlist (cygsidlist &tmp_list, PSID usersid, struct passwd *pw,
-                      PTOKEN_GROUPS my_grps, user_groups &groups,
-                      LUID auth_luid, int &auth_pos)
-{
-  tmp_list *= well_known_world_sid;
-  tmp_list *= well_known_authenticated_users_sid;
-  get_token_group_sidlist (tmp_list, my_grps, auth_luid, auth_pos);
-  get_server_groups (tmp_list, usersid, pw);
-  for (int gidx = 0; gidx < groups.sgsids.count (); gidx++)
-    tmp_list += groups.sgsids.sids[gidx];
-  tmp_list += groups.pgsid;
-}
-
-static ULONG sys_privs[] = {
-  SE_CREATE_TOKEN_PRIVILEGE,
-  SE_ASSIGNPRIMARYTOKEN_PRIVILEGE,             
-  SE_LOCK_MEMORY_PRIVILEGE,            
-  SE_INCREASE_QUOTA_PRIVILEGE,         
-  SE_TCB_PRIVILEGE,            
-  SE_SECURITY_PRIVILEGE,               
-  SE_TAKE_OWNERSHIP_PRIVILEGE,         
-  SE_LOAD_DRIVER_PRIVILEGE,            
-  SE_SYSTEM_PROFILE_PRIVILEGE,         /* Vista ONLY */
-  SE_SYSTEMTIME_PRIVILEGE,             
-  SE_PROF_SINGLE_PROCESS_PRIVILEGE,            
-  SE_INC_BASE_PRIORITY_PRIVILEGE,              
-  SE_CREATE_PAGEFILE_PRIVILEGE,                
-  SE_CREATE_PERMANENT_PRIVILEGE,               
-  SE_BACKUP_PRIVILEGE,         
-  SE_RESTORE_PRIVILEGE,                
-  SE_SHUTDOWN_PRIVILEGE,               
-  SE_DEBUG_PRIVILEGE,          
-  SE_AUDIT_PRIVILEGE,          
-  SE_SYSTEM_ENVIRONMENT_PRIVILEGE,             
-  SE_CHANGE_NOTIFY_PRIVILEGE,          
-  SE_UNDOCK_PRIVILEGE,
-  SE_MANAGE_VOLUME_PRIVILEGE,
-  SE_IMPERSONATE_PRIVILEGE,
-  SE_CREATE_GLOBAL_PRIVILEGE,
-  SE_INCREASE_WORKING_SET_PRIVILEGE,
-  SE_TIME_ZONE_PRIVILEGE,
-  SE_CREATE_SYMBOLIC_LINK_PRIVILEGE
-};
-
-#define SYSTEM_PRIVILEGES_COUNT (sizeof sys_privs / sizeof *sys_privs)
-
-static PTOKEN_PRIVILEGES
-get_system_priv_list (size_t &size)
-{
-  ULONG max_idx = 0;
-  while (max_idx < SYSTEM_PRIVILEGES_COUNT
-        && sys_privs[max_idx] != wincap.max_sys_priv ())
-    ++max_idx;
-  if (max_idx >= SYSTEM_PRIVILEGES_COUNT)
-    api_fatal ("Coding error: wincap privilege %u doesn't exist in sys_privs",
-              wincap.max_sys_priv ());
-  size = sizeof (ULONG) + (max_idx + 1) * sizeof (LUID_AND_ATTRIBUTES);
-  PTOKEN_PRIVILEGES privs = (PTOKEN_PRIVILEGES) malloc (size);
-  if (!privs)
-    {
-      debug_printf ("malloc (system_privs) failed.");
-      return NULL;
-    }
-  privs->PrivilegeCount = 0;
-  for (ULONG i = 0; i <= max_idx; ++i)
-    {
-      privs->Privileges[privs->PrivilegeCount].Luid.HighPart = 0L;
-      privs->Privileges[privs->PrivilegeCount].Luid.LowPart = sys_privs[i];
-      privs->Privileges[privs->PrivilegeCount].Attributes =
-       SE_PRIVILEGE_ENABLED | SE_PRIVILEGE_ENABLED_BY_DEFAULT;
-      ++privs->PrivilegeCount;
-    }
-  return privs;
-}
-
-static PTOKEN_PRIVILEGES
-get_priv_list (LSA_HANDLE lsa, cygsid &usersid, cygsidlist &grp_list,
-              size_t &size)
+LONG
+get_file_sd (HANDLE fh, path_conv &pc, security_descriptor &sd)
 {
-  PLSA_UNICODE_STRING privstrs;
-  ULONG cnt;
-  PTOKEN_PRIVILEGES privs = NULL;
-  NTSTATUS ret;
-  char buf[INTERNET_MAX_HOST_NAME_LENGTH + 1];
-
-  if (usersid == well_known_system_sid)
-    return get_system_priv_list (size);
+  NTSTATUS status = STATUS_SUCCESS;
+  ULONG len = 0;
+  int retry = 0;
+  int res = -1;
 
-  for (int grp = -1; grp < grp_list.count (); ++grp)
+  for (; retry < 2; ++retry)
     {
-      if (grp == -1)
+      if (fh)
        {
-         if ((ret = LsaEnumerateAccountRights (lsa, usersid, &privstrs,
-                                               &cnt)) != STATUS_SUCCESS)
-           continue;
-       }
-      else if ((ret = LsaEnumerateAccountRights (lsa, grp_list.sids[grp],
-                                                &privstrs, &cnt))
-              != STATUS_SUCCESS)
-       continue;
-      for (ULONG i = 0; i < cnt; ++i)
-       {
-         LUID priv;
-         PTOKEN_PRIVILEGES tmp;
-         DWORD tmp_count;
-
-         sys_wcstombs (buf, sizeof (buf),
-                       privstrs[i].Buffer, privstrs[i].Length / 2);
-         if (!privilege_luid (buf, &priv))
-           continue;
-
-         if (privs)
+         status = NtQuerySecurityObject (fh, ALL_SECURITY_INFORMATION,
+                                         sd, len, &len);
+         if (status == STATUS_BUFFER_TOO_SMALL)
            {
-             DWORD pcnt = privs->PrivilegeCount;
-             LUID_AND_ATTRIBUTES *p = privs->Privileges;
-             for (; pcnt > 0; --pcnt, ++p)
-               if (priv.HighPart == p->Luid.HighPart
-                   && priv.LowPart == p->Luid.LowPart)
-                 goto next_account_right;
+             if (!sd.malloc (len))
+               {
+                 set_errno (ENOMEM);
+                 break;
+               }
+             status = NtQuerySecurityObject (fh, ALL_SECURITY_INFORMATION,
+                                             sd, len, &len);
            }
-
-         tmp_count = privs ? privs->PrivilegeCount : 0;
-         size = sizeof (DWORD)
-                + (tmp_count + 1) * sizeof (LUID_AND_ATTRIBUTES);
-         tmp = (PTOKEN_PRIVILEGES) realloc (privs, size);
-         if (!tmp)
+         if (NT_SUCCESS (status))
            {
-             if (privs)
-               free (privs);
-             LsaFreeMemory (privstrs);
-             debug_printf ("realloc (privs) failed.");
-             return NULL;
+             res = 0;
+             break;
            }
-         tmp->PrivilegeCount = tmp_count;
-         privs = tmp;
-         privs->Privileges[privs->PrivilegeCount].Luid = priv;
-         privs->Privileges[privs->PrivilegeCount].Attributes =
-           SE_PRIVILEGE_ENABLED | SE_PRIVILEGE_ENABLED_BY_DEFAULT;
-         ++privs->PrivilegeCount;
-
-       next_account_right:
-         ;
        }
-      LsaFreeMemory (privstrs);
-    }
-  return privs;
-}
-
-/* Accept a token if
-   - the requested usersid matches the TokenUser and
-   - if setgroups has been called:
-       the token groups that are listed in /etc/group match the union of
-       the requested primary and supplementary groups in gsids.
-   - else the (unknown) implicitly requested supplementary groups and those
-       in the token are the groups associated with the usersid. We assume
-       they match and verify only the primary groups.
-       The requested primary group must appear in the token.
-       The primary group in the token is a group associated with the usersid,
-       except if the token is internal and the group is in the token SD
-       (see create_token). In that latter case that group must match the
-       requested primary group.  */
-bool
-verify_token (HANDLE token, cygsid &usersid, user_groups &groups, bool *pintern)
-{
-  DWORD size;
-  bool intern = false;
-
-  if (pintern)
-    {
-      TOKEN_SOURCE ts;
-      if (!GetTokenInformation (token, TokenSource,
-                               &ts, sizeof ts, &size))
-       debug_printf ("GetTokenInformation(), %E");
-      else
-       *pintern = intern = !memcmp (ts.SourceName, "Cygwin.1", 8);
-    }
-  /* Verify usersid */
-  cygsid tok_usersid = NO_SID;
-  if (!GetTokenInformation (token, TokenUser,
-                           &tok_usersid, sizeof tok_usersid, &size))
-    debug_printf ("GetTokenInformation(), %E");
-  if (usersid != tok_usersid)
-    return false;
-
-  /* For an internal token, if setgroups was not called and if the sd group
-     is not well_known_null_sid, it must match pgrpsid */
-  if (intern && !groups.issetgroups ())
-    {
-      const DWORD sd_buf_siz = MAX_SID_LEN + sizeof (SECURITY_DESCRIPTOR);
-      PSECURITY_DESCRIPTOR sd_buf = (PSECURITY_DESCRIPTOR) alloca (sd_buf_siz);
-      cygpsid gsid (NO_SID);
-      if (!GetKernelObjectSecurity (token, GROUP_SECURITY_INFORMATION,
-                                   sd_buf, sd_buf_siz, &size))
-       debug_printf ("GetKernelObjectSecurity(), %E");
-      else if (!GetSecurityDescriptorGroup (sd_buf, (PSID *) &gsid,
-                                           (BOOL *) &size))
-       debug_printf ("GetSecurityDescriptorGroup(), %E");
-      if (well_known_null_sid != gsid)
-       return gsid == groups.pgsid;
-    }
-
-  PTOKEN_GROUPS my_grps;
-  bool sawpg = false, ret = false;
-
-  if (!GetTokenInformation (token, TokenGroups, NULL, 0, &size) &&
-      GetLastError () != ERROR_INSUFFICIENT_BUFFER)
-    debug_printf ("GetTokenInformation(token, TokenGroups), %E");
-  else if (!(my_grps = (PTOKEN_GROUPS) alloca (size)))
-    debug_printf ("alloca (my_grps) failed.");
-  else if (!GetTokenInformation (token, TokenGroups, my_grps, size, &size))
-    debug_printf ("GetTokenInformation(my_token, TokenGroups), %E");
-  else
-    {
-      if (groups.issetgroups ()) /* setgroups was called */
-       {
-         cygsid gsid;
-         struct __group32 *gr;
-         bool saw[groups.sgsids.count ()];
-         memset (saw, 0, sizeof(saw));
-
-         /* token groups found in /etc/group match the user.gsids ? */
-         for (int gidx = 0; (gr = internal_getgrent (gidx)); ++gidx)
-           if (gsid.getfromgr (gr) && sid_in_token_groups (my_grps, gsid))
-             {
-               int pos = groups.sgsids.position (gsid);
-               if (pos >= 0)
-                 saw[pos] = true;
-               else if (groups.pgsid == gsid)
-                 sawpg = true;
-               else if (gsid != well_known_world_sid
-                        && gsid != usersid)
-                 goto done;
-             }
-         /* user.sgsids groups must be in the token */
-         for (int gidx = 0; gidx < groups.sgsids.count (); gidx++)
-           if (!saw[gidx] && !sid_in_token_groups (my_grps, groups.sgsids.sids[gidx]))
-             goto done;
-       }
-      /* The primary group must be in the token */
-      ret = sawpg
-       || sid_in_token_groups (my_grps, groups.pgsid)
-       || groups.pgsid == usersid;
-    }
-done:
-  return ret;
-}
-
-HANDLE
-create_token (cygsid &usersid, user_groups &new_groups, struct passwd *pw)
-{
-  NTSTATUS ret;
-  LSA_HANDLE lsa = INVALID_HANDLE_VALUE;
-
-  cygsidlist tmp_gsids (cygsidlist_auto, 12);
-
-  SECURITY_QUALITY_OF_SERVICE sqos =
-    { sizeof sqos, SecurityImpersonation, SECURITY_STATIC_TRACKING, FALSE };
-  OBJECT_ATTRIBUTES oa = { sizeof oa, 0, 0, 0, 0, &sqos };
-  LUID auth_luid = SYSTEM_LUID;
-  LARGE_INTEGER exp = { QuadPart:INT64_MAX };
-
-  TOKEN_USER user;
-  PTOKEN_GROUPS new_tok_gsids = NULL;
-  PTOKEN_PRIVILEGES privs = NULL;
-  TOKEN_OWNER owner;
-  TOKEN_PRIMARY_GROUP pgrp;
-  TOKEN_DEFAULT_DACL dacl = {};
-  TOKEN_SOURCE source;
-  TOKEN_STATISTICS stats;
-  memcpy (source.SourceName, "Cygwin.1", 8);
-  source.SourceIdentifier.HighPart = 0;
-  source.SourceIdentifier.LowPart = 0x0101;
-
-  HANDLE token = INVALID_HANDLE_VALUE;
-  HANDLE primary_token = INVALID_HANDLE_VALUE;
-
-  PTOKEN_GROUPS my_tok_gsids = NULL;
-  DWORD size;
-  size_t psize = 0;
-
-  /* SE_CREATE_TOKEN_NAME privilege needed to call NtCreateToken. */
-  push_self_privilege (SE_CREATE_TOKEN_PRIVILEGE, true);
-
-  /* Open policy object. */
-  if ((lsa = open_local_policy ()) == INVALID_HANDLE_VALUE)
-    goto out;
-
-  /* User, owner, primary group. */
-  user.User.Sid = usersid;
-  user.User.Attributes = 0;
-  owner.Owner = usersid;
-
-  /* Retrieve authentication id and group list from own process. */
-  if (hProcToken)
-    {
-      /* Switching user context to SYSTEM doesn't inherit the authentication
-        id of the user account running current process. */
-      if (usersid != well_known_system_sid)
-       if (!GetTokenInformation (hProcToken, TokenStatistics,
-                                 &stats, sizeof stats, &size))
-         debug_printf
-           ("GetTokenInformation(hProcToken, TokenStatistics), %E");
-       else
-         auth_luid = stats.AuthenticationId;
-
-      /* Retrieving current processes group list to be able to inherit
-        some important well known group sids. */
-      if (!GetTokenInformation (hProcToken, TokenGroups, NULL, 0, &size)
-         && GetLastError () != ERROR_INSUFFICIENT_BUFFER)
-       debug_printf ("GetTokenInformation(hProcToken, TokenGroups), %E");
-      else if (!(my_tok_gsids = (PTOKEN_GROUPS) malloc (size)))
-       debug_printf ("malloc (my_tok_gsids) failed.");
-      else if (!GetTokenInformation (hProcToken, TokenGroups, my_tok_gsids,
-                                    size, &size))
-       {
-         debug_printf ("GetTokenInformation(hProcToken, TokenGroups), %E");
-         free (my_tok_gsids);
-         my_tok_gsids = NULL;
-       }
-    }
-
-  /* Create list of groups, the user is member in. */
-  int auth_pos;
-  if (new_groups.issetgroups ())
-    get_setgroups_sidlist (tmp_gsids, usersid, pw, my_tok_gsids, new_groups,
-                          auth_luid, auth_pos);
-  else if (!get_initgroups_sidlist (tmp_gsids, usersid, new_groups.pgsid, pw,
-                                   my_tok_gsids, auth_luid, auth_pos))
-    goto out;
-
-  /* Primary group. */
-  pgrp.PrimaryGroup = new_groups.pgsid;
-
-  /* Create a TOKEN_GROUPS list from the above retrieved list of sids. */
-  new_tok_gsids = (PTOKEN_GROUPS)
-                 alloca (sizeof (DWORD) + tmp_gsids.count ()
-                                          * sizeof (SID_AND_ATTRIBUTES));
-  new_tok_gsids->GroupCount = tmp_gsids.count ();
-  for (DWORD i = 0; i < new_tok_gsids->GroupCount; ++i)
-    {
-      new_tok_gsids->Groups[i].Sid = tmp_gsids.sids[i];
-      new_tok_gsids->Groups[i].Attributes = SE_GROUP_MANDATORY
-                                           | SE_GROUP_ENABLED_BY_DEFAULT
-                                           | SE_GROUP_ENABLED;
-    }
-  if (auth_pos >= 0)
-    new_tok_gsids->Groups[auth_pos].Attributes |= SE_GROUP_LOGON_ID;
-  /* Retrieve list of privileges of that user. */
-  if (!(privs = get_priv_list (lsa, usersid, tmp_gsids, psize)))
-    goto out;
-
-  /* Let's be heroic... */
-  ret = NtCreateToken (&token, TOKEN_ALL_ACCESS, &oa, TokenImpersonation,
-                      &auth_luid, &exp, &user, new_tok_gsids, privs, &owner,
-                      &pgrp, &dacl, &source);
-  if (ret)
-    __seterrno_from_nt_status (ret);
-  else if (GetLastError () == ERROR_PROC_NOT_FOUND)
-    {
-      __seterrno ();
-      debug_printf ("Loading NtCreateToken failed.");
-    }
-  else
-    {
-      /* Convert to primary token. */
-      if (!DuplicateTokenEx (token, MAXIMUM_ALLOWED, &sec_none,
-                            SecurityImpersonation, TokenPrimary,
-                            &primary_token))
-       {
-         __seterrno ();
-         debug_printf ("DuplicateTokenEx %E");
-       }
-    }
-
-out:
-  pop_self_privilege ();
-  if (token != INVALID_HANDLE_VALUE)
-    CloseHandle (token);
-  if (privs)
-    free (privs);
-  if (my_tok_gsids)
-    free (my_tok_gsids);
-  close_local_policy (lsa);
-
-  debug_printf ("0x%x = create_token ()", primary_token);
-  return primary_token;
-}
-
-HANDLE
-lsaauth (cygsid &usersid, user_groups &new_groups, struct passwd *pw)
-{
-  cygsidlist tmp_gsids (cygsidlist_auto, 12);
-  cygpsid pgrpsid;
-  LSA_STRING name;
-  HANDLE lsa_hdl = NULL, lsa = INVALID_HANDLE_VALUE;
-  LSA_OPERATIONAL_MODE sec_mode;
-  NTSTATUS ret, ret2;
-  ULONG package_id, size;
-  LUID auth_luid = SYSTEM_LUID;
-  struct {
-    LSA_STRING str;
-    CHAR buf[16];
-  } origin;
-  cyglsa_t *authinf = NULL;
-  ULONG authinf_size;
-  TOKEN_SOURCE ts;
-  PCYG_TOKEN_GROUPS gsids = NULL;
-  PTOKEN_PRIVILEGES privs = NULL;
-  PACL dacl = NULL;
-  PVOID profile = NULL;
-  LUID luid;
-  QUOTA_LIMITS quota;
-  size_t psize = 0, gsize = 0, dsize = 0;
-  OFFSET offset, sids_offset;
-  int tmpidx, non_well_known_cnt;
-
-  HANDLE user_token = NULL;
-
-  push_self_privilege (SE_TCB_PRIVILEGE, true);
-
-  /* Register as logon process. */
-  str2lsa (name, "Cygwin");
-  SetLastError (0);
-  ret = LsaRegisterLogonProcess (&name, &lsa_hdl, &sec_mode);
-  if (ret != STATUS_SUCCESS)
-    {
-      debug_printf ("LsaRegisterLogonProcess: %p", ret);
-      __seterrno_from_win_error (LsaNtStatusToWinError (ret));
-      goto out;
-    }
-  else if (GetLastError () == ERROR_PROC_NOT_FOUND)
-    {
-      debug_printf ("Couldn't load Secur32.dll");
-      goto out;
-    }
-  /* Get handle to our own LSA package. */
-  str2lsa (name, CYG_LSA_PKGNAME);
-  ret = LsaLookupAuthenticationPackage (lsa_hdl, &name, &package_id);
-  if (ret != STATUS_SUCCESS)
-    {
-      debug_printf ("LsaLookupAuthenticationPackage: %p", ret);
-      __seterrno_from_win_error (LsaNtStatusToWinError (ret));
-      goto out;
-    }
-
-  /* Open policy object. */
-  if ((lsa = open_local_policy ()) == INVALID_HANDLE_VALUE)
-    goto out;
-
-  /* Create origin. */
-  str2buf2lsa (origin.str, origin.buf, "Cygwin");
-  /* Create token source. */
-  memcpy (ts.SourceName, "Cygwin.1", 8);
-  ts.SourceIdentifier.HighPart = 0;
-  ts.SourceIdentifier.LowPart = 0x0103;
-
-  /* Create list of groups, the user is member in. */
-  int auth_pos;
-  if (new_groups.issetgroups ())
-    get_setgroups_sidlist (tmp_gsids, usersid, pw, NULL, new_groups, auth_luid,
-                          auth_pos);
-  else if (!get_initgroups_sidlist (tmp_gsids, usersid, new_groups.pgsid, pw,
-                                   NULL, auth_luid, auth_pos))
-    goto out;
-  /* The logon SID entry is not generated automatically on Windows 2000
-     and earlier for some reason.  So add fake logon sid here, which is
-     filled with logon id values in the authentication package. */
-  if (wincap.needs_logon_sid_in_sid_list ())
-    tmp_gsids += fake_logon_sid;
-
-  tmp_gsids.debug_print ("tmp_gsids");
-
-  /* Evaluate size of TOKEN_GROUPS list */
-  non_well_known_cnt =  tmp_gsids.non_well_known_count ();
-  gsize = sizeof (DWORD) + non_well_known_cnt * sizeof (SID_AND_ATTRIBUTES);
-  tmpidx = -1;
-  for (int i = 0; i < non_well_known_cnt; ++i)
-    if ((tmpidx = tmp_gsids.next_non_well_known_sid (tmpidx)) >= 0)
-      gsize += GetLengthSid (tmp_gsids.sids[tmpidx]);
-
-  /* Retrieve list of privileges of that user. */
-  if (!(privs = get_priv_list (lsa, usersid, tmp_gsids, psize)))
-    goto out;
-
-  /* Create DefaultDacl. */
-  dsize = sizeof (ACL) + 3 * sizeof (ACCESS_ALLOWED_ACE)
-         + GetLengthSid (usersid)
-         + GetLengthSid (well_known_admins_sid)
-         + GetLengthSid (well_known_system_sid);
-  dacl = (PACL) alloca (dsize);
-  if (!InitializeAcl (dacl, dsize, ACL_REVISION))
-    goto out;
-  if (!AddAccessAllowedAce (dacl, ACL_REVISION, GENERIC_ALL, usersid))
-    goto out;
-  if (!AddAccessAllowedAce (dacl, ACL_REVISION, GENERIC_ALL,
-                           well_known_admins_sid))
-    goto out;
-  if (!AddAccessAllowedAce (dacl, ACL_REVISION, GENERIC_ALL,
-                           well_known_system_sid))
-    goto out;
-
-  /* Evaluate authinf size and allocate authinf. */
-  authinf_size = (authinf->data - (PBYTE) authinf);
-  authinf_size += GetLengthSid (usersid);          /* User SID */
-  authinf_size += gsize;                           /* Groups + Group SIDs */
-  /* When trying to define the admins group as primary group on Vista,
-     LsaLogonUser fails with error STATUS_INVALID_OWNER.  As workaround
-     we define "Local" as primary group here.  First, this adds the otherwise
-     missing "Local" group to the group list and second, seteuid32
-     sets the primary group to the group set in /etc/passwd anyway. */
-  pgrpsid = well_known_local_sid;
-  authinf_size += GetLengthSid (pgrpsid);          /* Primary Group SID */
-
-  authinf_size += psize;                           /* Privileges */
-  authinf_size += 0;                               /* Owner SID */
-  authinf_size += dsize;                           /* Default DACL */
-
-  authinf = (cyglsa_t *) alloca (authinf_size);
-  authinf->inf_size = authinf_size - ((PBYTE) &authinf->inf - (PBYTE) authinf);
-
-  authinf->magic = CYG_LSA_MAGIC;
-
-  extract_nt_dom_user (pw, authinf->domain, authinf->username);
-
-  /* Store stuff in authinf with offset relative to start of "inf" member,
-     instead of using pointers. */
-  offset = authinf->data - (PBYTE) &authinf->inf;
-
-  authinf->inf.ExpirationTime.LowPart = 0xffffffffL;
-  authinf->inf.ExpirationTime.HighPart = 0x7fffffffL;
-  /* User SID */
-  authinf->inf.User.User.Sid = offset;
-  authinf->inf.User.User.Attributes = 0;
-  CopySid (GetLengthSid (usersid), (PSID) ((PBYTE) &authinf->inf + offset),
-          usersid);
-  offset += GetLengthSid (usersid);
-  /* Groups */
-  authinf->inf.Groups = offset;
-  gsids = (PCYG_TOKEN_GROUPS) ((PBYTE) &authinf->inf + offset);
-  sids_offset = offset + sizeof (ULONG) + non_well_known_cnt
-                                         * sizeof (SID_AND_ATTRIBUTES);
-  gsids->GroupCount = non_well_known_cnt;
-  /* Group SIDs */
-  tmpidx = -1;
-  for (int i = 0; i < non_well_known_cnt; ++i)
-    {
-      if ((tmpidx = tmp_gsids.next_non_well_known_sid (tmpidx)) < 0)
-       break;
-      gsids->Groups[i].Sid = sids_offset;
-      gsids->Groups[i].Attributes = SE_GROUP_MANDATORY
-                                   | SE_GROUP_ENABLED_BY_DEFAULT
-                                   | SE_GROUP_ENABLED;
-      /* Mark logon SID as logon SID :) */
-      if (wincap.needs_logon_sid_in_sid_list ()
-         && tmp_gsids.sids[tmpidx] == fake_logon_sid)
-       gsids->Groups[i].Attributes += SE_GROUP_LOGON_ID;
-      CopySid (GetLengthSid (tmp_gsids.sids[tmpidx]),
-              (PSID) ((PBYTE) &authinf->inf + sids_offset),
-              tmp_gsids.sids[tmpidx]);
-      sids_offset += GetLengthSid (tmp_gsids.sids[tmpidx]);
-    }
-  offset += gsize;
-  /* Primary Group SID */
-  authinf->inf.PrimaryGroup.PrimaryGroup = offset;
-  CopySid (GetLengthSid (pgrpsid), (PSID) ((PBYTE) &authinf->inf + offset),
-          pgrpsid);
-  offset += GetLengthSid (pgrpsid);
-  /* Privileges */
-  authinf->inf.Privileges = offset;
-  memcpy ((PBYTE) &authinf->inf + offset, privs, psize);
-  offset += psize;
-  /* Owner */
-  authinf->inf.Owner.Owner = 0;
-  /* Default DACL */
-  authinf->inf.DefaultDacl.DefaultDacl = offset;
-  memcpy ((PBYTE) &authinf->inf + offset, dacl, dsize);
-
-  authinf->checksum = CYGWIN_VERSION_MAGIC (CYGWIN_VERSION_DLL_MAJOR,
-                                           CYGWIN_VERSION_DLL_MINOR);
-  PDWORD csp = (PDWORD) &authinf->username;
-  PDWORD csp_end = (PDWORD) ((PBYTE) authinf + authinf_size);
-  while (csp < csp_end)
-    authinf->checksum += *csp++;
-
-  /* Try to logon... */
-  ret = LsaLogonUser (lsa_hdl, (PLSA_STRING) &origin, Interactive, package_id,
-                     authinf, authinf_size, NULL, &ts, &profile, &size, &luid,
-                     &user_token, &quota, &ret2);
-  if (ret != STATUS_SUCCESS)
-    {
-      debug_printf ("LsaLogonUser: %p", ret);
-      __seterrno_from_win_error (LsaNtStatusToWinError (ret));
-      goto out;
-    }
-  if (profile)
-    LsaFreeReturnBuffer (profile);
-
-  if (wincap.has_mandatory_integrity_control ())
-    {
-      typedef struct _TOKEN_LINKED_TOKEN
-      {
-       HANDLE LinkedToken;
-      } TOKEN_LINKED_TOKEN, *PTOKEN_LINKED_TOKEN;
-#     define TokenLinkedToken ((TOKEN_INFORMATION_CLASS) 19)
-
-      TOKEN_LINKED_TOKEN linked;
-
-      if (GetTokenInformation (user_token, TokenLinkedToken,
-                              (PVOID) &linked, sizeof linked, &size))
-       {
-         debug_printf ("Linked Token: %lu", linked.LinkedToken);
-         if (linked.LinkedToken)
-           user_token = linked.LinkedToken;
+      if (!retry)
+        {
+         OBJECT_ATTRIBUTES attr;
+         IO_STATUS_BLOCK io;
+
+         status = NtOpenFile (&fh, READ_CONTROL,
+                              pc.get_object_attr (attr, sec_none_nih),
+                              &io, FILE_SHARE_VALID_FLAGS,
+                              FILE_OPEN_FOR_BACKUP_INTENT);
+         if (!NT_SUCCESS (status))
+           {
+             fh = NULL;
+             break;
+           }
        }
     }
-
-out:
-  if (privs)
-    free (privs);
-  close_local_policy (lsa);
-  if (lsa_hdl)
-    LsaDeregisterLogonProcess (lsa_hdl);
-  pop_self_privilege ();
-
-  debug_printf ("0x%x = lsaauth ()", user_token);
-  return user_token;
-}
-
-/* read_sd reads a security descriptor from a file.
-   In case of error, -1 is returned and errno is set.
-   If sd_buf is too small, 0 is returned and sd_size
-   is set to the needed buffer size.
-   On success, 1 is returned.
-
-   GetFileSecurity() is used instead of BackupRead()
-   to avoid access denied errors if the caller has
-   not the permission to open that file for read.
-
-   Originally the function should return the size
-   of the SD on success. Unfortunately NT returns
-   0 in `len' on success, while W2K returns the
-   correct size!
-
-   2003-11-26: Now the function allocates the space needed by itself so
-   it knows the real size and returns it in the security_descriptor object.
-*/
-
-LONG
-read_sd (const char *file, security_descriptor &sd)
-{
-
-  DWORD len = 0;
-  const char *pfile = file;
-  char fbuf[CYG_MAX_PATH];
-  if (current_codepage == oem_cp)
-    {
-      DWORD fname_len = min (sizeof (fbuf) - 1, strlen (file));
-      bzero (fbuf, sizeof (fbuf));
-      OemToCharBuff (file, fbuf, fname_len);
-      pfile = fbuf;
-    }
-
-  if (!GetFileSecurity (pfile,
-                       OWNER_SECURITY_INFORMATION
-                       | GROUP_SECURITY_INFORMATION
-                       | DACL_SECURITY_INFORMATION,
-                       NULL, 0, &len)
-      && GetLastError () != ERROR_INSUFFICIENT_BUFFER)
-    {
-      debug_printf ("file %s", file);
-      __seterrno ();
-      return -1;
-    }
-  debug_printf ("file %s: len %d", file, len);
-  if (!sd.malloc (len))
-    {
-      set_errno (ENOMEM);
-      return -1;
-    }
-  if (!GetFileSecurity (pfile,
-                       OWNER_SECURITY_INFORMATION
-                       | GROUP_SECURITY_INFORMATION
-                       | DACL_SECURITY_INFORMATION,
-                       sd, len, &len))
-    {
-      __seterrno ();
-      return -1;
-    }
-  return sd.size ();
+  if (retry && fh)
+    NtClose (fh);
+  if (!NT_SUCCESS (status))
+    __seterrno_from_nt_status (status);
+  return res;
 }
 
 LONG
-write_sd (HANDLE fh, const char *file, security_descriptor &sd)
+set_file_sd (HANDLE fh, path_conv &pc, security_descriptor &sd)
 {
-  NTSTATUS ret = STATUS_SUCCESS;
+  NTSTATUS status = STATUS_SUCCESS;
   int retry = 0;
   int res = -1;
+
   for (; retry < 2; ++retry)
     {
-      if (retry && (fh = CreateFile (file, WRITE_OWNER | WRITE_DAC,
-                                    FILE_SHARE_READ | FILE_SHARE_WRITE,
-                                    &sec_none_nih, OPEN_EXISTING,
-                                    FILE_ATTRIBUTE_NORMAL
-                                    | FILE_FLAG_BACKUP_SEMANTICS,
-                                    NULL)) == INVALID_HANDLE_VALUE)
-       break;
-      if (fh && (ret = NtSetSecurityObject (fh,
-                                           DACL_SECURITY_INFORMATION
-                                           | GROUP_SECURITY_INFORMATION
-                                           | OWNER_SECURITY_INFORMATION,
-                                           sd)) == STATUS_SUCCESS)
-       break;
+      if (fh)
+        {
+         status = NtSetSecurityObject (fh, ALL_SECURITY_INFORMATION, sd);
+         if (NT_SUCCESS (status))
+           {
+             res = 0;
+             break;
+           }
+       }
+      if (!retry)
+        {
+         OBJECT_ATTRIBUTES attr;
+         IO_STATUS_BLOCK io;
+
+         status = NtOpenFile (&fh, WRITE_OWNER | WRITE_DAC,
+                              pc.get_object_attr (attr, sec_none_nih),
+                              &io, FILE_SHARE_VALID_FLAGS,
+                              FILE_OPEN_FOR_RECOVERY);
+         if (!NT_SUCCESS (status))
+           {
+             fh = NULL;
+             break;
+           }
+       }
     }
-  if (retry && fh != INVALID_HANDLE_VALUE)
-    CloseHandle (fh);
-  if (fh == INVALID_HANDLE_VALUE)      /* CreateFile failed */
-    __seterrno ();
-  else if (ret != STATUS_SUCCESS)      /* NtSetSecurityObject failed */
-    __seterrno_from_nt_status (ret);
-  else                                 /* Everything's fine. */
-    res = 0;
+  if (retry && fh)
+    NtClose (fh);
+  if (!NT_SUCCESS (status))
+    __seterrno_from_nt_status (status);
   return res;
 }
 
@@ -1426,25 +282,19 @@ get_info_from_sd (PSECURITY_DESCRIPTOR psd, mode_t *attribute,
 }
 
 static int
-get_reg_security (HANDLE handle, security_descriptor &sd_ret)
+get_reg_sd (HANDLE handle, security_descriptor &sd_ret)
 {
   LONG ret;
   DWORD len = 0;
 
-  ret = RegGetKeySecurity ((HKEY) handle,
-                          DACL_SECURITY_INFORMATION
-                          | GROUP_SECURITY_INFORMATION
-                          | OWNER_SECURITY_INFORMATION,
+  ret = RegGetKeySecurity ((HKEY) handle, ALL_SECURITY_INFORMATION,
                           sd_ret, &len);
   if (ret == ERROR_INSUFFICIENT_BUFFER)
     {
       if (!sd_ret.malloc (len))
        set_errno (ENOMEM);
       else
-       ret = RegGetKeySecurity ((HKEY) handle,
-                                DACL_SECURITY_INFORMATION
-                                | GROUP_SECURITY_INFORMATION
-                                | OWNER_SECURITY_INFORMATION,
+       ret = RegGetKeySecurity ((HKEY) handle, ALL_SECURITY_INFORMATION,
                                 sd_ret, &len);
     }
   if (ret != ERROR_SUCCESS)
@@ -1456,87 +306,36 @@ get_reg_security (HANDLE handle, security_descriptor &sd_ret)
 }
 
 int
-get_nt_object_security (HANDLE handle, SE_OBJECT_TYPE object_type,
-                       security_descriptor &sd_ret)
-{
-  NTSTATUS ret;
-  ULONG len = 0;
-
-  /* Do not try to use GetSecurityInfo (again), unless we drop NT4 support.
-     GetSecurityInfo returns the wrong user information when running in
-     a user session using a token created with NtCreateToken under NT4.
-     Works fine in 2K and above, but that doesn't help a lot. */
-
-  /* Unfortunately, NtQuerySecurityObject doesn't work on predefined registry
-     keys like HKEY_LOCAL_MACHINE.  It fails with "Invalid Handle".  So we
-     have to retreat to the Win32 registry functions for registry keys.
-     What bugs me is that RegGetKeySecurity is obviously just a wrapper
-     around NtQuerySecurityObject, but there seems to be no function to
-     convert pseudo HKEY values to real handles. */
-  if (object_type == SE_REGISTRY_KEY)
-    return get_reg_security (handle, sd_ret);
-
-  ret = NtQuerySecurityObject (handle,
-                              DACL_SECURITY_INFORMATION
-                              | GROUP_SECURITY_INFORMATION
-                              | OWNER_SECURITY_INFORMATION,
-                              sd_ret, len, &len);
-  if (ret == STATUS_BUFFER_TOO_SMALL)
-    {
-      if (!sd_ret.malloc (len))
-       set_errno (ENOMEM);
-      else
-       ret = NtQuerySecurityObject (handle,
-                                    DACL_SECURITY_INFORMATION
-                                    | GROUP_SECURITY_INFORMATION
-                                    | OWNER_SECURITY_INFORMATION,
-                                    sd_ret, len, &len);
-    }
-  if (ret != STATUS_SUCCESS)
-    {
-      __seterrno_from_nt_status (ret);
-      return -1;
-    }
-  return 0;
-}
-
-int
-get_object_attribute (HANDLE handle, SE_OBJECT_TYPE object_type,
-                     mode_t *attribute, __uid32_t *uidret, __gid32_t *gidret)
+get_reg_attribute (HKEY hkey, mode_t *attribute, __uid32_t *uidret,
+                  __gid32_t *gidret)
 {
   if (allow_ntsec)
     {
       security_descriptor sd;
-      PSECURITY_DESCRIPTOR psd = NULL;
 
-      if (get_nt_object_security (handle, object_type, sd))
+      if (!get_reg_sd (hkey, sd))
        {
-         if (object_type == SE_FILE_OBJECT)
-           return -1;
+         get_info_from_sd (sd, attribute, uidret, gidret);
+         return 0;
        }
-      else
-       psd = sd;
-      get_info_from_sd (psd, attribute, uidret, gidret);
-      return 0;
     }
   /* The entries are already set to default values */
   return -1;
 }
 
 int
-get_file_attribute (int use_ntsec, HANDLE handle, const char *file,
+get_file_attribute (HANDLE handle, path_conv &pc,
                    mode_t *attribute, __uid32_t *uidret, __gid32_t *gidret)
 {
-  syscall_printf ("file: %s", file);
-
-  if (use_ntsec && allow_ntsec)
+  if (pc.has_acls () && allow_ntsec)
     {
       security_descriptor sd;
 
-      if (!handle || get_nt_object_security (handle, SE_FILE_OBJECT, sd))
-       read_sd (file, sd);
-      get_info_from_sd (sd, attribute, uidret, gidret);
-      return 0;
+      if (!get_file_sd (handle, pc, sd))
+       {
+         get_info_from_sd (sd, attribute, uidret, gidret);
+         return 0;
+       }
     }
 
   if (uidret)
@@ -1893,35 +692,25 @@ set_security_attribute (int attribute, PSECURITY_ATTRIBUTES psa,
 }
 
 int
-set_file_attribute (bool use_ntsec, HANDLE handle, const char *file,
+set_file_attribute (HANDLE handle, path_conv &pc,
                    __uid32_t uid, __gid32_t gid, int attribute)
 {
   int ret = -1;
 
-  if (use_ntsec && allow_ntsec)
+  if (pc.has_acls () && allow_ntsec)
     {
       security_descriptor sd;
 
-      if (((handle && !get_nt_object_security (handle, SE_FILE_OBJECT, sd))
-          || read_sd (file, sd) > 0)
-         && alloc_sd (uid, gid, attribute, sd))
-       ret = write_sd (handle, file, sd);
+      if (!get_file_sd (handle, pc, sd) && alloc_sd (uid, gid, attribute, sd))
+       ret = set_file_sd (handle, pc, sd);
     }
   else
     ret = 0;
   syscall_printf ("%d = set_file_attribute (%s, %d, %d, %p)",
-                 ret, file, uid, gid, attribute);
+                 ret, pc.get_win32 (), uid, gid, attribute);
   return ret;
 }
 
-int
-set_file_attribute (bool use_ntsec, HANDLE handle, const char *file,
-                   int attribute)
-{
-  return set_file_attribute (use_ntsec, handle, file,
-                            myself->uid, myself->gid, attribute);
-}
-
 static int
 check_access (security_descriptor &sd, GENERIC_MAPPING &mapping,
              DWORD desired, int flags)
@@ -1993,7 +782,7 @@ check_access (security_descriptor &sd, GENERIC_MAPPING &mapping,
 }
 
 int
-check_file_access (const char *fn, int flags)
+check_file_access (path_conv &pc, int flags)
 {
   security_descriptor sd;
   int ret = -1;
@@ -2008,7 +797,7 @@ check_file_access (const char *fn, int flags)
     desired |= FILE_WRITE_DATA;
   if (flags & X_OK)
     desired |= FILE_EXECUTE;
-  if (read_sd (fn, sd) > 0)
+  if (!get_file_sd (NULL, pc, sd))
     ret = check_access (sd, mapping, desired, flags);
   debug_printf ("flags %x, ret %d", flags, ret);
   return ret;
@@ -2030,7 +819,7 @@ check_registry_access (HANDLE hdl, int flags)
     desired |= KEY_SET_VALUE;
   if (flags & X_OK)
     desired |= KEY_QUERY_VALUE;
-  if (!get_nt_object_security (hdl, SE_REGISTRY_KEY, sd))
+  if (!get_reg_sd (hdl, sd))
     ret = check_access (sd, mapping, desired, flags);
   /* As long as we can't write the registry... */
   if (flags & W_OK)
index 9aaaadb..c697855 100644 (file)
@@ -335,19 +335,16 @@ extern bool allow_ntsec;
 extern bool allow_smbntsec;
 
 /* File manipulation */
-int __stdcall get_file_attribute (int, HANDLE, const char *, mode_t *,
-                                 __uid32_t * = NULL, __gid32_t * = NULL);
-int __stdcall set_file_attribute (bool, HANDLE, const char *, int);
-int __stdcall set_file_attribute (bool, HANDLE, const char *, __uid32_t, __gid32_t, int);
-int __stdcall get_nt_object_security (HANDLE, SE_OBJECT_TYPE,
-                                     security_descriptor &);
-int __stdcall get_object_attribute (HANDLE handle, SE_OBJECT_TYPE object_type, mode_t *,
-                                 __uid32_t * = NULL, __gid32_t * = NULL);
-LONG __stdcall read_sd (const char *file, security_descriptor &sd);
-LONG __stdcall write_sd (HANDLE fh, const char *file, security_descriptor &sd);
+int __stdcall get_file_attribute (HANDLE, path_conv &, mode_t *,
+                                 __uid32_t *, __gid32_t *);
+int __stdcall set_file_attribute (HANDLE, path_conv &,
+                                 __uid32_t, __gid32_t, int);
+int __stdcall get_reg_attribute (HKEY hkey, mode_t *, __uid32_t *, __gid32_t *);
+LONG __stdcall get_file_sd (HANDLE fh, path_conv &, security_descriptor &sd);
+LONG __stdcall set_file_sd (HANDLE fh, path_conv &, security_descriptor &sd);
 bool __stdcall add_access_allowed_ace (PACL acl, int offset, DWORD attributes, PSID sid, size_t &len_add, DWORD inherit);
 bool __stdcall add_access_denied_ace (PACL acl, int offset, DWORD attributes, PSID sid, size_t &len_add, DWORD inherit);
-int __stdcall check_file_access (const char *, int);
+int __stdcall check_file_access (path_conv &, int);
 int __stdcall check_registry_access (HANDLE, int);
 
 void set_security_attribute (int attribute, PSECURITY_ATTRIBUTES psa,
@@ -359,8 +356,8 @@ bool get_sids_info (cygpsid, cygpsid, __uid32_t * , __gid32_t *);
 struct __acl32;
 extern "C" int aclsort32 (int, int, __acl32 *);
 extern "C" int acl32 (const char *, int, int, __acl32 *);
-int getacl (HANDLE, const char *, DWORD, int, __acl32 *);
-int setacl (HANDLE, const char *, int, __acl32 *, bool &);
+int getacl (HANDLE, path_conv &, int, __acl32 *);
+int setacl (HANDLE, path_conv &, int, __acl32 *, bool &);
 
 struct _UNICODE_STRING;
 void __stdcall str2buf2uni (_UNICODE_STRING &, WCHAR *, const char *) __attribute__ ((regparm (3)));