Tcl Source Code

Artifact [d7fb5977c6]
Login

Artifact d7fb5977c602741ea01c8e6095916f143c0f3420:

Attachment "generic-testTcl.c.diff-u" to ticket [1344540fff] added by jfg118 2006-03-14 06:57:39.
--- ../../tcl8.4.12-src/tcl8.4.12/generic/tclTest.c	2005-10-23 16:01:30.000000000 -0700
+++ generic/tclTest.c	2006-03-13 09:45:39.481224000 -0800
@@ -4018,6 +4018,255 @@
  *---------------------------------------------------------------------------
  */
  
+#ifdef __WIN32__
+#include <aclapi.h>
+#endif
+
+static int Testplaftorm_chmod(const char *nativePath, int pmode)
+{
+#ifdef __WIN32__
+    static const char everyoneBuf[] = "EVERYONE";
+    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;
+
+    BYTE *secDesc = 0;
+    DWORD secDescLen;
+
+    const BOOL set_readOnly = !(pmode & 0222);
+    BOOL acl_readOnly_found = FALSE;
+
+    ACL_SIZE_INFORMATION ACLSize;
+    BOOL curAclPresent, curAclDefaulted;
+    PACL curAcl; 
+    PACL newAcl = 0;
+    DWORD newAclSize;
+
+    WORD j;
+  
+    DWORD userSidLen = 4096;
+    SID *userSid = 0;
+    DWORD userDomainLen = 32;
+    TCHAR *userDomain = 0;
+    SID_NAME_USE userSidUse;
+
+    DWORD attr;
+
+    int res = 0;
+
+    /*
+     * One time initialization, dynamically load Windows NT features
+     */
+    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 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;
+    if (!initialized) {
+        TCL_DECLARE_MUTEX(initialzeMutex)
+        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");
+                if (setNamedSecurityInfoProc && getAceProc
+                  && addAceProc && equalSidProc && addAccessDeniedAceProc
+                  && initializeAclProc && getLengthSidProc
+                  && getAclInformationProc && getSecurityDescriptorDaclProc
+                  && lookupAccountNameProc && getFileSecurityProc)
+                    initialized = 1;
+            }
+            if (!initialized)
+                initialized = -1;
+        }
+        Tcl_MutexUnlock(&intializeMutex);
+    }
+
+    /* Process the chmod request */
+    attr = GetFileAttributes(nativePath);
+
+    /* nativePath not found */
+    if (attr == 0xffffffff) {
+        res = -1;
+        goto done;
+    }
+
+    /* 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;
+
+    /* Set the result to error, if the ACL change is successful it will 
+     *  be reset to 0 
+     */
+    res = -1;
+
+    /*
+     * Read the security descriptor for the directory. Note the
+     * first call obtains the size of the security descriptor.
+     */
+    if (!getFileSecurityProc(nativePath, infoBits, NULL, 0, &secDescLen)) {
+        if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
+            DWORD secDescLen2 = 0;
+            secDesc = (BYTE *) ckalloc(secDescLen);
+            if (!getFileSecurityProc(nativePath, infoBits, secDesc, 
+                                     secDescLen, &secDescLen2) 
+                || (secDescLen < secDescLen2)) {
+                goto done;
+            }
+        } else {
+            goto done;
+        }
+    }
+
+    /* Get the "Everyone" SID */
+    userSid = (SID *) ckalloc(userSidLen);
+    userDomain = (TCHAR *) ckalloc(userDomainLen);
+    if (!lookupAccountNameProc(NULL, everyoneBuf, userSid, &userSidLen, 
+                               userDomain, &userDomainLen, &userSidUse)) {
+        if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
+            ckfree((char *)userSid);
+            userSid = (SID *) ckalloc(userSidLen);
+            ckfree(userDomain);
+            userDomain = (TCHAR *) ckalloc(userDomainLen);
+            if (!lookupAccountNameProc(NULL, everyoneBuf, userSid, 
+              &userSidLen, userDomain, &userDomainLen, &userSidUse))
+                goto done;
+        } else
+            goto done;
+    }
+
+    /* If curAclPresent == false then curAcl and curAclDefaulted not valid */
+    if (!getSecurityDescriptorDaclProc(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;
+
+    /* Allocate memory for the new ACL */
+    newAclSize = ACLSize.AclBytesInUse + sizeof (ACCESS_DENIED_ACE) 
+      + getLengthSidProc(userSid) - sizeof (DWORD);
+    newAcl = (ACL *) ckalloc (newAclSize);
+  
+    /* Initialize the new ACL */
+    if(!initializeAclProc(newAcl, newAclSize, ACL_REVISION))
+        goto done;
+
+    /* Add denied to make readonly, this will be known as a "read-only tag" */
+    if (set_readOnly && !addAccessDeniedAceProc(newAcl, ACL_REVISION, 
+      readOnlyMask, userSid))
+        goto done;
+
+    acl_readOnly_found = FALSE;
+    for (j = 0; j < ACLSize.AceCount; j++) {
+        PACL *pACE2;
+        ACE_HEADER *phACE2;
+        if (! getAceProc (curAcl, j, (LPVOID*) &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, pACE2, 
+          ((PACE_HEADER) pACE2)->AceSize))
+            goto done;
+    }
+
+    /* Apply the new ACL */
+    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 (secDesc)
+        ckfree(secDesc);
+    if (newAcl)
+        ckfree((char *)newAcl);
+    if (userSid)
+        ckfree((char *)userSid);
+    if (userDomain)
+        ckfree(userDomain);
+
+    if (res != 0)
+        return res;
+#endif
+
+    /* Run normal chmod command */
+    return chmod(nativePath, pmode);
+}
+
 static int
 TestchmodCmd(dummy, interp, argc, argv)
     ClientData dummy;			/* Not used. */
@@ -4048,7 +4297,7 @@
         if (translated == NULL) {
             return TCL_ERROR;
         }
-	if (chmod(translated, (unsigned) mode) != 0) {
+	if (Testplaftorm_chmod(translated, (unsigned) mode) != 0) {
 	    Tcl_AppendResult(interp, translated, ": ", Tcl_PosixError(interp),
 		    (char *) NULL);
 	    return TCL_ERROR;