From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mail-yw1-x1131.google.com (mail-yw1-x1131.google.com [IPv6:2607:f8b0:4864:20::1131]) by sourceware.org (Postfix) with ESMTPS id AF41B3858D39 for ; Wed, 3 Apr 2024 02:08:07 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org AF41B3858D39 Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=gmail.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org AF41B3858D39 Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=2607:f8b0:4864:20::1131 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1712110089; cv=none; b=SaclE4Rju9y+lEVE+DWaBMIGtDZyVqYvrRTMLTA2CViRVgWx7kZ/U3SH4c1c2xdDhC8v2xyp0BTFwsxmQ17pG74UYwkkOIcZolV9rxR5tnSe37wEBF+snM33ZyMtXSUg81nHiAst8aXbuVsGPglJ8/7VEHWBZDGdVno8AXQAm5k= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1712110089; c=relaxed/simple; bh=ab0S2NphcxxFRQbB8m/dKcJopLj+DR9XhADmM/Ytpck=; h=DKIM-Signature:MIME-Version:From:Date:Message-ID:Subject:To; b=lZMLCLy8UJd7WniFQKabt6/eB4xn+AgXwm7uqvOhOgNTGYKoM6M6YkFPE25NMZlvk6qqi5WD7Q5CdAsQdn4AIsbKjEABzqk8Ad8IRkINa/bMytidG1Cv+1jfGE2goW6Nya4Ua8MlDx8LEBW1mGQjCW6us0XMZY/NRXZ6QLAxHXQ= ARC-Authentication-Results: i=1; server2.sourceware.org Received: by mail-yw1-x1131.google.com with SMTP id 00721157ae682-611248b4805so58302057b3.0 for ; Tue, 02 Apr 2024 19:08:07 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1712110086; x=1712714886; darn=cygwin.com; h=content-transfer-encoding:to:subject:message-id:date:from:reply-to :in-reply-to:references:mime-version:from:to:cc:subject:date :message-id:reply-to; bh=M7s7kMVliNsjvpdi0OsbC3GXahdo2yp2MmPSMZcBMQs=; b=aW6/OTJ5lLoF5U6HaBJ4gFsUIyWowP6Pv9UDCvLOjXEdZTa8WDzAf6bpUln/l8XrCo fW+rPTleh2aj63axN34t5ngDQo4PxbSwkK7AS3HhLZNJPZfO32WSbyUo0sg3uoj3I44x Byc80/CPUltT1OouuRERXMT4HYyV1NnjejUal+niP0el/Q+Jwp9gZ30sSmOKfDqtniD8 sAjZxR67KvHHqFsrSssrma1KquElW9Ug3JB+tX2Z0CX8VOsuFVN9ie2RZUj7h9L9g6DQ kLf4keDqxKtYnGj/mfMKgWGDPal3J54DU9vMJaVcFaWRyf5fSBL1Z7tvaKTVATAMzJ5r GDtg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1712110086; x=1712714886; h=content-transfer-encoding:to:subject:message-id:date:from:reply-to :in-reply-to:references:mime-version:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=M7s7kMVliNsjvpdi0OsbC3GXahdo2yp2MmPSMZcBMQs=; b=kG1/MdPmkEncYZ3Z8eLEMEUkaM0WRgsoRmXJhcQ7JBvQ1T4CoMEJt4xmhILg8W/MUM Jd/NoWWuQJpezADX2PolNylE+5XXTJ0qh3Z6pgoS8EVhok9LfbTnNVjy8tteF3s5lKSA MFcrlehGcvW9hAWGHykanS6ERxvQgXHBA9PhZtjfxLXWzLPYEUMlDYAJJw4SgnI0N9iE QRftC7tk/Mnp+/3u6p56QWwcRnvVmoWn/oyx8u4pzFxTSZnSxaeOyaJU40+nhDAuRiU2 N+BOGwZLHWPqu7IIfZ+ePcvtyi+WHOstNSs0PGNzA32PxDrTv9SzcA4xfufftEH00ssB DMzg== X-Gm-Message-State: AOJu0YxK3bed4yN2pGOSygx9Kk52we3Az5t6P3F9P8FeNxlI9nuFHVuC WRhdPpr53QVdrZBmvHxjTYIYxcGFtA4+OrUep9X7AhOlCDDb3umU3lrs3mvoysSGtOFe365aGkg deErxVrLFcTmb8kOpEK7e9EZzE+ctTpF3tLc= X-Google-Smtp-Source: AGHT+IE0KnTFwQTwjByFOnOeHIHC5p7tEzsE4lirx+wEGqZWa2GMV8U73ZbipXUU7XoPyO73nOVN+87YNzhVbhMGEW0= X-Received: by 2002:a25:8a84:0:b0:dbe:4f15:b5cf with SMTP id h4-20020a258a84000000b00dbe4f15b5cfmr1244320ybl.15.1712110086333; Tue, 02 Apr 2024 19:08:06 -0700 (PDT) MIME-Version: 1.0 References: In-Reply-To: Reply-To: John.Ruckstuhl@gmail.com From: John Ruckstuhl Date: Tue, 2 Apr 2024 19:07:54 -0700 Message-ID: Subject: Re: cygwin utils can access directory and its contents, but W10 utils claim to have no access, why? To: cygwin@cygwin.com, John.Ruckstuhl@gmail.com Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable X-Spam-Status: No, score=1.5 required=5.0 tests=BAYES_00,CLAIM_SUBJECT,DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,FREEMAIL_FROM,RCVD_IN_DNSWL_NONE,SPF_HELO_NONE,SPF_PASS,TXREP autolearn=no autolearn_force=no version=3.4.6 X-Spam-Level: * X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org List-Id: On Mon, Jan 22, 2024 at 10:59=E2=80=AFAM John Ruckstuhl wrote: > > Thanks for the replies Brian & Corinna, I learned a lot. > > On Mon, Jan 22, 2024 at 1:48=E2=80=AFAM Corinna Vinschen > wrote: > > Users in the Administrators group have these privileges in their user > > token. Under UAC, both privileges are removed from the token. In an > > elevated shell, though, both privileges are present. > > > > The funny thing here is this: While both privileges are present in the > > token, they are disabled by default. > > > > They have to be enabled explicitely before you can exercise the > > privileges. Usually you do this in the same application > > programatically. > > Now I see... > Local administrator Bob reports his User Access Token info > (with Windows whoami, not cygwin whoami) > C:\>whoami /priv > > PRIVILEGES INFORMATION > ---------------------- > > Privilege Name ... State > =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D ... =3D=3D=3D=3D=3D= =3D=3D=3D > ... > SeBackupPrivilege ... Disabled > SeRestorePrivilege ... Disabled > ... > > C:\> > > Thanks very much. > John Ruckstuhl The clue about UAT and disabled privileges was crucial. Thank you again, Corinna. I'm still doing my cleanup with ordinary Python (not the Cygwin Python linked to the cygwin dll). But I wrote an EnablePrivilege function to enable the privs if if necessary= . Best regards, John Ruckstuhl 1 """ 2 This module exports functions for removing old files and directorie= s. 3 4 Functions 5 myremove -- Remove the file or dir, and return the number of bytes freed. 6 """ 7 8 # standard library imports 9 import logging 10 import os 11 import shutil 12 import subprocess 13 14 # related third party imports 15 import win32api 16 import win32security 17 18 # no local application/library specific imports 19 20 21 logger =3D logging.getLogger(__name__) 22 23 # this custom startupinfo is used to suppress display of the subprocess window 24 startupinfo =3D subprocess.STARTUPINFO() 25 startupinfo.dwFlags |=3D subprocess.STARTF_USESHOWWINDOW 26 27 28 def _remove(path): 29 """Remove the file or dir, and return the number of bytes freed= .""" 30 31 ... 32 33 34 def myremove(path): 35 """Remove the file or dir, and return the number of bytes freed= . 36 37 Attempt removal different ways, until successful (or defeated). 38 39 1. Attempt call _remove (without additional prep). 40 2. Attempt to enable privileges SeBackupPrivilege and 41 SeRestorePrivilege, then call _remove. 42 3. Attempt to takeown, then call _remove. 43 44 The enable privileges approach is ~6x faster than the takeown approach, 45 because takeown of an MEI dir containing ~1K files takes time (8-9 sec). 46 47 Example results, enable privs approach 48 MEI dirs: 113/113 removed, 2047.5 MB recovered in 2.0 minut= es 49 50 Example results, takeown approach 51 MEI dirs: 126/126 removed, 2453.8 MB recovered in 15.0 minu= tes 52 53 By default, the User Access Token for a member of local group 54 Administrators has the privileges SeBackupPrivilege and SeRestorePrivilege, 55 but they are disabled. 56 57 The MEI dirs are typically ~1000 files occupying ~20 MB. 58 The MEI dirs are created by users running the pyinstaller -gene= rated 59 executables ... 60 61 Presumably the process that calls this function is run as a use= r 62 which is a member of local group "Administrators". So this process will 63 have privileges SeBackupPrivilege and SeRestorePrivilege grante= d but 64 disabled. Also this process will be able to take ownership, if needed. 65 """ 66 67 logger.debug('%s(%r)', 'myremove', path) 68 69 # first try, attempt _remove 70 try: 71 logger.debug('%s(%r)', '_remove', path) 72 nbytes =3D _remove(path) 73 return nbytes 74 except WindowsError as e: 75 if e.args =3D=3D (5, 'Access is denied'): 76 # report the exception and carry on to next attempt 77 logger.debug(e) 78 else: 79 # re-raise any other WindowsError 80 raise 81 82 # second try, attempt enable privs then _remove 83 try: 84 logger.debug('%s(%r)', '_remove', path) 85 EnablePrivilege(win32security.SE_BACKUP_NAME) 86 EnablePrivilege(win32security.SE_RESTORE_NAME) 87 nbytes =3D _remove(path) 88 return nbytes 89 except Exception as e: 90 # report the exception and carry on to next attempt 91 logger.debug(e) 92 93 # third try, attempt takeown then _remove 94 try: 95 logger.debug('%s(%r)', '_remove', path) 96 takeown(path) 97 nbytes =3D _remove(path) 98 return nbytes 99 except Exception as e: 100 # report the exception and carry on ... 101 logger.debug(e) 102 103 # accept defeat 104 raise 105 106 107 def takeown(path): 108 subprocess.check_call( 109 [ 110 'takeown', 111 '/A', 112 '/F', path.replace('/', '\\'), 113 '/R', 114 '/D', 'Y', 115 ], 116 startupinfo=3Dstartupinfo) 117 118 119 def EnablePrivilege(privilege): 120 """Enable a privilege, if it's already granted in the User Access Token. 121 122 From [1]: 123 When a user holds a privilege, it allows that user to do things that 124 other users without that privilege are not allowed to do. For example, 125 the SeBackupPrivilege allows a user to read any file, even if the 126 security descriptor denies access. 127 But just having the SeBackupPrivilege is not enough: it needs to be 128 enabled 129 130 [1] https://blog.didierstevens.com/2021/07/19/using-sebackupprivilege-with-pyth= on # noqa: E501 131 """ 132 hToken =3D win32security.OpenProcessToken( 133 win32api.GetCurrentProcess(), 134 win32security.TOKEN_ADJUST_PRIVILEGES | win32security.TOKEN_QUERY 135 ) 136 win32security.AdjustTokenPrivileges( 137 hToken, 138 0, 139 [( 140 win32security.LookupPrivilegeValue(None, privilege), 141 win32security.SE_PRIVILEGE_ENABLED 142 )] 143 ) 144 win32api.CloseHandle(hToken)