Welcome to mirror list, hosted at ThFree Co, Russian Federation.

cygwin.com/git/newlib-cygwin.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCorinna Vinschen <corinna@vinschen.de>2007-07-20 18:29:43 +0400
committerCorinna Vinschen <corinna@vinschen.de>2007-07-20 18:29:43 +0400
commiteea4e4820871fcc7c39392606e8ac07620ebe49b (patch)
tree9e65dc78ab11fa976c49b6eee3bfdacf93b0e89e
parentf36b37ed6ea793ce33ec84c694f772fb6de1ddd4 (diff)
* 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.
-rw-r--r--winsup/cygwin/ChangeLog33
-rw-r--r--winsup/cygwin/Makefile.in12
-rw-r--r--winsup/cygwin/fhandler.cc2
-rw-r--r--winsup/cygwin/fhandler_disk_file.cc21
-rw-r--r--winsup/cygwin/fhandler_registry.cc4
-rw-r--r--winsup/cygwin/sec_acl.cc35
-rw-r--r--winsup/cygwin/sec_auth.cc1119
-rw-r--r--winsup/cygwin/sec_helper.cc10
-rw-r--r--winsup/cygwin/security.cc1409
-rw-r--r--winsup/cygwin/security.h23
10 files changed, 1287 insertions, 1381 deletions
diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog
index 47f009c7e..72cf45ceb 100644
--- a/winsup/cygwin/ChangeLog
+++ b/winsup/cygwin/ChangeLog
@@ -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.
diff --git a/winsup/cygwin/Makefile.in b/winsup/cygwin/Makefile.in
index eb0c85814..5251ff9b8 100644
--- a/winsup/cygwin/Makefile.in
+++ b/winsup/cygwin/Makefile.in
@@ -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
diff --git a/winsup/cygwin/fhandler.cc b/winsup/cygwin/fhandler.cc
index 960b37549..0ee0bbb8a 100644
--- a/winsup/cygwin/fhandler.cc
+++ b/winsup/cygwin/fhandler.cc
@@ -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)
diff --git a/winsup/cygwin/fhandler_disk_file.cc b/winsup/cygwin/fhandler_disk_file.cc
index 5d37d04d5..59fcb4450 100644
--- a/winsup/cygwin/fhandler_disk_file.cc
+++ b/winsup/cygwin/fhandler_disk_file.cc
@@ -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);
diff --git a/winsup/cygwin/fhandler_registry.cc b/winsup/cygwin/fhandler_registry.cc
index 62cd8f454..23d88c82a 100644
--- a/winsup/cygwin/fhandler_registry.cc
+++ b/winsup/cygwin/fhandler_registry.cc
@@ -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;
diff --git a/winsup/cygwin/sec_acl.cc b/winsup/cygwin/sec_acl.cc
index 87c6428fe..54d443b17 100644
--- a/winsup/cygwin/sec_acl.cc
+++ b/winsup/cygwin/sec_acl.cc
@@ -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
index 000000000..7cf2cb43f
--- /dev/null
+++ b/winsup/cygwin/sec_auth.cc
@@ -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;
+}
diff --git a/winsup/cygwin/sec_helper.cc b/winsup/cygwin/sec_helper.cc
index 4fb6252bc..7fc9492ad 100644
--- a/winsup/cygwin/sec_helper.cc
+++ b/winsup/cygwin/sec_helper.cc
@@ -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"
diff --git a/winsup/cygwin/security.cc b/winsup/cygwin/security.cc
index 5fca3d8ed..5740446e7 100644
--- a/winsup/cygwin/security.cc
+++ b/winsup/cygwin/security.cc
@@ -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)
diff --git a/winsup/cygwin/security.h b/winsup/cygwin/security.h
index 9aaaadb7d..c69785563 100644
--- a/winsup/cygwin/security.h
+++ b/winsup/cygwin/security.h
@@ -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)));