summaryrefslogtreecommitdiffstats
path: root/win
diff options
context:
space:
mode:
authorvincentdarley <vincentdarley>2003-10-13 16:48:05 (GMT)
committervincentdarley <vincentdarley>2003-10-13 16:48:05 (GMT)
commit8eb669eea67550509d7223f16753001c943d3ee3 (patch)
treeccb9c39961e0f152b829dff8a1e6b47fcc6d99a3 /win
parent805e2ca6c7ac542dd65701379332c399bde0dd1d (diff)
downloadtcl-8eb669eea67550509d7223f16753001c943d3ee3.zip
tcl-8eb669eea67550509d7223f16753001c943d3ee3.tar.gz
tcl-8eb669eea67550509d7223f16753001c943d3ee3.tar.bz2
filesystem bug fixes
Diffstat (limited to 'win')
-rw-r--r--win/tclWin32Dll.c37
-rw-r--r--win/tclWinFCmd.c31
-rw-r--r--win/tclWinFile.c158
-rw-r--r--win/tclWinInt.h27
4 files changed, 228 insertions, 25 deletions
diff --git a/win/tclWin32Dll.c b/win/tclWin32Dll.c
index 09b9046..dc497f4 100644
--- a/win/tclWin32Dll.c
+++ b/win/tclWin32Dll.c
@@ -9,7 +9,7 @@
* See the file "license.terms" for information on usage and redistribution
* of this file, and for a DISCLAIMER OF ALL WARRANTIES.
*
- * RCS: @(#) $Id: tclWin32Dll.c,v 1.27 2003/09/29 22:38:21 dkf Exp $
+ * RCS: @(#) $Id: tclWin32Dll.c,v 1.28 2003/10/13 16:48:07 vincentdarley Exp $
*/
#include "tclWinInt.h"
@@ -99,6 +99,8 @@ static TclWinProcs asciiProcs = {
(int (__cdecl*)(CONST TCHAR *, struct _utimbuf *)) _utime,
NULL,
NULL,
+ /* Security SDK - not available on 95,98,ME */
+ NULL, NULL, NULL, NULL, NULL, NULL
};
static TclWinProcs unicodeProcs = {
@@ -148,6 +150,8 @@ static TclWinProcs unicodeProcs = {
(int (__cdecl*)(CONST TCHAR *, struct _utimbuf *)) _wutime,
NULL,
NULL,
+ /* Security SDK - will be filled in on NT,XP,2000,2003 */
+ NULL, NULL, NULL, NULL, NULL, NULL
};
TclWinProcs *tclWinProcs;
@@ -567,6 +571,37 @@ TclWinSetInterfaces(
"GetVolumeNameForVolumeMountPointW");
FreeLibrary(hInstance);
}
+ hInstance = LoadLibraryA("advapi32");
+ if (hInstance != NULL) {
+ tclWinProcs->getFileSecurityProc = (BOOL (WINAPI *)(
+ LPCTSTR lpFileName,
+ SECURITY_INFORMATION RequestedInformation,
+ PSECURITY_DESCRIPTOR pSecurityDescriptor, DWORD nLength,
+ LPDWORD lpnLengthNeeded)) GetProcAddress(hInstance,
+ "GetFileSecurityW");
+ tclWinProcs->impersonateSelfProc = (BOOL (WINAPI *) (
+ SECURITY_IMPERSONATION_LEVEL ImpersonationLevel))
+ GetProcAddress(hInstance, "ImpersonateSelf");
+ tclWinProcs->openThreadTokenProc = (BOOL (WINAPI *) (
+ HANDLE ThreadHandle, DWORD DesiredAccess, BOOL OpenAsSelf,
+ PHANDLE TokenHandle)) GetProcAddress(hInstance,
+ "OpenThreadToken");
+ tclWinProcs->revertToSelfProc = (BOOL (WINAPI *) (void))
+ GetProcAddress(hInstance, "RevertToSelf");
+ tclWinProcs->mapGenericMaskProc = (VOID (WINAPI *) (
+ PDWORD AccessMask, PGENERIC_MAPPING GenericMapping))
+ GetProcAddress(hInstance, "MapGenericMask");
+ tclWinProcs->accessCheckProc = (BOOL (WINAPI *)(
+ PSECURITY_DESCRIPTOR pSecurityDescriptor,
+ HANDLE ClientToken, DWORD DesiredAccess,
+ PGENERIC_MAPPING GenericMapping,
+ PPRIVILEGE_SET PrivilegeSet,
+ LPDWORD PrivilegeSetLength,
+ LPDWORD GrantedAccess,
+ LPBOOL AccessStatus)) GetProcAddress(hInstance,
+ "AccessCheck");
+ FreeLibrary(hInstance);
+ }
}
} else {
tclWinProcs = &asciiProcs;
diff --git a/win/tclWinFCmd.c b/win/tclWinFCmd.c
index 3f2addb..519df62 100644
--- a/win/tclWinFCmd.c
+++ b/win/tclWinFCmd.c
@@ -9,7 +9,7 @@
* See the file "license.terms" for information on usage and redistribution
* of this file, and for a DISCLAIMER OF ALL WARRANTIES.
*
- * RCS: @(#) $Id: tclWinFCmd.c,v 1.36 2003/06/02 15:58:47 vincentdarley Exp $
+ * RCS: @(#) $Id: tclWinFCmd.c,v 1.37 2003/10/13 16:48:07 vincentdarley Exp $
*/
#include "tclWinInt.h"
@@ -862,12 +862,13 @@ TclpObjCopyDirectory(srcPathPtr, destPathPtr, errorPtr)
{
Tcl_DString ds;
Tcl_DString srcString, dstString;
+ Tcl_Obj *normSrcPtr, *normDestPtr;
int ret;
- Tcl_WinUtfToTChar(Tcl_FSGetTranslatedStringPath(NULL,srcPathPtr),
- -1, &srcString);
- Tcl_WinUtfToTChar(Tcl_FSGetTranslatedStringPath(NULL,destPathPtr),
- -1, &dstString);
+ normSrcPtr = Tcl_FSGetNormalizedPath(NULL,srcPathPtr);
+ Tcl_WinUtfToTChar(Tcl_GetString(normSrcPtr), -1, &srcString);
+ normDestPtr = Tcl_FSGetNormalizedPath(NULL,destPathPtr);
+ Tcl_WinUtfToTChar(Tcl_GetString(normDestPtr), -1, &dstString);
ret = TraverseWinTree(TraversalCopy, &srcString, &dstString, &ds);
@@ -875,7 +876,13 @@ TclpObjCopyDirectory(srcPathPtr, destPathPtr, errorPtr)
Tcl_DStringFree(&dstString);
if (ret != TCL_OK) {
- *errorPtr = Tcl_NewStringObj(Tcl_DStringValue(&ds), -1);
+ if (!strcmp(Tcl_DStringValue(&ds), Tcl_GetString(normSrcPtr))) {
+ *errorPtr = srcPathPtr;
+ } else if (!strcmp(Tcl_DStringValue(&ds), Tcl_GetString(normDestPtr))) {
+ *errorPtr = destPathPtr;
+ } else {
+ *errorPtr = Tcl_NewStringObj(Tcl_DStringValue(&ds), -1);
+ }
Tcl_DStringFree(&ds);
Tcl_IncrRefCount(*errorPtr);
}
@@ -918,6 +925,7 @@ TclpObjRemoveDirectory(pathPtr, recursive, errorPtr)
Tcl_Obj **errorPtr;
{
Tcl_DString ds;
+ Tcl_Obj *normPtr = NULL;
int ret;
if (recursive) {
/*
@@ -926,8 +934,8 @@ TclpObjRemoveDirectory(pathPtr, recursive, errorPtr)
* optimize this case easily.
*/
Tcl_DString native;
- Tcl_WinUtfToTChar(Tcl_FSGetTranslatedStringPath(NULL, pathPtr),
- -1, &native);
+ normPtr = Tcl_FSGetNormalizedPath(NULL, pathPtr);
+ Tcl_WinUtfToTChar(Tcl_GetString(normPtr), -1, &native);
ret = DoRemoveDirectory(&native, recursive, &ds);
Tcl_DStringFree(&native);
} else {
@@ -937,7 +945,12 @@ TclpObjRemoveDirectory(pathPtr, recursive, errorPtr)
if (ret != TCL_OK) {
int len = Tcl_DStringLength(&ds);
if (len > 0) {
- *errorPtr = Tcl_NewStringObj(Tcl_DStringValue(&ds), -1);
+ if (normPtr != NULL
+ && !strcmp(Tcl_DStringValue(&ds), Tcl_GetString(normPtr))) {
+ *errorPtr = pathPtr;
+ } else {
+ *errorPtr = Tcl_NewStringObj(Tcl_DStringValue(&ds), -1);
+ }
Tcl_IncrRefCount(*errorPtr);
}
Tcl_DStringFree(&ds);
diff --git a/win/tclWinFile.c b/win/tclWinFile.c
index 8768261..f787669 100644
--- a/win/tclWinFile.c
+++ b/win/tclWinFile.c
@@ -11,7 +11,7 @@
* See the file "license.terms" for information on usage and redistribution
* of this file, and for a DISCLAIMER OF ALL WARRANTIES.
*
- * RCS: @(#) $Id: tclWinFile.c,v 1.54 2003/09/29 22:38:21 dkf Exp $
+ * RCS: @(#) $Id: tclWinFile.c,v 1.55 2003/10/13 16:48:07 vincentdarley Exp $
*/
//#define _WIN32_WINNT 0x0500
@@ -1291,9 +1291,10 @@ TclpGetUserHome(name, bufferPtr)
*/
static int
-NativeAccess(
- CONST TCHAR *nativePath, /* Path of file to access (UTF-8). */
- int mode) /* Permission setting. */
+NativeAccess(nativePath, mode)
+ CONST TCHAR *nativePath; /* Path of file to access, native
+ * encoding. */
+ int mode; /* Permission setting. */
{
DWORD attr;
@@ -1312,26 +1313,151 @@ NativeAccess(
/*
* File is not writable.
*/
-
Tcl_SetErrno(EACCES);
return -1;
}
if (mode & X_OK) {
- if (attr & FILE_ATTRIBUTE_DIRECTORY) {
+ if (!(attr & FILE_ATTRIBUTE_DIRECTORY) && !NativeIsExec(nativePath)) {
/*
- * Directories are always executable.
+ * It's not a directory and doesn't have the correct
+ * extension. Therefore it can't be executable
*/
-
- return 0;
- }
- if (NativeIsExec(nativePath)) {
- return 0;
+ Tcl_SetErrno(EACCES);
+ return -1;
}
- 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) && (tclWinProcs->getFileSecurityProc != NULL)) {
+ SECURITY_DESCRIPTOR *sdPtr = NULL;
+ unsigned long size;
+ GENERIC_MAPPING genMap;
+ HANDLE hToken = NULL;
+ DWORD desiredAccess = 0;
+ DWORD grantedAccess;
+ BOOL accessYesNo;
+ 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) {
+ /*
+ * Most likely case is ERROR_ACCESS_DENIED, which
+ * we will convert to EACCES - just what we want!
+ */
+ TclWinConvertError(error);
+ return -1;
+ }
+
+ /*
+ * Now size contains the size of buffer needed
+ */
+ sdPtr = (SECURITY_DESCRIPTOR *) HeapAlloc(GetProcessHeap(), 0, size);
+
+ if (sdPtr == NULL) {
+ goto accessError;
+ }
+
+ /*
+ * 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)) {
+ /*
+ * Unable to perform security impersonation.
+ */
+ goto accessError;
+ }
+ if (!(*tclWinProcs->openThreadTokenProc)(GetCurrentThread (),
+ TOKEN_DUPLICATE | TOKEN_QUERY, FALSE, &hToken)) {
+ /*
+ * Unable to get current thread's token.
+ */
+ goto accessError;
+ }
+ (*tclWinProcs->revertToSelfProc)();
+ memset (&genMap, 0x00, sizeof (GENERIC_MAPPING));
+ /*
+ * Fill GenericMask type according to access priveleges
+ * we are checking.
+ */
+ genMap.GenericAll = 0;
+ if (mode & R_OK) {
+ genMap.GenericRead = FILE_GENERIC_READ;
+ }
+ if (mode & W_OK) {
+ genMap.GenericWrite = FILE_GENERIC_WRITE;
+ }
+ if (mode & X_OK) {
+ genMap.GenericExecute = FILE_GENERIC_EXECUTE;
+ }
+ (*tclWinProcs->mapGenericMaskProc)(&desiredAccess, &genMap);
+ /*
+ * Perform access check using the token.
+ */
+ if (!(*tclWinProcs->accessCheckProc )(sdPtr, hToken, desiredAccess,
+ &genMap, &privSet, &privSetSize, &grantedAccess,
+ &accessYesNo)) {
+ /*
+ * Unable to perform access check.
+ */
+ accessError:
+ TclWinConvertError(GetLastError());
+ if (sdPtr != NULL) {
+ HeapFree(GetProcessHeap(), 0, sdPtr);
+ }
+ if (hToken != NULL) {
+ CloseHandle(hToken);
+ }
+ return -1;
+ }
+ /*
+ * Clean up.
+ */
+ HeapFree(GetProcessHeap (), 0, sdPtr);
+ CloseHandle(hToken);
+ if (!accessYesNo) {
+ Tcl_SetErrno(EACCES);
+ return -1;
+ }
+ }
return 0;
}
@@ -1582,9 +1708,13 @@ TclpObjStat(pathPtr, statPtr)
transPtr = Tcl_FSGetTranslatedPath(NULL, pathPtr);
if (transPtr == NULL || (strpbrk(Tcl_GetString(transPtr), "?*") != NULL)) {
+ if (transPtr != NULL) {
+ Tcl_DecrRefCount(transPtr);
+ }
Tcl_SetErrno(ENOENT);
return -1;
}
+ Tcl_DecrRefCount(transPtr);
#endif
/*
diff --git a/win/tclWinInt.h b/win/tclWinInt.h
index d953c5b..b2cb74e 100644
--- a/win/tclWinInt.h
+++ b/win/tclWinInt.h
@@ -8,7 +8,7 @@
* See the file "license.terms" for information on usage and redistribution
* of this file, and for a DISCLAIMER OF ALL WARRANTIES.
*
- * RCS: @(#) $Id: tclWinInt.h,v 1.22 2003/04/18 20:17:45 hobbs Exp $
+ * RCS: @(#) $Id: tclWinInt.h,v 1.23 2003/10/13 16:48:07 vincentdarley Exp $
*/
#ifndef _TCLWININT
@@ -111,6 +111,31 @@ typedef struct TclWinProcs {
LPVOID, UINT,
LPVOID, DWORD);
BOOL (WINAPI *getVolumeNameForVMPProc)(CONST TCHAR*, TCHAR*, DWORD);
+ /*
+ * These six are for the security sdk to get correct file
+ * permissions on NT, 2000, XP, etc. On 95,98,ME they are
+ * always null.
+ */
+ BOOL (WINAPI *getFileSecurityProc)(LPCTSTR lpFileName,
+ SECURITY_INFORMATION RequestedInformation,
+ PSECURITY_DESCRIPTOR pSecurityDescriptor,
+ DWORD nLength,
+ LPDWORD lpnLengthNeeded);
+ BOOL (WINAPI *impersonateSelfProc) (SECURITY_IMPERSONATION_LEVEL
+ ImpersonationLevel);
+ BOOL (WINAPI *openThreadTokenProc) (HANDLE ThreadHandle,
+ DWORD DesiredAccess, BOOL OpenAsSelf,
+ PHANDLE TokenHandle);
+ BOOL (WINAPI *revertToSelfProc) (void);
+ VOID (WINAPI *mapGenericMaskProc) (PDWORD AccessMask,
+ PGENERIC_MAPPING GenericMapping);
+ BOOL (WINAPI *accessCheckProc)(PSECURITY_DESCRIPTOR pSecurityDescriptor,
+ HANDLE ClientToken, DWORD DesiredAccess,
+ PGENERIC_MAPPING GenericMapping,
+ PPRIVILEGE_SET PrivilegeSet,
+ LPDWORD PrivilegeSetLength,
+ LPDWORD GrantedAccess,
+ LPBOOL AccessStatus);
} TclWinProcs;
EXTERN TclWinProcs *tclWinProcs;