+Mon Apr 30 22:09:00 2001 Corinna Vinschen <corinna@vinschen.de>
+
+ * autoload.cc: Add LoadDLLinitfunc for secur32.dll.
+ Add LoadDLLfuncEx statements for AllocateLocallyUniqueId@4,
+ DuplicateTokenEx@24, LsaNtStatusToWinError@4,
+ LsaDeregisterLogonProcess@4, LsaFreeReturnBuffer@4,
+ LsaLogonUser@56, LsaLookupAuthenticationPackage@12,
+ LsaRegisterLogonProcess@12,
+ * environ.cc: Add extern declaration for `subauth_id'.
+ (subauth_id_init): New function for setting `subauth_id'.
+ (struct parse_thing): Add entry for `subauth_id'.
+ * fork.cc (fork_parent): Call `RevertToSelf' and
+ `ImpersonateLoggedOnUser' instead of `seteuid'.
+ * security.cc: Define global variable `subauth_id'.
+ (extract_nt_dom_user): New function.
+ (cygwin_logon_user): Call `extract_nt_dom_user' now.
+ (str2lsa): New static function.
+ (str2buf2lsa): Ditto.
+ (str2buf2uni): Ditto.
+ (subauth): Ditto.
+ * security.h: Add prototype for `subauth'.
+ * spawn.cc (spawn_guts): Use cygheap->user.token only if impersonated.
+ Use `cygsid' type. Remove impersonation before allowing access to
+ workstation/desktop to everyone. Call `RevertToSelf' and
+ `ImpersonateLoggedOnUser' instead of `seteuid'.
+ * syscalls.cc (seteuid): Rearranged to allow using subauthentication
+ to retrieve user tokens when needed.
+
Mon Apr 30 20:26:00 2001 Corinna Vinschen <corinna@vinschen.de>
* uinfo.cc (internal_getlogin): Formatting change.
return 0;
}
+LoadDLLinitfunc (secur32)
+{
+ HANDLE h;
+ static NO_COPY LONG here = -1L;
+
+ while (InterlockedIncrement (&here))
+ {
+ InterlockedDecrement (&here);
+ Sleep (0);
+ }
+
+ if (secur32_handle)
+ /* nothing to do */;
+ else if ((h = LoadLibrary ("secur32.dll")) != NULL)
+ secur32_handle = h;
+ else if (!secur32_handle)
+ api_fatal ("could not load secur32.dll, %E");
+
+ InterlockedDecrement (&here);
+ return 0; /* Already done by another thread? */
+}
+
LoadDLLinitfunc (user32)
{
HANDLE h;
LoadDLLfunc (AddAccessDeniedAce, 16, advapi32)
LoadDLLfunc (AddAce, 20, advapi32)
LoadDLLfunc (AdjustTokenPrivileges, 24, advapi32)
+LoadDLLfuncEx (AllocateLocallyUniqueId, 4, advapi32, 1)
LoadDLLfunc (CopySid, 12, advapi32)
LoadDLLfunc (CreateProcessAsUserA, 44, advapi32)
LoadDLLfuncEx (CryptAcquireContextA, 20, advapi32, 1)
LoadDLLfuncEx (CryptGenRandom, 12, advapi32, 1)
LoadDLLfuncEx (CryptReleaseContext, 8, advapi32, 1)
LoadDLLfunc (DeregisterEventSource, 4, advapi32)
+LoadDLLfuncEx (DuplicateTokenEx, 24, advapi32, 1)
LoadDLLfunc (EqualSid, 8, advapi32)
LoadDLLfunc (GetAce, 12, advapi32)
LoadDLLfunc (GetFileSecurityA, 20, advapi32)
LoadDLLfunc (LookupAccountNameA, 28, advapi32)
LoadDLLfunc (LookupAccountSidA, 28, advapi32)
LoadDLLfunc (LookupPrivilegeValueA, 12, advapi32)
+LoadDLLfuncEx (LsaNtStatusToWinError, 4, advapi32, 1)
LoadDLLfunc (MakeSelfRelativeSD, 12, advapi32)
LoadDLLfunc (OpenProcessToken, 12, advapi32)
LoadDLLfunc (RegCloseKey, 4, advapi32)
LoadDLLfuncEx (RtlNtStatusToDosError, 4, ntdll, 1)
LoadDLLfuncEx (ZwQuerySystemInformation, 16, ntdll, 1)
+LoadDLLinit (secur32)
+LoadDLLfuncEx (LsaDeregisterLogonProcess, 4, secur32, 1)
+LoadDLLfuncEx (LsaFreeReturnBuffer, 4, secur32, 1)
+LoadDLLfuncEx (LsaLogonUser, 56, secur32, 1)
+LoadDLLfuncEx (LsaLookupAuthenticationPackage, 12, secur32, 1)
+LoadDLLfuncEx (LsaRegisterLogonProcess, 12, secur32, 1)
+
LoadDLLinit (user32)
LoadDLLfunc (CharToOemA, 8, user32)
LoadDLLfunc (CharToOemBuffA, 12, user32)
extern BOOL strip_title_path;
extern int pcheck_case;
extern DWORD chunksize;
+extern int subauth_id;
BOOL reset_com = TRUE;
static BOOL envcache = TRUE;
}
}
+static void
+subauth_id_init (const char *buf)
+{
+ if (!buf || !*buf)
+ return;
+
+ int i = strtol (buf, NULL, 0);
+
+ /* 0..127 are reserved by Microsoft, 132 is IIS subauthentication. */
+ if (i > 127 && i != 132 && i <= 255)
+ subauth_id = i;
+}
+
/* The structure below is used to set up an array which is used to
parse the CYGWIN environment variable or, if enabled, options from
the registry. */
{"smbntsec", {&allow_smbntsec}, justset, NULL, {{FALSE}, {TRUE}}},
{"reset_com", {&reset_com}, justset, NULL, {{FALSE}, {TRUE}}},
{"strip_title", {&strip_title_path}, justset, NULL, {{FALSE}, {TRUE}}},
+ {"subauth_id", {func: &subauth_id_init}, isfunc, NULL, {{0}, {0}}},
{"title", {&display_title}, justset, NULL, {{FALSE}, {TRUE}}},
{"tty", {NULL}, set_process_state, NULL, {{0}, {PID_USETTY}}},
{"winsymlinks", {&allow_winsymlinks}, justset, NULL, {{FALSE}, {TRUE}}},
uid_t uid;
uid = geteuid();
if (cygheap->user.impersonated && cygheap->user.token != INVALID_HANDLE_VALUE)
- seteuid (cygheap->user.orig_uid);
+ RevertToSelf ();
ch.parent = hParent;
ch.cygheap = cygheap;
/* Restore impersonation */
if (cygheap->user.impersonated
&& cygheap->user.token != INVALID_HANDLE_VALUE)
- seteuid (uid);
+ ImpersonateLoggedOnUser (cygheap->user.token);
return -1;
}
/* Restore impersonation */
if (cygheap->user.impersonated && cygheap->user.token != INVALID_HANDLE_VALUE)
- seteuid (uid);
+ ImpersonateLoggedOnUser (cygheap->user.token);
ProtectHandle (pi.hThread);
/* Protect the handle but name it similarly to the way it will
#include <ctype.h>
#include <wingdi.h>
#include <winuser.h>
+#include <wininet.h>
+#include <ntsecapi.h>
+#include <subauth.h>
#include "cygerrno.h"
#include "perprocess.h"
#include "fhandler.h"
}
}
+static void
+extract_nt_dom_user (const struct passwd *pw, char *domain, char *user)
+{
+ char buf[INTERNET_MAX_HOST_NAME_LENGTH + UNLEN + 2];
+ char *c;
+
+ strcpy (domain, "");
+ strcpy (buf, pw->pw_name);
+ debug_printf ("pw_gecos = %x (%s)", pw->pw_gecos, pw->pw_gecos);
+ if (pw->pw_gecos)
+ {
+ if ((c = strstr (pw->pw_gecos, "U-")) != NULL &&
+ (c == pw->pw_gecos || c[-1] == ','))
+ {
+ buf[0] = '\0';
+ strncat (buf, c + 2, INTERNET_MAX_HOST_NAME_LENGTH + UNLEN + 1);
+ if ((c = strchr (buf, ',')) != NULL)
+ *c = '\0';
+ }
+ }
+ if ((c = strchr (buf, '\\')) != NULL)
+ {
+ *c++ = '\0';
+ strcpy (domain, buf);
+ strcpy (user, c);
+ }
+ else
+ {
+ strcpy (domain, "");
+ strcpy (user, buf);
+ }
+}
+
extern "C"
HANDLE
cygwin_logon_user (const struct passwd *pw, const char *password)
return INVALID_HANDLE_VALUE;
}
- char *c, *nt_user, *nt_domain = NULL;
- char usernamebuf[256];
+ char nt_domain[INTERNET_MAX_HOST_NAME_LENGTH + 1];
+ char nt_user[UNLEN + 1];
HANDLE hToken;
- strcpy (usernamebuf, pw->pw_name);
- debug_printf ("pw_gecos = %x (%s)", pw->pw_gecos, pw->pw_gecos);
- if (pw->pw_gecos)
- {
- if ((c = strstr (pw->pw_gecos, "U-")) != NULL &&
- (c == pw->pw_gecos || c[-1] == ','))
- {
- usernamebuf[0] = '\0';
- strncat (usernamebuf, c + 2, 255);
- if ((c = strchr (usernamebuf, ',')) != NULL)
- *c = '\0';
- }
- }
- nt_user = usernamebuf;
- if ((c = strchr (nt_user, '\\')) != NULL)
- {
- nt_domain = nt_user;
- *c = '\0';
- nt_user = c + 1;
- }
+ extract_nt_dom_user (pw, nt_domain, nt_user);
debug_printf ("LogonUserA (%s, %s, %s, ...)", nt_user, nt_domain, password);
- if (!LogonUserA (nt_user, nt_domain, (char *) password,
+ if (!LogonUserA (nt_user, *nt_domain ? nt_domain : NULL, (char *) password,
LOGON32_LOGON_INTERACTIVE,
LOGON32_PROVIDER_DEFAULT,
&hToken)
return hToken;
}
+static void
+str2lsa (LSA_STRING &tgt, const char *srcstr)
+{
+ tgt.Length = strlen(srcstr);
+ tgt.MaximumLength = tgt.Length + 1;
+ tgt.Buffer = (PCHAR) srcstr;
+}
+
+static void
+str2buf2lsa (LSA_STRING &tgt, char *buf, const char *srcstr)
+{
+ tgt.Length = strlen(srcstr);
+ tgt.MaximumLength = tgt.Length + 1;
+ tgt.Buffer = (PCHAR) buf;
+ memcpy(buf, srcstr, tgt.MaximumLength);
+}
+
+static void
+str2buf2uni (UNICODE_STRING &tgt, WCHAR *buf, const char *srcstr)
+{
+ tgt.Length = strlen(srcstr) * sizeof (WCHAR);
+ tgt.MaximumLength = tgt.Length + sizeof(WCHAR);
+ tgt.Buffer = (PWCHAR) buf;
+ mbstowcs (buf, srcstr, tgt.MaximumLength);
+}
+
+int subauth_id = 255;
+
+HANDLE
+subauth (struct passwd *pw)
+{
+ LSA_STRING name;
+ HANDLE lsa_hdl;
+ LSA_OPERATIONAL_MODE sec_mode;
+ NTSTATUS ret, ret2;
+ ULONG package_id, size;
+ struct {
+ LSA_STRING str;
+ CHAR buf[16];
+ } origin;
+ struct {
+ MSV1_0_LM20_LOGON auth;
+ WCHAR dombuf[INTERNET_MAX_HOST_NAME_LENGTH + 1];
+ WCHAR usrbuf[UNLEN + 1];
+ WCHAR wkstbuf[1];
+ CHAR authinf1[1];
+ CHAR authinf2[1];
+ } subbuf;
+ 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];
+
+ set_process_privilege(SE_TCB_NAME);
+
+ /* Register as logon process. */
+ str2lsa (name, "Cygwin");
+ ret = LsaRegisterLogonProcess(&name, &lsa_hdl, &sec_mode);
+ if (ret != STATUS_SUCCESS)
+ {
+ debug_printf ("LsaRegisterLogonProcess: %d", ret);
+ set_errno (LsaNtStatusToWinError(ret));
+ return INVALID_HANDLE_VALUE;
+ }
+ /* Get handle to MSV1_0 package. */
+ str2lsa (name, MSV1_0_PACKAGE_NAME);
+ ret = LsaLookupAuthenticationPackage(lsa_hdl, &name, &package_id);
+ if (ret != STATUS_SUCCESS)
+ {
+ debug_printf ("LsaLookupAuthenticationPackage: %d", ret);
+ set_errno (LsaNtStatusToWinError(ret));
+ LsaDeregisterLogonProcess(lsa_hdl);
+ return INVALID_HANDLE_VALUE;
+ }
+ /* Create origin. */
+ str2buf2lsa (origin.str, origin.buf, "Cygwin");
+ /* Create token source. */
+ memcpy(ts.SourceName, "Cygwin.1", 8);
+ AllocateLocallyUniqueId(&ts.SourceIdentifier);
+ /* Get user information. */
+ extract_nt_dom_user (pw, nt_domain, nt_user);
+ /* Fill subauth with values. */
+ subbuf.auth.MessageType = MsV1_0NetworkLogon;
+ str2buf2uni(subbuf.auth.LogonDomainName, subbuf.dombuf, nt_domain);
+ str2buf2uni(subbuf.auth.UserName, subbuf.usrbuf, nt_user);
+ str2buf2uni(subbuf.auth.Workstation, subbuf.wkstbuf, "");
+ memcpy(subbuf.auth.ChallengeToClient, "12345678", MSV1_0_CHALLENGE_LENGTH);
+ str2buf2lsa(subbuf.auth.CaseSensitiveChallengeResponse, subbuf.authinf1, "");
+ str2buf2lsa(subbuf.auth.CaseInsensitiveChallengeResponse, subbuf.authinf2,"");
+ subbuf.auth.ParameterControl = 0 | (subauth_id << 24);
+ /* Try to logon... */
+ ret = LsaLogonUser(lsa_hdl, (PLSA_STRING) &origin, Network,
+ package_id, &subbuf, sizeof subbuf,
+ NULL, &ts, (PVOID *)&profile, &size,
+ &luid, &user_token, "a, &ret2);
+ if (ret != STATUS_SUCCESS)
+ {
+ debug_printf ("LsaLogonUser: %d", ret);
+ set_errno (LsaNtStatusToWinError(ret));
+ LsaDeregisterLogonProcess(lsa_hdl);
+ return INVALID_HANDLE_VALUE;
+ }
+ 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);
+ return primary_token;
+}
+
/* read_sd reads a security descriptor from a file.
In case of error, -1 is returned and errno is set.
If sd_buf is too small, 0 is returned and sd_size
BOOL __stdcall add_access_allowed_ace (PACL acl, int offset, DWORD attributes, PSID sid, size_t &len_add, DWORD inherit);
BOOL __stdcall add_access_denied_ace (PACL acl, int offset, DWORD attributes, PSID sid, size_t &len_add, DWORD inherit);
+/* Try a subauthentication. */
+HANDLE subauth (struct passwd *pw);
/* sec_helper.cc: Security helper functions. */
char *__stdcall convert_sid_to_string_sid (PSID psid, char *sid_str);
/* Preallocated buffer for `sec_user' call */
char sa_buf[1024];
- if (!hToken && cygheap->user.token != INVALID_HANDLE_VALUE)
+ if (!hToken && cygheap->user.impersonated
+ && cygheap->user.token != INVALID_HANDLE_VALUE)
hToken = cygheap->user.token;
const char *runpath = null_app_name ? NULL : (const char *) real_path;
}
else
{
+ cygsid sid;
+ DWORD ret_len;
+ if (!GetTokenInformation (hToken, TokenUser, &sid, sizeof sid, &ret_len))
+ {
+ sid = NULL;
+ system_printf ("GetTokenInformation: %E");
+ }
+
+ /* Retrieve security attributes before setting psid to NULL
+ since it's value is needed by `sec_user'. */
+ PSECURITY_ATTRIBUTES sec_attribs = allow_ntsec && sid
+ ? sec_user (sa_buf, sid)
+ : &sec_all_nih;
+
+ /* Remove impersonation */
+ if (cygheap->user.impersonated
+ && cygheap->user.token != INVALID_HANDLE_VALUE)
+ RevertToSelf ();
+
+ /* Load users registry hive. */
+ load_registry_hive (sid);
+
/* allow the child to interact with our window station/desktop */
HANDLE hwst, hdsk;
SECURITY_INFORMATION dsi = DACL_SECURITY_INFORMATION;
strcat (wstname, dskname);
si.lpDesktop = wstname;
- char tu[1024];
- PSID sid = NULL;
- DWORD ret_len;
- if (GetTokenInformation (hToken, TokenUser,
- (LPVOID) &tu, sizeof tu,
- &ret_len))
- sid = ((TOKEN_USER *) &tu)->User.Sid;
- else
- system_printf ("GetTokenInformation: %E");
-
- /* Retrieve security attributes before setting psid to NULL
- since it's value is needed by `sec_user'. */
- PSECURITY_ATTRIBUTES sec_attribs = allow_ntsec && sid
- ? sec_user (sa_buf, sid)
- : &sec_all_nih;
-
- /* Remove impersonation */
- uid_t uid = geteuid ();
- if (cygheap->user.impersonated
- && cygheap->user.token != INVALID_HANDLE_VALUE)
- seteuid (cygheap->user.orig_uid);
-
- /* Load users registry hive. */
- load_registry_hive (sid);
-
rc = CreateProcessAsUser (hToken,
runpath, /* image name - with full path */
one_line.buf, /* what was passed to exec */
if (mode != _P_OVERLAY && mode != _P_VFORK
&& cygheap->user.impersonated
&& cygheap->user.token != INVALID_HANDLE_VALUE)
- seteuid (uid);
+ ImpersonateLoggedOnUser (cygheap->user.token);
}
MALLOC_CHECK;
}
if (uid != myself->uid)
- 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 if (!cygheap->user.impersonated)
- {
- debug_printf ("Impersonate (uid == %d)", uid);
- RevertToSelf ();
- if (cygheap->user.token != INVALID_HANDLE_VALUE)
- {
- struct group *gr;
- cygsid sid;
- DWORD siz;
-
- /* Try setting owner to same value as user. */
- if (!GetTokenInformation (cygheap->user.token, TokenUser,
- &sid, sizeof sid, &siz))
- debug_printf ("GetTokenInformation(): %E");
- else if (!SetTokenInformation (cygheap->user.token,
- TokenOwner,
- &sid, sizeof sid))
- debug_printf ("SetTokenInformation(user.token, "
- "TokenOwner): %E");
- /* Try setting primary group in token to current group. */
- if ((gr = getgrgid (myself->gid)) &&
- get_gr_sid (sid, gr) &&
- !SetTokenInformation (cygheap->user.token,
- TokenPrimaryGroup,
- &sid, sizeof sid))
- debug_printf ("SetTokenInformation(user.token, "
- "TokenPrimaryGroup): %E");
-
- /* Now try to impersonate. */
- if (!ImpersonateLoggedOnUser (cygheap->user.token))
- system_printf ("Impersonate (%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;
+ 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 tsid, psid, gsid;
+ DWORD siz;
+
+ /* Check if new user == user of impersonation token. */
+ if (cygheap->user.token != INVALID_HANDLE_VALUE)
+ {
+ if (!GetTokenInformation (cygheap->user.token, TokenUser,
+ &tsid, sizeof tsid, &siz))
+ debug_printf ("GetTokenInformation(): %E");
+ else if (get_pw_sid (psid, pw_new) && tsid != psid)
+ {
+ /* If not, RevertToSelf and close old token. */
+ RevertToSelf ();
+ cygwin_set_impersonation_token (INVALID_HANDLE_VALUE);
+ }
+ }
+ /* 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.impersonated)
+ {
+ debug_printf ("Impersonate (uid == %d)", uid);
+ RevertToSelf ();
+ if (cygheap->user.token != INVALID_HANDLE_VALUE)
+ {
+ 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)) &&
+ get_gr_sid (gsid, gr) &&
+ !SetTokenInformation (cygheap->user.token,
+ TokenPrimaryGroup,
+ &gsid, sizeof gsid))
+ debug_printf ("SetTokenInformation(user.token, "
+ "TokenPrimaryGroup): %E");
+
+ /* 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;
}
- myself->uid = uid;
- cygheap->user = user;
}
}
else