Tcl Source Code

Check-in [23cc9bf170]
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.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 23cc9bf170fd4489f71ab6d9c36133c2506353ca
User & Date: dgp 2012-02-02 17:35:59
Context
2012-02-02
18:01
inverted logic check-in: 4ebc3a8e1e user: dgp tags: trunk
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
2012-02-01
13:00
[Bug 3482614]: Documentation nit. check-in: 7f49ede254 user: dkf tags: trunk
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-30  Donal K. Fellows  <[email protected]>

	* generic/tclCompCmds.c (TclCompileCatchCmd): Added a more efficient
>
>
>
>
>
>
>
>
>







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.

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

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

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

	* generic/tclCompCmds.c (TclCompileCatchCmd): Added a more efficient

Changes to win/tclWinFile.c.

1536
1537
1538
1539
1540
1541
1542




1543



1544
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
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
	    FindClose(hFind);
	} else {
	    TclWinConvertError(GetLastError());
	    return -1;
	}
    }





#ifndef UNICODE



    if ((mode & W_OK)
	    && (attr & FILE_ATTRIBUTE_READONLY)) {

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




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

	Tcl_SetErrno(EACCES);
	return -1;
    }
#endif /* !UNICODE */

    if (mode & X_OK) {
	if (!(attr & FILE_ATTRIBUTE_DIRECTORY) && !NativeIsExec(nativePath)) {
	    /*
	     * It's not a directory and doesn't have the correct extension.
	     * Therefore it can't be executable
	     */

	    Tcl_SetErrno(EACCES);
	    return -1;
	}
    }

    /*
     * 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) {
	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;
	GetFileSecurity(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) {







>
>
>
>
|
>
>
>

|
>

<
|
>
>
>
>
|
|





<


















|
|
|
<
<
|
<


>
>
>















|
>







1536
1537
1538
1539
1540
1541
1542
1543
1544
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
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
1616
1617
	    FindClose(hFind);
	} else {
	    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) {
	if (!(attr & FILE_ATTRIBUTE_DIRECTORY) && !NativeIsExec(nativePath)) {
	    /*
	     * It's not a directory and doesn't have the correct extension.
	     * Therefore it can't be executable
	     */

	    Tcl_SetErrno(EACCES);
	    return -1;
	}
    }

    /*
     * 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.
     */

#ifndef UNICODE


    {

	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;
	GetFileSecurity(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) {
1625
1626
1627
1628
1629
1630
1631
1632

1633
1634
1635
1636
1637
1638




















1639
1640
1641
1642
1643
1644
1645

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

	if (!GetFileSecurity(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 (!ImpersonateSelf(SecurityImpersonation)) {







|
>






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







1636
1637
1638
1639
1640
1641
1642
1643
1644
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

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

	if (!GetFileSecurity(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 (!ImpersonateSelf(SecurityImpersonation)) {
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
	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;
}

/*
 *----------------------------------------------------------------------
 *
 * NativeIsExec --







<
<
<
<
|
|
<
<
<
<
<
<







1742
1743
1744
1745
1746
1747
1748




1749
1750






1751
1752
1753
1754
1755
1756
1757
	HeapFree(GetProcessHeap(), 0, sdPtr);
	CloseHandle(hToken);
	if (!accessYesNo) {
	    Tcl_SetErrno(EACCES);
	    return -1;
	}





    }
#endif /* !UNICODE */






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