summaryrefslogtreecommitdiffstats
path: root/win/tclWinTest.c
diff options
context:
space:
mode:
Diffstat (limited to 'win/tclWinTest.c')
-rw-r--r--win/tclWinTest.c531
1 files changed, 299 insertions, 232 deletions
diff --git a/win/tclWinTest.c b/win/tclWinTest.c
index ec12f67..e493fbf 100644
--- a/win/tclWinTest.c
+++ b/win/tclWinTest.c
@@ -3,27 +3,20 @@
*
* Contains commands for platform specific tests on Windows.
*
- * Copyright © 1996 Sun Microsystems, Inc.
+ * Copyright (c) 1996 Sun Microsystems, Inc.
*
* See the file "license.terms" for information on usage and redistribution of
* this file, and for a DISCLAIMER OF ALL WARRANTIES.
*/
-#ifndef USE_TCL_STUBS
-# define USE_TCL_STUBS
-#endif
#include "tclInt.h"
-#ifdef TCL_WITH_EXTERNAL_TOMMATH
-# include "tommath.h"
-#else
-# include "tclTomMath.h"
-#endif
/*
* For TestplatformChmod on Windows
*/
+#ifdef __WIN32__
#include <aclapi.h>
-#include <sddl.h>
+#endif
/*
* MinGW 3.4.2 does not define this.
@@ -36,14 +29,20 @@
* Forward declarations of functions defined later in this file:
*/
-static Tcl_ObjCmdProc TesteventloopCmd;
-static Tcl_ObjCmdProc TestvolumetypeCmd;
-static Tcl_ObjCmdProc TestwinclockCmd;
-static Tcl_ObjCmdProc TestwinsleepCmd;
-static Tcl_ObjCmdProc TestSizeCmd;
+int TclplatformtestInit(Tcl_Interp *interp);
+static int TesteventloopCmd(ClientData dummy, Tcl_Interp *interp,
+ int argc, const char **argv);
+static int TestvolumetypeCmd(ClientData dummy,
+ Tcl_Interp *interp, int objc,
+ Tcl_Obj *const objv[]);
+static int TestwinclockCmd(ClientData dummy, Tcl_Interp* interp,
+ int objc, Tcl_Obj *const objv[]);
+static int TestwinsleepCmd(ClientData dummy, Tcl_Interp* interp,
+ int objc, Tcl_Obj *const objv[]);
static Tcl_ObjCmdProc TestExceptionCmd;
static int TestplatformChmod(const char *nativePath, int pmode);
-static Tcl_ObjCmdProc TestchmodCmd;
+static int TestchmodCmd(ClientData dummy,
+ Tcl_Interp *interp, int argc, const char **argv);
/*
*----------------------------------------------------------------------
@@ -70,14 +69,13 @@ TclplatformtestInit(
* Add commands for platform specific tests for Windows here.
*/
- Tcl_CreateObjCommand(interp, "testchmod", TestchmodCmd, NULL, NULL);
- Tcl_CreateObjCommand(interp, "testeventloop", TesteventloopCmd, NULL, NULL);
+ Tcl_CreateCommand(interp, "testchmod", TestchmodCmd, NULL, NULL);
+ Tcl_CreateCommand(interp, "testeventloop", TesteventloopCmd, NULL, NULL);
Tcl_CreateObjCommand(interp, "testvolumetype", TestvolumetypeCmd,
NULL, NULL);
Tcl_CreateObjCommand(interp, "testwinclock", TestwinclockCmd, NULL, NULL);
Tcl_CreateObjCommand(interp, "testwinsleep", TestwinsleepCmd, NULL, NULL);
Tcl_CreateObjCommand(interp, "testexcept", TestExceptionCmd, NULL, NULL);
- Tcl_CreateObjCommand(interp, "testsize", TestSizeCmd, NULL, NULL);
return TCL_OK;
}
@@ -101,22 +99,23 @@ TclplatformtestInit(
static int
TesteventloopCmd(
- TCL_UNUSED(void *),
+ ClientData clientData, /* Not used. */
Tcl_Interp *interp, /* Current interpreter. */
- int objc, /* Number of arguments. */
- Tcl_Obj *const objv[]) /* Argument objects. */
+ int argc, /* Number of arguments. */
+ const char **argv) /* Argument strings. */
{
static int *framePtr = NULL;/* Pointer to integer on stack frame of
* innermost invocation of the "wait"
* subcommand. */
- if (objc < 2) {
- Tcl_WrongNumArgs(interp, 1, objv, "option ...");
+ if (argc < 2) {
+ Tcl_AppendResult(interp, "wrong # arguments: should be \"", argv[0],
+ " option ... \"", NULL);
return TCL_ERROR;
}
- if (strcmp(Tcl_GetString(objv[1]), "done") == 0) {
+ if (strcmp(argv[1], "done") == 0) {
*framePtr = 1;
- } else if (strcmp(Tcl_GetString(objv[1]), "wait") == 0) {
+ } else if (strcmp(argv[1], "wait") == 0) {
int *oldFramePtr, done;
int oldMode = Tcl_SetServiceMode(TCL_SERVICE_ALL);
@@ -136,7 +135,7 @@ TesteventloopCmd(
while (!done) {
MSG msg;
- if (!GetMessageW(&msg, NULL, 0, 0)) {
+ if (!GetMessage(&msg, NULL, 0, 0)) {
/*
* The application is exiting, so repost the quit message and
* start unwinding.
@@ -146,13 +145,13 @@ TesteventloopCmd(
break;
}
TranslateMessage(&msg);
- DispatchMessageW(&msg);
+ DispatchMessage(&msg);
}
(void) Tcl_SetServiceMode(oldMode);
framePtr = oldFramePtr;
} else {
- Tcl_AppendResult(interp, "bad option \"", Tcl_GetString(objv[1]),
- "\": must be done or wait", (char *)NULL);
+ Tcl_AppendResult(interp, "bad option \"", argv[1],
+ "\": must be done or wait", NULL);
return TCL_ERROR;
}
return TCL_OK;
@@ -177,7 +176,7 @@ TesteventloopCmd(
static int
TestvolumetypeCmd(
- TCL_UNUSED(void *),
+ ClientData clientData, /* Not used. */
Tcl_Interp *interp, /* Current interpreter. */
int objc, /* Number of arguments. */
Tcl_Obj *const objv[]) /* Argument objects. */
@@ -185,7 +184,7 @@ TestvolumetypeCmd(
#define VOL_BUF_SIZE 32
int found;
char volType[VOL_BUF_SIZE];
- const char *path;
+ char *path;
if (objc > 2) {
Tcl_WrongNumArgs(interp, 1, objv, "?name?");
@@ -206,11 +205,11 @@ TestvolumetypeCmd(
if (found == 0) {
Tcl_AppendResult(interp, "could not get volume type for \"",
- (path?path:""), "\"", (char *)NULL);
- Tcl_WinConvertError(GetLastError());
+ (path?path:""), "\"", NULL);
+ TclWinConvertError(GetLastError());
return TCL_ERROR;
}
- Tcl_AppendResult(interp, volType, (char *)NULL);
+ Tcl_SetResult(interp, volType, TCL_VOLATILE);
return TCL_OK;
#undef VOL_BUF_SIZE
}
@@ -243,7 +242,7 @@ TestvolumetypeCmd(
static int
TestwinclockCmd(
- TCL_UNUSED(void *),
+ ClientData dummy, /* Unused */
Tcl_Interp* interp, /* Tcl interpreter */
int objc, /* Argument count */
Tcl_Obj *const objv[]) /* Argument vector */
@@ -276,11 +275,11 @@ TestwinclockCmd(
result = Tcl_NewObj();
Tcl_ListObjAppendElement(interp, result,
- Tcl_NewWideIntObj(t2.QuadPart / 10000000));
+ Tcl_NewIntObj((int) (t2.QuadPart / 10000000)));
Tcl_ListObjAppendElement(interp, result,
- Tcl_NewWideIntObj((t2.QuadPart / 10) % 1000000));
- Tcl_ListObjAppendElement(interp, result, Tcl_NewWideIntObj(tclTime.sec));
- Tcl_ListObjAppendElement(interp, result, Tcl_NewWideIntObj(tclTime.usec));
+ Tcl_NewIntObj((int) ((t2.QuadPart / 10) % 1000000)));
+ Tcl_ListObjAppendElement(interp, result, Tcl_NewIntObj(tclTime.sec));
+ Tcl_ListObjAppendElement(interp, result, Tcl_NewIntObj(tclTime.usec));
Tcl_ListObjAppendElement(interp, result, Tcl_NewWideIntObj(p1.QuadPart));
Tcl_ListObjAppendElement(interp, result, Tcl_NewWideIntObj(p2.QuadPart));
@@ -292,7 +291,7 @@ TestwinclockCmd(
static int
TestwinsleepCmd(
- TCL_UNUSED(void *),
+ ClientData clientData, /* Unused */
Tcl_Interp* interp, /* Tcl interpreter */
int objc, /* Parameter count */
Tcl_Obj *const * objv) /* Parameter vector */
@@ -310,28 +309,6 @@ TestwinsleepCmd(
return TCL_OK;
}
-static int
-TestSizeCmd(
- TCL_UNUSED(void *),
- Tcl_Interp* interp, /* Tcl interpreter */
- int objc, /* Parameter count */
- Tcl_Obj *const * objv) /* Parameter vector */
-{
-
- if (objc != 2) {
- goto syntax;
- }
- if (strcmp(Tcl_GetString(objv[1]), "st_mtime") == 0) {
- Tcl_StatBuf *statPtr;
- Tcl_SetObjResult(interp, Tcl_NewWideIntObj(sizeof(statPtr->st_mtime)));
- return TCL_OK;
- }
-
-syntax:
- Tcl_WrongNumArgs(interp, 1, objv, "st_mtime");
- return TCL_ERROR;
-}
-
/*
*----------------------------------------------------------------------
*
@@ -357,12 +334,12 @@ syntax:
static int
TestExceptionCmd(
- TCL_UNUSED(void *),
+ ClientData dummy, /* Unused */
Tcl_Interp* interp, /* Tcl interpreter */
int objc, /* Argument count */
Tcl_Obj *const objv[]) /* Argument vector */
{
- static const char *const cmds[] = {
+ static const char *cmds[] = {
"access_violation", "datatype_misalignment", "array_bounds",
"float_denormal", "float_divbyzero", "float_inexact",
"float_invalidop", "float_overflow", "float_stack", "float_underflow",
@@ -410,225 +387,311 @@ TestExceptionCmd(
/* SMASH! */
RaiseException(exceptions[cmd], EXCEPTION_NONCONTINUABLE, 0, NULL);
+ /* NOTREACHED */
return TCL_OK;
}
-/*
- * This "chmod" works sufficiently for test script purposes. Do not expect
- * it to be exact emulation of Unix chmod (not sure if that's even possible)
- */
static int
TestplatformChmod(
const char *nativePath,
int pmode)
{
+ typedef DWORD (WINAPI *getSidLengthRequiredDef)(UCHAR);
+ typedef BOOL (WINAPI *initializeSidDef)(PSID, PSID_IDENTIFIER_AUTHORITY,
+ BYTE);
+ typedef PDWORD (WINAPI *getSidSubAuthorityDef)(PSID, DWORD);
+ typedef DWORD (WINAPI *setNamedSecurityInfoADef)(IN LPSTR,
+ IN SE_OBJECT_TYPE, IN SECURITY_INFORMATION, IN PSID, IN PSID,
+ IN PACL, IN PACL);
+ typedef BOOL (WINAPI *getAceDef)(PACL, DWORD, LPVOID *);
+ typedef BOOL (WINAPI *addAceDef)(PACL, DWORD, DWORD, LPVOID, DWORD);
+ typedef BOOL (WINAPI *equalSidDef)(PSID, PSID);
+ typedef BOOL (WINAPI *addAccessDeniedAceDef)(PACL, DWORD, DWORD, PSID);
+ typedef BOOL (WINAPI *initializeAclDef)(PACL, DWORD, DWORD);
+ typedef DWORD (WINAPI *getLengthSidDef)(PSID);
+ typedef BOOL (WINAPI *getAclInformationDef)(PACL, LPVOID, DWORD,
+ ACL_INFORMATION_CLASS);
+ typedef BOOL (WINAPI *getSecurityDescriptorDaclDef)(PSECURITY_DESCRIPTOR,
+ LPBOOL, PACL *, LPBOOL);
+ typedef BOOL (WINAPI *lookupAccountNameADef)(LPCSTR, LPCSTR, PSID,
+ PDWORD, LPSTR, LPDWORD, PSID_NAME_USE);
+ typedef BOOL (WINAPI *getFileSecurityADef)(LPCSTR, SECURITY_INFORMATION,
+ PSECURITY_DESCRIPTOR, DWORD, LPDWORD);
+
+ static const SECURITY_INFORMATION infoBits = OWNER_SECURITY_INFORMATION
+ | GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION;
+ static const DWORD readOnlyMask = FILE_DELETE_CHILD | FILE_ADD_FILE
+ | FILE_ADD_SUBDIRECTORY | FILE_WRITE_EA | FILE_APPEND_DATA
+ | FILE_WRITE_DATA | DELETE;
+
/*
- * Note FILE_DELETE_CHILD missing from dirWriteMask because we do
- * not want overriding of child's delete setting when testing
+ * References to security functions (only available on NT and later).
*/
- static const DWORD dirWriteMask =
- FILE_WRITE_ATTRIBUTES | FILE_WRITE_EA |
- FILE_ADD_FILE | FILE_ADD_SUBDIRECTORY | STANDARD_RIGHTS_WRITE | DELETE |
- SYNCHRONIZE;
- static const DWORD dirReadMask =
- FILE_READ_ATTRIBUTES | FILE_READ_EA | FILE_LIST_DIRECTORY |
- STANDARD_RIGHTS_READ | SYNCHRONIZE;
- /* Note - default user privileges allow ignoring TRAVERSE setting */
- static const DWORD dirExecuteMask =
- FILE_TRAVERSE | STANDARD_RIGHTS_READ | SYNCHRONIZE;
-
- static const DWORD fileWriteMask =
- FILE_WRITE_ATTRIBUTES | FILE_WRITE_EA | FILE_WRITE_DATA |
- FILE_APPEND_DATA | STANDARD_RIGHTS_WRITE | DELETE | SYNCHRONIZE;
- static const DWORD fileReadMask =
- FILE_READ_ATTRIBUTES | FILE_READ_EA | FILE_READ_DATA |
- STANDARD_RIGHTS_READ | SYNCHRONIZE;
- static const DWORD fileExecuteMask =
- FILE_EXECUTE | STANDARD_RIGHTS_READ | SYNCHRONIZE;
-
- DWORD attr, newAclSize;
- PACL newAcl = NULL;
+
+ static getSidLengthRequiredDef getSidLengthRequiredProc;
+ static initializeSidDef initializeSidProc;
+ static getSidSubAuthorityDef getSidSubAuthorityProc;
+ static setNamedSecurityInfoADef setNamedSecurityInfoProc;
+ static getAceDef getAceProc;
+ static addAceDef addAceProc;
+ static equalSidDef equalSidProc;
+ static addAccessDeniedAceDef addAccessDeniedAceProc;
+ static initializeAclDef initializeAclProc;
+ static getLengthSidDef getLengthSidProc;
+ static getAclInformationDef getAclInformationProc;
+ static getSecurityDescriptorDaclDef getSecurityDescriptorDaclProc;
+ static lookupAccountNameADef lookupAccountNameProc;
+ static getFileSecurityADef getFileSecurityProc;
+ static int initialized = 0;
+
+ const BOOL set_readOnly = !(pmode & 0222);
+ BOOL acl_readOnly_found = FALSE, curAclPresent, curAclDefaulted;
+ SID_IDENTIFIER_AUTHORITY userSidAuthority = {
+ SECURITY_WORLD_SID_AUTHORITY
+ };
+ BYTE *secDesc = 0;
+ DWORD secDescLen, attr, newAclSize;
+ ACL_SIZE_INFORMATION ACLSize;
+ PACL curAcl, newAcl = 0;
+ WORD j;
+ SID *userSid = 0;
+ TCHAR *userDomain = 0;
int res = 0;
- HANDLE hToken = NULL;
- int i;
- int nSids = 0;
- struct {
- PSID pSid;
- DWORD mask;
- DWORD sidLen;
- } aceEntry[3];
- DWORD dw;
- int isDir;
- TOKEN_USER *pTokenUser = NULL;
-
- res = -1; /* Assume failure */
-
- attr = GetFileAttributesA(nativePath);
- if (attr == 0xFFFFFFFF) {
- goto done; /* Not found */
+ /*
+ * One time initialization, dynamically load Windows NT features
+ */
+
+ if (!initialized) {
+ TCL_DECLARE_MUTEX(initializeMutex)
+ Tcl_MutexLock(&initializeMutex);
+ if (!initialized) {
+ HINSTANCE hInstance = LoadLibrary("Advapi32");
+
+ if (hInstance != NULL) {
+ setNamedSecurityInfoProc = (setNamedSecurityInfoADef)
+ GetProcAddress(hInstance, "SetNamedSecurityInfoA");
+ getFileSecurityProc = (getFileSecurityADef)
+ GetProcAddress(hInstance, "GetFileSecurityA");
+ getAceProc = (getAceDef)
+ GetProcAddress(hInstance, "GetAce");
+ addAceProc = (addAceDef)
+ GetProcAddress(hInstance, "AddAce");
+ equalSidProc = (equalSidDef)
+ GetProcAddress(hInstance, "EqualSid");
+ addAccessDeniedAceProc = (addAccessDeniedAceDef)
+ GetProcAddress(hInstance, "AddAccessDeniedAce");
+ initializeAclProc = (initializeAclDef)
+ GetProcAddress(hInstance, "InitializeAcl");
+ getLengthSidProc = (getLengthSidDef)
+ GetProcAddress(hInstance, "GetLengthSid");
+ getAclInformationProc = (getAclInformationDef)
+ GetProcAddress(hInstance, "GetAclInformation");
+ getSecurityDescriptorDaclProc = (getSecurityDescriptorDaclDef)
+ GetProcAddress(hInstance, "GetSecurityDescriptorDacl");
+ lookupAccountNameProc = (lookupAccountNameADef)
+ GetProcAddress(hInstance, "LookupAccountNameA");
+ getSidLengthRequiredProc = (getSidLengthRequiredDef)
+ GetProcAddress(hInstance, "GetSidLengthRequired");
+ initializeSidProc = (initializeSidDef)
+ GetProcAddress(hInstance, "InitializeSid");
+ getSidSubAuthorityProc = (getSidSubAuthorityDef)
+ GetProcAddress(hInstance, "GetSidSubAuthority");
+
+ if (setNamedSecurityInfoProc && getAceProc && addAceProc
+ && equalSidProc && addAccessDeniedAceProc
+ && initializeAclProc && getLengthSidProc
+ && getAclInformationProc
+ && getSecurityDescriptorDaclProc
+ && lookupAccountNameProc && getFileSecurityProc
+ && getSidLengthRequiredProc && initializeSidProc
+ && getSidSubAuthorityProc) {
+ initialized = 1;
+ }
+ }
+ if (!initialized) {
+ initialized = -1;
+ }
+ }
+ Tcl_MutexUnlock(&initializeMutex);
}
- isDir = (attr & FILE_ATTRIBUTE_DIRECTORY) != 0;
+ /*
+ * Process the chmod request.
+ */
- if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken)) {
- goto done;
- }
+ attr = GetFileAttributes(nativePath);
- /* Get process SID */
- if (!GetTokenInformation(hToken, TokenUser, NULL, 0, &dw)
- && GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
- goto done;
- }
- pTokenUser = (TOKEN_USER *)ckalloc(dw);
- if (!GetTokenInformation(hToken, TokenUser, pTokenUser, dw, &dw)) {
+ /*
+ * nativePath not found
+ */
+
+ if (attr == 0xffffffff) {
+ res = -1;
goto done;
}
- aceEntry[nSids].sidLen = GetLengthSid(pTokenUser->User.Sid);
- aceEntry[nSids].pSid = ckalloc(aceEntry[nSids].sidLen);
- if (!CopySid(aceEntry[nSids].sidLen, aceEntry[nSids].pSid,
- pTokenUser->User.Sid)) {
- ckfree(aceEntry[nSids].pSid); /* Since we have not ++'ed nSids */
+
+ /*
+ * If no ACL API is present or nativePath is not a directory, there is no
+ * special handling.
+ */
+
+ if (initialized < 0 || !(attr & FILE_ATTRIBUTE_DIRECTORY)) {
goto done;
}
+
/*
- * Always include DACL modify rights so we don't get locked out
+ * Set the result to error, if the ACL change is successful it will be
+ * reset to 0.
*/
- aceEntry[nSids].mask = READ_CONTROL | WRITE_DAC | WRITE_OWNER | SYNCHRONIZE |
- FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES;
- if (pmode & 0700) {
- /* Owner permissions. Assumes current process is owner */
- if (pmode & 0400) {
- aceEntry[nSids].mask |= isDir ? dirReadMask : fileReadMask;
- }
- if (pmode & 0200) {
- aceEntry[nSids].mask |= isDir ? dirWriteMask : fileWriteMask;
- }
- if (pmode & 0100) {
- aceEntry[nSids].mask |= isDir ? dirExecuteMask : fileExecuteMask;
- }
- }
- ++nSids;
- if (pmode & 0070) {
- /* Group permissions. */
+ res = -1;
- TOKEN_PRIMARY_GROUP *pTokenGroup;
+ /*
+ * Read the security descriptor for the directory. Note the first call
+ * obtains the size of the security descriptor.
+ */
- /* Get primary group SID */
- if (!GetTokenInformation(
- hToken, TokenPrimaryGroup, NULL, 0, &dw) &&
- GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
- goto done;
- }
- pTokenGroup = (TOKEN_PRIMARY_GROUP *)ckalloc(dw);
- if (!GetTokenInformation(hToken, TokenPrimaryGroup, pTokenGroup, dw, &dw)) {
- ckfree(pTokenGroup);
+ if (!getFileSecurityProc(nativePath, infoBits, NULL, 0, &secDescLen)) {
+ DWORD secDescLen2 = 0;
+
+ if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
goto done;
}
- aceEntry[nSids].sidLen = GetLengthSid(pTokenGroup->PrimaryGroup);
- aceEntry[nSids].pSid = ckalloc(aceEntry[nSids].sidLen);
- if (!CopySid(aceEntry[nSids].sidLen, aceEntry[nSids].pSid, pTokenGroup->PrimaryGroup)) {
- ckfree(pTokenGroup);
- ckfree(aceEntry[nSids].pSid); /* Since we have not ++'ed nSids */
+
+ secDesc = (BYTE *) ckalloc(secDescLen);
+ if (!getFileSecurityProc(nativePath, infoBits,
+ (PSECURITY_DESCRIPTOR) secDesc, secDescLen, &secDescLen2)
+ || (secDescLen < secDescLen2)) {
goto done;
}
- ckfree(pTokenGroup);
+ }
- /* Generate mask for group ACL */
+ /*
+ * Get the World SID.
+ */
- aceEntry[nSids].mask = 0;
- if (pmode & 0040) {
- aceEntry[nSids].mask |= isDir ? dirReadMask : fileReadMask;
- }
- if (pmode & 0020) {
- aceEntry[nSids].mask |= isDir ? dirWriteMask : fileWriteMask;
- }
- if (pmode & 0010) {
- aceEntry[nSids].mask |= isDir ? dirExecuteMask : fileExecuteMask;
- }
- ++nSids;
+ userSid = (SID *) ckalloc(getSidLengthRequiredProc((UCHAR) 1));
+ initializeSidProc(userSid, &userSidAuthority, (BYTE) 1);
+ *(getSidSubAuthorityProc(userSid, 0)) = SECURITY_WORLD_RID;
+
+ /*
+ * If curAclPresent == false then curAcl and curAclDefaulted not valid.
+ */
+
+ if (!getSecurityDescriptorDaclProc((PSECURITY_DESCRIPTOR) secDesc,
+ &curAclPresent, &curAcl, &curAclDefaulted)) {
+ goto done;
+ }
+ if (!curAclPresent || !curAcl) {
+ ACLSize.AclBytesInUse = 0;
+ ACLSize.AceCount = 0;
+ } else if (!getAclInformationProc(curAcl, &ACLSize, sizeof(ACLSize),
+ AclSizeInformation)) {
+ goto done;
}
- if (pmode & 0007) {
- /* World permissions */
- PSID pWorldSid;
- if (!ConvertStringSidToSidA("S-1-1-0", &pWorldSid)) {
- goto done;
- }
- aceEntry[nSids].sidLen = GetLengthSid(pWorldSid);
- aceEntry[nSids].pSid = ckalloc(aceEntry[nSids].sidLen);
- if (!CopySid(aceEntry[nSids].sidLen, aceEntry[nSids].pSid, pWorldSid)) {
- LocalFree(pWorldSid);
- ckfree(aceEntry[nSids].pSid); /* Since we have not ++'ed nSids */
- goto done;
- }
- LocalFree(pWorldSid);
+ /*
+ * Allocate memory for the new ACL.
+ */
- /* Generate mask for world ACL */
+ newAclSize = ACLSize.AclBytesInUse + sizeof(ACCESS_DENIED_ACE)
+ + getLengthSidProc(userSid) - sizeof(DWORD);
+ newAcl = (ACL *) ckalloc(newAclSize);
- aceEntry[nSids].mask = 0;
- if (pmode & 0004) {
- aceEntry[nSids].mask |= isDir ? dirReadMask : fileReadMask;
- }
- if (pmode & 0002) {
- aceEntry[nSids].mask |= isDir ? dirWriteMask : fileWriteMask;
- }
- if (pmode & 0001) {
- aceEntry[nSids].mask |= isDir ? dirExecuteMask : fileExecuteMask;
- }
- ++nSids;
+ /*
+ * Initialize the new ACL.
+ */
+
+ if (!initializeAclProc(newAcl, newAclSize, ACL_REVISION)) {
+ goto done;
}
- /* Allocate memory and initialize the new ACL. */
+ /*
+ * Add denied to make readonly, this will be known as a "read-only tag".
+ */
- newAclSize = sizeof(ACL);
- /* Add in size required for each ACE entry in the ACL */
- for (i = 0; i < nSids; ++i) {
- newAclSize +=
- offsetof(ACCESS_ALLOWED_ACE, SidStart) + aceEntry[i].sidLen;
- }
- newAcl = (PACL)ckalloc(newAclSize);
- if (!InitializeAcl(newAcl, newAclSize, ACL_REVISION)) {
+ if (set_readOnly && !addAccessDeniedAceProc(newAcl, ACL_REVISION,
+ readOnlyMask, userSid)) {
goto done;
}
- for (i = 0; i < nSids; ++i) {
- if (!AddAccessAllowedAce(newAcl, ACL_REVISION, aceEntry[i].mask, aceEntry[i].pSid)) {
+ acl_readOnly_found = FALSE;
+ for (j = 0; j < ACLSize.AceCount; j++) {
+ LPVOID pACE2;
+ ACE_HEADER *phACE2;
+
+ if (!getAceProc(curAcl, j, &pACE2)) {
+ goto done;
+ }
+
+ phACE2 = (ACE_HEADER *) pACE2;
+
+ /*
+ * Do NOT propagate inherited ACEs.
+ */
+
+ if (phACE2->AceFlags & INHERITED_ACE) {
+ continue;
+ }
+
+ /*
+ * Skip the "read-only tag" restriction (either added above, or it is
+ * being removed).
+ */
+
+ if (phACE2->AceType == ACCESS_DENIED_ACE_TYPE) {
+ ACCESS_DENIED_ACE *pACEd = (ACCESS_DENIED_ACE *) phACE2;
+
+ if (pACEd->Mask == readOnlyMask
+ && equalSidProc(userSid, (PSID) &pACEd->SidStart)) {
+ acl_readOnly_found = TRUE;
+ continue;
+ }
+ }
+
+ /*
+ * Copy the current ACE from the old to the new ACL.
+ */
+
+ if (!addAceProc(newAcl, ACL_REVISION, MAXDWORD, (PACL *)pACE2,
+ ((PACE_HEADER) pACE2)->AceSize)) {
goto done;
}
}
/*
- * Apply the new ACL. Note PROTECTED_DACL_SECURITY_INFORMATION can be used
- * to remove inherited ACL (we need to overwrite the default ACL's in this case)
+ * Apply the new ACL.
*/
- if (SetNamedSecurityInfoA((LPSTR)nativePath, SE_FILE_OBJECT,
- DACL_SECURITY_INFORMATION | PROTECTED_DACL_SECURITY_INFORMATION,
+ if (set_readOnly == acl_readOnly_found || setNamedSecurityInfoProc(
+ (LPSTR) nativePath, SE_FILE_OBJECT, DACL_SECURITY_INFORMATION,
NULL, NULL, newAcl, NULL) == ERROR_SUCCESS) {
res = 0;
}
done:
- if (pTokenUser) {
- ckfree(pTokenUser);
- }
- if (hToken) {
- CloseHandle(hToken);
+ if (secDesc) {
+ ckfree((char *) secDesc);
}
if (newAcl) {
- ckfree(newAcl);
+ ckfree((char *) newAcl);
+ }
+ if (userSid) {
+ ckfree((char *) userSid);
}
- for (i = 0; i < nSids; ++i) {
- ckfree(aceEntry[i].pSid);
+ if (userDomain) {
+ ckfree(userDomain);
}
if (res != 0) {
return res;
}
- /* Run normal chmod command */
+ /*
+ * Run normal chmod command.
+ */
+
return chmod(nativePath, pmode);
}
@@ -653,33 +716,37 @@ TestplatformChmod(
static int
TestchmodCmd(
- TCL_UNUSED(void *),
+ ClientData dummy, /* Not used. */
Tcl_Interp *interp, /* Current interpreter. */
- int objc, /* Parameter count */
- Tcl_Obj *const * objv) /* Parameter vector */
+ int argc, /* Number of arguments. */
+ const char **argv) /* Argument strings. */
{
int i, mode;
+ char *rest;
- if (objc < 2) {
- Tcl_WrongNumArgs(interp, 1, objv, "mode file ?file ...?");
+ if (argc < 2) {
+ usage:
+ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
+ " mode file ?file ...?", NULL);
return TCL_ERROR;
}
- if (Tcl_GetIntFromObj(interp, objv[1], &mode) != TCL_OK) {
- return TCL_ERROR;
+ mode = (int) strtol(argv[1], &rest, 8);
+ if ((rest == argv[1]) || (*rest != '\0')) {
+ goto usage;
}
- for (i = 2; i < objc; i++) {
+ for (i = 2; i < argc; i++) {
Tcl_DString buffer;
const char *translated;
- translated = Tcl_TranslateFileName(interp, Tcl_GetString(objv[i]), &buffer);
+ translated = Tcl_TranslateFileName(interp, argv[i], &buffer);
if (translated == NULL) {
return TCL_ERROR;
}
if (TestplatformChmod(translated, mode) != 0) {
Tcl_AppendResult(interp, translated, ": ", Tcl_PosixError(interp),
- (char *)NULL);
+ NULL);
return TCL_ERROR;
}
Tcl_DStringFree(&buffer);