2007-07-20 16:29:43 +02:00
|
|
|
/* sec_auth.cc: NT authentication functions
|
|
|
|
|
2013-01-21 05:38:31 +01:00
|
|
|
Copyright 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007,
|
2015-01-21 17:31:38 +01:00
|
|
|
2008, 2009, 2010, 2011, 2012, 2013, 2014, 2015 Red Hat, Inc.
|
2007-07-20 16:29:43 +02:00
|
|
|
|
|
|
|
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>
|
2008-07-09 13:58:38 +02:00
|
|
|
#include <wchar.h>
|
2007-07-20 16:29:43 +02:00
|
|
|
#include <wininet.h>
|
|
|
|
#include <ntsecapi.h>
|
|
|
|
#include "cygerrno.h"
|
|
|
|
#include "security.h"
|
|
|
|
#include "path.h"
|
|
|
|
#include "fhandler.h"
|
|
|
|
#include "dtable.h"
|
|
|
|
#include "cygheap.h"
|
2014-12-02 11:49:47 +01:00
|
|
|
#include "registry.h"
|
2007-07-20 16:29:43 +02:00
|
|
|
#include "ntdll.h"
|
2008-07-30 14:10:20 +02:00
|
|
|
#include "tls_pbuf.h"
|
2008-07-11 12:00:36 +02:00
|
|
|
#include <lm.h>
|
|
|
|
#include <iptypes.h>
|
2014-12-02 11:49:47 +01:00
|
|
|
#include <wininet.h>
|
|
|
|
#include <userenv.h>
|
2007-07-20 16:29:43 +02:00
|
|
|
#include "cyglsa.h"
|
2008-11-26 11:18:10 +01:00
|
|
|
#include "cygserver_setpwd.h"
|
2007-07-20 16:29:43 +02:00
|
|
|
#include <cygwin/version.h>
|
|
|
|
|
2015-03-03 13:58:34 +01:00
|
|
|
/* OpenBSD 2.0 and later. */
|
|
|
|
extern "C"
|
|
|
|
int
|
|
|
|
issetugid (void)
|
|
|
|
{
|
|
|
|
return cygheap->user.issetuid () ? 1 : 0;
|
|
|
|
}
|
|
|
|
|
2010-02-06 14:13:15 +01:00
|
|
|
/* Starting with Windows Vista, the token returned by system functions
|
|
|
|
is a restricted token. The full admin token is linked to it and can
|
2011-04-29 09:34:05 +02:00
|
|
|
be fetched with NtQueryInformationToken. This function returns the original
|
2010-02-06 14:13:15 +01:00
|
|
|
token on pre-Vista, and the elevated token on Vista++ if it's available,
|
|
|
|
the original token otherwise. The token handle is also made inheritable
|
|
|
|
since that's necessary anyway. */
|
|
|
|
static HANDLE
|
|
|
|
get_full_privileged_inheritable_token (HANDLE token)
|
|
|
|
{
|
|
|
|
if (wincap.has_mandatory_integrity_control ())
|
|
|
|
{
|
|
|
|
TOKEN_LINKED_TOKEN linked;
|
2011-04-29 09:34:05 +02:00
|
|
|
ULONG size;
|
2010-02-06 14:13:15 +01:00
|
|
|
|
|
|
|
/* When fetching the linked token without TCB privs, then the linked
|
|
|
|
token is not a primary token, only an impersonation token, which is
|
|
|
|
not suitable for CreateProcessAsUser. Converting it to a primary
|
|
|
|
token using DuplicateTokenEx does NOT work for the linked token in
|
|
|
|
this case. So we have to switch on TCB privs to get a primary token.
|
|
|
|
This is generally performed in the calling functions. */
|
2011-04-29 09:34:05 +02:00
|
|
|
if (NT_SUCCESS (NtQueryInformationToken (token, TokenLinkedToken,
|
|
|
|
(PVOID) &linked, sizeof linked,
|
|
|
|
&size)))
|
2010-02-06 14:13:15 +01:00
|
|
|
{
|
|
|
|
debug_printf ("Linked Token: %p", linked.LinkedToken);
|
|
|
|
if (linked.LinkedToken)
|
|
|
|
{
|
|
|
|
TOKEN_TYPE type;
|
|
|
|
|
|
|
|
/* At this point we don't know if the user actually had TCB
|
|
|
|
privileges. Check if the linked token is a primary token.
|
|
|
|
If not, just return the original token. */
|
2011-04-29 09:34:05 +02:00
|
|
|
if (NT_SUCCESS (NtQueryInformationToken (linked.LinkedToken,
|
|
|
|
TokenType, (PVOID) &type,
|
|
|
|
sizeof type, &size))
|
2010-02-06 14:13:15 +01:00
|
|
|
&& type != TokenPrimary)
|
|
|
|
debug_printf ("Linked Token is not a primary token!");
|
|
|
|
else
|
|
|
|
{
|
|
|
|
CloseHandle (token);
|
|
|
|
token = linked.LinkedToken;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!SetHandleInformation (token, HANDLE_FLAG_INHERIT, HANDLE_FLAG_INHERIT))
|
|
|
|
{
|
|
|
|
__seterrno ();
|
|
|
|
CloseHandle (token);
|
|
|
|
token = NULL;
|
|
|
|
}
|
|
|
|
return token;
|
|
|
|
}
|
|
|
|
|
2009-10-13 12:23:31 +02:00
|
|
|
void
|
|
|
|
set_imp_token (HANDLE token, int type)
|
|
|
|
{
|
2013-04-23 11:44:36 +02:00
|
|
|
debug_printf ("set_imp_token (%p, %d)", token, type);
|
2009-10-13 12:23:31 +02:00
|
|
|
cygheap->user.external_token = (token == INVALID_HANDLE_VALUE
|
|
|
|
? NO_IMPERSONATION : token);
|
|
|
|
cygheap->user.ext_token_is_restricted = (type == CW_TOKEN_RESTRICTED);
|
|
|
|
}
|
|
|
|
|
2007-07-20 16:29:43 +02:00
|
|
|
extern "C" void
|
|
|
|
cygwin_set_impersonation_token (const HANDLE hToken)
|
|
|
|
{
|
2009-10-13 12:23:31 +02:00
|
|
|
set_imp_token (hToken, CW_TOKEN_IMPERSONATION);
|
2007-07-20 16:29:43 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2008-07-30 14:10:20 +02:00
|
|
|
extract_nt_dom_user (const struct passwd *pw, PWCHAR domain, PWCHAR user)
|
2007-07-20 16:29:43 +02:00
|
|
|
{
|
|
|
|
|
2008-07-11 12:00:36 +02:00
|
|
|
cygsid psid;
|
|
|
|
DWORD ulen = UNLEN + 1;
|
|
|
|
DWORD dlen = MAX_DOMAIN_NAME_LEN + 1;
|
|
|
|
SID_NAME_USE use;
|
|
|
|
|
2013-04-23 11:44:36 +02:00
|
|
|
debug_printf ("pw_gecos %p (%s)", pw->pw_gecos, pw->pw_gecos);
|
2007-07-20 16:29:43 +02:00
|
|
|
|
2015-03-18 17:15:27 +01:00
|
|
|
/* The incoming passwd entry is not necessarily a pointer to the
|
|
|
|
internal passwd buffers, thus we must not rely on being able to
|
|
|
|
cast it to pg_pwd. */
|
|
|
|
if (psid.getfrompw_gecos (pw)
|
2008-07-30 14:10:20 +02:00
|
|
|
&& LookupAccountSidW (NULL, psid, user, &ulen, domain, &dlen, &use))
|
2008-07-11 12:00:36 +02:00
|
|
|
return;
|
|
|
|
|
|
|
|
char *d, *u, *c;
|
2008-07-30 14:10:20 +02:00
|
|
|
domain[0] = L'\0';
|
|
|
|
sys_mbstowcs (user, UNLEN + 1, pw->pw_name);
|
2007-07-20 16:29:43 +02:00
|
|
|
if ((d = strstr (pw->pw_gecos, "U-")) != NULL &&
|
|
|
|
(d == pw->pw_gecos || d[-1] == ','))
|
|
|
|
{
|
2012-10-27 14:09:38 +02:00
|
|
|
c = strchrnul (d + 2, ',');
|
|
|
|
if ((u = strchrnul (d + 2, '\\')) >= c)
|
2008-07-11 12:00:36 +02:00
|
|
|
u = d + 1;
|
|
|
|
else if (u - d <= MAX_DOMAIN_NAME_LEN + 2)
|
2008-07-30 14:10:20 +02:00
|
|
|
sys_mbstowcs (domain, MAX_DOMAIN_NAME_LEN + 1, d + 2, u - d - 1);
|
2007-07-20 16:29:43 +02:00
|
|
|
if (c - u <= UNLEN + 1)
|
2008-07-30 14:10:20 +02:00
|
|
|
sys_mbstowcs (user, UNLEN + 1, u + 1, c - u);
|
2007-07-20 16:29:43 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
extern "C" HANDLE
|
|
|
|
cygwin_logon_user (const struct passwd *pw, const char *password)
|
|
|
|
{
|
2008-07-30 14:10:20 +02:00
|
|
|
if (!pw || !password)
|
2007-07-20 16:29:43 +02:00
|
|
|
{
|
|
|
|
set_errno (EINVAL);
|
|
|
|
return INVALID_HANDLE_VALUE;
|
|
|
|
}
|
|
|
|
|
2008-07-30 14:10:20 +02:00
|
|
|
WCHAR nt_domain[MAX_DOMAIN_NAME_LEN + 1];
|
|
|
|
WCHAR nt_user[UNLEN + 1];
|
|
|
|
PWCHAR passwd;
|
2007-07-20 16:29:43 +02:00
|
|
|
HANDLE hToken;
|
2008-07-30 14:10:20 +02:00
|
|
|
tmp_pathbuf tp;
|
2007-07-20 16:29:43 +02:00
|
|
|
|
|
|
|
extract_nt_dom_user (pw, nt_domain, nt_user);
|
2008-07-30 14:10:20 +02:00
|
|
|
debug_printf ("LogonUserW (%W, %W, ...)", nt_user, nt_domain);
|
|
|
|
sys_mbstowcs (passwd = tp.w_get (), NT_MAX_PATH, password);
|
2007-07-20 16:29:43 +02:00
|
|
|
/* CV 2005-06-08: LogonUser should run under the primary process token,
|
2008-07-11 12:00:36 +02:00
|
|
|
otherwise it returns with ERROR_ACCESS_DENIED. */
|
|
|
|
cygheap->user.deimpersonate ();
|
2008-07-30 14:10:20 +02:00
|
|
|
if (!LogonUserW (nt_user, *nt_domain ? nt_domain : NULL, passwd,
|
|
|
|
LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT,
|
2007-07-20 16:29:43 +02:00
|
|
|
&hToken))
|
|
|
|
{
|
|
|
|
__seterrno ();
|
|
|
|
hToken = INVALID_HANDLE_VALUE;
|
|
|
|
}
|
2010-02-06 14:13:15 +01:00
|
|
|
else
|
2007-07-20 16:29:43 +02:00
|
|
|
{
|
2010-02-06 14:13:15 +01:00
|
|
|
/* See the comment in get_full_privileged_inheritable_token for a
|
|
|
|
description why we enable TCB privileges here. */
|
|
|
|
push_self_privilege (SE_TCB_PRIVILEGE, true);
|
|
|
|
hToken = get_full_privileged_inheritable_token (hToken);
|
|
|
|
pop_self_privilege ();
|
|
|
|
if (!hToken)
|
|
|
|
hToken = INVALID_HANDLE_VALUE;
|
2007-07-20 16:29:43 +02:00
|
|
|
}
|
2014-05-20 12:21:34 +02:00
|
|
|
RtlSecureZeroMemory (passwd, NT_MAX_PATH);
|
2007-07-20 16:29:43 +02:00
|
|
|
cygheap->user.reimpersonate ();
|
2011-12-03 22:43:27 +01:00
|
|
|
debug_printf ("%R = logon_user(%s,...)", hToken, pw->pw_name);
|
2007-07-20 16:29:43 +02:00
|
|
|
return hToken;
|
|
|
|
}
|
|
|
|
|
2014-12-02 11:49:47 +01:00
|
|
|
/* The buffer path points to should be at least MAX_PATH bytes. */
|
|
|
|
PWCHAR
|
|
|
|
get_user_profile_directory (PCWSTR sidstr, PWCHAR path, SIZE_T path_len)
|
|
|
|
{
|
|
|
|
if (!sidstr || !path)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
UNICODE_STRING buf;
|
|
|
|
tmp_pathbuf tp;
|
|
|
|
tp.u_get (&buf);
|
|
|
|
NTSTATUS status;
|
|
|
|
|
|
|
|
RTL_QUERY_REGISTRY_TABLE tab[2] = {
|
|
|
|
{ NULL, RTL_QUERY_REGISTRY_NOEXPAND | RTL_QUERY_REGISTRY_DIRECT
|
|
|
|
| RTL_QUERY_REGISTRY_REQUIRED,
|
|
|
|
L"ProfileImagePath", &buf, REG_NONE, NULL, 0 },
|
|
|
|
{ NULL, 0, NULL, NULL, 0, NULL, 0 }
|
|
|
|
};
|
|
|
|
|
|
|
|
WCHAR key[wcslen (sidstr) + 16];
|
|
|
|
wcpcpy (wcpcpy (key, L"ProfileList\\"), sidstr);
|
|
|
|
status = RtlQueryRegistryValues (RTL_REGISTRY_WINDOWS_NT, key, tab,
|
|
|
|
NULL, NULL);
|
|
|
|
if (!NT_SUCCESS (status) || buf.Length == 0)
|
|
|
|
{
|
|
|
|
debug_printf ("ProfileImagePath for %W not found, status %y", sidstr,
|
|
|
|
status);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
ExpandEnvironmentStringsW (buf.Buffer, path, path_len);
|
|
|
|
debug_printf ("ProfileImagePath for %W: %W", sidstr, path);
|
|
|
|
return path;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* The CreateProfile prototype is for some reason missing in our w32api headers,
|
|
|
|
even though it's defined upstream since Dec-2013. */
|
|
|
|
extern "C" {
|
|
|
|
HRESULT WINAPI CreateProfile (LPCWSTR pszUserSid, LPCWSTR pszUserName,
|
|
|
|
LPWSTR pszProfilePath, DWORD cchProfilePath);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Load user profile if it's not already loaded. If the user profile doesn't
|
|
|
|
exist on the machine, and if we're running Vista or later, try to create it.
|
|
|
|
|
|
|
|
Return a handle to the loaded user registry hive only if it got actually
|
|
|
|
loaded here, not if it already existed. There's no reliable way to know
|
|
|
|
when to unload the hive yet, so we're leaking this registry handle for now.
|
|
|
|
TODO: Try to find a way to reliably unload the user profile again. */
|
|
|
|
HANDLE
|
|
|
|
load_user_profile (HANDLE token, struct passwd *pw, cygpsid &usersid)
|
|
|
|
{
|
|
|
|
WCHAR domain[DNLEN + 1];
|
|
|
|
WCHAR username[UNLEN + 1];
|
|
|
|
WCHAR sid[128];
|
|
|
|
HKEY hkey;
|
|
|
|
WCHAR userpath[MAX_PATH];
|
|
|
|
PROFILEINFOW pi;
|
|
|
|
WCHAR server[INTERNET_MAX_HOST_NAME_LENGTH + 3];
|
|
|
|
NET_API_STATUS nas = NERR_UserNotFound;
|
|
|
|
PUSER_INFO_3 ui;
|
|
|
|
|
|
|
|
extract_nt_dom_user (pw, domain, username);
|
|
|
|
usersid.string (sid);
|
|
|
|
debug_printf ("user: <%W> <%W>", username, sid);
|
|
|
|
/* Check if user hive is already loaded. */
|
|
|
|
if (!RegOpenKeyExW (HKEY_USERS, sid, 0, KEY_READ, &hkey))
|
|
|
|
{
|
|
|
|
debug_printf ("User registry hive for %W already exists", username);
|
|
|
|
RegCloseKey (hkey);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
/* Check if the local profile dir has already been created. */
|
|
|
|
if (!get_user_profile_directory (sid, userpath, MAX_PATH))
|
|
|
|
{
|
|
|
|
/* No, try to create it. This function exists only on Vista and later. */
|
|
|
|
HRESULT res = CreateProfile (sid, username, userpath, MAX_PATH);
|
|
|
|
if (res != S_OK)
|
|
|
|
{
|
|
|
|
/* If res is 1 (S_FALSE), autoloading failed (XP or 2K3). */
|
|
|
|
if (res != S_FALSE)
|
|
|
|
debug_printf ("CreateProfile, HRESULT %x", res);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/* Fill PROFILEINFO */
|
|
|
|
memset (&pi, 0, sizeof pi);
|
|
|
|
pi.dwSize = sizeof pi;
|
|
|
|
pi.dwFlags = PI_NOUI;
|
|
|
|
pi.lpUserName = username;
|
|
|
|
/* Check if user has a roaming profile and fill in lpProfilePath, if so. */
|
|
|
|
if (get_logon_server (domain, server, DS_IS_FLAT_NAME))
|
|
|
|
{
|
|
|
|
nas = NetUserGetInfo (server, username, 3, (PBYTE *) &ui);
|
|
|
|
if (NetUserGetInfo (server, username, 3, (PBYTE *) &ui) != NERR_Success)
|
|
|
|
debug_printf ("NetUserGetInfo, %u", nas);
|
|
|
|
else if (ui->usri3_profile && *ui->usri3_profile)
|
|
|
|
pi.lpProfilePath = ui->usri3_profile;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!LoadUserProfileW (token, &pi))
|
|
|
|
debug_printf ("LoadUserProfileW, %E");
|
|
|
|
/* Free buffer created by NetUserGetInfo */
|
|
|
|
if (nas == NERR_Success)
|
|
|
|
NetApiBufferFree (ui);
|
|
|
|
return pi.hProfile;
|
|
|
|
}
|
|
|
|
|
2008-11-26 11:18:10 +01:00
|
|
|
HANDLE
|
2014-01-23 18:02:30 +01:00
|
|
|
lsa_open_policy (PWCHAR server, ACCESS_MASK access)
|
2007-07-20 16:29:43 +02:00
|
|
|
{
|
2014-01-23 18:02:30 +01:00
|
|
|
LSA_UNICODE_STRING srvbuf;
|
|
|
|
PLSA_UNICODE_STRING srv = NULL;
|
|
|
|
static LSA_OBJECT_ATTRIBUTES oa = { 0, 0, 0, 0, 0, 0 };
|
|
|
|
HANDLE lsa;
|
2007-07-20 16:29:43 +02:00
|
|
|
|
2014-01-23 18:02:30 +01:00
|
|
|
if (server)
|
|
|
|
{
|
|
|
|
srv = &srvbuf;
|
|
|
|
RtlInitUnicodeString (srv, server);
|
|
|
|
}
|
|
|
|
NTSTATUS status = LsaOpenPolicy (srv, &oa, access, &lsa);
|
2011-04-01 10:41:26 +02:00
|
|
|
if (!NT_SUCCESS (status))
|
2008-12-15 21:25:44 +01:00
|
|
|
{
|
2011-04-01 10:41:26 +02:00
|
|
|
__seterrno_from_nt_status (status);
|
2014-01-23 18:02:30 +01:00
|
|
|
lsa = NULL;
|
2008-12-15 21:25:44 +01:00
|
|
|
}
|
2007-07-20 16:29:43 +02:00
|
|
|
return lsa;
|
|
|
|
}
|
|
|
|
|
2014-01-23 18:02:30 +01:00
|
|
|
void
|
|
|
|
lsa_close_policy (HANDLE lsa)
|
2007-07-20 16:29:43 +02:00
|
|
|
{
|
2014-01-23 18:02:30 +01:00
|
|
|
if (lsa)
|
2007-07-20 16:29:43 +02:00
|
|
|
LsaClose (lsa);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
2015-01-21 17:31:38 +01:00
|
|
|
get_logon_server (PCWSTR domain, PWCHAR server, ULONG flags)
|
2007-07-20 16:29:43 +02:00
|
|
|
{
|
Drop NT4 support.
* autoload.cc (DnsQuery_A): Fatal if not available.
(DnsRecordListFree): Ditto.
(DsGetDcNameW): Ditto.
(NetGetAnyDCName): Remove.
(NetGetDCName): Remove.
(EnumProcessModules): Fatal if not available.
(GetModuleFileNameExW): Ditto.
(GetModuleInformation): Ditto.
(GetProcessMemoryInfo): Ditto.
(QueryWorkingSet): Ditto.
(LsaRegisterLogonProcess): Ditto.
* fenv.cc (_feinitialise): Drop supports_sse condition.
* fhandler_disk_file.cc (path_conv::isgood_inode): Fix comment.
(fhandler_base::fstat_by_name): Drop has_fileid_dirinfo condition.
(fhandler_disk_file::opendir): Ditto.
* fhandler_netdrive.cc (fhandler_netdrive::readdir): Fix comment.
* fhandler_proc.cc (format_proc_partitions): Drop NT4-only code.
* fhandler_process.cc (get_process_state): Ditto.
* kernel32.cc (GetWindowsDirectoryW): Remove.
(GetWindowsDirectoryA): Remove.
* miscfuncs.cc (nice_to_winprio): Drop NT4-only code.
* mount.cc (fs_info::update): Fix comments.
* net.cc (get_2k_ifs): Drop NT4-only code.
* sec_auth.cc (get_logon_server): Ditto.
(lsaauth): Drop NT4-specific error handling.
* security.cc (alloc_sd): Set SE_DACL_PROTECTED unconditionally.
* select.cc (select_stuff::wait): Always use MWMO_INPUTAVAILABLE.
(peek_windows): Drop NT4-only condition in call to PeekMessage.
* syscalls.cc (gethostid): Remove NT4-only workaround.
* wincap.cc: Througout, drop has_dacl_protect,
has_broken_if_oper_status, has_process_io_counters,
has_terminal_services, has_extended_priority_class, has_guid_volumes,
has_fileid_dirinfo, has_mwmo_inputavailable and supports_sse from
wincaps.
(wincap_nt4sp4): Remove.
(wincap_minimal): Set to wincap_2000.
(wincapc::init): Rely on availability of OSVERSIONINFOEX structure.
Treat error from GetVersionEx as fatal. Treat NT4 as fatal.
* wincap.h (struct wincaps): Drop has_dacl_protect,
has_broken_if_oper_status, has_process_io_counters,
has_terminal_services, has_extended_priority_class, has_guid_volumes,
has_fileid_dirinfo, has_mwmo_inputavailable and supports_sse flags
and methods.
* winlean.h (GetWindowsDirectoryW) Define as GetSystemWindowsDirectoryW.
(GetWindowsDirectoryA): Define as GetSystemWindowsDirectoryA.
2011-04-04 14:23:36 +02:00
|
|
|
DWORD ret;
|
2008-07-09 13:58:38 +02:00
|
|
|
PDOMAIN_CONTROLLER_INFOW pci;
|
2007-07-20 16:29:43 +02:00
|
|
|
|
|
|
|
/* Empty domain is interpreted as local system */
|
2014-02-19 19:29:52 +01:00
|
|
|
if (cygheap->dom.init ()
|
|
|
|
&& (!domain[0]
|
|
|
|
|| !wcscasecmp (domain, cygheap->dom.account_flat_name ())))
|
2007-07-20 16:29:43 +02:00
|
|
|
{
|
2014-02-09 20:44:56 +01:00
|
|
|
wcpcpy (wcpcpy (server, L"\\\\"), cygheap->dom.account_flat_name ());
|
2007-07-20 16:29:43 +02:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Try to get any available domain controller for this domain */
|
2014-02-09 20:44:56 +01:00
|
|
|
ret = DsGetDcNameW (NULL, domain, NULL, NULL, flags, &pci);
|
Drop NT4 support.
* autoload.cc (DnsQuery_A): Fatal if not available.
(DnsRecordListFree): Ditto.
(DsGetDcNameW): Ditto.
(NetGetAnyDCName): Remove.
(NetGetDCName): Remove.
(EnumProcessModules): Fatal if not available.
(GetModuleFileNameExW): Ditto.
(GetModuleInformation): Ditto.
(GetProcessMemoryInfo): Ditto.
(QueryWorkingSet): Ditto.
(LsaRegisterLogonProcess): Ditto.
* fenv.cc (_feinitialise): Drop supports_sse condition.
* fhandler_disk_file.cc (path_conv::isgood_inode): Fix comment.
(fhandler_base::fstat_by_name): Drop has_fileid_dirinfo condition.
(fhandler_disk_file::opendir): Ditto.
* fhandler_netdrive.cc (fhandler_netdrive::readdir): Fix comment.
* fhandler_proc.cc (format_proc_partitions): Drop NT4-only code.
* fhandler_process.cc (get_process_state): Ditto.
* kernel32.cc (GetWindowsDirectoryW): Remove.
(GetWindowsDirectoryA): Remove.
* miscfuncs.cc (nice_to_winprio): Drop NT4-only code.
* mount.cc (fs_info::update): Fix comments.
* net.cc (get_2k_ifs): Drop NT4-only code.
* sec_auth.cc (get_logon_server): Ditto.
(lsaauth): Drop NT4-specific error handling.
* security.cc (alloc_sd): Set SE_DACL_PROTECTED unconditionally.
* select.cc (select_stuff::wait): Always use MWMO_INPUTAVAILABLE.
(peek_windows): Drop NT4-only condition in call to PeekMessage.
* syscalls.cc (gethostid): Remove NT4-only workaround.
* wincap.cc: Througout, drop has_dacl_protect,
has_broken_if_oper_status, has_process_io_counters,
has_terminal_services, has_extended_priority_class, has_guid_volumes,
has_fileid_dirinfo, has_mwmo_inputavailable and supports_sse from
wincaps.
(wincap_nt4sp4): Remove.
(wincap_minimal): Set to wincap_2000.
(wincapc::init): Rely on availability of OSVERSIONINFOEX structure.
Treat error from GetVersionEx as fatal. Treat NT4 as fatal.
* wincap.h (struct wincaps): Drop has_dacl_protect,
has_broken_if_oper_status, has_process_io_counters,
has_terminal_services, has_extended_priority_class, has_guid_volumes,
has_fileid_dirinfo, has_mwmo_inputavailable and supports_sse flags
and methods.
* winlean.h (GetWindowsDirectoryW) Define as GetSystemWindowsDirectoryW.
(GetWindowsDirectoryA): Define as GetSystemWindowsDirectoryA.
2011-04-04 14:23:36 +02:00
|
|
|
if (ret == ERROR_SUCCESS)
|
2007-07-20 16:29:43 +02:00
|
|
|
{
|
2008-07-11 12:00:36 +02:00
|
|
|
wcscpy (server, pci->DomainControllerName);
|
2007-07-20 16:29:43 +02:00
|
|
|
NetApiBufferFree (pci);
|
2014-02-09 20:44:56 +01:00
|
|
|
debug_printf ("DC: server: %W", server);
|
2007-07-20 16:29:43 +02:00
|
|
|
return true;
|
|
|
|
}
|
Drop NT4 support.
* autoload.cc (DnsQuery_A): Fatal if not available.
(DnsRecordListFree): Ditto.
(DsGetDcNameW): Ditto.
(NetGetAnyDCName): Remove.
(NetGetDCName): Remove.
(EnumProcessModules): Fatal if not available.
(GetModuleFileNameExW): Ditto.
(GetModuleInformation): Ditto.
(GetProcessMemoryInfo): Ditto.
(QueryWorkingSet): Ditto.
(LsaRegisterLogonProcess): Ditto.
* fenv.cc (_feinitialise): Drop supports_sse condition.
* fhandler_disk_file.cc (path_conv::isgood_inode): Fix comment.
(fhandler_base::fstat_by_name): Drop has_fileid_dirinfo condition.
(fhandler_disk_file::opendir): Ditto.
* fhandler_netdrive.cc (fhandler_netdrive::readdir): Fix comment.
* fhandler_proc.cc (format_proc_partitions): Drop NT4-only code.
* fhandler_process.cc (get_process_state): Ditto.
* kernel32.cc (GetWindowsDirectoryW): Remove.
(GetWindowsDirectoryA): Remove.
* miscfuncs.cc (nice_to_winprio): Drop NT4-only code.
* mount.cc (fs_info::update): Fix comments.
* net.cc (get_2k_ifs): Drop NT4-only code.
* sec_auth.cc (get_logon_server): Ditto.
(lsaauth): Drop NT4-specific error handling.
* security.cc (alloc_sd): Set SE_DACL_PROTECTED unconditionally.
* select.cc (select_stuff::wait): Always use MWMO_INPUTAVAILABLE.
(peek_windows): Drop NT4-only condition in call to PeekMessage.
* syscalls.cc (gethostid): Remove NT4-only workaround.
* wincap.cc: Througout, drop has_dacl_protect,
has_broken_if_oper_status, has_process_io_counters,
has_terminal_services, has_extended_priority_class, has_guid_volumes,
has_fileid_dirinfo, has_mwmo_inputavailable and supports_sse from
wincaps.
(wincap_nt4sp4): Remove.
(wincap_minimal): Set to wincap_2000.
(wincapc::init): Rely on availability of OSVERSIONINFOEX structure.
Treat error from GetVersionEx as fatal. Treat NT4 as fatal.
* wincap.h (struct wincaps): Drop has_dacl_protect,
has_broken_if_oper_status, has_process_io_counters,
has_terminal_services, has_extended_priority_class, has_guid_volumes,
has_fileid_dirinfo, has_mwmo_inputavailable and supports_sse flags
and methods.
* winlean.h (GetWindowsDirectoryW) Define as GetSystemWindowsDirectoryW.
(GetWindowsDirectoryA): Define as GetSystemWindowsDirectoryA.
2011-04-04 14:23:36 +02:00
|
|
|
__seterrno_from_win_error (ret);
|
2007-07-20 16:29:43 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool
|
2008-07-11 12:00:36 +02:00
|
|
|
get_user_groups (WCHAR *logonserver, cygsidlist &grp_list,
|
|
|
|
PWCHAR user, PWCHAR domain)
|
2007-07-20 16:29:43 +02:00
|
|
|
{
|
2008-07-11 12:00:36 +02:00
|
|
|
WCHAR dgroup[MAX_DOMAIN_NAME_LEN + GNLEN + 2];
|
2007-07-20 16:29:43 +02:00
|
|
|
LPGROUP_USERS_INFO_0 buf;
|
|
|
|
DWORD cnt, tot, len;
|
|
|
|
NET_API_STATUS ret;
|
|
|
|
|
2014-10-21 21:17:09 +02:00
|
|
|
/* Look only on logonserver */
|
|
|
|
ret = NetUserGetGroups (logonserver, user, 0, (LPBYTE *) &buf,
|
|
|
|
MAX_PREFERRED_LENGTH, &cnt, &tot);
|
2007-07-20 16:29:43 +02:00
|
|
|
if (ret)
|
|
|
|
{
|
|
|
|
__seterrno_from_win_error (ret);
|
2013-06-10 17:33:12 +02:00
|
|
|
/* It's no error when the user name can't be found.
|
|
|
|
It's also no error if access has been denied. Yes, sounds weird, but
|
|
|
|
keep in mind that ERROR_ACCESS_DENIED means the current user has no
|
|
|
|
permission to access the AD user information. However, if we return
|
|
|
|
an error, Cygwin will call DsGetDcName with DS_FORCE_REDISCOVERY set
|
|
|
|
to ask for another server. This is not only time consuming, it's also
|
|
|
|
useless; the next server will return access denied again. */
|
|
|
|
return ret == NERR_UserNotFound || ret == ERROR_ACCESS_DENIED;
|
2007-07-20 16:29:43 +02:00
|
|
|
}
|
|
|
|
|
2008-07-11 12:00:36 +02:00
|
|
|
len = wcslen (domain);
|
|
|
|
wcscpy (dgroup, domain);
|
2008-07-09 13:58:38 +02:00
|
|
|
dgroup[len++] = L'\\';
|
2007-07-20 16:29:43 +02:00
|
|
|
|
|
|
|
for (DWORD i = 0; i < cnt; ++i)
|
|
|
|
{
|
|
|
|
cygsid gsid;
|
2014-05-06 14:28:33 +02:00
|
|
|
DWORD glen = SECURITY_MAX_SID_SIZE;
|
2008-07-11 12:00:36 +02:00
|
|
|
WCHAR dom[MAX_DOMAIN_NAME_LEN + 1];
|
|
|
|
DWORD dlen = sizeof (dom);
|
2007-07-20 16:29:43 +02:00
|
|
|
SID_NAME_USE use = SidTypeInvalid;
|
|
|
|
|
2008-07-09 13:58:38 +02:00
|
|
|
wcscpy (dgroup + len, buf[i].grui0_name);
|
2008-07-11 12:00:36 +02:00
|
|
|
if (!LookupAccountNameW (NULL, dgroup, gsid, &glen, dom, &dlen, &use))
|
|
|
|
debug_printf ("LookupAccountName(%W), %E", dgroup);
|
2011-04-04 11:00:02 +02:00
|
|
|
else if (well_known_sid_type (use))
|
|
|
|
grp_list *= gsid;
|
2007-07-20 16:29:43 +02:00
|
|
|
else if (legal_sid_type (use))
|
|
|
|
grp_list += gsid;
|
|
|
|
else
|
2013-04-23 11:44:36 +02:00
|
|
|
debug_printf ("Global group %W invalid. Use: %u", dgroup, use);
|
2007-07-20 16:29:43 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
NetApiBufferFree (buf);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool
|
2008-07-11 12:00:36 +02:00
|
|
|
get_user_local_groups (PWCHAR logonserver, PWCHAR domain,
|
2009-02-20 17:10:45 +01:00
|
|
|
cygsidlist &grp_list, PWCHAR user)
|
2007-07-20 16:29:43 +02:00
|
|
|
{
|
|
|
|
LPLOCALGROUP_INFO_0 buf;
|
|
|
|
DWORD cnt, tot;
|
|
|
|
NET_API_STATUS ret;
|
|
|
|
|
2014-10-21 21:17:09 +02:00
|
|
|
ret = NetUserGetLocalGroups (logonserver, user, 0, LG_INCLUDE_INDIRECT,
|
|
|
|
(LPBYTE *) &buf, MAX_PREFERRED_LENGTH,
|
|
|
|
&cnt, &tot);
|
2007-07-20 16:29:43 +02:00
|
|
|
if (ret)
|
|
|
|
{
|
|
|
|
__seterrno_from_win_error (ret);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2008-07-11 12:00:36 +02:00
|
|
|
WCHAR domlocal_grp[MAX_DOMAIN_NAME_LEN + GNLEN + 2];
|
2010-02-12 18:40:42 +01:00
|
|
|
WCHAR builtin_grp[2 * GNLEN + 2];
|
|
|
|
PWCHAR dg_ptr, bg_ptr = NULL;
|
2007-07-20 16:29:43 +02:00
|
|
|
SID_NAME_USE use;
|
|
|
|
|
2008-07-11 12:00:36 +02:00
|
|
|
dg_ptr = wcpcpy (domlocal_grp, domain);
|
2008-07-09 13:58:38 +02:00
|
|
|
*dg_ptr++ = L'\\';
|
2007-07-20 16:29:43 +02:00
|
|
|
|
|
|
|
for (DWORD i = 0; i < cnt; ++i)
|
2009-02-20 17:10:45 +01:00
|
|
|
{
|
|
|
|
cygsid gsid;
|
2014-05-06 14:28:33 +02:00
|
|
|
DWORD glen = SECURITY_MAX_SID_SIZE;
|
2009-02-20 17:10:45 +01:00
|
|
|
WCHAR dom[MAX_DOMAIN_NAME_LEN + 1];
|
2010-02-12 18:40:42 +01:00
|
|
|
DWORD domlen = MAX_DOMAIN_NAME_LEN + 1;
|
2009-02-20 17:10:45 +01:00
|
|
|
|
|
|
|
use = SidTypeInvalid;
|
|
|
|
wcscpy (dg_ptr, buf[i].lgrpi0_name);
|
2009-02-23 19:27:48 +01:00
|
|
|
if (LookupAccountNameW (NULL, domlocal_grp, gsid, &glen,
|
|
|
|
dom, &domlen, &use))
|
2009-02-20 17:10:45 +01:00
|
|
|
{
|
2011-04-04 11:00:02 +02:00
|
|
|
if (well_known_sid_type (use))
|
|
|
|
grp_list *= gsid;
|
|
|
|
else if (legal_sid_type (use))
|
2009-02-23 19:27:48 +01:00
|
|
|
grp_list += gsid;
|
2011-04-04 11:00:02 +02:00
|
|
|
else
|
2013-04-23 11:44:36 +02:00
|
|
|
debug_printf ("Rejecting local %W. use: %u", dg_ptr, use);
|
2009-02-23 19:27:48 +01:00
|
|
|
}
|
|
|
|
else if (GetLastError () == ERROR_NONE_MAPPED)
|
|
|
|
{
|
|
|
|
/* Check if it's a builtin group. */
|
2010-02-12 18:40:42 +01:00
|
|
|
if (!bg_ptr)
|
2009-02-23 19:27:48 +01:00
|
|
|
{
|
2010-02-12 18:40:42 +01:00
|
|
|
/* Retrieve name of builtin group from system since it's
|
2011-06-06 07:02:13 +02:00
|
|
|
localized. */
|
2010-02-12 18:40:42 +01:00
|
|
|
glen = 2 * GNLEN + 2;
|
|
|
|
if (!LookupAccountSidW (NULL, well_known_builtin_sid,
|
|
|
|
builtin_grp, &glen, domain, &domlen, &use))
|
|
|
|
debug_printf ("LookupAccountSid(BUILTIN), %E");
|
2009-02-23 19:27:48 +01:00
|
|
|
else
|
2010-02-12 18:40:42 +01:00
|
|
|
{
|
|
|
|
bg_ptr = builtin_grp + wcslen (builtin_grp);
|
|
|
|
bg_ptr = wcpcpy (builtin_grp, L"\\");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (bg_ptr)
|
|
|
|
{
|
|
|
|
wcscpy (bg_ptr, dg_ptr);
|
2014-05-06 14:28:33 +02:00
|
|
|
glen = SECURITY_MAX_SID_SIZE;
|
2010-02-12 18:40:42 +01:00
|
|
|
domlen = MAX_DOMAIN_NAME_LEN + 1;
|
|
|
|
if (LookupAccountNameW (NULL, builtin_grp, gsid, &glen,
|
|
|
|
dom, &domlen, &use))
|
|
|
|
{
|
|
|
|
if (!legal_sid_type (use))
|
2013-04-23 11:44:36 +02:00
|
|
|
debug_printf ("Rejecting local %W. use: %u", dg_ptr, use);
|
2010-02-12 18:40:42 +01:00
|
|
|
else
|
|
|
|
grp_list *= gsid;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
debug_printf ("LookupAccountName(%W), %E", builtin_grp);
|
2009-02-23 19:27:48 +01:00
|
|
|
}
|
2009-02-20 17:10:45 +01:00
|
|
|
}
|
|
|
|
else
|
2009-02-23 19:27:48 +01:00
|
|
|
debug_printf ("LookupAccountName(%W), %E", domlocal_grp);
|
2009-02-20 17:10:45 +01:00
|
|
|
}
|
2007-07-20 16:29:43 +02:00
|
|
|
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_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;
|
2011-10-15 18:31:57 +02:00
|
|
|
if (wincap.has_console_logon_sid ())
|
|
|
|
grp_list += well_known_console_logon_sid;
|
2007-07-20 16:29:43 +02:00
|
|
|
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;
|
2011-10-15 18:31:57 +02:00
|
|
|
#if 0
|
|
|
|
/* Don't add the SERVICE group when switching the user context.
|
|
|
|
That's much too dangerous, since the service group adds the
|
|
|
|
SE_IMPERSONATE_NAME privilege to the user. After all, the
|
|
|
|
process started with this token is not the service process
|
|
|
|
anymore anyway. */
|
2007-07-20 16:29:43 +02:00
|
|
|
if (sid_in_token_groups (my_grps, well_known_service_sid))
|
|
|
|
grp_list *= well_known_service_sid;
|
2011-10-15 18:31:57 +02:00
|
|
|
#endif
|
2007-07-20 16:29:43 +02:00
|
|
|
if (sid_in_token_groups (my_grps, well_known_this_org_sid))
|
|
|
|
grp_list *= well_known_this_org_sid;
|
2010-01-08 16:55:27 +01:00
|
|
|
grp_list *= well_known_users_sid;
|
2007-07-20 16:29:43 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
grp_list += well_known_local_sid;
|
|
|
|
grp_list *= well_known_interactive_sid;
|
2010-01-08 16:55:27 +01:00
|
|
|
grp_list *= well_known_users_sid;
|
2007-07-20 16:29:43 +02:00
|
|
|
}
|
|
|
|
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
|
2015-03-18 16:54:19 +01:00
|
|
|
get_server_groups (cygsidlist &grp_list, PSID usersid)
|
2007-07-20 16:29:43 +02:00
|
|
|
{
|
2008-07-11 12:00:36 +02:00
|
|
|
WCHAR user[UNLEN + 1];
|
|
|
|
WCHAR domain[MAX_DOMAIN_NAME_LEN + 1];
|
|
|
|
WCHAR server[INTERNET_MAX_HOST_NAME_LENGTH + 3];
|
|
|
|
DWORD ulen = UNLEN + 1;
|
|
|
|
DWORD dlen = MAX_DOMAIN_NAME_LEN + 1;
|
|
|
|
SID_NAME_USE use;
|
2007-07-20 16:29:43 +02:00
|
|
|
|
|
|
|
if (well_known_system_sid == usersid)
|
|
|
|
{
|
|
|
|
grp_list *= well_known_admins_sid;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
grp_list *= well_known_world_sid;
|
|
|
|
grp_list *= well_known_authenticated_users_sid;
|
2008-07-11 12:00:36 +02:00
|
|
|
|
|
|
|
if (!LookupAccountSidW (NULL, usersid, user, &ulen, domain, &dlen, &use))
|
|
|
|
{
|
|
|
|
__seterrno ();
|
|
|
|
return false;
|
|
|
|
}
|
2014-05-14 13:27:47 +02:00
|
|
|
/* If the SID does NOT start with S-1-5-21, the domain is some builtin
|
2014-05-22 18:40:13 +02:00
|
|
|
domain. The search for a logon server and fetching group accounts
|
|
|
|
is moot. */
|
2014-05-14 13:27:47 +02:00
|
|
|
if (sid_id_auth (usersid) == 5 /* SECURITY_NT_AUTHORITY */
|
|
|
|
&& sid_sub_auth (usersid, 0) == SECURITY_NT_NON_UNIQUE
|
|
|
|
&& get_logon_server (domain, server, DS_IS_FLAT_NAME))
|
2014-05-22 18:40:13 +02:00
|
|
|
{
|
|
|
|
get_user_groups (server, grp_list, user, domain);
|
|
|
|
get_user_local_groups (server, domain, grp_list, user);
|
|
|
|
}
|
2009-06-23 12:23:16 +02:00
|
|
|
return true;
|
2007-07-20 16:29:43 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static bool
|
2015-03-18 16:54:19 +01:00
|
|
|
get_initgroups_sidlist (cygsidlist &grp_list, PSID usersid, PSID pgrpsid,
|
2007-07-20 16:29:43 +02:00
|
|
|
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);
|
2015-03-18 16:54:19 +01:00
|
|
|
if (!get_server_groups (grp_list, usersid))
|
2007-07-20 16:29:43 +02:00
|
|
|
return false;
|
|
|
|
|
|
|
|
/* special_pgrp true if pgrpsid is not in normal groups */
|
|
|
|
grp_list += pgrpsid;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2015-03-18 16:54:19 +01:00
|
|
|
get_setgroups_sidlist (cygsidlist &tmp_list, PSID usersid,
|
2007-07-20 16:29:43 +02:00
|
|
|
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);
|
2015-03-18 16:54:19 +01:00
|
|
|
get_server_groups (tmp_list, usersid);
|
2007-07-20 16:29:43 +02:00
|
|
|
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,
|
2008-02-15 18:53:11 +01:00
|
|
|
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,
|
2007-07-20 16:29:43 +02:00
|
|
|
SE_SYSTEM_PROFILE_PRIVILEGE, /* Vista ONLY */
|
2008-02-15 18:53:11 +01:00
|
|
|
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,
|
2007-07-20 16:29:43 +02:00
|
|
|
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
|
2011-06-06 07:02:13 +02:00
|
|
|
&& sys_privs[max_idx] != wincap.max_sys_priv ())
|
2007-07-20 16:29:43 +02:00
|
|
|
++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,
|
2011-10-15 18:31:57 +02:00
|
|
|
size_t &size, cygpsid *mandatory_integrity_sid)
|
2007-07-20 16:29:43 +02:00
|
|
|
{
|
|
|
|
PLSA_UNICODE_STRING privstrs;
|
|
|
|
ULONG cnt;
|
|
|
|
PTOKEN_PRIVILEGES privs = NULL;
|
|
|
|
|
|
|
|
if (usersid == well_known_system_sid)
|
2011-10-15 18:31:57 +02:00
|
|
|
{
|
|
|
|
if (mandatory_integrity_sid)
|
|
|
|
*mandatory_integrity_sid = mandatory_system_integrity_sid;
|
|
|
|
return get_system_priv_list (size);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (mandatory_integrity_sid)
|
|
|
|
*mandatory_integrity_sid = mandatory_medium_integrity_sid;
|
2007-07-20 16:29:43 +02:00
|
|
|
|
|
|
|
for (int grp = -1; grp < grp_list.count (); ++grp)
|
|
|
|
{
|
|
|
|
if (grp == -1)
|
|
|
|
{
|
2011-12-22 12:02:36 +01:00
|
|
|
if (LsaEnumerateAccountRights (lsa, usersid, &privstrs, &cnt)
|
|
|
|
!= STATUS_SUCCESS)
|
2007-07-20 16:29:43 +02:00
|
|
|
continue;
|
|
|
|
}
|
2011-12-22 12:02:36 +01:00
|
|
|
else if (LsaEnumerateAccountRights (lsa, grp_list.sids[grp],
|
|
|
|
&privstrs, &cnt) != STATUS_SUCCESS)
|
2007-07-20 16:29:43 +02:00
|
|
|
continue;
|
|
|
|
for (ULONG i = 0; i < cnt; ++i)
|
|
|
|
{
|
|
|
|
LUID priv;
|
|
|
|
PTOKEN_PRIVILEGES tmp;
|
|
|
|
DWORD tmp_count;
|
2011-10-15 18:31:57 +02:00
|
|
|
bool high_integrity;
|
2007-07-20 16:29:43 +02:00
|
|
|
|
2011-10-15 18:31:57 +02:00
|
|
|
if (!privilege_luid (privstrs[i].Buffer, priv, high_integrity))
|
2007-07-20 16:29:43 +02:00
|
|
|
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;
|
2011-10-15 18:31:57 +02:00
|
|
|
if (mandatory_integrity_sid && high_integrity)
|
|
|
|
*mandatory_integrity_sid = mandatory_high_integrity_sid;
|
2007-07-20 16:29:43 +02:00
|
|
|
|
|
|
|
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)
|
|
|
|
{
|
2011-04-29 09:34:05 +02:00
|
|
|
NTSTATUS status;
|
|
|
|
ULONG size;
|
2007-07-20 16:29:43 +02:00
|
|
|
bool intern = false;
|
|
|
|
|
|
|
|
if (pintern)
|
|
|
|
{
|
|
|
|
TOKEN_SOURCE ts;
|
2011-04-29 09:34:05 +02:00
|
|
|
status = NtQueryInformationToken (token, TokenSource, &ts, sizeof ts,
|
|
|
|
&size);
|
|
|
|
if (!NT_SUCCESS (status))
|
2013-04-23 11:44:36 +02:00
|
|
|
debug_printf ("NtQueryInformationToken(), %y", status);
|
2007-07-20 16:29:43 +02:00
|
|
|
else
|
|
|
|
*pintern = intern = !memcmp (ts.SourceName, "Cygwin.1", 8);
|
|
|
|
}
|
|
|
|
/* Verify usersid */
|
2014-02-16 17:02:18 +01:00
|
|
|
cygsid tok_usersid (NO_SID);
|
2011-04-29 09:34:05 +02:00
|
|
|
status = NtQueryInformationToken (token, TokenUser, &tok_usersid,
|
|
|
|
sizeof tok_usersid, &size);
|
|
|
|
if (!NT_SUCCESS (status))
|
2013-04-23 11:44:36 +02:00
|
|
|
debug_printf ("NtQueryInformationToken(), %y", status);
|
2007-07-20 16:29:43 +02:00
|
|
|
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 ())
|
|
|
|
{
|
2014-05-06 14:28:33 +02:00
|
|
|
const DWORD sd_buf_siz = SECURITY_MAX_SID_SIZE
|
|
|
|
+ sizeof (SECURITY_DESCRIPTOR);
|
2007-07-20 16:29:43 +02:00
|
|
|
PSECURITY_DESCRIPTOR sd_buf = (PSECURITY_DESCRIPTOR) alloca (sd_buf_siz);
|
|
|
|
cygpsid gsid (NO_SID);
|
2011-04-01 10:41:26 +02:00
|
|
|
NTSTATUS status;
|
|
|
|
status = NtQuerySecurityObject (token, GROUP_SECURITY_INFORMATION,
|
|
|
|
sd_buf, sd_buf_siz, &size);
|
|
|
|
if (!NT_SUCCESS (status))
|
2013-04-23 11:44:36 +02:00
|
|
|
debug_printf ("NtQuerySecurityObject(), %y", status);
|
2011-04-28 11:53:11 +02:00
|
|
|
else
|
|
|
|
{
|
|
|
|
BOOLEAN dummy;
|
|
|
|
status = RtlGetGroupSecurityDescriptor (sd_buf, (PSID *) &gsid,
|
|
|
|
&dummy);
|
|
|
|
if (!NT_SUCCESS (status))
|
2013-04-23 11:44:36 +02:00
|
|
|
debug_printf ("RtlGetGroupSecurityDescriptor(), %y", status);
|
2011-04-28 11:53:11 +02:00
|
|
|
}
|
2007-07-20 16:29:43 +02:00
|
|
|
if (well_known_null_sid != gsid)
|
|
|
|
return gsid == groups.pgsid;
|
|
|
|
}
|
|
|
|
|
|
|
|
PTOKEN_GROUPS my_grps;
|
2011-04-29 09:34:05 +02:00
|
|
|
|
|
|
|
status = NtQueryInformationToken (token, TokenGroups, NULL, 0, &size);
|
|
|
|
if (!NT_SUCCESS (status) && status != STATUS_BUFFER_TOO_SMALL)
|
2007-07-20 16:29:43 +02:00
|
|
|
{
|
2013-04-23 11:44:36 +02:00
|
|
|
debug_printf ("NtQueryInformationToken(token, TokenGroups), %y", status);
|
2011-04-29 09:34:05 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
my_grps = (PTOKEN_GROUPS) alloca (size);
|
|
|
|
status = NtQueryInformationToken (token, TokenGroups, my_grps, size, &size);
|
|
|
|
if (!NT_SUCCESS (status))
|
|
|
|
{
|
2013-04-23 11:44:36 +02:00
|
|
|
debug_printf ("NtQueryInformationToken(my_token, TokenGroups), %y",
|
2011-04-29 09:34:05 +02:00
|
|
|
status);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool sawpg = false;
|
|
|
|
|
|
|
|
if (groups.issetgroups ()) /* setgroups was called */
|
|
|
|
{
|
2014-02-09 20:44:56 +01:00
|
|
|
cygpsid gsid;
|
2011-04-29 09:34:05 +02:00
|
|
|
bool saw[groups.sgsids.count ()];
|
|
|
|
|
2014-02-09 20:44:56 +01:00
|
|
|
/* Check that all groups in the setgroups () list are in the token.
|
|
|
|
A token created through ADVAPI should be allowed to contain more
|
|
|
|
groups than requested through setgroups(), especially since Vista
|
|
|
|
and the addition of integrity groups. */
|
|
|
|
memset (saw, 0, sizeof(saw));
|
|
|
|
for (int gidx = 0; gidx < groups.sgsids.count (); gidx++)
|
|
|
|
{
|
|
|
|
gsid = groups.sgsids.sids[gidx];
|
|
|
|
if (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;
|
|
|
|
}
|
|
|
|
}
|
2011-04-29 09:34:05 +02:00
|
|
|
/* user.sgsids groups must be in the token, except for builtin groups.
|
|
|
|
These can be different on domain member machines compared to
|
|
|
|
domain controllers, so these builtin groups may be validly missing
|
|
|
|
from a token created through password or lsaauth logon. */
|
|
|
|
for (int gidx = 0; gidx < groups.sgsids.count (); gidx++)
|
|
|
|
if (!saw[gidx]
|
|
|
|
&& !groups.sgsids.sids[gidx].is_well_known_sid ()
|
|
|
|
&& !sid_in_token_groups (my_grps, groups.sgsids.sids[gidx]))
|
|
|
|
return false;
|
2007-07-20 16:29:43 +02:00
|
|
|
}
|
2011-04-29 09:34:05 +02:00
|
|
|
/* The primary group must be in the token */
|
|
|
|
return sawpg
|
|
|
|
|| sid_in_token_groups (my_grps, groups.pgsid)
|
|
|
|
|| groups.pgsid == usersid;
|
2007-07-20 16:29:43 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
HANDLE
|
2015-03-18 16:54:19 +01:00
|
|
|
create_token (cygsid &usersid, user_groups &new_groups)
|
2007-07-20 16:29:43 +02:00
|
|
|
{
|
2011-04-01 10:41:26 +02:00
|
|
|
NTSTATUS status;
|
2014-03-28 21:34:04 +01:00
|
|
|
LSA_HANDLE lsa = NULL;
|
2007-07-20 16:29:43 +02:00
|
|
|
|
|
|
|
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;
|
2011-10-15 18:31:57 +02:00
|
|
|
cygpsid mandatory_integrity_sid;
|
2011-04-29 09:34:05 +02:00
|
|
|
ULONG size;
|
2007-07-20 16:29:43 +02:00
|
|
|
size_t psize = 0;
|
|
|
|
|
|
|
|
/* SE_CREATE_TOKEN_NAME privilege needed to call NtCreateToken. */
|
|
|
|
push_self_privilege (SE_CREATE_TOKEN_PRIVILEGE, true);
|
|
|
|
|
|
|
|
/* Open policy object. */
|
2014-01-23 18:02:30 +01:00
|
|
|
if (!(lsa = lsa_open_policy (NULL, POLICY_EXECUTE)))
|
2007-07-20 16:29:43 +02:00
|
|
|
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. */
|
2008-09-11 06:34:24 +02:00
|
|
|
if (usersid == well_known_system_sid)
|
|
|
|
/* nothing to do */;
|
|
|
|
else
|
2011-04-29 09:34:05 +02:00
|
|
|
{
|
|
|
|
status = NtQueryInformationToken (hProcToken, TokenStatistics,
|
|
|
|
&stats, sizeof stats, &size);
|
|
|
|
if (!NT_SUCCESS (status))
|
|
|
|
debug_printf ("NtQueryInformationToken(hProcToken, "
|
2013-04-23 11:44:36 +02:00
|
|
|
"TokenStatistics), %y", status);
|
2011-04-29 09:34:05 +02:00
|
|
|
else
|
|
|
|
auth_luid = stats.AuthenticationId;
|
|
|
|
}
|
2007-07-20 16:29:43 +02:00
|
|
|
|
|
|
|
/* Retrieving current processes group list to be able to inherit
|
|
|
|
some important well known group sids. */
|
2011-04-29 09:34:05 +02:00
|
|
|
status = NtQueryInformationToken (hProcToken, TokenGroups, NULL, 0,
|
|
|
|
&size);
|
|
|
|
if (!NT_SUCCESS (status) && status != STATUS_BUFFER_TOO_SMALL)
|
2013-04-23 11:44:36 +02:00
|
|
|
debug_printf ("NtQueryInformationToken(hProcToken, TokenGroups), %y",
|
2011-04-29 09:34:05 +02:00
|
|
|
status);
|
2007-07-20 16:29:43 +02:00
|
|
|
else if (!(my_tok_gsids = (PTOKEN_GROUPS) malloc (size)))
|
|
|
|
debug_printf ("malloc (my_tok_gsids) failed.");
|
2011-04-29 09:34:05 +02:00
|
|
|
else
|
2007-07-20 16:29:43 +02:00
|
|
|
{
|
2011-04-29 09:34:05 +02:00
|
|
|
status = NtQueryInformationToken (hProcToken, TokenGroups,
|
|
|
|
my_tok_gsids, size, &size);
|
|
|
|
if (!NT_SUCCESS (status))
|
|
|
|
{
|
|
|
|
debug_printf ("NtQueryInformationToken(hProcToken, TokenGroups), "
|
2013-04-23 11:44:36 +02:00
|
|
|
"%y", status);
|
2011-04-29 09:34:05 +02:00
|
|
|
free (my_tok_gsids);
|
|
|
|
my_tok_gsids = NULL;
|
|
|
|
}
|
2007-07-20 16:29:43 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Create list of groups, the user is member in. */
|
|
|
|
int auth_pos;
|
|
|
|
if (new_groups.issetgroups ())
|
2015-03-18 16:54:19 +01:00
|
|
|
get_setgroups_sidlist (tmp_gsids, usersid, my_tok_gsids, new_groups,
|
2007-07-20 16:29:43 +02:00
|
|
|
auth_luid, auth_pos);
|
2015-03-18 16:54:19 +01:00
|
|
|
else if (!get_initgroups_sidlist (tmp_gsids, usersid, new_groups.pgsid,
|
2007-07-20 16:29:43 +02:00
|
|
|
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)
|
2008-04-22 12:45:34 +02:00
|
|
|
alloca (sizeof (DWORD) + (tmp_gsids.count () + 1)
|
2007-07-20 16:29:43 +02:00
|
|
|
* 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;
|
2008-04-22 12:45:34 +02:00
|
|
|
|
2011-10-15 18:31:57 +02:00
|
|
|
/* Retrieve list of privileges of that user. Based on the usersid and
|
|
|
|
the returned privileges, get_priv_list sets the mandatory_integrity_sid
|
|
|
|
pointer to the correct MIC SID for UAC. */
|
|
|
|
if (!(privs = get_priv_list (lsa, usersid, tmp_gsids, psize,
|
|
|
|
&mandatory_integrity_sid)))
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
/* On systems supporting Mandatory Integrity Control, add the MIC SID. */
|
2008-04-22 12:45:34 +02:00
|
|
|
if (wincap.has_mandatory_integrity_control ())
|
|
|
|
{
|
|
|
|
new_tok_gsids->Groups[new_tok_gsids->GroupCount].Attributes =
|
|
|
|
SE_GROUP_INTEGRITY | SE_GROUP_INTEGRITY_ENABLED;
|
2011-10-15 18:31:57 +02:00
|
|
|
new_tok_gsids->Groups[new_tok_gsids->GroupCount++].Sid
|
|
|
|
= mandatory_integrity_sid;
|
2008-04-22 12:45:34 +02:00
|
|
|
}
|
|
|
|
|
2007-07-20 16:29:43 +02:00
|
|
|
/* Let's be heroic... */
|
2011-04-01 10:41:26 +02:00
|
|
|
status = NtCreateToken (&token, TOKEN_ALL_ACCESS, &oa, TokenImpersonation,
|
|
|
|
&auth_luid, &exp, &user, new_tok_gsids, privs, &owner,
|
|
|
|
&pgrp, &dacl, &source);
|
|
|
|
if (status)
|
|
|
|
__seterrno_from_nt_status (status);
|
2007-07-20 16:29:43 +02:00
|
|
|
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);
|
2014-01-23 18:02:30 +01:00
|
|
|
lsa_close_policy (lsa);
|
2007-07-20 16:29:43 +02:00
|
|
|
|
2008-07-11 12:00:36 +02:00
|
|
|
debug_printf ("%p = create_token ()", primary_token);
|
2007-07-20 16:29:43 +02:00
|
|
|
return primary_token;
|
|
|
|
}
|
|
|
|
|
|
|
|
HANDLE
|
2015-03-18 16:54:19 +01:00
|
|
|
lsaauth (cygsid &usersid, user_groups &new_groups)
|
2007-07-20 16:29:43 +02:00
|
|
|
{
|
|
|
|
cygsidlist tmp_gsids (cygsidlist_auto, 12);
|
|
|
|
cygpsid pgrpsid;
|
|
|
|
LSA_STRING name;
|
2014-03-28 21:34:04 +01:00
|
|
|
HANDLE lsa_hdl = NULL, lsa = NULL;
|
2007-07-20 16:29:43 +02:00
|
|
|
LSA_OPERATIONAL_MODE sec_mode;
|
2011-04-01 10:41:26 +02:00
|
|
|
NTSTATUS status, sub_status;
|
2007-07-20 16:29:43 +02:00
|
|
|
ULONG package_id, size;
|
|
|
|
LUID auth_luid = SYSTEM_LUID;
|
|
|
|
struct {
|
|
|
|
LSA_STRING str;
|
|
|
|
CHAR buf[16];
|
|
|
|
} origin;
|
2008-07-11 12:00:36 +02:00
|
|
|
DWORD ulen = UNLEN + 1;
|
|
|
|
DWORD dlen = MAX_DOMAIN_NAME_LEN + 1;
|
|
|
|
SID_NAME_USE use;
|
2007-07-20 16:29:43 +02:00
|
|
|
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. */
|
2014-12-02 11:04:53 +01:00
|
|
|
RtlInitAnsiString (&name, "Cygwin");
|
2007-07-20 16:29:43 +02:00
|
|
|
SetLastError (0);
|
2011-04-01 10:41:26 +02:00
|
|
|
status = LsaRegisterLogonProcess (&name, &lsa_hdl, &sec_mode);
|
|
|
|
if (status != STATUS_SUCCESS)
|
2007-07-20 16:29:43 +02:00
|
|
|
{
|
2013-04-23 11:44:36 +02:00
|
|
|
debug_printf ("LsaRegisterLogonProcess: %y", status);
|
Drop NT4 support.
* autoload.cc (DnsQuery_A): Fatal if not available.
(DnsRecordListFree): Ditto.
(DsGetDcNameW): Ditto.
(NetGetAnyDCName): Remove.
(NetGetDCName): Remove.
(EnumProcessModules): Fatal if not available.
(GetModuleFileNameExW): Ditto.
(GetModuleInformation): Ditto.
(GetProcessMemoryInfo): Ditto.
(QueryWorkingSet): Ditto.
(LsaRegisterLogonProcess): Ditto.
* fenv.cc (_feinitialise): Drop supports_sse condition.
* fhandler_disk_file.cc (path_conv::isgood_inode): Fix comment.
(fhandler_base::fstat_by_name): Drop has_fileid_dirinfo condition.
(fhandler_disk_file::opendir): Ditto.
* fhandler_netdrive.cc (fhandler_netdrive::readdir): Fix comment.
* fhandler_proc.cc (format_proc_partitions): Drop NT4-only code.
* fhandler_process.cc (get_process_state): Ditto.
* kernel32.cc (GetWindowsDirectoryW): Remove.
(GetWindowsDirectoryA): Remove.
* miscfuncs.cc (nice_to_winprio): Drop NT4-only code.
* mount.cc (fs_info::update): Fix comments.
* net.cc (get_2k_ifs): Drop NT4-only code.
* sec_auth.cc (get_logon_server): Ditto.
(lsaauth): Drop NT4-specific error handling.
* security.cc (alloc_sd): Set SE_DACL_PROTECTED unconditionally.
* select.cc (select_stuff::wait): Always use MWMO_INPUTAVAILABLE.
(peek_windows): Drop NT4-only condition in call to PeekMessage.
* syscalls.cc (gethostid): Remove NT4-only workaround.
* wincap.cc: Througout, drop has_dacl_protect,
has_broken_if_oper_status, has_process_io_counters,
has_terminal_services, has_extended_priority_class, has_guid_volumes,
has_fileid_dirinfo, has_mwmo_inputavailable and supports_sse from
wincaps.
(wincap_nt4sp4): Remove.
(wincap_minimal): Set to wincap_2000.
(wincapc::init): Rely on availability of OSVERSIONINFOEX structure.
Treat error from GetVersionEx as fatal. Treat NT4 as fatal.
* wincap.h (struct wincaps): Drop has_dacl_protect,
has_broken_if_oper_status, has_process_io_counters,
has_terminal_services, has_extended_priority_class, has_guid_volumes,
has_fileid_dirinfo, has_mwmo_inputavailable and supports_sse flags
and methods.
* winlean.h (GetWindowsDirectoryW) Define as GetSystemWindowsDirectoryW.
(GetWindowsDirectoryA): Define as GetSystemWindowsDirectoryA.
2011-04-04 14:23:36 +02:00
|
|
|
__seterrno_from_nt_status (status);
|
2007-07-20 16:29:43 +02:00
|
|
|
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. */
|
2014-12-02 11:04:53 +01:00
|
|
|
RtlInitAnsiString (&name, CYG_LSA_PKGNAME);
|
2011-04-01 10:41:26 +02:00
|
|
|
status = LsaLookupAuthenticationPackage (lsa_hdl, &name, &package_id);
|
|
|
|
if (status != STATUS_SUCCESS)
|
2007-07-20 16:29:43 +02:00
|
|
|
{
|
2013-04-23 11:44:36 +02:00
|
|
|
debug_printf ("LsaLookupAuthenticationPackage: %y", status);
|
2011-04-01 10:41:26 +02:00
|
|
|
__seterrno_from_nt_status (status);
|
2007-07-20 16:29:43 +02:00
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Open policy object. */
|
2014-01-23 18:02:30 +01:00
|
|
|
if (!(lsa = lsa_open_policy (NULL, POLICY_EXECUTE)))
|
2007-07-20 16:29:43 +02:00
|
|
|
goto out;
|
|
|
|
|
|
|
|
/* Create origin. */
|
2014-12-02 11:04:53 +01:00
|
|
|
stpcpy (origin.buf, "Cygwin");
|
|
|
|
RtlInitAnsiString (&origin.str, origin.buf);
|
2007-07-20 16:29:43 +02:00
|
|
|
/* 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 ())
|
2015-03-18 16:54:19 +01:00
|
|
|
get_setgroups_sidlist (tmp_gsids, usersid, NULL, new_groups, auth_luid,
|
2007-07-20 16:29:43 +02:00
|
|
|
auth_pos);
|
2015-03-18 16:54:19 +01:00
|
|
|
else if (!get_initgroups_sidlist (tmp_gsids, usersid, new_groups.pgsid,
|
2007-07-20 16:29:43 +02:00
|
|
|
NULL, auth_luid, auth_pos))
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
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)
|
2011-04-28 10:34:49 +02:00
|
|
|
gsize += RtlLengthSid (tmp_gsids.sids[tmpidx]);
|
2007-07-20 16:29:43 +02:00
|
|
|
|
2011-10-15 18:31:57 +02:00
|
|
|
/* Retrieve list of privileges of that user. The MIC SID is created by
|
|
|
|
the LSA here. */
|
|
|
|
if (!(privs = get_priv_list (lsa, usersid, tmp_gsids, psize, NULL)))
|
2007-07-20 16:29:43 +02:00
|
|
|
goto out;
|
|
|
|
|
|
|
|
/* Create DefaultDacl. */
|
|
|
|
dsize = sizeof (ACL) + 3 * sizeof (ACCESS_ALLOWED_ACE)
|
2011-04-28 10:34:49 +02:00
|
|
|
+ RtlLengthSid (usersid)
|
|
|
|
+ RtlLengthSid (well_known_admins_sid)
|
|
|
|
+ RtlLengthSid (well_known_system_sid);
|
2007-07-20 16:29:43 +02:00
|
|
|
dacl = (PACL) alloca (dsize);
|
2011-04-28 11:30:36 +02:00
|
|
|
if (!NT_SUCCESS (RtlCreateAcl (dacl, dsize, ACL_REVISION)))
|
2007-07-20 16:29:43 +02:00
|
|
|
goto out;
|
2011-04-29 12:38:12 +02:00
|
|
|
if (!NT_SUCCESS (RtlAddAccessAllowedAce (dacl, ACL_REVISION, GENERIC_ALL,
|
|
|
|
usersid)))
|
2007-07-20 16:29:43 +02:00
|
|
|
goto out;
|
2011-04-29 12:38:12 +02:00
|
|
|
if (!NT_SUCCESS (RtlAddAccessAllowedAce (dacl, ACL_REVISION, GENERIC_ALL,
|
|
|
|
well_known_admins_sid)))
|
2007-07-20 16:29:43 +02:00
|
|
|
goto out;
|
2011-04-29 12:38:12 +02:00
|
|
|
if (!NT_SUCCESS (RtlAddAccessAllowedAce (dacl, ACL_REVISION, GENERIC_ALL,
|
|
|
|
well_known_system_sid)))
|
2007-07-20 16:29:43 +02:00
|
|
|
goto out;
|
|
|
|
|
|
|
|
/* Evaluate authinf size and allocate authinf. */
|
|
|
|
authinf_size = (authinf->data - (PBYTE) authinf);
|
2011-04-28 10:34:49 +02:00
|
|
|
authinf_size += RtlLengthSid (usersid); /* User SID */
|
2007-07-20 16:29:43 +02:00
|
|
|
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
|
2008-07-10 20:01:25 +02:00
|
|
|
we define "Local" as primary group here. Seteuid32 sets the primary
|
|
|
|
group to the group set in /etc/passwd anyway. */
|
|
|
|
if (new_groups.pgsid == well_known_admins_sid)
|
|
|
|
pgrpsid = well_known_local_sid;
|
|
|
|
else
|
|
|
|
pgrpsid = new_groups.pgsid;
|
|
|
|
|
2011-04-28 10:34:49 +02:00
|
|
|
authinf_size += RtlLengthSid (pgrpsid); /* Primary Group SID */
|
2007-07-20 16:29:43 +02:00
|
|
|
|
|
|
|
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;
|
|
|
|
|
2008-07-11 12:00:36 +02:00
|
|
|
if (!LookupAccountSidW (NULL, usersid, authinf->username, &ulen,
|
|
|
|
authinf->domain, &dlen, &use))
|
|
|
|
{
|
|
|
|
__seterrno ();
|
|
|
|
goto out;
|
|
|
|
}
|
2007-07-20 16:29:43 +02:00
|
|
|
|
|
|
|
/* 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;
|
2011-04-29 12:38:12 +02:00
|
|
|
RtlCopySid (RtlLengthSid (usersid), (PSID) ((PBYTE) &authinf->inf + offset),
|
|
|
|
usersid);
|
2011-04-28 10:34:49 +02:00
|
|
|
offset += RtlLengthSid (usersid);
|
2007-07-20 16:29:43 +02:00
|
|
|
/* 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;
|
2011-04-29 12:38:12 +02:00
|
|
|
RtlCopySid (RtlLengthSid (tmp_gsids.sids[tmpidx]),
|
|
|
|
(PSID) ((PBYTE) &authinf->inf + sids_offset),
|
|
|
|
tmp_gsids.sids[tmpidx]);
|
2011-04-28 10:34:49 +02:00
|
|
|
sids_offset += RtlLengthSid (tmp_gsids.sids[tmpidx]);
|
2007-07-20 16:29:43 +02:00
|
|
|
}
|
|
|
|
offset += gsize;
|
|
|
|
/* Primary Group SID */
|
|
|
|
authinf->inf.PrimaryGroup.PrimaryGroup = offset;
|
2011-04-29 12:38:12 +02:00
|
|
|
RtlCopySid (RtlLengthSid (pgrpsid), (PSID) ((PBYTE) &authinf->inf + offset),
|
|
|
|
pgrpsid);
|
2011-04-28 10:34:49 +02:00
|
|
|
offset += RtlLengthSid (pgrpsid);
|
2007-07-20 16:29:43 +02:00
|
|
|
/* 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);
|
|
|
|
|
2010-01-29 20:51:11 +01:00
|
|
|
authinf->checksum = CYG_LSA_MAGIC;
|
2008-09-11 06:34:24 +02:00
|
|
|
PDWORD csp;
|
|
|
|
PDWORD csp_end;
|
|
|
|
csp = (PDWORD) &authinf->username;
|
|
|
|
csp_end = (PDWORD) ((PBYTE) authinf + authinf_size);
|
2007-07-20 16:29:43 +02:00
|
|
|
while (csp < csp_end)
|
|
|
|
authinf->checksum += *csp++;
|
|
|
|
|
|
|
|
/* Try to logon... */
|
2011-04-01 10:41:26 +02:00
|
|
|
status = LsaLogonUser (lsa_hdl, (PLSA_STRING) &origin, Interactive,
|
|
|
|
package_id, authinf, authinf_size, NULL, &ts,
|
|
|
|
&profile, &size, &luid, &user_token, "a,
|
|
|
|
&sub_status);
|
|
|
|
if (status != STATUS_SUCCESS)
|
2007-07-20 16:29:43 +02:00
|
|
|
{
|
2013-04-23 11:44:36 +02:00
|
|
|
debug_printf ("LsaLogonUser: %y (sub-status %y)", status, sub_status);
|
2011-04-01 10:41:26 +02:00
|
|
|
__seterrno_from_nt_status (status);
|
2007-07-20 16:29:43 +02:00
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
if (profile)
|
2008-07-10 20:01:25 +02:00
|
|
|
{
|
|
|
|
#ifdef JUST_ANOTHER_NONWORKING_SOLUTION
|
|
|
|
/* See ../lsaauth/cyglsa.c. */
|
|
|
|
cygprf_t *prf = (cygprf_t *) profile;
|
|
|
|
if (prf->magic_pre == MAGIC_PRE && prf->magic_post == MAGIC_POST
|
|
|
|
&& prf->token)
|
|
|
|
{
|
|
|
|
CloseHandle (user_token);
|
|
|
|
user_token = prf->token;
|
|
|
|
system_printf ("Got token through profile: %p", user_token);
|
|
|
|
}
|
|
|
|
#endif /* JUST_ANOTHER_NONWORKING_SOLUTION */
|
|
|
|
LsaFreeReturnBuffer (profile);
|
|
|
|
}
|
2010-02-06 14:13:15 +01:00
|
|
|
user_token = get_full_privileged_inheritable_token (user_token);
|
2008-06-10 17:16:01 +02:00
|
|
|
|
2007-07-20 16:29:43 +02:00
|
|
|
out:
|
|
|
|
if (privs)
|
|
|
|
free (privs);
|
2014-01-23 18:02:30 +01:00
|
|
|
lsa_close_policy (lsa);
|
2007-07-20 16:29:43 +02:00
|
|
|
if (lsa_hdl)
|
|
|
|
LsaDeregisterLogonProcess (lsa_hdl);
|
|
|
|
pop_self_privilege ();
|
|
|
|
|
2008-07-11 12:00:36 +02:00
|
|
|
debug_printf ("%p = lsaauth ()", user_token);
|
2007-07-20 16:29:43 +02:00
|
|
|
return user_token;
|
|
|
|
}
|
2008-11-26 11:18:10 +01:00
|
|
|
|
|
|
|
#define SFU_LSA_KEY_SUFFIX L"_microsoft_sfu_utility"
|
|
|
|
|
|
|
|
HANDLE
|
|
|
|
lsaprivkeyauth (struct passwd *pw)
|
|
|
|
{
|
|
|
|
NTSTATUS status;
|
2014-03-28 21:34:04 +01:00
|
|
|
HANDLE lsa = NULL;
|
2008-11-26 11:18:10 +01:00
|
|
|
HANDLE token = NULL;
|
|
|
|
WCHAR sid[256];
|
|
|
|
WCHAR domain[MAX_DOMAIN_NAME_LEN + 1];
|
|
|
|
WCHAR user[UNLEN + 1];
|
|
|
|
WCHAR key_name[MAX_DOMAIN_NAME_LEN + UNLEN + wcslen (SFU_LSA_KEY_SUFFIX) + 2];
|
|
|
|
UNICODE_STRING key;
|
2014-05-20 12:21:34 +02:00
|
|
|
PUNICODE_STRING data = NULL;
|
2008-11-26 11:18:10 +01:00
|
|
|
cygsid psid;
|
2014-05-20 12:21:34 +02:00
|
|
|
BOOL ret;
|
2008-11-26 11:18:10 +01:00
|
|
|
|
|
|
|
push_self_privilege (SE_TCB_PRIVILEGE, true);
|
|
|
|
|
|
|
|
/* Open policy object. */
|
2014-01-23 18:02:30 +01:00
|
|
|
if (!(lsa = lsa_open_policy (NULL, POLICY_GET_PRIVATE_INFORMATION)))
|
2008-11-26 11:18:10 +01:00
|
|
|
goto out;
|
|
|
|
|
|
|
|
/* Needed for Interix key and LogonUser. */
|
|
|
|
extract_nt_dom_user (pw, domain, user);
|
|
|
|
|
|
|
|
/* First test for a Cygwin entry. */
|
|
|
|
if (psid.getfrompw (pw) && psid.string (sid))
|
|
|
|
{
|
|
|
|
wcpcpy (wcpcpy (key_name, CYGWIN_LSA_KEY_PREFIX), sid);
|
|
|
|
RtlInitUnicodeString (&key, key_name);
|
|
|
|
status = LsaRetrievePrivateData (lsa, &key, &data);
|
|
|
|
if (!NT_SUCCESS (status))
|
2014-05-20 12:21:34 +02:00
|
|
|
data = NULL;
|
2008-11-26 11:18:10 +01:00
|
|
|
}
|
2014-05-20 12:21:34 +02:00
|
|
|
/* No Cygwin key, try Interix key. */
|
|
|
|
if (!data && *domain)
|
2008-11-26 11:18:10 +01:00
|
|
|
{
|
2014-05-20 12:21:34 +02:00
|
|
|
__small_swprintf (key_name, L"%W_%W%W",
|
|
|
|
domain, user, SFU_LSA_KEY_SUFFIX);
|
|
|
|
RtlInitUnicodeString (&key, key_name);
|
|
|
|
status = LsaRetrievePrivateData (lsa, &key, &data);
|
|
|
|
if (!NT_SUCCESS (status))
|
|
|
|
data = NULL;
|
2008-11-26 11:18:10 +01:00
|
|
|
}
|
2014-05-20 12:21:34 +02:00
|
|
|
/* Found an entry? Try to logon. */
|
|
|
|
if (data)
|
|
|
|
{
|
|
|
|
/* The key is not 0-terminated. */
|
|
|
|
PWCHAR passwd;
|
|
|
|
size_t pwdsize = data->Length + sizeof (WCHAR);
|
|
|
|
|
|
|
|
passwd = (PWCHAR) alloca (pwdsize);
|
|
|
|
*wcpncpy (passwd, data->Buffer, data->Length / sizeof (WCHAR)) = L'\0';
|
|
|
|
/* Weird: LsaFreeMemory invalidates the content of the UNICODE_STRING
|
|
|
|
structure, but it does not invalidate the Buffer content. */
|
|
|
|
RtlSecureZeroMemory (data->Buffer, data->Length);
|
|
|
|
LsaFreeMemory (data);
|
|
|
|
debug_printf ("Try logon for %W\\%W", domain, user);
|
|
|
|
ret = LogonUserW (user, domain, passwd, LOGON32_LOGON_INTERACTIVE,
|
|
|
|
LOGON32_PROVIDER_DEFAULT, &token);
|
|
|
|
RtlSecureZeroMemory (passwd, pwdsize);
|
|
|
|
if (!ret)
|
|
|
|
{
|
|
|
|
__seterrno ();
|
|
|
|
token = NULL;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
token = get_full_privileged_inheritable_token (token);
|
|
|
|
}
|
|
|
|
lsa_close_policy (lsa);
|
2008-11-26 11:18:10 +01:00
|
|
|
|
|
|
|
out:
|
|
|
|
pop_self_privilege ();
|
|
|
|
return token;
|
|
|
|
}
|