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
path: root/winsup
diff options
context:
space:
mode:
authorCorinna Vinschen <corinna@vinschen.de>2001-05-20 12:10:47 +0400
committerCorinna Vinschen <corinna@vinschen.de>2001-05-20 12:10:47 +0400
commit1fcc912f135e11aa78a4ed529c70d6887cfcb317 (patch)
treec4b324e704e1744bea60ee46e6695c67665549c7 /winsup
parentdf7cd7fb0c3a857b652238573fb303ffce7eeb12 (diff)
* autoload.cc: Add load statements for `LookupAccountNameW',
`LsaClose', `LsaEnumerateAccountRights', `LsaFreeMemory', `LsaOpenPolicy', `LsaQueryInformationPolicy', `NetLocalGroupEnum', `NetLocalGroupGetMembers', `NetServerEnum', `NetUserGetGroups' and `NtCreateToken'. * ntdll.h: Add declaration for `NtCreateToken'. * sec_helper.cc: Add `well_known_local_sid', `well_known_dialup_sid', `well_known_network_sid', `well_known_batch_sid', `well_known_interactive_sid', `well_known_service_sid' and `well_known_authenticated_users_sid'. (cygsid::string): Define as const method. (cygsid::get_sid): Set psid to NO_SID on error. (cygsid::getfromstr): Ditto. (cygsid::getfrompw): Simplify. (cygsid::getfromgr): Check for gr == NULL. (legal_sid_type): Move to security.h. (set_process_privilege): Return -1 on error, otherwise 0 or 1 related to previous privilege setting. * security.cc (extract_nt_dom_user): Remove `static'. (lsa2wchar): New function. (open_local_policy): Ditto. (close_local_policy): Ditto. (get_lsa_srv_inf): Ditto. (get_logon_server): Ditto. (get_logon_server_and_user_domain): Ditto. (get_user_groups): Ditto. (is_group_member): Ditto. (get_user_local_groups): Ditto. (sid_in_token_groups): Ditto. (get_user_primary_group): Ditto. (get_group_sidlist): Ditto. (get_system_priv_list): Ditto. (get_priv_list): Ditto. (get_dacl): Ditto. (create_token): Ditto. (subauth): Return immediately if SE_TCB_NAME can't be assigned. Change all return statements in case of error to jumps to `out' label. Add `out' label to support cleanup. * security.h: Add extern declarations for `well_known_local_sid', `well_known_dialup_sid', `well_known_network_sid', `well_known_batch_sid', `well_known_interactive_sid', `well_known_service_sid' and `well_known_authenticated_users_sid'. Add extern declarations for functions `create_token', `extract_nt_dom_user' and `get_logon_server_and_user_domain'. (class cygsid): Add method `assign'. Change operator= to call new `assign' method. Add `debug_print' method. (class cygsidlist): New class. (legal_sid_type): Moved from sec_helper.cc to here. * spawn.cc (spawn_guts) Revert reversion of previous patch. Call `RevertToSelf' and `ImpersonateLoggedOnUser' instead of `seteuid' again. * syscalls.cc (seteuid): Rearranged. Call `create_token' now when needed. Call `subauth' if `create_token' fails. Try setting token owner and primary group only if token was not explicitely created by `create_token'. * uinfo.cc (internal_getlogin): Try harder to generate correct user information. Especially don't trust return value of `GetUserName'.
Diffstat (limited to 'winsup')
-rw-r--r--winsup/cygwin/ChangeLog60
-rw-r--r--winsup/cygwin/autoload.cc17
-rw-r--r--winsup/cygwin/ntdll.h7
-rw-r--r--winsup/cygwin/sec_helper.cc61
-rw-r--r--winsup/cygwin/security.cc673
-rw-r--r--winsup/cygwin/security.h105
-rw-r--r--winsup/cygwin/spawn.cc5
-rw-r--r--winsup/cygwin/syscalls.cc223
-rw-r--r--winsup/cygwin/uinfo.cc51
9 files changed, 1041 insertions, 161 deletions
diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog
index 5cb09f361..ac15783f9 100644
--- a/winsup/cygwin/ChangeLog
+++ b/winsup/cygwin/ChangeLog
@@ -1,3 +1,63 @@
+Sat May 19 23:40:00 2001 Corinna Vinschen <corinna@vinschen.de>
+
+ * autoload.cc: Add load statements for `LookupAccountNameW',
+ `LsaClose', `LsaEnumerateAccountRights', `LsaFreeMemory',
+ `LsaOpenPolicy', `LsaQueryInformationPolicy', `NetLocalGroupEnum',
+ `NetLocalGroupGetMembers', `NetServerEnum', `NetUserGetGroups' and
+ `NtCreateToken'.
+ * ntdll.h: Add declaration for `NtCreateToken'.
+ * sec_helper.cc: Add `well_known_local_sid', `well_known_dialup_sid',
+ `well_known_network_sid', `well_known_batch_sid',
+ `well_known_interactive_sid', `well_known_service_sid' and
+ `well_known_authenticated_users_sid'.
+ (cygsid::string): Define as const method.
+ (cygsid::get_sid): Set psid to NO_SID on error.
+ (cygsid::getfromstr): Ditto.
+ (cygsid::getfrompw): Simplify.
+ (cygsid::getfromgr): Check for gr == NULL.
+ (legal_sid_type): Move to security.h.
+ (set_process_privilege): Return -1 on error, otherwise 0 or 1 related
+ to previous privilege setting.
+ * security.cc (extract_nt_dom_user): Remove `static'.
+ (lsa2wchar): New function.
+ (open_local_policy): Ditto.
+ (close_local_policy): Ditto.
+ (get_lsa_srv_inf): Ditto.
+ (get_logon_server): Ditto.
+ (get_logon_server_and_user_domain): Ditto.
+ (get_user_groups): Ditto.
+ (is_group_member): Ditto.
+ (get_user_local_groups): Ditto.
+ (sid_in_token_groups): Ditto.
+ (get_user_primary_group): Ditto.
+ (get_group_sidlist): Ditto.
+ (get_system_priv_list): Ditto.
+ (get_priv_list): Ditto.
+ (get_dacl): Ditto.
+ (create_token): Ditto.
+ (subauth): Return immediately if SE_TCB_NAME can't be assigned.
+ Change all return statements in case of error to jumps to `out'
+ label. Add `out' label to support cleanup.
+ * security.h: Add extern declarations for `well_known_local_sid',
+ `well_known_dialup_sid', `well_known_network_sid',
+ `well_known_batch_sid', `well_known_interactive_sid',
+ `well_known_service_sid' and `well_known_authenticated_users_sid'.
+ Add extern declarations for functions `create_token',
+ `extract_nt_dom_user' and `get_logon_server_and_user_domain'.
+ (class cygsid): Add method `assign'. Change operator= to call new
+ `assign' method. Add `debug_print' method.
+ (class cygsidlist): New class.
+ (legal_sid_type): Moved from sec_helper.cc to here.
+ * spawn.cc (spawn_guts) Revert reversion of previous patch.
+ Call `RevertToSelf' and `ImpersonateLoggedOnUser' instead of `seteuid'
+ again.
+ * syscalls.cc (seteuid): Rearranged. Call `create_token' now when
+ needed. Call `subauth' if `create_token' fails. Try setting token
+ owner and primary group only if token was not explicitely created
+ by `create_token'.
+ * uinfo.cc (internal_getlogin): Try harder to generate correct user
+ information. Especially don't trust return value of `GetUserName'.
+
Sat May 19 21:16:07 2001 Christopher Faylor <cgf@cygnus.com>
* fork.cc (fork_parent): Move atforkprepare call here.
diff --git a/winsup/cygwin/autoload.cc b/winsup/cygwin/autoload.cc
index 6e20e0be5..9da788957 100644
--- a/winsup/cygwin/autoload.cc
+++ b/winsup/cygwin/autoload.cc
@@ -333,9 +333,15 @@ LoadDLLfunc (InitializeSid, 12, advapi32)
LoadDLLfunc (IsValidSid, 4, advapi32)
LoadDLLfunc (LogonUserA, 24, advapi32)
LoadDLLfunc (LookupAccountNameA, 28, advapi32)
+LoadDLLfunc (LookupAccountNameW, 28, advapi32)
LoadDLLfunc (LookupAccountSidA, 28, advapi32)
LoadDLLfunc (LookupPrivilegeValueA, 12, advapi32)
-LoadDLLfuncEx (LsaNtStatusToWinError, 4, advapi32, 1)
+LoadDLLfunc (LsaClose, 4, advapi32)
+LoadDLLfunc (LsaEnumerateAccountRights, 16, advapi32)
+LoadDLLfunc (LsaFreeMemory, 4, advapi32)
+LoadDLLfunc (LsaNtStatusToWinError, 4, advapi32)
+LoadDLLfunc (LsaOpenPolicy, 16, advapi32)
+LoadDLLfunc (LsaQueryInformationPolicy, 12, advapi32)
LoadDLLfunc (MakeSelfRelativeSD, 12, advapi32)
LoadDLLfunc (OpenProcessToken, 12, advapi32)
LoadDLLfunc (RegCloseKey, 4, advapi32)
@@ -358,10 +364,15 @@ LoadDLLfunc (SetSecurityDescriptorGroup, 12, advapi32)
LoadDLLfunc (SetSecurityDescriptorOwner, 12, advapi32)
LoadDLLfunc (SetTokenInformation, 16, advapi32)
-LoadDLLfunc (NetWkstaUserGetInfo, 12, netapi32)
-LoadDLLfunc (NetUserGetInfo, 16, netapi32)
LoadDLLfunc (NetApiBufferFree, 4, netapi32)
+LoadDLLfunc (NetLocalGroupEnum, 28, netapi32)
+LoadDLLfunc (NetLocalGroupGetMembers, 32, netapi32)
+LoadDLLfunc (NetServerEnum, 36, netapi32)
+LoadDLLfunc (NetUserGetGroups, 28, netapi32)
+LoadDLLfunc (NetUserGetInfo, 16, netapi32)
+LoadDLLfunc (NetWkstaUserGetInfo, 12, netapi32)
+LoadDLLfuncEx (NtCreateToken, 52, ntdll, 1)
LoadDLLfuncEx (NtMapViewOfSection, 40, ntdll, 1)
LoadDLLfuncEx (NtOpenSection, 12, ntdll, 1)
LoadDLLfuncEx (NtQuerySystemInformation, 16, ntdll, 1)
diff --git a/winsup/cygwin/ntdll.h b/winsup/cygwin/ntdll.h
index 5b9b51453..465d60969 100644
--- a/winsup/cygwin/ntdll.h
+++ b/winsup/cygwin/ntdll.h
@@ -136,12 +136,17 @@ typedef struct _SYSTEM_PROCESSES
standard Win32 header. */
extern "C"
{
+ NTSTATUS NTAPI NtCreateToken (PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES,
+ TOKEN_TYPE, PLUID, PLARGE_INTEGER, PTOKEN_USER,
+ PTOKEN_GROUPS, PTOKEN_PRIVILEGES, PTOKEN_OWNER,
+ PTOKEN_PRIMARY_GROUP, PTOKEN_DEFAULT_DACL,
+ PTOKEN_SOURCE);
NTSTATUS NTAPI NtMapViewOfSection (HANDLE, HANDLE, PVOID *, ULONG, ULONG,
PLARGE_INTEGER, PULONG, SECTION_INHERIT,
ULONG, ULONG);
+ NTSTATUS NTAPI NtOpenSection (PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES);
NTSTATUS NTAPI NtQuerySystemInformation (SYSTEM_INFORMATION_CLASS,
PVOID, ULONG, PULONG);
- NTSTATUS NTAPI NtOpenSection (PHANDLE, ACCESS_MASK, POBJECT_ATTRIBUTES);
NTSTATUS NTAPI NtUnmapViewOfSection (HANDLE, PVOID);
VOID NTAPI RtlInitUnicodeString (PUNICODE_STRING, PCWSTR);
ULONG NTAPI RtlNtStatusToDosError (NTSTATUS);
diff --git a/winsup/cygwin/sec_helper.cc b/winsup/cygwin/sec_helper.cc
index 31672a8cf..264aac4ec 100644
--- a/winsup/cygwin/sec_helper.cc
+++ b/winsup/cygwin/sec_helper.cc
@@ -44,13 +44,20 @@ SID_IDENTIFIER_AUTHORITY sid_auth[] = {
{SECURITY_NT_AUTHORITY}
};
-cygsid well_known_admin_sid ("S-1-5-32-544");
-cygsid well_known_system_sid ("S-1-5-18");
-cygsid well_known_creator_owner_sid ("S-1-3-0");
cygsid well_known_world_sid ("S-1-1-0");
+cygsid well_known_local_sid ("S-1-2-0");
+cygsid well_known_creator_owner_sid ("S-1-3-0");
+cygsid well_known_dialup_sid ("S-1-5-1");
+cygsid well_known_network_sid ("S-1-5-2");
+cygsid well_known_batch_sid ("S-1-5-3");
+cygsid well_known_interactive_sid ("S-1-5-4");
+cygsid well_known_service_sid ("S-1-5-6");
+cygsid well_known_authenticated_users_sid ("S-1-5-11");
+cygsid well_known_system_sid ("S-1-5-18");
+cygsid well_known_admin_sid ("S-1-5-32-544");
char *
-cygsid::string (char *nsidstr)
+cygsid::string (char *nsidstr) const
{
char t[32];
DWORD i;
@@ -74,7 +81,10 @@ cygsid::get_sid (DWORD s, DWORD cnt, DWORD *r)
DWORD i;
if (s > 5 || cnt < 1 || cnt > 8)
- return NULL;
+ {
+ psid = NO_SID;
+ return NULL;
+ }
set ();
InitializeSid(psid, &sid_auth[s], cnt);
for (i = 0; i < cnt; ++i)
@@ -92,7 +102,10 @@ cygsid::getfromstr (const char *nsidstr)
DWORD i, r[8];
if (!nsidstr || strncmp (nsidstr, "S-1-", 4))
- return NULL;
+ {
+ psid = NO_SID;
+ return NULL;
+ }
strcpy (sid_buf, nsidstr);
@@ -110,17 +123,15 @@ cygsid::getfromstr (const char *nsidstr)
BOOL
cygsid::getfrompw (struct passwd *pw)
{
- char *sp = pw->pw_gecos ? strrchr (pw->pw_gecos, ',') : NULL;
-
- if (!sp)
- return FALSE;
- return (*this = ++sp) != NULL;
+ char *sp = (pw && pw->pw_gecos) ? strrchr (pw->pw_gecos, ',') : NULL;
+ return (*this = sp ? sp + 1 : "") != NULL;
}
BOOL
cygsid::getfromgr (struct group *gr)
{
- return (*this = gr->gr_passwd) != NULL;
+ char *sp = (gr && gr->gr_passwd) ? gr->gr_passwd : NULL;
+ return (*this = sp ?: "") != NULL;
}
int
@@ -238,13 +249,6 @@ cygsid::get_id (BOOL search_grp, int *type)
return id;
}
-static inline BOOL
-legal_sid_type (SID_NAME_USE type)
-{
- return type == SidTypeUser || type == SidTypeGroup
- || type == SidTypeAlias || type == SidTypeWellKnownGroup;
-}
-
BOOL
is_grp_member (uid_t uid, gid_t gid)
{
@@ -338,10 +342,12 @@ set_process_privilege (const char *privilege, BOOL enable)
{
HANDLE hToken = NULL;
LUID restore_priv;
- TOKEN_PRIVILEGES new_priv;
+ TOKEN_PRIVILEGES new_priv, orig_priv;
int ret = -1;
+ DWORD size;
- if (!OpenProcessToken (hMainProc, TOKEN_ADJUST_PRIVILEGES, &hToken))
+ if (!OpenProcessToken (hMainProc, TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES,
+ &hToken))
{
__seterrno ();
goto out;
@@ -357,13 +363,22 @@ set_process_privilege (const char *privilege, BOOL enable)
new_priv.Privileges[0].Luid = restore_priv;
new_priv.Privileges[0].Attributes = enable ? SE_PRIVILEGE_ENABLED : 0;
- if (!AdjustTokenPrivileges (hToken, FALSE, &new_priv, 0, NULL, NULL))
+ if (!AdjustTokenPrivileges (hToken, FALSE, &new_priv,
+ sizeof orig_priv, &orig_priv, &size))
+ {
+ __seterrno ();
+ goto out;
+ }
+ /* AdjustTokenPrivileges returns TRUE even if the privilege could not
+ be enabled. GetLastError() returns an correct error code, though. */
+ if (enable && GetLastError () == ERROR_NOT_ALL_ASSIGNED)
{
+ debug_printf ("Privilege %s couldn't be assigned", privilege);
__seterrno ();
goto out;
}
- ret = 0;
+ ret = orig_priv.Privileges[0].Attributes == SE_PRIVILEGE_ENABLED ? 1 : 0;
out:
if (hToken)
diff --git a/winsup/cygwin/security.cc b/winsup/cygwin/security.cc
index 17bb6dd88..f54fffaec 100644
--- a/winsup/cygwin/security.cc
+++ b/winsup/cygwin/security.cc
@@ -37,6 +37,10 @@ details. */
#include "pinfo.h"
#include "cygheap.h"
#include "security.h"
+#include <ntdef.h>
+#include "ntdll.h"
+#include "lm.h"
+
extern BOOL allow_ntea;
BOOL allow_ntsec = FALSE;
@@ -57,7 +61,7 @@ cygwin_set_impersonation_token (const HANDLE hToken)
}
}
-static void
+void
extract_nt_dom_user (const struct passwd *pw, char *domain, char *user)
{
char buf[INTERNET_MAX_HOST_NAME_LENGTH + UNLEN + 2];
@@ -129,7 +133,7 @@ cygwin_logon_user (const struct passwd *pw, const char *password)
static void
str2lsa (LSA_STRING &tgt, const char *srcstr)
{
- tgt.Length = strlen(srcstr);
+ tgt.Length = strlen (srcstr);
tgt.MaximumLength = tgt.Length + 1;
tgt.Buffer = (PCHAR) srcstr;
}
@@ -137,7 +141,7 @@ str2lsa (LSA_STRING &tgt, const char *srcstr)
static void
str2buf2lsa (LSA_STRING &tgt, char *buf, const char *srcstr)
{
- tgt.Length = strlen(srcstr);
+ tgt.Length = strlen (srcstr);
tgt.MaximumLength = tgt.Length + 1;
tgt.Buffer = (PCHAR) buf;
memcpy(buf, srcstr, tgt.MaximumLength);
@@ -146,12 +150,644 @@ str2buf2lsa (LSA_STRING &tgt, char *buf, const char *srcstr)
static void
str2buf2uni (UNICODE_STRING &tgt, WCHAR *buf, const char *srcstr)
{
- tgt.Length = strlen(srcstr) * sizeof (WCHAR);
+ tgt.Length = strlen (srcstr) * sizeof (WCHAR);
tgt.MaximumLength = tgt.Length + sizeof(WCHAR);
tgt.Buffer = (PWCHAR) buf;
mbstowcs (buf, srcstr, tgt.MaximumLength);
}
+static void
+lsa2wchar (WCHAR *tgt, LSA_UNICODE_STRING &src, int size)
+{
+ size = (size - 1) * sizeof (WCHAR);
+ if (src.Length < size)
+ size = src.Length;
+ memcpy (tgt, src.Buffer, size);
+ size >>= 1;
+ tgt[size] = 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_ALL_ACCESS, &lsa);
+ if (ret != STATUS_SUCCESS)
+ set_errno (LsaNtStatusToWinError (ret));
+ return lsa;
+}
+
+static void
+close_local_policy (LSA_HANDLE &lsa)
+{
+ if (lsa != INVALID_HANDLE_VALUE)
+ LsaClose (lsa);
+ lsa = INVALID_HANDLE_VALUE;
+}
+
+static BOOL
+get_lsa_srv_inf (LSA_HANDLE lsa, char *logonserver, char *domain)
+{
+ NET_API_STATUS ret;
+ LPSERVER_INFO_101 buf;
+ DWORD cnt, tot;
+ char name[INTERNET_MAX_HOST_NAME_LENGTH + 1];
+ WCHAR account[INTERNET_MAX_HOST_NAME_LENGTH + 1];
+ WCHAR primary[INTERNET_MAX_HOST_NAME_LENGTH + 1];
+ PPOLICY_ACCOUNT_DOMAIN_INFO adi;
+ PPOLICY_PRIMARY_DOMAIN_INFO pdi;
+
+ if ((ret = LsaQueryInformationPolicy (lsa, PolicyAccountDomainInformation,
+ (PVOID *) &adi)) != STATUS_SUCCESS)
+ {
+ set_errno (LsaNtStatusToWinError(ret));
+ return FALSE;
+ }
+ lsa2wchar (account, adi->DomainName, INTERNET_MAX_HOST_NAME_LENGTH + 1);
+ LsaFreeMemory (adi);
+ if ((ret = LsaQueryInformationPolicy (lsa, PolicyPrimaryDomainInformation,
+ (PVOID *) &pdi)) != STATUS_SUCCESS)
+ {
+ set_errno (LsaNtStatusToWinError(ret));
+ return FALSE;
+ }
+ lsa2wchar (primary, pdi->Name, INTERNET_MAX_HOST_NAME_LENGTH + 1);
+ LsaFreeMemory (pdi);
+ if ((ret = NetServerEnum (NULL, 101, (LPBYTE *) &buf, MAX_PREFERRED_LENGTH,
+ &cnt, &tot, SV_TYPE_DOMAIN_CTRL, primary, NULL))
+ == STATUS_SUCCESS && cnt > 0)
+ {
+ wcstombs (name, buf[0].sv101_name, INTERNET_MAX_HOST_NAME_LENGTH + 1);
+ if (domain)
+ wcstombs (domain, primary, INTERNET_MAX_HOST_NAME_LENGTH + 1);
+ }
+ else
+ {
+ wcstombs (name, account, INTERNET_MAX_HOST_NAME_LENGTH + 1);
+ if (domain)
+ wcstombs (domain, account, INTERNET_MAX_HOST_NAME_LENGTH + 1);
+ }
+ if (ret == STATUS_SUCCESS)
+ NetApiBufferFree (buf);
+ strcpy (logonserver, "\\\\");
+ strcat (logonserver, name);
+ return TRUE;
+}
+
+static BOOL
+get_logon_server (LSA_HANDLE lsa, char *logonserver)
+{
+ return get_lsa_srv_inf (lsa, logonserver, NULL);
+}
+
+BOOL
+get_logon_server_and_user_domain (char *logonserver, char *userdomain)
+{
+ BOOL ret = FALSE;
+ LSA_HANDLE lsa = open_local_policy ();
+ if (lsa)
+ {
+ ret = get_lsa_srv_inf (lsa, logonserver, userdomain);
+ close_local_policy (lsa);
+ }
+ return ret;
+}
+
+static BOOL
+get_user_groups (WCHAR *wlogonserver, cygsidlist &grp_list, char *user)
+{
+ WCHAR wuser[UNLEN + 1];
+ mbstowcs (wuser, user, UNLEN + 1);
+ LPGROUP_USERS_INFO_0 buf;
+ DWORD cnt, tot;
+ NET_API_STATUS ret;
+
+ if ((ret = NetUserGetGroups (wlogonserver, wuser, 0, (LPBYTE *) &buf,
+ MAX_PREFERRED_LENGTH, &cnt, &tot)))
+ {
+ debug_printf ("%d = NetUserGetGroups ()", ret);
+ set_errno (ret);
+ /* It's no error when the user name can't be found. */
+ return ret == NERR_UserNotFound;
+ }
+
+ for (DWORD i = 0; i < cnt; ++i)
+ {
+ cygsid gsid;
+ char group[UNLEN + 1];
+ char domain[INTERNET_MAX_HOST_NAME_LENGTH + 1];
+ DWORD glen = UNLEN + 1;
+ DWORD dlen = INTERNET_MAX_HOST_NAME_LENGTH + 1;
+ SID_NAME_USE use = SidTypeInvalid;
+
+ wcstombs (group, buf[i].grui0_name, UNLEN + 1);
+ if (!LookupAccountName (NULL, group, gsid, &glen, domain, &dlen, &use))
+ debug_printf ("LookupAccountName(%s): %lu\n", group, GetLastError ());
+ if (!legal_sid_type (use))
+ {
+ strcat (strcpy (group, domain), "\\");
+ wcstombs (group + strlen (group), buf[i].grui0_name,
+ UNLEN + 1 - strlen (group));
+ glen = UNLEN + 1;
+ dlen = INTERNET_MAX_HOST_NAME_LENGTH + 1;
+ if (!LookupAccountName(NULL, group, gsid, &glen, domain, &dlen, &use))
+ debug_printf ("LookupAccountName(%s): %lu\n", group,GetLastError());
+ }
+ if (legal_sid_type (use))
+ grp_list += gsid;
+ }
+
+ NetApiBufferFree (buf);
+ return TRUE;
+}
+
+static BOOL
+is_group_member (WCHAR *wlogonserver, WCHAR *wgroup,
+ cygsid &usersid, cygsidlist &grp_list)
+{
+ LPLOCALGROUP_MEMBERS_INFO_0 buf;
+ DWORD cnt, tot;
+ BOOL ret = FALSE;
+
+ if (NetLocalGroupGetMembers (wlogonserver, wgroup, 0, (LPBYTE *) &buf,
+ MAX_PREFERRED_LENGTH, &cnt, &tot, NULL))
+ return FALSE;
+
+ for (DWORD bidx = 0; !ret && bidx < cnt; ++bidx)
+ if (EqualSid (usersid, buf[bidx].lgrmi0_sid))
+ ret = TRUE;
+ else
+ for (int glidx = 0; !ret && glidx < grp_list.count; ++glidx)
+ if (EqualSid (grp_list.sids[glidx], buf[bidx].lgrmi0_sid))
+ ret = TRUE;
+
+ NetApiBufferFree (buf);
+ return ret;
+}
+
+static BOOL
+get_user_local_groups (WCHAR *wlogonserver, const char *logonserver,
+ cygsidlist &grp_list, cygsid &usersid)
+{
+ LPLOCALGROUP_INFO_0 buf;
+ DWORD cnt, tot;
+ NET_API_STATUS ret;
+
+ if ((ret = NetLocalGroupEnum (wlogonserver, 0, (LPBYTE *) &buf,
+ MAX_PREFERRED_LENGTH, &cnt, &tot, NULL)))
+ {
+ debug_printf ("%d = NetLocalGroupEnum ()", ret);
+ set_errno (ret);
+ return FALSE;
+ }
+
+ for (DWORD i = 0; i < cnt; ++i)
+ if (is_group_member (wlogonserver, buf[i].lgrpi0_name, usersid, grp_list))
+ {
+ cygsid gsid;
+ char group[UNLEN + 1];
+ char domain[INTERNET_MAX_HOST_NAME_LENGTH + 1];
+ DWORD glen = UNLEN + 1;
+ DWORD dlen = INTERNET_MAX_HOST_NAME_LENGTH + 1;
+ SID_NAME_USE use = SidTypeInvalid;
+
+ wcstombs (group, buf[i].lgrpi0_name, UNLEN + 1);
+ if (!LookupAccountName (NULL, group, gsid, &glen, domain, &dlen, &use))
+ {
+ glen = UNLEN + 1;
+ dlen = INTERNET_MAX_HOST_NAME_LENGTH + 1;
+ if (!LookupAccountName (logonserver + 2, group,
+ gsid, &glen, domain, &dlen, &use))
+ debug_printf ("LookupAccountName(%s): %lu\n", group,
+ GetLastError ());
+ }
+ else if (!legal_sid_type (use))
+ {
+ strcat (strcpy (group, domain), "\\");
+ wcstombs (group + strlen (group), buf[i].lgrpi0_name,
+ UNLEN + 1 - strlen (group));
+ glen = UNLEN + 1;
+ dlen = INTERNET_MAX_HOST_NAME_LENGTH + 1;
+ if (!LookupAccountName (NULL, group, gsid, &glen,
+ domain, &dlen, &use))
+ debug_printf ("LookupAccountName(%s): %lu\n", group,
+ GetLastError ());
+ }
+ if (legal_sid_type (use))
+ grp_list += gsid;
+ }
+
+ NetApiBufferFree (buf);
+ return TRUE;
+}
+
+static BOOL
+sid_in_token_groups (PTOKEN_GROUPS grps, cygsid &sid)
+{
+ if (!grps)
+ return FALSE;
+ for (DWORD i = 0; i < grps->GroupCount; ++i)
+ if (sid == grps->Groups[i].Sid)
+ return TRUE;
+ return FALSE;
+}
+
+static BOOL
+get_user_primary_group (WCHAR *wlogonserver, const char *user,
+ cygsid &usersid, cygsid &pgrpsid)
+{
+ LPUSER_INFO_3 buf;
+ WCHAR wuser[UNLEN + 1];
+ BOOL ret = FALSE;
+ UCHAR count;
+
+ if (usersid == well_known_system_sid)
+ {
+ pgrpsid = well_known_system_sid;
+ return TRUE;
+ }
+
+ mbstowcs (wuser, user, UNLEN + 1);
+ if (NetUserGetInfo (wlogonserver, wuser, 3, (LPBYTE *) &buf))
+ return FALSE;
+ pgrpsid = usersid;
+ if (IsValidSid (pgrpsid) && (count = *GetSidSubAuthorityCount (pgrpsid)) > 1)
+ {
+ *GetSidSubAuthority (pgrpsid, count - 1) = buf->usri3_primary_group_id;
+ ret = TRUE;
+ }
+ NetApiBufferFree (buf);
+ return ret;
+}
+
+static BOOL
+get_group_sidlist (const char *logonserver, cygsidlist &grp_list,
+ cygsid &usersid, cygsid &pgrpsid,
+ PTOKEN_GROUPS my_grps, LUID auth_luid, int &auth_pos)
+{
+ WCHAR wserver[INTERNET_MAX_HOST_NAME_LENGTH + 1];
+ char user[INTERNET_MAX_HOST_NAME_LENGTH + 1];
+ char domain[INTERNET_MAX_HOST_NAME_LENGTH + 1];
+ DWORD ulen = INTERNET_MAX_HOST_NAME_LENGTH + 1;
+ DWORD dlen = INTERNET_MAX_HOST_NAME_LENGTH + 1;
+ SID_NAME_USE use;
+
+ auth_pos = -1;
+ mbstowcs (wserver, logonserver, INTERNET_MAX_HOST_NAME_LENGTH + 1);
+ if (!LookupAccountSid (NULL, usersid, user, &ulen, domain, &dlen, &use))
+ {
+ debug_printf ("LookupAccountSid () %E");
+ __seterrno ();
+ return FALSE;
+ }
+ grp_list += well_known_world_sid;
+ if (usersid == well_known_system_sid)
+ {
+ grp_list += well_known_system_sid;
+ grp_list += well_known_admin_sid;
+ }
+ else
+ {
+ if (my_grps)
+ {
+ if (sid_in_token_groups (my_grps, well_known_local_sid))
+ 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;
+ if (sid_in_token_groups (my_grps, well_known_interactive_sid))
+ grp_list += well_known_interactive_sid;
+ if (sid_in_token_groups (my_grps, well_known_service_sid))
+ grp_list += well_known_service_sid;
+ grp_list += well_known_authenticated_users_sid;
+ }
+ else
+ {
+ grp_list += well_known_local_sid;
+ grp_list += well_known_interactive_sid;
+ grp_list += well_known_authenticated_users_sid;
+ }
+ if (auth_luid.QuadPart != 999) /* != SYSTEM_LUID */
+ {
+ char buf[64];
+ __small_sprintf (buf, "S-1-5-5-%u-%u", auth_luid.HighPart,
+ auth_luid.LowPart);
+ grp_list += buf;
+ auth_pos = grp_list.count - 1;
+ }
+ }
+ if (!pgrpsid)
+ get_user_primary_group (wserver, user, usersid, pgrpsid);
+ if (!get_user_groups (wserver, grp_list, user) ||
+ !get_user_local_groups (wserver, logonserver, grp_list, usersid))
+ return FALSE;
+ if (!grp_list.contains (pgrpsid))
+ grp_list += pgrpsid;
+ return TRUE;
+}
+
+static const char *sys_privs[] = {
+ SE_TCB_NAME,
+ SE_ASSIGNPRIMARYTOKEN_NAME,
+ SE_CREATE_TOKEN_NAME,
+ SE_CHANGE_NOTIFY_NAME,
+ SE_SECURITY_NAME,
+ SE_BACKUP_NAME,
+ SE_RESTORE_NAME,
+ SE_SYSTEMTIME_NAME,
+ SE_SHUTDOWN_NAME,
+ SE_REMOTE_SHUTDOWN_NAME,
+ SE_TAKE_OWNERSHIP_NAME,
+ SE_DEBUG_NAME,
+ SE_SYSTEM_ENVIRONMENT_NAME,
+ SE_SYSTEM_PROFILE_NAME,
+ SE_PROF_SINGLE_PROCESS_NAME,
+ SE_INC_BASE_PRIORITY_NAME,
+ SE_LOAD_DRIVER_NAME,
+ SE_CREATE_PAGEFILE_NAME,
+ SE_INCREASE_QUOTA_NAME
+};
+
+#define SYSTEM_PERMISSION_COUNT (sizeof sys_privs / sizeof (const char *))
+
+PTOKEN_PRIVILEGES
+get_system_priv_list (cygsidlist &grp_list)
+{
+ LUID priv;
+ PTOKEN_PRIVILEGES privs = (PTOKEN_PRIVILEGES) malloc (sizeof (ULONG) +
+ 20 * sizeof (LUID_AND_ATTRIBUTES));
+ if (!privs)
+ {
+ debug_printf ("malloc (system_privs) failed.");
+ return NULL;
+ }
+ privs->PrivilegeCount = 0;
+
+ for (DWORD i = 0; i < SYSTEM_PERMISSION_COUNT; ++i)
+ if (LookupPrivilegeValue (NULL, sys_privs[i], &priv))
+ {
+ privs->Privileges[privs->PrivilegeCount].Luid = priv;
+ privs->Privileges[privs->PrivilegeCount].Attributes =
+ SE_PRIVILEGE_ENABLED | SE_PRIVILEGE_ENABLED_BY_DEFAULT;
+ ++privs->PrivilegeCount;
+ }
+ return privs;
+}
+
+PTOKEN_PRIVILEGES
+get_priv_list (LSA_HANDLE lsa, cygsid &usersid, cygsidlist &grp_list)
+{
+ 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 (grp_list);
+
+ 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;
+
+ wcstombs (buf, privstrs[i].Buffer, INTERNET_MAX_HOST_NAME_LENGTH + 1);
+ if (!LookupPrivilegeValue (NULL, buf, &priv))
+ continue;
+
+ for (DWORD p = 0; privs && p < privs->PrivilegeCount; ++p)
+ if (!memcmp (&priv, &privs->Privileges[p].Luid, sizeof (LUID)))
+ goto next_account_right;
+
+ tmp_count = privs ? privs->PrivilegeCount : 0;
+ tmp = (PTOKEN_PRIVILEGES)
+ realloc (privs, sizeof (ULONG) +
+ (tmp_count + 1) * sizeof (LUID_AND_ATTRIBUTES));
+ 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;
+}
+
+#define token_acl_size (sizeof (ACL) + \
+ 2 * (sizeof (ACCESS_ALLOWED_ACE) + MAX_SID_LEN))
+
+static BOOL
+get_dacl (PACL acl, cygsid usersid, cygsidlist &grp_list)
+{
+ if (!InitializeAcl(acl, token_acl_size, ACL_REVISION))
+ {
+ __seterrno ();
+ return FALSE;
+ }
+ if (grp_list.contains (well_known_admin_sid))
+ {
+ if (!AddAccessAllowedAce(acl, ACL_REVISION, GENERIC_ALL,
+ well_known_admin_sid))
+ {
+ __seterrno ();
+ return FALSE;
+ }
+ }
+ else if (!AddAccessAllowedAce(acl, ACL_REVISION, GENERIC_ALL, usersid))
+ {
+ __seterrno ();
+ return FALSE;
+ }
+ if (!AddAccessAllowedAce(acl, ACL_REVISION, GENERIC_ALL,
+ well_known_system_sid))
+ {
+ __seterrno ();
+ return FALSE;
+ }
+ return TRUE;
+}
+
+HANDLE
+create_token (cygsid &usersid, cygsid &pgrpsid)
+{
+ NTSTATUS ret;
+ LSA_HANDLE lsa = NULL;
+ char logonserver[INTERNET_MAX_HOST_NAME_LENGTH + 1];
+ int old_priv_state;
+
+ cygsidlist grpsids;
+
+ SECURITY_QUALITY_OF_SERVICE sqos =
+ { sizeof sqos, SecurityImpersonation, SECURITY_STATIC_TRACKING, FALSE };
+ OBJECT_ATTRIBUTES oa =
+ { sizeof oa, 0, 0, 0, 0, &sqos };
+ SECURITY_ATTRIBUTES sa = { sizeof sa, NULL, TRUE };
+ LUID auth_luid = SYSTEM_LUID;
+ LARGE_INTEGER exp = { 0x7fffffffffffffffLL } ;
+
+ TOKEN_USER user;
+ PTOKEN_GROUPS grps = NULL;
+ PTOKEN_PRIVILEGES privs = NULL;
+ TOKEN_OWNER owner;
+ TOKEN_PRIMARY_GROUP pgrp;
+ char acl_buf[token_acl_size];
+ 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;
+ HANDLE primary_token = INVALID_HANDLE_VALUE;
+
+ HANDLE my_token = INVALID_HANDLE_VALUE;
+ PTOKEN_GROUPS my_grps = NULL;
+ DWORD size;
+
+ /* SE_CREATE_TOKEN_NAME privilege needed to call NtCreateToken. */
+ if ((old_priv_state = set_process_privilege (SE_CREATE_TOKEN_NAME)) < 0)
+ goto out;
+
+ /* Open policy object. */
+ if ((lsa = open_local_policy ()) == INVALID_HANDLE_VALUE)
+ goto out;
+
+ /* Get logon server. */
+ if (!get_logon_server (lsa, logonserver))
+ 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 (!OpenProcessToken (GetCurrentProcess (), TOKEN_QUERY, &my_token))
+ debug_printf ("OpenProcessToken(my_token): %E\n");
+ else
+ {
+ /* 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 (my_token, TokenStatistics,
+ &stats, sizeof stats, &size))
+ debug_printf ("GetTokenInformation(my_token, TokenStatistics): %E\n");
+ else
+ auth_luid = stats.AuthenticationId;
+
+ /* Retrieving current processes group list to be able to inherit
+ some important well known group sids. */
+ if (!GetTokenInformation (my_token, TokenGroups, NULL, 0, &size) &&
+ GetLastError () != ERROR_INSUFFICIENT_BUFFER)
+ debug_printf ("GetTokenInformation(my_token, TokenGroups): %E\n");
+ else if (!(my_grps = (PTOKEN_GROUPS) malloc (size)))
+ debug_printf ("malloc (my_grps) failed.");
+ else if (!GetTokenInformation (my_token, TokenGroups, my_grps,
+ size, &size))
+ {
+ debug_printf ("GetTokenInformation(my_token, TokenGroups): %E\n");
+ free (my_grps);
+ my_grps = NULL;
+ }
+ }
+
+ /* Create list of groups, the user is member in. */
+ int auth_pos;
+ if (!get_group_sidlist (logonserver, grpsids, usersid, pgrpsid,
+ my_grps, auth_luid, auth_pos))
+ goto out;
+
+ /* Primary group. */
+ pgrp.PrimaryGroup = pgrpsid;
+
+ /* Create a TOKEN_GROUPS list from the above retrieved list of sids. */
+ char grps_buf[sizeof (ULONG) + grpsids.count * sizeof (SID_AND_ATTRIBUTES)];
+ grps = (PTOKEN_GROUPS) grps_buf;
+ grps->GroupCount = grpsids.count;
+ for (DWORD i = 0; i < grps->GroupCount; ++i)
+ {
+ grps->Groups[i].Sid = grpsids.sids[i];
+ grps->Groups[i].Attributes = SE_GROUP_MANDATORY |
+ SE_GROUP_ENABLED_BY_DEFAULT |
+ SE_GROUP_ENABLED;
+ if (auth_pos >= 0 && i == (DWORD) auth_pos)
+ grps->Groups[i].Attributes |= SE_GROUP_LOGON_ID;
+ }
+
+ /* Retrieve list of privileges of that user. */
+ if (!(privs = get_priv_list (lsa, usersid, grpsids)))
+ goto out;
+
+ /* Create default dacl. */
+ if (!get_dacl ((PACL) acl_buf, usersid, grpsids))
+ goto out;
+ dacl.DefaultDacl = (PACL) acl_buf;
+
+ /* Let's be heroic... */
+ ret = NtCreateToken (&token, TOKEN_ALL_ACCESS, &oa, TokenImpersonation,
+ &auth_luid, &exp, &user, grps, privs, &owner, &pgrp,
+ &dacl, &source);
+ if (ret)
+ set_errno (RtlNtStatusToDosError (ret));
+ else if (GetLastError () == ERROR_PROC_NOT_FOUND)
+ {
+ __seterrno ();
+ debug_printf ("Loading NtCreateToken failed.");
+ }
+
+ /* Convert to primary token. */
+ if (!DuplicateTokenEx (token, TOKEN_ALL_ACCESS, &sa,
+ SecurityImpersonation, TokenPrimary,
+ &primary_token))
+ __seterrno ();
+
+out:
+ if (old_priv_state >= 0)
+ set_process_privilege (SE_CREATE_TOKEN_NAME, old_priv_state);
+ if (token != INVALID_HANDLE_VALUE)
+ CloseHandle (token);
+ if (privs)
+ free (privs);
+ if (my_grps)
+ free (my_grps);
+ close_local_policy (lsa);
+
+ debug_printf ("%d = create_token ()", primary_token);
+ return primary_token;
+}
+
int subauth_id = 255;
HANDLE
@@ -177,12 +813,16 @@ subauth (struct passwd *pw)
TOKEN_SOURCE ts;
PMSV1_0_LM20_LOGON_PROFILE profile;
LUID luid;
- HANDLE user_token;
QUOTA_LIMITS quota;
char nt_domain[INTERNET_MAX_HOST_NAME_LENGTH + 1];
char nt_user[UNLEN + 1];
+ SECURITY_ATTRIBUTES sa = { sizeof sa, NULL, TRUE };
+ HANDLE user_token = INVALID_HANDLE_VALUE;
+ HANDLE primary_token = INVALID_HANDLE_VALUE;
+ int old_tcb_state;
- set_process_privilege(SE_TCB_NAME);
+ if ((old_tcb_state = set_process_privilege(SE_TCB_NAME)) < 0)
+ return INVALID_HANDLE_VALUE;
/* Register as logon process. */
str2lsa (name, "Cygwin");
@@ -192,12 +832,12 @@ subauth (struct passwd *pw)
{
debug_printf ("LsaRegisterLogonProcess: %d", ret);
set_errno (LsaNtStatusToWinError(ret));
- return INVALID_HANDLE_VALUE;
+ goto out;
}
else if (GetLastError () == ERROR_PROC_NOT_FOUND)
{
debug_printf ("Couldn't load Secur32.dll");
- return INVALID_HANDLE_VALUE;
+ goto out;
}
/* Get handle to MSV1_0 package. */
str2lsa (name, MSV1_0_PACKAGE_NAME);
@@ -207,7 +847,7 @@ subauth (struct passwd *pw)
debug_printf ("LsaLookupAuthenticationPackage: %d", ret);
set_errno (LsaNtStatusToWinError(ret));
LsaDeregisterLogonProcess(lsa_hdl);
- return INVALID_HANDLE_VALUE;
+ goto out;
}
/* Create origin. */
str2buf2lsa (origin.str, origin.buf, "Cygwin");
@@ -236,20 +876,19 @@ subauth (struct passwd *pw)
debug_printf ("LsaLogonUser: %d", ret);
set_errno (LsaNtStatusToWinError(ret));
LsaDeregisterLogonProcess(lsa_hdl);
- return INVALID_HANDLE_VALUE;
+ goto out;
}
LsaFreeReturnBuffer(profile);
/* Convert to primary token. */
- SECURITY_ATTRIBUTES sa = { sizeof sa, NULL, TRUE };
- HANDLE primary_token;
if (!DuplicateTokenEx (user_token, TOKEN_ALL_ACCESS, &sa,
SecurityImpersonation, TokenPrimary,
&primary_token))
- {
- CloseHandle (user_token);
- return INVALID_HANDLE_VALUE;
- }
- CloseHandle (user_token);
+ __seterrno ();
+
+out:
+ set_process_privilege(SE_TCB_NAME, old_tcb_state);
+ if (user_token != INVALID_HANDLE_VALUE)
+ CloseHandle (user_token);
return primary_token;
}
diff --git a/winsup/cygwin/security.h b/winsup/cygwin/security.h
index 5f2a38141..c915c1b6c 100644
--- a/winsup/cygwin/security.h
+++ b/winsup/cygwin/security.h
@@ -26,6 +26,18 @@ class cygsid {
const PSID getfromstr (const char *nsidstr);
PSID get_sid (DWORD s, DWORD cnt, DWORD *r);
+ inline const PSID assign (const PSID nsid)
+ {
+ if (!nsid)
+ psid = NO_SID;
+ else
+ {
+ psid = (PSID) sbuf;
+ CopySid (MAX_SID_LEN, psid, nsid);
+ }
+ return psid;
+ }
+
public:
inline cygsid () : psid ((PSID) sbuf) {}
inline cygsid (const PSID nsid) { *this = nsid; }
@@ -40,19 +52,12 @@ public:
inline int get_uid () { return get_id (FALSE); }
inline int get_gid () { return get_id (TRUE); }
- char *string (char *nsidstr);
+ char *string (char *nsidstr) const;
+ inline const PSID operator= (cygsid &nsid)
+ { return assign (nsid); }
inline const PSID operator= (const PSID nsid)
- {
- if (!nsid)
- psid = NULL;
- else
- {
- psid = (PSID) sbuf;
- CopySid (MAX_SID_LEN, psid, nsid);
- }
- return psid;
- }
+ { return assign (nsid); }
inline const PSID operator= (const char *nsidstr)
{ return getfromstr (nsidstr); }
@@ -73,12 +78,77 @@ public:
{ return !(*this == nsidstr); }
inline operator const PSID () { return psid; }
+
+ void debug_print (const char *prefix = NULL) const
+ {
+ char buf[256];
+ debug_printf ("%s %s", prefix ?: "", string (buf) ?: "NULL");
+ }
+};
+
+class cygsidlist {
+public:
+ int count;
+ cygsid *sids;
+
+ cygsidlist () : count (0), sids (NULL) {}
+ ~cygsidlist () { delete [] sids; }
+
+ BOOL add (cygsid &nsi)
+ {
+ cygsid *tmp = new cygsid [count + 1];
+ if (!tmp)
+ return FALSE;
+ for (int i = 0; i < count; ++i)
+ tmp[i] = sids[i];
+ delete [] sids;
+ sids = tmp;
+ sids[count++] = nsi;
+ return TRUE;
+ }
+ BOOL add (const PSID nsid) { return add (nsid); }
+ BOOL add (const char *sidstr)
+ { cygsid nsi (sidstr); return add (nsi); }
+
+ BOOL operator+= (cygsid &si) { return add (si); }
+ BOOL operator+= (const char *sidstr) { return add (sidstr); }
+
+ BOOL contains (cygsid &sid) const
+ {
+ for (int i = 0; i < count; ++i)
+ if (sids[i] == sid)
+ return TRUE;
+ return FALSE;
+ }
+ void debug_print (const char *prefix = NULL) const
+ {
+ debug_printf ("-- begin sidlist ---");
+ if (!count)
+ debug_printf ("No elements");
+ for (int i = 0; i < count; ++i)
+ sids[i].debug_print (prefix);
+ debug_printf ("-- ende sidlist ---");
+ }
};
-extern cygsid well_known_admin_sid;
-extern cygsid well_known_system_sid;
-extern cygsid well_known_creator_owner_sid;
extern cygsid well_known_world_sid;
+extern cygsid well_known_local_sid;
+extern cygsid well_known_creator_owner_sid;
+extern cygsid well_known_dialup_sid;
+extern cygsid well_known_network_sid;
+extern cygsid well_known_batch_sid;
+extern cygsid well_known_interactive_sid;
+extern cygsid well_known_service_sid;
+extern cygsid well_known_authenticated_users_sid;
+extern cygsid well_known_system_sid;
+extern cygsid well_known_admin_sid;
+
+inline BOOL
+legal_sid_type (SID_NAME_USE type)
+{
+ return type == SidTypeUser || type == SidTypeGroup
+ || type == SidTypeAlias || type == SidTypeWellKnownGroup;
+}
extern BOOL allow_ntsec;
extern BOOL allow_smbntsec;
@@ -102,6 +172,13 @@ BOOL __stdcall add_access_denied_ace (PACL acl, int offset, DWORD attributes, PS
/* Try a subauthentication. */
HANDLE subauth (struct passwd *pw);
+/* Try creating a token directly. */
+HANDLE create_token (cygsid &usersid, cygsid &pgrpsid);
+
+/* Extract U-domain\user field from passwd entry. */
+void extract_nt_dom_user (const struct passwd *pw, char *domain, char *user);
+/* Get default logonserver and domain for this box. */
+BOOL get_logon_server_and_user_domain (char *logonserver, char *domain);
/* sec_helper.cc: Security helper functions. */
BOOL __stdcall is_grp_member (uid_t uid, gid_t gid);
diff --git a/winsup/cygwin/spawn.cc b/winsup/cygwin/spawn.cc
index b49e0f8f4..ccf9ed1f6 100644
--- a/winsup/cygwin/spawn.cc
+++ b/winsup/cygwin/spawn.cc
@@ -622,10 +622,9 @@ skip_arg_parsing:
: &sec_all_nih;
/* Remove impersonation */
- uid_t uid = geteuid ();
if (cygheap->user.impersonated
&& cygheap->user.token != INVALID_HANDLE_VALUE)
- seteuid (cygheap->user.orig_uid);
+ RevertToSelf ();
/* Load users registry hive. */
load_registry_hive (sid);
@@ -664,7 +663,7 @@ skip_arg_parsing:
if (mode != _P_OVERLAY && mode != _P_VFORK
&& cygheap->user.impersonated
&& cygheap->user.token != INVALID_HANDLE_VALUE)
- seteuid (uid);
+ ImpersonateLoggedOnUser (cygheap->user.token);
}
MALLOC_CHECK;
diff --git a/winsup/cygwin/syscalls.cc b/winsup/cygwin/syscalls.cc
index e4df8eb3b..48a8d72d2 100644
--- a/winsup/cygwin/syscalls.cc
+++ b/winsup/cygwin/syscalls.cc
@@ -1954,109 +1954,156 @@ seteuid (uid_t uid)
sigframe thisframe (mainthread);
if (os_being_run == winNT)
{
- if (uid != (uid_t) -1)
+ if (uid == (uid_t) -1 || uid == myself->uid)
{
- struct passwd *pw_new = getpwuid (uid);
- if (!pw_new)
- {
- set_errno (EINVAL);
- return -1;
- }
+ debug_printf ("new euid == current euid, nothing happens");
+ return 0;
+ }
+ struct passwd *pw_new = getpwuid (uid);
+ if (!pw_new)
+ {
+ set_errno (EINVAL);
+ return -1;
+ }
+
+ if (uid == cygheap->user.orig_uid)
+ {
+ debug_printf ("RevertToSelf () (uid == orig_uid, token=%d)",
+ cygheap->user.token);
+ RevertToSelf ();
+ if (cygheap->user.token != INVALID_HANDLE_VALUE)
+ cygheap->user.impersonated = FALSE;
+ }
+ else
+ {
+ cygsid usersid, pgrpsid, tok_usersid, tok_pgrpsid;
+ DWORD siz;
+ HANDLE sav_token = INVALID_HANDLE_VALUE;
+ BOOL sav_impersonation;
+ BOOL explicitely_created_token = FALSE;
+
+ struct group *gr = getgrgid (myself->gid);
+ debug_printf ("myself->gid: %d, gr: %d", myself->gid, gr);
- if (uid != myself->uid)
+ usersid.getfrompw (pw_new);
+ pgrpsid.getfromgr (gr);
+
+ /* Check if new user == user of impersonation token and
+ - if available - new pgrp == pgrp of impersonation token. */
+ if (cygheap->user.token != INVALID_HANDLE_VALUE)
{
- if (uid == cygheap->user.orig_uid)
+ if (!GetTokenInformation (cygheap->user.token, TokenUser,
+ &tok_usersid, sizeof tok_usersid, &siz))
+ {
+ debug_printf ("GetTokenInformation(): %E");
+ tok_usersid = NO_SID;
+ }
+ if (!GetTokenInformation (cygheap->user.token, TokenPrimaryGroup,
+ &tok_pgrpsid, sizeof tok_pgrpsid, &siz))
{
- debug_printf ("RevertToSelf () (uid == orig_uid, token=%d)",
- cygheap->user.token);
+ debug_printf ("GetTokenInformation(): %E");
+ tok_pgrpsid = NO_SID;
+ }
+ if ((usersid && tok_usersid && usersid != tok_usersid) ||
+ (pgrpsid && tok_pgrpsid && pgrpsid != tok_pgrpsid))
+ {
+ /* If not, RevertToSelf and close old token. */
+ debug_printf ("tsid != usersid");
RevertToSelf ();
- if (cygheap->user.token != INVALID_HANDLE_VALUE)
- cygheap->user.impersonated = FALSE;
+ sav_token = cygheap->user.token;
+ sav_impersonation = cygheap->user.impersonated;
+ cygheap->user.token = INVALID_HANDLE_VALUE;
+ cygheap->user.impersonated = FALSE;
}
+ }
+
+ /* If no impersonation token is available, try to
+ authenticate using NtCreateToken() or subauthentication. */
+ if (cygheap->user.token == INVALID_HANDLE_VALUE)
+ {
+ HANDLE ptok = INVALID_HANDLE_VALUE;
+
+ ptok = create_token (usersid, pgrpsid);
+ if (ptok != INVALID_HANDLE_VALUE)
+ explicitely_created_token = TRUE;
else
{
- cygsid tsid, psid, gsid;
- DWORD siz;
-
- /* Check if new user == user of impersonation token. */
- if (cygheap->user.token != INVALID_HANDLE_VALUE)
+ /* create_token failed. Try subauthentication. */
+ debug_printf ("create token failed, try subauthentication.");
+ ptok = subauth (pw_new);
+ }
+ if (ptok != INVALID_HANDLE_VALUE)
+ {
+ cygwin_set_impersonation_token (ptok);
+ /* If sav_token was internally created, destroy it. */
+ if (sav_token != INVALID_HANDLE_VALUE)
{
- if (!GetTokenInformation (cygheap->user.token, TokenUser,
- &tsid, sizeof tsid, &siz))
+ TOKEN_SOURCE ts;
+ if (!GetTokenInformation (sav_token, TokenSource,
+ &ts, sizeof ts, &siz))
debug_printf ("GetTokenInformation(): %E");
- else if (psid.getfrompw (pw_new) && tsid != psid)
- {
- /* If not, RevertToSelf and close old token. */
- char tstr[256], pstr[256];
- debug_printf ("tsid (%s) != psid (%s)",
- tsid.string (tstr), psid.string (pstr));
- RevertToSelf ();
- cygwin_set_impersonation_token (INVALID_HANDLE_VALUE);
- }
+ else if (!memcmp (ts.SourceName, "Cygwin.1", 8))
+ CloseHandle (sav_token);
}
- /* If no impersonation token is available, try to
- authenticate using subauthentication. */
- if (cygheap->user.token == INVALID_HANDLE_VALUE)
- {
- HANDLE ptok = subauth (pw_new);
- if (ptok != INVALID_HANDLE_VALUE)
- cygwin_set_impersonation_token (ptok);
- else
- cygheap->user.impersonated = TRUE;
- }
- /* If no impersonation is active but an impersonation
- token is available, try to impersonate. */
- if (cygheap->user.token != INVALID_HANDLE_VALUE &&
- !cygheap->user.impersonated)
- {
- debug_printf ("Impersonate (uid == %d)", uid);
- RevertToSelf ();
-
- struct group *gr;
-
- /* Try setting owner to same value as user. */
- if (!SetTokenInformation (cygheap->user.token,
- TokenOwner,
- &tsid, sizeof tsid))
- debug_printf ("SetTokenInformation(user.token, "
- "TokenOwner): %E");
- /* Try setting primary group in token to current group. */
- if ((gr = getgrgid (myself->gid)) &&
- gsid.getfromgr (gr) &&
- !SetTokenInformation (cygheap->user.token,
- TokenPrimaryGroup,
- &gsid, sizeof gsid))
- debug_printf ("SetTokenInformation(user.token, "
- "TokenPrimaryGroup): %E");
+ }
+ else if (sav_token != INVALID_HANDLE_VALUE)
+ cygheap->user.token = sav_token;
+ }
+ /* If no impersonation is active but an impersonation
+ token is available, try to impersonate. */
+ if (cygheap->user.token != INVALID_HANDLE_VALUE &&
+ !cygheap->user.impersonated)
+ {
+ debug_printf ("Impersonate (uid == %d)", uid);
+ RevertToSelf ();
- /* Now try to impersonate. */
- if (!ImpersonateLoggedOnUser (cygheap->user.token))
- system_printf ("Impersonating (%d) in set(e)uid "
- "failed: %E", cygheap->user.token);
- else
- cygheap->user.impersonated = TRUE;
- }
- }
+ /* If the token was explicitely created, all information has
+ already been set correctly. */
+ if (!explicitely_created_token)
+ {
+ /* Try setting owner to same value as user. */
+ if (usersid &&
+ !SetTokenInformation (cygheap->user.token, TokenOwner,
+ &usersid, sizeof usersid))
+ debug_printf ("SetTokenInformation(user.token, "
+ "TokenOwner): %E");
+ /* Try setting primary group in token to current group
+ if token not explicitely created. */
+ if (pgrpsid &&
+ !SetTokenInformation (cygheap->user.token,
+ TokenPrimaryGroup,
+ &pgrpsid, sizeof pgrpsid))
+ debug_printf ("SetTokenInformation(user.token, "
+ "TokenPrimaryGroup): %E");
- cygheap_user user;
- /* user.token is used in internal_getlogin () to determine if
- impersonation is active. If so, the token is used for
- retrieving user's SID. */
- user.token = cygheap->user.impersonated ? cygheap->user.token
- : INVALID_HANDLE_VALUE;
- struct passwd *pw_cur = internal_getlogin (user);
- if (pw_cur != pw_new)
- {
- debug_printf ("Diffs!!! token: %d, cur: %d, new: %d, orig: %d",
- cygheap->user.token, pw_cur->pw_uid,
- pw_new->pw_uid, cygheap->user.orig_uid);
- set_errno (EPERM);
- return -1;
- }
- myself->uid = uid;
- cygheap->user = user;
+ }
+
+ /* Now try to impersonate. */
+ if (!ImpersonateLoggedOnUser (cygheap->user.token))
+ system_printf ("Impersonating (%d) in set(e)uid failed: %E",
+ cygheap->user.token);
+ else
+ cygheap->user.impersonated = TRUE;
}
}
+
+ cygheap_user user;
+ /* user.token is used in internal_getlogin () to determine if
+ impersonation is active. If so, the token is used for
+ retrieving user's SID. */
+ user.token = cygheap->user.impersonated ? cygheap->user.token
+ : INVALID_HANDLE_VALUE;
+ struct passwd *pw_cur = internal_getlogin (user);
+ if (pw_cur != pw_new)
+ {
+ debug_printf ("Diffs!!! token: %d, cur: %d, new: %d, orig: %d",
+ cygheap->user.token, pw_cur->pw_uid,
+ pw_new->pw_uid, cygheap->user.orig_uid);
+ set_errno (EPERM);
+ return -1;
+ }
+ myself->uid = uid;
+ cygheap->user = user;
}
else
set_errno (ENOSYS);
diff --git a/winsup/cygwin/uinfo.cc b/winsup/cygwin/uinfo.cc
index aea8fece4..0bb947df0 100644
--- a/winsup/cygwin/uinfo.cc
+++ b/winsup/cygwin/uinfo.cc
@@ -38,12 +38,15 @@ internal_getlogin (cygheap_user &user)
user.set_name ("unknown");
else
user.set_name (username);
+ debug_printf ("GetUserName() = %s", user.name ());
if (os_being_run == winNT)
{
LPWKSTA_USER_INFO_1 wui;
- char buf[MAX_PATH], *env;
- char *un = NULL;
+ NET_API_STATUS ret;
+ char buf[512];
+ char dom[INTERNET_MAX_HOST_NAME_LENGTH + 1];
+ char *env, *un = NULL;
/* First trying to get logon info from environment */
if ((env = getenv ("USERNAME")) != NULL)
@@ -58,10 +61,8 @@ internal_getlogin (cygheap_user &user)
debug_printf ("Domain: %s, Logon Server: %s",
user.domain (), user.logsrv ());
/* If that failed, try to get that info from NetBIOS */
- else if (!NetWkstaUserGetInfo (NULL, 1, (LPBYTE *)&wui))
+ else if (!(ret = NetWkstaUserGetInfo (NULL, 1, (LPBYTE *)&wui)))
{
- char buf[512]; /* Bigger than each of the below defines. */
-
sys_wcstombs (buf, wui->wkui1_username, UNLEN + 1);
user.set_name (buf);
sys_wcstombs (buf, wui->wkui1_logon_server,
@@ -112,6 +113,22 @@ internal_getlogin (cygheap_user &user)
user.domain (), user.logsrv (), user.name ());
NetApiBufferFree (wui);
}
+ else
+ {
+ /* If `NetWkstaUserGetInfo' failed, try to get default values known
+ by local policy object.*/
+ debug_printf ("NetWkstaUserGetInfo() Err %d", ret);
+
+ if (get_logon_server_and_user_domain (buf, dom))
+ {
+ user.set_logsrv (buf + 2);
+ user.set_domain (dom);
+ setenv ("LOGONSERVER", buf, 1);
+ setenv ("USERDOMAIN", dom, 1);
+ }
+ else
+ debug_printf ("get_logon_server_and_user_domain() failed");
+ }
if (allow_ntsec)
{
HANDLE ptok = user.token; /* Which is INVALID_HANDLE_VALUE if no
@@ -147,7 +164,7 @@ internal_getlogin (cygheap_user &user)
/* If that fails, too, as a last resort try to get the SID from
the logon server. */
if (!ret && !(ret = lookup_name (user.name (), user.logsrv (),
- user.sid ())))
+ user.sid ())))
debug_printf ("Couldn't retrieve SID from '%s'!", user.logsrv ());
/* If we have a SID, try to get the corresponding Cygwin user name
@@ -157,12 +174,6 @@ internal_getlogin (cygheap_user &user)
{
cygsid psid;
- if (!strcasematch (user.name (), "SYSTEM")
- && user.domain () && user.logsrv ())
- {
- if (get_registry_hive_path (user.sid (), buf))
- setenv ("USERPROFILE", buf, 1);
- }
for (int pidx = 0; (pw = internal_getpwent (pidx)); ++pidx)
if (psid.getfrompw (pw) && EqualSid (user.sid (), psid))
{
@@ -171,8 +182,24 @@ internal_getlogin (cygheap_user &user)
if (gr)
if (!gsid.getfromgr (gr))
gsid = NO_SID;
+ extract_nt_dom_user (pw, dom, buf);
+ setenv ("USERNAME", buf, 1);
+ if (*dom)
+ user.set_domain (dom);
+ else if (user.logsrv ())
+ user.set_domain (user.logsrv ());
+ if (user.domain ())
+ setenv ("USERDOMAIN", user.domain (), 1);
break;
}
+ if (!strcasematch (user.name (), "SYSTEM")
+ && user.domain () && user.logsrv ())
+ {
+ if (get_registry_hive_path (user.sid (), buf))
+ setenv ("USERPROFILE", buf, 1);
+ else
+ unsetenv ("USERPROFILE");
+ }
}
/* If this process is started from a non Cygwin process,