Tcl Source Code

Check-in [6203735037]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:2974459,2879351,1951574,1852572,1661378,1613456 Revisions to the NativeAccess() routine that queries file permissions on Windows native filesystems. Meant to fix numerous bugs where [file writable|readable|executable] "lies" about what operations are possible, especially when the file resides on a Samba share. Patch merged from the fix-win-native-access branch.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | core-8-5-branch
Files: files | file ages | folders
SHA1: 62037350379a959584fe6592914e76771000869a
User & Date: dgp 2012-02-02 17:21:39
References
2017-06-15
16:01 Ticket [1613456fff] file readable lies with samba shared folder or file status still Open with 3 other changes artifact: c4ab3b0b58 user: sebres
14:41 Ticket [1613456fff]: 4 changes artifact: 3100fbaa50 user: oehhar
11:43 Ticket [1613456fff]: 3 changes artifact: e41e9178f4 user: sebres
Context
2012-02-02
21:13
[Frq 3464401] Support Unicode 6.1 check-in: 0090ba5598 user: jan.nijtmans tags: core-8-5-branch
17:35
2974459,2879351,1951574,1852572,1661378,1613456 Revisions to the NativeAccess() routine that queries... check-in: 23cc9bf170 user: dgp tags: trunk
17:21
2974459,2879351,1951574,1852572,1661378,1613456 Revisions to the NativeAccess() routine that queries... check-in: 6203735037 user: dgp tags: core-8-5-branch
16:44
2974459,2879351,1951574,1852572,1661378,1613456 Revisions to the NativeAccess() routine that queries... check-in: 63315eaf46 user: dgp tags: core-8-4-branch
2012-02-01
15:46
merge to bugfix branch Closed-Leaf check-in: 0b276de667 user: dgp tags: fix-win-native-access
12:55
[Bug 3482614]: Documentation nit. check-in: 39b0b3fb61 user: dkf tags: core-8-5-branch
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to ChangeLog.










1
2
3
4
5
6
7









2012-02-01  Donal K. Fellows  <[email protected]>

	* doc/AddErrInfo.3: [Bug 3482614]: Documentation nit.

2012-01-26  Don Porter  <[email protected]>

	* generic/tclPathObj.c:	[Bug 3475569]: Add checks for unshared values
>
>
>
>
>
>
>
>
>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
2012-02-02  Don Porter  <[email protected]>

	* win/tclWinFile.c:	[Bugs 2974459,2879351,1951574,1852572,
	1661378,1613456]: Revisions to the NativeAccess() routine that
	queries file permissions on Windows native filesystems.  Meant to
	fix numerous bugs where [file writable|readable|executable] "lies"
	about what operations are possible, especially when the file resides
	on a Samba share.  Patch merged from the fix-win-native-access branch.

2012-02-01  Donal K. Fellows  <[email protected]>

	* doc/AddErrInfo.3: [Bug 3482614]: Documentation nit.

2012-01-26  Don Porter  <[email protected]>

	* generic/tclPathObj.c:	[Bug 3475569]: Add checks for unshared values

Changes to win/tclWinFile.c.

1545
1546
1547
1548
1549
1550
1551
1552








1553
1554
1555

1556
1557
1558




1559
1560
1561
1562
1563
1564
1565
1566
1567
	/*
	 * File doesn't exist.
	 */

	TclWinConvertError(GetLastError());
	return -1;
    }









    if ((mode & W_OK)
	    && (tclWinProcs->getFileSecurityProc == NULL)
	    && (attr & FILE_ATTRIBUTE_READONLY)) {

	/*
	 * We don't have the advanced 'getFileSecurityProc', and our
	 * attributes say the file is not writable. If we do have




	 * 'getFileSecurityProc', we'll do a more robust XP-related check
	 * below.
	 */

	Tcl_SetErrno(EACCES);
	return -1;
    }

    if (mode & X_OK) {








>
>
>
>
>
>
>
>

<
|
>

<
|
>
>
>
>
|
|







1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561

1562
1563
1564

1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
	/*
	 * File doesn't exist.
	 */

	TclWinConvertError(GetLastError());
	return -1;
    }

    if (mode == F_OK) {
	/*
	 * File exists, nothing else to check.
	 */

	return 0;
    }

    if ((mode & W_OK)

	&& (attr & FILE_ATTRIBUTE_READONLY)
	&& !(attr & FILE_ATTRIBUTE_DIRECTORY)) {
	/*

	 * The attributes say the file is not writable.	 If the file is a
	 * regular file (i.e., not a directory), then the file is not
	 * writable, full stop.	 For directories, the read-only bit is
	 * (mostly) ignored by Windows, so we can't ascertain anything about
	 * directory access from the attrib data.  However, if we have the
	 * advanced 'getFileSecurityProc', then more robust ACL checks
	 * will be done below.
	 */

	Tcl_SetErrno(EACCES);
	return -1;
    }

    if (mode & X_OK) {
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592



1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608

1609
1610
1611
1612
1613
1614
1615
    }

    /*
     * It looks as if the permissions are ok, but if we are on NT, 2000 or XP,
     * we have a more complex permissions structure so we try to check that.
     * The code below is remarkably complex for such a simple thing as finding
     * what permissions the OS has set for a file.
     *
     * If we are simply checking for file existence, then we don't need all
     * these complications (which are really quite slow: with this code 'file
     * readable' is 5-6 times slower than 'file exists').
     */

    if ((mode != F_OK) && (tclWinProcs->getFileSecurityProc != NULL)) {
	SECURITY_DESCRIPTOR *sdPtr = NULL;
	unsigned long size;



	GENERIC_MAPPING genMap;
	HANDLE hToken = NULL;
	DWORD desiredAccess = 0, grantedAccess = 0;
	BOOL accessYesNo = FALSE;
	PRIVILEGE_SET privSet;
	DWORD privSetSize = sizeof(PRIVILEGE_SET);
	int error;

	/*
	 * First find out how big the buffer needs to be
	 */

	size = 0;
	(*tclWinProcs->getFileSecurityProc)(nativePath,
		OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION
		| DACL_SECURITY_INFORMATION, 0, 0, &size);


	/*
	 * Should have failed with ERROR_INSUFFICIENT_BUFFER
	 */

	error = GetLastError();
	if (error != ERROR_INSUFFICIENT_BUFFER) {







<
<
<
<


|


>
>
>















|
>







1588
1589
1590
1591
1592
1593
1594




1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
    }

    /*
     * It looks as if the permissions are ok, but if we are on NT, 2000 or XP,
     * we have a more complex permissions structure so we try to check that.
     * The code below is remarkably complex for such a simple thing as finding
     * what permissions the OS has set for a file.




     */

    if (tclWinProcs->getFileSecurityProc != NULL) {
	SECURITY_DESCRIPTOR *sdPtr = NULL;
	unsigned long size;
	SID *pSid = 0;
	BOOL SidDefaulted;
	SID_IDENTIFIER_AUTHORITY samba_unmapped = { 0, 0, 0, 0, 0, 22 };
	GENERIC_MAPPING genMap;
	HANDLE hToken = NULL;
	DWORD desiredAccess = 0, grantedAccess = 0;
	BOOL accessYesNo = FALSE;
	PRIVILEGE_SET privSet;
	DWORD privSetSize = sizeof(PRIVILEGE_SET);
	int error;

	/*
	 * First find out how big the buffer needs to be
	 */

	size = 0;
	(*tclWinProcs->getFileSecurityProc)(nativePath,
		OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION
		| DACL_SECURITY_INFORMATION | LABEL_SECURITY_INFORMATION,
		0, 0, &size);

	/*
	 * Should have failed with ERROR_INSUFFICIENT_BUFFER
	 */

	error = GetLastError();
	if (error != ERROR_INSUFFICIENT_BUFFER) {
1634
1635
1636
1637
1638
1639
1640
1641

1642
1643
1644
1645
1646
1647




















1648
1649
1650
1651
1652
1653
1654

	/*
	 * Call GetFileSecurity() for real.
	 */

	if (!(*tclWinProcs->getFileSecurityProc)(nativePath,
		OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION
		| DACL_SECURITY_INFORMATION, sdPtr, size, &size)) {

	    /*
	     * Error getting owner SD
	     */

	    goto accessError;
	}





















	/*
	 * Perform security impersonation of the user and open the resulting
	 * thread token.
	 */

	if (!(*tclWinProcs->impersonateSelfProc)(SecurityImpersonation)) {







|
>






>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686

	/*
	 * Call GetFileSecurity() for real.
	 */

	if (!(*tclWinProcs->getFileSecurityProc)(nativePath,
		OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION
		| DACL_SECURITY_INFORMATION | LABEL_SECURITY_INFORMATION,
		sdPtr, size, &size)) {
	    /*
	     * Error getting owner SD
	     */

	    goto accessError;
	}

	/*
	 * As of Samba 3.0.23 (10-Jul-2006), unmapped users and groups are
	 * assigned to SID domains S-1-22-1 and S-1-22-2, where "22" is the
	 * top-level authority.	 If the file owner and group is unmapped then
	 * the ACL access check below will only test against world access,
	 * which is likely to be more restrictive than the actual access
	 * restrictions.  Since the ACL tests are more likely wrong than
	 * right, skip them.  Moreover, the unix owner access permissions are
	 * usually mapped to the Windows attributes, so if the user is the
	 * file owner then the attrib checks above are correct (as far as they
	 * go).
	 */

	if(!GetSecurityDescriptorOwner(sdPtr,&pSid,&SidDefaulted) ||
	   memcmp(GetSidIdentifierAuthority(pSid),&samba_unmapped,
		  sizeof(SID_IDENTIFIER_AUTHORITY))==0) {
	    HeapFree(GetProcessHeap(), 0, sdPtr);
	    return 0; /* Attrib tests say access allowed. */
	}

	/*
	 * Perform security impersonation of the user and open the resulting
	 * thread token.
	 */

	if (!(*tclWinProcs->impersonateSelfProc)(SecurityImpersonation)) {
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
	HeapFree(GetProcessHeap(), 0, sdPtr);
	CloseHandle(hToken);
	if (!accessYesNo) {
	    Tcl_SetErrno(EACCES);
	    return -1;
	}

	/*
	 * For directories the above checks are ok. For files, though, we must
	 * still check the 'attr' value.
	 */

	if ((mode & W_OK)
		&& !(attr & FILE_ATTRIBUTE_DIRECTORY)
		&& (attr & FILE_ATTRIBUTE_READONLY)) {
	    Tcl_SetErrno(EACCES);
	    return -1;
	}
    }
    return 0;
}

/*
 *----------------------------------------------------------------------
 *







<
<
<
<
<
<
<
<
<
<
<







1751
1752
1753
1754
1755
1756
1757











1758
1759
1760
1761
1762
1763
1764
	HeapFree(GetProcessHeap(), 0, sdPtr);
	CloseHandle(hToken);
	if (!accessYesNo) {
	    Tcl_SetErrno(EACCES);
	    return -1;
	}












    }
    return 0;
}

/*
 *----------------------------------------------------------------------
 *