diff options
Diffstat (limited to 'winsup/cygwin/security.cc')
-rw-r--r-- | winsup/cygwin/security.cc | 1628 |
1 files changed, 0 insertions, 1628 deletions
diff --git a/winsup/cygwin/security.cc b/winsup/cygwin/security.cc deleted file mode 100644 index cf30386e8..000000000 --- a/winsup/cygwin/security.cc +++ /dev/null @@ -1,1628 +0,0 @@ -/* security.cc: NT security functions - - Copyright 1997, 1998, 1999, 2000, 2001 Red Hat, Inc. - - Originaly written by Gunther Ebert, gunther.ebert@ixos-leipzig.de - Completely rewritten by Corinna Vinschen <corinna@vinschen.de> - -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 <grp.h> -#include <pwd.h> -#include <unistd.h> -#include <stdlib.h> -#include <errno.h> -#include <limits.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <sys/acl.h> -#include <ctype.h> -#include <winnls.h> -#include <wingdi.h> -#include <winuser.h> -#include <wininet.h> -#include <ntsecapi.h> -#include <subauth.h> -#include "cygerrno.h" -#include "perprocess.h" -#include "security.h" -#include "fhandler.h" -#include "path.h" -#include "dtable.h" -#include "sync.h" -#include "sigproc.h" -#include "pinfo.h" -#include "cygheap.h" -#include <ntdef.h> -#include "ntdll.h" -#include "lm.h" - - -extern BOOL allow_ntea; -BOOL allow_ntsec; -/* allow_smbntsec is handled exclusively in path.cc (path_conv::check). - It's defined here because of it's strong relationship to allow_ntsec. - The default is TRUE to reflect the old behaviour. */ -BOOL allow_smbntsec = TRUE; - -extern "C" -void -cygwin_set_impersonation_token (const HANDLE hToken) -{ - debug_printf ("set_impersonation_token (%d)", hToken); - if (cygheap->user.token != hToken) - { - cygheap->user.token = hToken; - cygheap->user.impersonated = FALSE; - } -} - -void -extract_nt_dom_user (const struct passwd *pw, char *domain, char *user) -{ - cygsid psid; - DWORD ulen = UNLEN + 1; - DWORD dlen = INTERNET_MAX_HOST_NAME_LENGTH + 1; - SID_NAME_USE use; - 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 (psid.getfrompw (pw) && - LookupAccountSid (NULL, psid, user, &ulen, domain, &dlen, &use)) - return; - - 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) -{ - if (!wincap.has_security ()) - { - set_errno (ENOSYS); - return INVALID_HANDLE_VALUE; - } - if (!pw) - { - set_errno (EINVAL); - return INVALID_HANDLE_VALUE; - } - - char nt_domain[INTERNET_MAX_HOST_NAME_LENGTH + 1]; - char nt_user[UNLEN + 1]; - HANDLE hToken; - - extract_nt_dom_user (pw, nt_domain, nt_user); - debug_printf ("LogonUserA (%s, %s, %s, ...)", nt_user, nt_domain, password); - if (!LogonUserA (nt_user, *nt_domain ? nt_domain : NULL, (char *) password, - LOGON32_LOGON_INTERACTIVE, - LOGON32_PROVIDER_DEFAULT, - &hToken) - || !SetHandleInformation (hToken, - HANDLE_FLAG_INHERIT, - HANDLE_FLAG_INHERIT)) - { - __seterrno (); - return INVALID_HANDLE_VALUE; - } - debug_printf ("%d = logon_user(%s,...)", hToken, pw->pw_name); - return hToken; -} - -static void -str2lsa (LSA_STRING &tgt, const char *srcstr) -{ - tgt.Length = strlen (srcstr); - tgt.MaximumLength = tgt.Length + 1; - tgt.Buffer = (PCHAR) srcstr; -} - -static void -str2buf2lsa (LSA_STRING &tgt, char *buf, const char *srcstr) -{ - tgt.Length = strlen (srcstr); - tgt.MaximumLength = tgt.Length + 1; - tgt.Buffer = (PCHAR) buf; - memcpy(buf, srcstr, tgt.MaximumLength); -} - -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; - sys_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) - { - sys_wcstombs (name, buf[0].sv101_name, INTERNET_MAX_HOST_NAME_LENGTH + 1); - if (domain) - sys_wcstombs (domain, primary, INTERNET_MAX_HOST_NAME_LENGTH + 1); - } - else - { - sys_wcstombs (name, account, INTERNET_MAX_HOST_NAME_LENGTH + 1); - if (domain) - sys_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]; - sys_mbstowcs (wuser, user, UNLEN + 1); - LPGROUP_USERS_INFO_0 buf; - DWORD cnt, tot; - NET_API_STATUS ret; - - ret = NetUserGetGroups (wlogonserver, wuser, 0, (LPBYTE *) &buf, - MAX_PREFERRED_LENGTH, &cnt, &tot); - if (ret == ERROR_BAD_NETPATH || ret == RPC_S_SERVER_UNAVAILABLE) - ret = NetUserGetGroups (NULL, wuser, 0, (LPBYTE *) &buf, - MAX_PREFERRED_LENGTH, &cnt, &tot); - if (ret) - { - 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; - - sys_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), "\\"); - sys_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; - NET_API_STATUS ret; - BOOL retval = FALSE; - - ret = NetLocalGroupGetMembers (NULL, wgroup, 0, (LPBYTE *) &buf, - MAX_PREFERRED_LENGTH, &cnt, &tot, NULL); - if (ret) - return FALSE; - - for (DWORD bidx = 0; !retval && bidx < cnt; ++bidx) - if (EqualSid (usersid, buf[bidx].lgrmi0_sid)) - retval = TRUE; - else - for (int glidx = 0; !retval && glidx < grp_list.count; ++glidx) - if (EqualSid (grp_list.sids[glidx], buf[bidx].lgrmi0_sid)) - retval = TRUE; - - NetApiBufferFree (buf); - return retval; -} - -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; - - ret = NetLocalGroupEnum (NULL, 0, (LPBYTE *) &buf, - MAX_PREFERRED_LENGTH, &cnt, &tot, NULL); - if (ret) - { - 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; - - sys_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), "\\"); - sys_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]; - NET_API_STATUS ret; - BOOL retval = FALSE; - UCHAR count = 0; - - if (usersid == well_known_system_sid) - { - pgrpsid = well_known_system_sid; - return TRUE; - } - - sys_mbstowcs (wuser, user, UNLEN + 1); - ret = NetUserGetInfo (wlogonserver, wuser, 3, (LPBYTE *) &buf); - if (ret == ERROR_BAD_NETPATH || ret == RPC_S_SERVER_UNAVAILABLE) - ret = NetUserGetInfo (NULL, wuser, 3, (LPBYTE *) &buf); - if (ret) - { - debug_printf ("%d = NetUserGetInfo ()", ret); - set_errno (ret); - return FALSE; - } - - pgrpsid = usersid; - if (IsValidSid (pgrpsid) && (count = *GetSidSubAuthorityCount (pgrpsid)) > 1) - { - *GetSidSubAuthority (pgrpsid, count - 1) = buf->usri3_primary_group_id; - retval = TRUE; - } - NetApiBufferFree (buf); - return retval; -} - -static int -get_supplementary_group_sidlist (const char *username, cygsidlist &grp_list) -{ - struct group *gr; - int cnt = 0; - - for (int gidx = 0; (gr = internal_getgrent (gidx)); ++gidx) - { - if (gr->gr_mem) - for (int gi = 0; gr->gr_mem[gi]; ++gi) - if (strcasematch (username, gr->gr_mem[gi])) - { - if (gr->gr_passwd && *gr->gr_passwd) - { - cygsid sid (gr->gr_passwd); - if ((PSID)sid && grp_list.add (sid)) - ++cnt; - } - break; - } - } - return cnt; -} - -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; - cygsidlist sup_list; - - auth_pos = -1; - sys_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_admins_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; - if (get_supplementary_group_sidlist (user, sup_list)) - { - for (int i = 0; i < sup_list.count; ++i) - if (!grp_list.contains (sup_list.sids[i])) - grp_list += sup_list.sids[i]; - } - 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; - - sys_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_admins_sid)) - { - if (!AddAccessAllowedAce(acl, ACL_REVISION, GENERIC_ALL, - well_known_admins_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 = { QuadPart: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 -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; - 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; - - if ((old_tcb_state = set_process_privilege(SE_TCB_NAME)) < 0) - return INVALID_HANDLE_VALUE; - - /* Register as logon process. */ - str2lsa (name, "Cygwin"); - SetLastError (0); - ret = LsaRegisterLogonProcess(&name, &lsa_hdl, &sec_mode); - if (ret != STATUS_SUCCESS) - { - debug_printf ("LsaRegisterLogonProcess: %d", ret); - set_errno (LsaNtStatusToWinError(ret)); - goto out; - } - else if (GetLastError () == ERROR_PROC_NOT_FOUND) - { - debug_printf ("Couldn't load Secur32.dll"); - goto out; - } - /* 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); - goto out; - } - /* Create origin. */ - str2buf2lsa (origin.str, origin.buf, "Cygwin"); - /* Create token source. */ - memcpy(ts.SourceName, "Cygwin.1", 8); - ts.SourceIdentifier.HighPart = 0; - ts.SourceIdentifier.LowPart = 0x0100; - /* 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); - goto out; - } - LsaFreeReturnBuffer(profile); - /* Convert to primary token. */ - if (!DuplicateTokenEx (user_token, TOKEN_ALL_ACCESS, &sa, - SecurityImpersonation, TokenPrimary, - &primary_token)) - __seterrno (); - -out: - set_process_privilege(SE_TCB_NAME, old_tcb_state); - if (user_token != 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 - is set to the needed buffer size. - On success, 1 is returned. - - GetFileSecurity() is used instead of BackupRead() - to avoid access denied errors if the caller has - not the permission to open that file for read. - - Originally the function should return the size - of the SD on success. Unfortunately NT returns - 0 in `len' on success, while W2K returns the - correct size! -*/ - -LONG -read_sd(const char *file, PSECURITY_DESCRIPTOR sd_buf, LPDWORD sd_size) -{ - /* Check parameters */ - if (!sd_size) - { - set_errno (EINVAL); - return -1; - } - - debug_printf("file = %s", file); - - DWORD len = 0; - const char *pfile = file; - char fbuf [PATH_MAX]; - if (current_codepage == oem_cp) - { - DWORD fname_len = min (sizeof (fbuf) - 1, strlen (file)); - bzero (fbuf, sizeof (fbuf)); - OemToCharBuff(file, fbuf, fname_len); - pfile = fbuf; - } - - if (!GetFileSecurity (pfile, - OWNER_SECURITY_INFORMATION - | GROUP_SECURITY_INFORMATION - | DACL_SECURITY_INFORMATION, - sd_buf, *sd_size, &len)) - { - __seterrno (); - return -1; - } - debug_printf("file = %s: len=%d", file, len); - if (len > *sd_size) - { - *sd_size = len; - return 0; - } - return 1; -} - -LONG -write_sd(const char *file, PSECURITY_DESCRIPTOR sd_buf, DWORD sd_size) -{ - /* Check parameters */ - if (!sd_buf || !sd_size) - { - set_errno (EINVAL); - return -1; - } - - /* No need to be thread save. */ - static BOOL first_time = TRUE; - if (first_time) - { - set_process_privilege (SE_RESTORE_NAME); - first_time = FALSE; - } - - HANDLE fh; - fh = CreateFile (file, - WRITE_OWNER | WRITE_DAC, - FILE_SHARE_READ | FILE_SHARE_WRITE, - &sec_none_nih, - OPEN_EXISTING, - FILE_ATTRIBUTE_NORMAL | FILE_FLAG_BACKUP_SEMANTICS, - NULL); - - if (fh == INVALID_HANDLE_VALUE) - { - __seterrno (); - return -1; - } - - LPVOID context = NULL; - DWORD bytes_written = 0; - WIN32_STREAM_ID header; - - memset (&header, 0, sizeof (header)); - /* write new security info header */ - header.dwStreamId = BACKUP_SECURITY_DATA; - header.dwStreamAttributes = STREAM_CONTAINS_SECURITY; - header.Size.HighPart = 0; - header.Size.LowPart = sd_size; - header.dwStreamNameSize = 0; - if (!BackupWrite (fh, (LPBYTE) &header, - 3 * sizeof (DWORD) + sizeof (LARGE_INTEGER), - &bytes_written, FALSE, TRUE, &context)) - { - __seterrno (); - CloseHandle (fh); - return -1; - } - - /* write new security descriptor */ - if (!BackupWrite (fh, (LPBYTE) sd_buf, - header.Size.LowPart + header.dwStreamNameSize, - &bytes_written, FALSE, TRUE, &context)) - { - /* Samba returns ERROR_NOT_SUPPORTED. - FAT returns ERROR_INVALID_SECURITY_DESCR. - This shouldn't return as error, but better be ignored. */ - DWORD ret = GetLastError (); - if (ret != ERROR_NOT_SUPPORTED && ret != ERROR_INVALID_SECURITY_DESCR) - { - __seterrno (); - BackupWrite (fh, NULL, 0, &bytes_written, TRUE, TRUE, &context); - CloseHandle (fh); - return -1; - } - } - - /* terminate the restore process */ - BackupWrite (fh, NULL, 0, &bytes_written, TRUE, TRUE, &context); - CloseHandle (fh); - return 0; -} - -static int -get_nt_attribute (const char *file, int *attribute, - uid_t *uidret, gid_t *gidret) -{ - if (!wincap.has_security ()) - return 0; - - syscall_printf ("file: %s", file); - - /* Yeah, sounds too much, but I've seen SDs of 2100 bytes!*/ - DWORD sd_size = 4096; - char sd_buf[4096]; - PSECURITY_DESCRIPTOR psd = (PSECURITY_DESCRIPTOR) sd_buf; - - int ret; - if ((ret = read_sd (file, psd, &sd_size)) <= 0) - { - debug_printf ("read_sd %E"); - return ret; - } - - PSID owner_sid; - PSID group_sid; - BOOL dummy; - - if (!GetSecurityDescriptorOwner (psd, &owner_sid, &dummy)) - debug_printf ("GetSecurityDescriptorOwner %E"); - if (!GetSecurityDescriptorGroup (psd, &group_sid, &dummy)) - debug_printf ("GetSecurityDescriptorGroup %E"); - - PACL acl; - BOOL acl_exists; - - if (!GetSecurityDescriptorDacl (psd, &acl_exists, &acl, &dummy)) - { - __seterrno (); - debug_printf ("GetSecurityDescriptorDacl %E"); - return -1; - } - - uid_t uid = cygsid(owner_sid).get_uid (); - gid_t gid = cygsid(group_sid).get_gid (); - if (uidret) - *uidret = uid; - if (gidret) - *gidret = gid; - - if (!attribute) - { - syscall_printf ("file: %s uid %d, gid %d", file, uid, gid); - return 0; - } - - BOOL grp_member = is_grp_member (uid, gid); - - if (!acl_exists || !acl) - { - *attribute |= S_IRWXU | S_IRWXG | S_IRWXO; - syscall_printf ("file: %s No ACL = %x, uid %d, gid %d", - file, *attribute, uid, gid); - return 0; - } - - ACCESS_ALLOWED_ACE *ace; - int allow = 0; - int deny = 0; - int *flags, *anti; - - for (DWORD i = 0; i < acl->AceCount; ++i) - { - if (!GetAce (acl, i, (PVOID *) &ace)) - continue; - if (ace->Header.AceFlags & INHERIT_ONLY_ACE) - continue; - switch (ace->Header.AceType) - { - case ACCESS_ALLOWED_ACE_TYPE: - flags = &allow; - anti = &deny; - break; - case ACCESS_DENIED_ACE_TYPE: - flags = &deny; - anti = &allow; - break; - default: - continue; - } - - cygsid ace_sid ((PSID) &ace->SidStart); - if (owner_sid && ace_sid == owner_sid) - { - if (ace->Mask & FILE_READ_DATA) - *flags |= S_IRUSR; - if (ace->Mask & FILE_WRITE_DATA) - *flags |= S_IWUSR; - if (ace->Mask & FILE_EXECUTE) - *flags |= S_IXUSR; - } - else if (group_sid && ace_sid == group_sid) - { - if (ace->Mask & FILE_READ_DATA) - *flags |= S_IRGRP - | ((grp_member && !(*anti & S_IRUSR)) ? S_IRUSR : 0); - if (ace->Mask & FILE_WRITE_DATA) - *flags |= S_IWGRP - | ((grp_member && !(*anti & S_IWUSR)) ? S_IWUSR : 0); - if (ace->Mask & FILE_EXECUTE) - *flags |= S_IXGRP - | ((grp_member && !(*anti & S_IXUSR)) ? S_IXUSR : 0); - } - else if (ace_sid == well_known_world_sid) - { - if (ace->Mask & FILE_READ_DATA) - *flags |= S_IROTH - | ((!(*anti & S_IRGRP)) ? S_IRGRP : 0) - | ((!(*anti & S_IRUSR)) ? S_IRUSR : 0); - if (ace->Mask & FILE_WRITE_DATA) - *flags |= S_IWOTH - | ((!(*anti & S_IWGRP)) ? S_IWGRP : 0) - | ((!(*anti & S_IWUSR)) ? S_IWUSR : 0); - if (ace->Mask & FILE_EXECUTE) - { - *flags |= S_IXOTH - | ((!(*anti & S_IXGRP)) ? S_IXGRP : 0) - | ((!(*anti & S_IXUSR)) ? S_IXUSR : 0); - } - if ((*attribute & S_IFDIR) && - (ace->Mask & (FILE_WRITE_DATA | FILE_EXECUTE | FILE_DELETE_CHILD)) - == (FILE_WRITE_DATA | FILE_EXECUTE)) - *flags |= S_ISVTX; - } - else if (ace_sid == well_known_null_sid) - { - /* Read SUID, SGID and VTX bits from NULL ACE. */ - if (ace->Mask & FILE_READ_DATA) - *flags |= S_ISVTX; - if (ace->Mask & FILE_WRITE_DATA) - *flags |= S_ISGID; - if (ace->Mask & FILE_APPEND_DATA) - *flags |= S_ISUID; - } - } - *attribute &= ~(S_IRWXU | S_IRWXG | S_IRWXO | S_ISVTX | S_ISGID | S_ISUID); - *attribute |= allow; - *attribute &= ~deny; - syscall_printf ("file: %s %x, uid %d, gid %d", file, *attribute, uid, gid); - return 0; -} - -int -get_file_attribute (int use_ntsec, const char *file, - int *attribute, uid_t *uidret, gid_t *gidret) -{ - int res; - - if (use_ntsec && allow_ntsec) - { - res = get_nt_attribute (file, attribute, uidret, gidret); - if (attribute && (*attribute & S_IFLNK) == S_IFLNK) - *attribute |= S_IRWXU | S_IRWXG | S_IRWXO; - return res; - } - - if (uidret) - *uidret = getuid (); - if (gidret) - *gidret = getgid (); - - if (!attribute) - return 0; - - if (allow_ntea) - { - int oatt = *attribute; - res = NTReadEA (file, ".UNIXATTR", (char *) attribute, sizeof (*attribute)); - *attribute |= oatt; - } - else - res = 0; - - /* symlinks are everything for everyone!*/ - if ((*attribute & S_IFLNK) == S_IFLNK) - *attribute |= S_IRWXU | S_IRWXG | S_IRWXO; - - return res > 0 ? 0 : -1; -} - -BOOL -add_access_allowed_ace (PACL acl, int offset, DWORD attributes, - PSID sid, size_t &len_add, DWORD inherit) -{ - if (!AddAccessAllowedAce (acl, ACL_REVISION, attributes, sid)) - { - __seterrno (); - return FALSE; - } - ACCESS_ALLOWED_ACE *ace; - if (GetAce(acl, offset, (PVOID *) &ace)) - ace->Header.AceFlags |= inherit; - len_add += sizeof (ACCESS_DENIED_ACE) - sizeof (DWORD) - + GetLengthSid (sid); - return TRUE; -} - -BOOL -add_access_denied_ace (PACL acl, int offset, DWORD attributes, - PSID sid, size_t &len_add, DWORD inherit) -{ - if (!AddAccessDeniedAce (acl, ACL_REVISION, attributes, sid)) - { - __seterrno (); - return FALSE; - } - ACCESS_DENIED_ACE *ace; - if (GetAce(acl, offset, (PVOID *) &ace)) - ace->Header.AceFlags |= inherit; - len_add += sizeof (ACCESS_DENIED_ACE) - sizeof (DWORD) - + GetLengthSid (sid); - return TRUE; -} - -PSECURITY_DESCRIPTOR -alloc_sd (uid_t uid, gid_t gid, const char *logsrv, int attribute, - PSECURITY_DESCRIPTOR sd_ret, DWORD *sd_size_ret) -{ - BOOL dummy; - - if (!wincap.has_security ()) - return NULL; - - if (!sd_ret || !sd_size_ret) - { - set_errno (EINVAL); - return NULL; - } - - /* Get SID and name of new owner. */ - char owner[UNLEN + 1]; - cygsid owner_sid; - struct passwd *pw = getpwuid (uid); - strcpy (owner, pw ? pw->pw_name : getlogin ()); - if ((!pw || !owner_sid.getfrompw (pw)) - && !lookup_name (owner, logsrv, owner_sid)) - return NULL; - debug_printf ("owner: %s [%d]", owner, - *GetSidSubAuthority(owner_sid, - *GetSidSubAuthorityCount(owner_sid) - 1)); - - /* Get SID and name of new group. */ - cygsid group_sid (NO_SID); - struct group *grp = getgrgid (gid); - if (grp) - { - if ((!grp || !group_sid.getfromgr (grp)) - && !lookup_name (grp->gr_name, logsrv, group_sid)) - return NULL; - } - else - debug_printf ("no group"); - - /* Initialize local security descriptor. */ - SECURITY_DESCRIPTOR sd; - PSECURITY_DESCRIPTOR psd = NULL; - if (!InitializeSecurityDescriptor (&sd, SECURITY_DESCRIPTOR_REVISION)) - { - __seterrno (); - return NULL; - } - - /* - * We set the SE_DACL_PROTECTED flag here to prevent the DACL from being - * modified by inheritable ACEs. - * This flag as well as the SetSecurityDescriptorControl call are available - * only since Win2K. - */ - if (wincap.has_security_descriptor_control ()) - SetSecurityDescriptorControl (&sd, SE_DACL_PROTECTED, SE_DACL_PROTECTED); - - /* Create owner for local security descriptor. */ - if (!SetSecurityDescriptorOwner(&sd, owner_sid, FALSE)) - { - __seterrno (); - return NULL; - } - - /* Create group for local security descriptor. */ - if (group_sid && !SetSecurityDescriptorGroup(&sd, group_sid, FALSE)) - { - __seterrno (); - return NULL; - } - - /* Initialize local access control list. */ - char acl_buf[3072]; - PACL acl = (PACL) acl_buf; - if (!InitializeAcl (acl, 3072, ACL_REVISION)) - { - __seterrno (); - return NULL; - } - - /* From here fill ACL. */ - size_t acl_len = sizeof (ACL); - int ace_off = 0; - - /* Construct allow attribute for owner. */ - DWORD owner_allow = (STANDARD_RIGHTS_ALL & ~DELETE) - | FILE_WRITE_ATTRIBUTES | FILE_WRITE_EA; - if (attribute & S_IRUSR) - owner_allow |= FILE_GENERIC_READ; - if (attribute & S_IWUSR) - owner_allow |= FILE_GENERIC_WRITE | DELETE; - if (attribute & S_IXUSR) - owner_allow |= FILE_GENERIC_EXECUTE; - if ((attribute & (S_IFDIR | S_IWUSR | S_IXUSR)) - == (S_IFDIR | S_IWUSR | S_IXUSR)) - owner_allow |= FILE_DELETE_CHILD; - - /* Construct allow attribute for group. */ - DWORD group_allow = STANDARD_RIGHTS_READ - | FILE_READ_ATTRIBUTES | FILE_READ_EA; - if (attribute & S_IRGRP) - group_allow |= FILE_GENERIC_READ; - if (attribute & S_IWGRP) - group_allow |= STANDARD_RIGHTS_WRITE | FILE_GENERIC_WRITE; - if (attribute & S_IXGRP) - group_allow |= FILE_GENERIC_EXECUTE; - if ((attribute & (S_IFDIR | S_IWGRP | S_IXGRP)) - == (S_IFDIR | S_IWGRP | S_IXGRP) - && !(attribute & S_ISVTX)) - group_allow |= FILE_DELETE_CHILD; - - /* Construct allow attribute for everyone. */ - DWORD other_allow = STANDARD_RIGHTS_READ - | FILE_READ_ATTRIBUTES | FILE_READ_EA; - if (attribute & S_IROTH) - other_allow |= FILE_GENERIC_READ; - if (attribute & S_IWOTH) - other_allow |= STANDARD_RIGHTS_WRITE | FILE_GENERIC_WRITE; - if (attribute & S_IXOTH) - other_allow |= FILE_GENERIC_EXECUTE; - if ((attribute & (S_IFDIR | S_IWOTH | S_IXOTH)) - == (S_IFDIR | S_IWOTH | S_IXOTH) - && !(attribute & S_ISVTX)) - other_allow |= FILE_DELETE_CHILD; - - /* Construct SUID, SGID and VTX bits in NULL ACE. */ - DWORD null_allow = 0L; - if (attribute & (S_ISUID | S_ISGID | S_ISVTX)) - { - if (attribute & S_ISUID) - null_allow |= FILE_APPEND_DATA; - if (attribute & S_ISGID) - null_allow |= FILE_WRITE_DATA; - if (attribute & S_ISVTX) - null_allow |= FILE_READ_DATA; - } - - /* Construct deny attributes for owner and group. */ - DWORD owner_deny = 0; - if (is_grp_member (uid, gid)) - owner_deny = ~owner_allow & (group_allow | other_allow); - else - owner_deny = ~owner_allow & other_allow; - owner_deny &= ~(STANDARD_RIGHTS_READ - | FILE_READ_ATTRIBUTES | FILE_READ_EA - | FILE_WRITE_ATTRIBUTES | FILE_WRITE_EA); - DWORD group_deny = ~group_allow & other_allow; - group_deny &= ~(STANDARD_RIGHTS_READ | FILE_READ_ATTRIBUTES | FILE_READ_EA); - - /* Construct appropriate inherit attribute. */ - DWORD inherit = (attribute & S_IFDIR) ? INHERIT_ALL : DONT_INHERIT; - - /* Set deny ACE for owner. */ - if (owner_deny - && !add_access_denied_ace (acl, ace_off++, owner_deny, - owner_sid, acl_len, inherit)) - return NULL; - /* Set allow ACE for owner. */ - if (!add_access_allowed_ace (acl, ace_off++, owner_allow, - owner_sid, acl_len, inherit)) - return NULL; - /* Set deny ACE for group. */ - if (group_deny - && !add_access_denied_ace (acl, ace_off++, group_deny, - group_sid, acl_len, inherit)) - return NULL; - /* Set allow ACE for group. */ - if (!add_access_allowed_ace (acl, ace_off++, group_allow, - group_sid, acl_len, inherit)) - return NULL; - - /* Set allow ACE for everyone. */ - if (!add_access_allowed_ace (acl, ace_off++, other_allow, - well_known_world_sid, acl_len, inherit)) - return NULL; - /* Set null ACE for special bits. */ - if (null_allow - && !add_access_allowed_ace (acl, ace_off++, null_allow, - well_known_null_sid, acl_len, DONT_INHERIT)) - return NULL; - - /* Get owner and group from current security descriptor. */ - PSID cur_owner_sid = NULL; - PSID cur_group_sid = NULL; - if (!GetSecurityDescriptorOwner (sd_ret, &cur_owner_sid, &dummy)) - debug_printf ("GetSecurityDescriptorOwner %E"); - if (!GetSecurityDescriptorGroup (sd_ret, &cur_group_sid, &dummy)) - debug_printf ("GetSecurityDescriptorGroup %E"); - - /* Fill ACL with unrelated ACEs from current security descriptor. */ - PACL oacl; - BOOL acl_exists; - ACCESS_ALLOWED_ACE *ace; - if (GetSecurityDescriptorDacl (sd_ret, &acl_exists, &oacl, &dummy) - && acl_exists && oacl) - for (DWORD i = 0; i < oacl->AceCount; ++i) - if (GetAce (oacl, i, (PVOID *) &ace)) - { - cygsid ace_sid ((PSID) &ace->SidStart); - /* Check for related ACEs. */ - if ((cur_owner_sid && ace_sid == cur_owner_sid) - || (owner_sid && ace_sid == owner_sid) - || (cur_group_sid && ace_sid == cur_group_sid) - || (group_sid && ace_sid == group_sid) - || (ace_sid == well_known_world_sid) - || (ace_sid == well_known_null_sid)) - continue; - /* - * Add unrelated ACCESS_DENIED_ACE to the beginning but - * behind the owner_deny, ACCESS_ALLOWED_ACE to the end. - */ - if (!AddAce(acl, ACL_REVISION, - ace->Header.AceType == ACCESS_DENIED_ACE_TYPE ? - (owner_deny ? 1 : 0) : MAXDWORD, - (LPVOID) ace, ace->Header.AceSize)) - { - __seterrno (); - return NULL; - } - acl_len += ace->Header.AceSize; - } - - /* Set AclSize to computed value. */ - acl->AclSize = acl_len; - debug_printf ("ACL-Size: %d", acl_len); - - /* Create DACL for local security descriptor. */ - if (!SetSecurityDescriptorDacl (&sd, TRUE, acl, FALSE)) - { - __seterrno (); - return NULL; - } - - /* Make self relative security descriptor. */ - *sd_size_ret = 0; - MakeSelfRelativeSD (&sd, sd_ret, sd_size_ret); - if (*sd_size_ret <= 0) - { - __seterrno (); - return NULL; - } - if (!MakeSelfRelativeSD (&sd, sd_ret, sd_size_ret)) - { - __seterrno (); - return NULL; - } - psd = sd_ret; - debug_printf ("Created SD-Size: %d", *sd_size_ret); - - return psd; -} - -void -set_security_attribute (int attribute, PSECURITY_ATTRIBUTES psa, - void *sd_buf, DWORD sd_buf_size) -{ - /* symlinks are anything for everyone!*/ - if ((attribute & S_IFLNK) == S_IFLNK) - attribute |= S_IRWXU | S_IRWXG | S_IRWXO; - - psa->lpSecurityDescriptor = sd_buf; - InitializeSecurityDescriptor ((PSECURITY_DESCRIPTOR)sd_buf, - SECURITY_DESCRIPTOR_REVISION); - psa->lpSecurityDescriptor = alloc_sd (geteuid (), getegid (), - cygheap->user.logsrv (), - attribute, (PSECURITY_DESCRIPTOR)sd_buf, - &sd_buf_size); -} - -static int -set_nt_attribute (const char *file, uid_t uid, gid_t gid, - const char *logsrv, int attribute) -{ - if (!wincap.has_security ()) - return 0; - - DWORD sd_size = 4096; - char sd_buf[4096]; - PSECURITY_DESCRIPTOR psd = (PSECURITY_DESCRIPTOR) sd_buf; - - int ret; - if ((ret = read_sd (file, psd, &sd_size)) <= 0) - { - debug_printf ("read_sd %E"); - return -1; - } - - sd_size = 4096; - if (!(psd = alloc_sd (uid, gid, logsrv, attribute, psd, &sd_size))) - return -1; - - return write_sd (file, psd, sd_size); -} - -int -set_file_attribute (int use_ntsec, const char *file, - uid_t uid, gid_t gid, - int attribute, const char *logsrv) -{ - int ret = 0; - - if (use_ntsec && allow_ntsec) - ret = set_nt_attribute (file, uid, gid, logsrv, attribute); - else if (allow_ntea && !NTWriteEA (file, ".UNIXATTR", (char *) &attribute, - sizeof (attribute))) - { - __seterrno (); - ret = -1; - } - syscall_printf ("%d = set_file_attribute (%s, %d, %d, %p)", - ret, file, uid, gid, attribute); - return ret; -} - -int -set_file_attribute (int use_ntsec, const char *file, int attribute) -{ - return set_file_attribute (use_ntsec, file, - myself->uid, myself->gid, - attribute, cygheap->user.logsrv ()); -} |