HRESULT COpcSecurity::AttachObject(HANDLE hObject) { HRESULT hr; DWORD dwSize = 0; PSECURITY_DESCRIPTOR pSD = NULL; GetKernelObjectSecurity(hObject, OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION, pSD, 0, &dwSize); hr = GetLastError(); if (hr != ERROR_INSUFFICIENT_BUFFER) return HRESULT_FROM_WIN32(hr); pSD = (PSECURITY_DESCRIPTOR) malloc(dwSize); if (pSD == NULL) return E_OUTOFMEMORY; if (!GetKernelObjectSecurity(hObject, OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION, pSD, dwSize, &dwSize)) { hr = HRESULT_FROM_WIN32(GetLastError()); free(pSD); return hr; } hr = Attach(pSD); free(pSD); return hr; }
static VOID GetRemotePrivilegesGet(char *FileName, PDWORD dwRemotePrivileges) { HANDLE hFile; *dwRemotePrivileges = 0; /* see if we have the SeBackupPrivilege */ hFile = CreateFileA( FileName, ACCESS_SYSTEM_SECURITY | GENERIC_READ | READ_CONTROL, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL ); if(hFile != INVALID_HANDLE_VALUE) { /* no remote way to determine SeBackupPrivilege -- just try a read to simulate it */ SECURITY_INFORMATION si = DACL_SECURITY_INFORMATION | SACL_SECURITY_INFORMATION; PSECURITY_DESCRIPTOR sd; DWORD cbBuf = 0; GetKernelObjectSecurity(hFile, si, NULL, cbBuf, &cbBuf); if(ERROR_INSUFFICIENT_BUFFER == GetLastError()) { if((sd = HeapAlloc(GetProcessHeap(), 0, cbBuf)) != NULL) { if(GetKernelObjectSecurity(hFile, si, sd, cbBuf, &cbBuf)) { *dwRemotePrivileges |= OVERRIDE_BACKUP; } HeapFree(GetProcessHeap(), 0, sd); } } CloseHandle(hFile); } else { /* see if we have the SeSecurityPrivilege */ /* note we don't need this if we have SeBackupPrivilege */ hFile = CreateFileA( FileName, ACCESS_SYSTEM_SECURITY, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, /* maximum sharing */ NULL, OPEN_EXISTING, 0, NULL ); if(hFile != INVALID_HANDLE_VALUE) { CloseHandle(hFile); *dwRemotePrivileges |= OVERRIDE_SACL; } } }
static NTSTATUS GetSecurityByName(FSP_FILE_SYSTEM *FileSystem, PWSTR FileName, PUINT32 PFileAttributes, PSECURITY_DESCRIPTOR SecurityDescriptor, SIZE_T *PSecurityDescriptorSize) { PTFS *Ptfs = (PTFS *)FileSystem->UserContext; WCHAR FullPath[FULLPATH_SIZE]; HANDLE Handle; FILE_ATTRIBUTE_TAG_INFO AttributeTagInfo; DWORD SecurityDescriptorSizeNeeded; NTSTATUS Result; if (!ConcatPath(Ptfs, FileName, FullPath)) return STATUS_OBJECT_NAME_INVALID; Handle = CreateFileW(FullPath, FILE_READ_ATTRIBUTES | READ_CONTROL, 0, 0, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0); if (INVALID_HANDLE_VALUE == Handle) { Result = FspNtStatusFromWin32(GetLastError()); goto exit; } if (0 != PFileAttributes) { if (!GetFileInformationByHandleEx(Handle, FileAttributeTagInfo, &AttributeTagInfo, sizeof AttributeTagInfo)) { Result = FspNtStatusFromWin32(GetLastError()); goto exit; } *PFileAttributes = AttributeTagInfo.FileAttributes; } if (0 != PSecurityDescriptorSize) { if (!GetKernelObjectSecurity(Handle, OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION, SecurityDescriptor, (DWORD)*PSecurityDescriptorSize, &SecurityDescriptorSizeNeeded)) { *PSecurityDescriptorSize = SecurityDescriptorSizeNeeded; Result = FspNtStatusFromWin32(GetLastError()); goto exit; } *PSecurityDescriptorSize = SecurityDescriptorSizeNeeded; } Result = STATUS_SUCCESS; exit: if (INVALID_HANDLE_VALUE != Handle) CloseHandle(Handle); return Result; }
static NTSTATUS GetSecurity(FSP_FILE_SYSTEM *FileSystem, PVOID FileContext, PSECURITY_DESCRIPTOR SecurityDescriptor, SIZE_T *PSecurityDescriptorSize) { HANDLE Handle = HandleFromContext(FileContext); DWORD SecurityDescriptorSizeNeeded; if (!GetKernelObjectSecurity(Handle, OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION, SecurityDescriptor, (DWORD)*PSecurityDescriptorSize, &SecurityDescriptorSizeNeeded)) { *PSecurityDescriptorSize = SecurityDescriptorSizeNeeded; return FspNtStatusFromWin32(GetLastError()); } *PSecurityDescriptorSize = SecurityDescriptorSizeNeeded; return STATUS_SUCCESS; }
// https://ru.wikipedia.org/wiki/DACL + https://github.com/hfiref0x/WinObjEx64/tree/master/Source BOOL AddAllowSidForDevice(PWCHAR wchPath, PSID lpSid, DWORD dwSidLength) { OBJECT_ATTRIBUTES ObjAtt; RtlZeroMemory(&ObjAtt, sizeof(ObjAtt)); UNICODE_STRING UserModeDeviceName; WCHAR PathBuffer[MAX_PATH] = { 0 }; wcscpy_s(PathBuffer, L"\\??\\"); wcscat_s(PathBuffer, wchPath); UserModeDeviceName.Buffer = PathBuffer; UserModeDeviceName.Length = (USHORT)(wcslen(PathBuffer) * sizeof(WCHAR)); UserModeDeviceName.MaximumLength = (USHORT)(UserModeDeviceName.Length + sizeof(WCHAR)); InitializeObjectAttributes(&ObjAtt, &UserModeDeviceName, 0, 0, 0); HANDLE hFile; IO_STATUS_BLOCK IoStatusBlock; NTSTATUS status = ntdll_ZwOpenFile(&hFile, WRITE_DAC | READ_CONTROL, &ObjAtt, &IoStatusBlock, 0, 0); if (status != STATUS_SUCCESS) { DebugOut("ZwOpenFile(..., %S,...) failed! (status=%x)\n", wchPath, status); return FALSE; } DWORD LastError; SECURITY_DESCRIPTOR *lpSd = NULL; // адрес дескриптора безопасности DWORD dwSdLength = 0; // длина SD if (!GetKernelObjectSecurity(hFile, DACL_SECURITY_INFORMATION, NULL, dwSdLength, &dwSdLength)) { LastError = GetLastError(); if (LastError == ERROR_INSUFFICIENT_BUFFER) { dwSdLength += 1000; // !! FIX_ME lpSd = (SECURITY_DESCRIPTOR*)malloc(dwSdLength); if (!GetKernelObjectSecurity(hFile, DACL_SECURITY_INFORMATION, lpSd, dwSdLength, &dwSdLength)) { DebugOut("GetKernelObjectSecurity[2](...) failed! (LastError=0x%x)\n", GetLastError()); CloseHandle(hFile); return FALSE; } } else { DebugOut("GetKernelObjectSecurity[1](...) failed! (LastError=0x%x)\n", LastError); CloseHandle(hFile); return FALSE; } } ACL* lpOldDacl; // указатель на старый DACL BOOL bDaclPresent; // признак присутствия списка DACL BOOL bDaclDefaulted; // признак списка DACL по умолчанию if (!GetSecurityDescriptorDacl(lpSd, &bDaclPresent, &lpOldDacl, &bDaclDefaulted)) { // получаем список DACL из дескриптора безопасности DebugOut("GetSecurityDescriptorDacl(...) failed! (LastError=0x%x)\n", GetLastError()); CloseHandle(hFile); return FALSE; } DWORD dwDaclLength = lpOldDacl->AclSize + sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD) + dwSidLength; // определяем длину нового DACL ACL* lpNewDacl = (ACL*)malloc(dwDaclLength); if (!InitializeAcl(lpNewDacl, dwDaclLength, ACL_REVISION)) { // инициализируем новый DACL DebugOut("InitializeAcl(...) failed! (LastError=0x%x)\n", GetLastError()); free(lpNewDacl); CloseHandle(hFile); return FALSE; } if (!AddAccessAllowedAce(lpNewDacl, ACL_REVISION,ACCOUNT_ALLOW_RIGHTS, lpSid)) { // добавляем новый элемент в новый DACL DebugOut("AddAccessAllowedAce(...) failed! (LastError=0x%x)\n", GetLastError()); free(lpNewDacl); CloseHandle(hFile); return FALSE; } LPVOID lpAce; // указатель на элемент ACE if (!GetAce(lpOldDacl, 0, &lpAce)) { // получаем адрес первого ACE в старом списке DACL DebugOut("GetAce(...) failed! (LastError=0x%x)\n", GetLastError()); free(lpNewDacl); CloseHandle(hFile); return FALSE; } // переписываем элементы из старого DACL в новый DACL if (bDaclPresent) { if (!AddAce(lpNewDacl, ACL_REVISION, MAXDWORD, lpAce, lpOldDacl->AclSize - sizeof(ACL))) { DebugOut("AddAce(...) failed! (LastError=0x%x)\n", GetLastError()); free(lpNewDacl); CloseHandle(hFile); return FALSE; } } if (!IsValidAcl(lpNewDacl)) { // проверяем достоверность DACL DebugOut("IsValidAcl(...) == FALSE! (LastError=0x%x)\n", GetLastError()); free(lpNewDacl); CloseHandle(hFile); return FALSE; } SECURITY_DESCRIPTOR sdAbsoluteSd; // абсолютный формат SD if (!InitializeSecurityDescriptor(&sdAbsoluteSd, SECURITY_DESCRIPTOR_REVISION)) { // создаем новый дескриптор безопасности в абсолютной форме DebugOut("InitializeSecurityDescriptor(...) failed! (LastError=0x%x)\n", GetLastError()); free(lpNewDacl); CloseHandle(hFile); return FALSE; } if (!SetSecurityDescriptorDacl(&sdAbsoluteSd, TRUE, lpNewDacl, FALSE)) { // устанавливаем DACL в новый дескриптор безопасности DebugOut("SetSecurityDescriptorDacl(...) failed! (LastError=0x%x)\n", GetLastError()); free(lpNewDacl); CloseHandle(hFile); return FALSE; } // проверяем структуру дескриптора безопасности if (!IsValidSecurityDescriptor(&sdAbsoluteSd)) { DebugOut("IsValidSecurityDescriptor(...) == FALSE! (LastError=0x%x)\n", GetLastError()); free(lpNewDacl); CloseHandle(hFile); return FALSE; } if (!SetKernelObjectSecurity(hFile, DACL_SECURITY_INFORMATION, &sdAbsoluteSd)) { // устанавливаем новый дескриптор безопасности DebugOut("IsValidSecurityDescriptor(...) == FALSE! (LastError=0x%x)\n", GetLastError()); free(lpNewDacl); CloseHandle(hFile); return FALSE; } free(lpNewDacl); CloseHandle(hFile); DebugOut("ACL Rules applyed to \"%S\"\n", PathBuffer); return TRUE; }
static VOID Test(PWSTR Prefix) { static PWSTR Sddl = L"D:P(A;;GA;;;SY)(A;;GA;;;BA)(A;;GA;;;WD)"; static const GUID ReparseGuid = { 0x2cf25cfa, 0x41af, 0x4796, { 0xb5, 0xef, 0xac, 0xa3, 0x85, 0x3, 0xe2, 0xd8 } }; WCHAR FileName[1024], VolumeName[MAX_PATH]; PSECURITY_DESCRIPTOR SecurityDescriptor; HANDLE Handle; BOOL Success; UINT8 RdBuffer[4096], WrBuffer[4096]; REPARSE_GUID_DATA_BUFFER ReparseDataBuf; DWORD BytesTransferred, Offset; WIN32_FIND_DATAW FindData; WIN32_FIND_STREAM_DATA FindStreamData; memset(WrBuffer, 'B', sizeof WrBuffer); Success = ConvertStringSecurityDescriptorToSecurityDescriptorW( Sddl, SDDL_REVISION_1, &SecurityDescriptor, 0); ASSERT(Success); wsprintfW(FileName, L"%s\\", Prefix); Success = GetVolumeInformationW(FileName, VolumeName, MAX_PATH, 0, 0, 0, 0, 0); ASSERT(Success); wsprintfW(FileName, L"%s\\", Prefix); Success = SetVolumeLabelW(FileName, VolumeName); //ASSERT(Success); wsprintfW(FileName, L"%s\\fscrash", Prefix); Success = CreateDirectoryW(FileName, 0); ASSERT(Success); wsprintfW(FileName, L"%s\\fscrash\\file0", Prefix); Handle = CreateFileW(FileName, GENERIC_ALL, 0, 0, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0); ASSERT(INVALID_HANDLE_VALUE != Handle); Success = CloseHandle(Handle); ASSERT(Success); wsprintfW(FileName, L"%s\\fscrash\\file0", Prefix); Handle = CreateFileW(FileName, GENERIC_ALL, 0, 0, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0); ASSERT(INVALID_HANDLE_VALUE != Handle); Success = WriteFile(Handle, WrBuffer, sizeof WrBuffer, &BytesTransferred, 0); ASSERT(Success); ASSERT(sizeof WrBuffer == BytesTransferred); Success = FlushFileBuffers(Handle); ASSERT(Success); Offset = SetFilePointer(Handle, 0, 0, FILE_BEGIN); ASSERT(0 == Offset); Success = ReadFile(Handle, RdBuffer, sizeof RdBuffer, &BytesTransferred, 0); ASSERT(Success); ASSERT(sizeof WrBuffer == BytesTransferred); Offset = SetFilePointer(Handle, 0, 0, FILE_BEGIN); ASSERT(0 == Offset); Success = SetEndOfFile(Handle); ASSERT(Success); Offset = GetFileSize(Handle, 0); ASSERT(0 == Offset); Success = LockFile(Handle, 0, 0, 1, 0); ASSERT(Success); Success = UnlockFile(Handle, 0, 0, 1, 0); ASSERT(Success); Success = SetKernelObjectSecurity(Handle, DACL_SECURITY_INFORMATION, SecurityDescriptor); ASSERT(Success); Success = GetKernelObjectSecurity(Handle, DACL_SECURITY_INFORMATION, 0, 0, &BytesTransferred); ASSERT(!Success); ASSERT(ERROR_INSUFFICIENT_BUFFER == GetLastError()); ReparseDataBuf.ReparseTag = 0x1234; ReparseDataBuf.ReparseDataLength = 0; ReparseDataBuf.Reserved = 0; memcpy(&ReparseDataBuf.ReparseGuid, &ReparseGuid, sizeof ReparseGuid); Success = DeviceIoControl(Handle, FSCTL_SET_REPARSE_POINT, &ReparseDataBuf, REPARSE_GUID_DATA_BUFFER_HEADER_SIZE + ReparseDataBuf.ReparseDataLength, 0, 0, &BytesTransferred, 0); ASSERT(Success); Success = CloseHandle(Handle); ASSERT(Success); wsprintfW(FileName, L"%s\\fscrash\\*", Prefix); Handle = FindFirstFileW(FileName, &FindData); ASSERT(INVALID_HANDLE_VALUE != Handle); do { } while (FindNextFileW(Handle, &FindData)); ASSERT(ERROR_NO_MORE_FILES == GetLastError()); Success = FindClose(Handle); ASSERT(Success); wsprintfW(FileName, L"%s\\fscrash\\file0", Prefix); Handle = FindFirstStreamW(FileName, FindStreamInfoStandard, &FindStreamData, 0); ASSERT(INVALID_HANDLE_VALUE != Handle); do { } while (FindNextStreamW(Handle, &FindStreamData)); ASSERT(ERROR_HANDLE_EOF == GetLastError()); Success = FindClose(Handle); ASSERT(Success); wsprintfW(FileName, L"%s\\fscrash\\file0", Prefix); Success = DeleteFileW(FileName); ASSERT(Success); wsprintfW(FileName, L"%s\\fscrash", Prefix); Success = RemoveDirectoryW(FileName); ASSERT(Success); LocalFree(SecurityDescriptor); }
BOOL SecurityGet( char *resource, PVOLUMECAPS VolumeCaps, unsigned char *buffer, DWORD *cbBuffer ) { HANDLE hFile; DWORD dwDesiredAccess; DWORD dwFlags; PSECURITY_DESCRIPTOR sd = (PSECURITY_DESCRIPTOR)buffer; SECURITY_INFORMATION RequestedInfo; BOOL bBackupPrivilege = FALSE; BOOL bSaclPrivilege = FALSE; BOOL bSuccess = FALSE; DWORD cchResourceLen; if(!bZipInitialized) if(!Initialize()) return FALSE; /* see if we are dealing with a directory */ /* rely on the fact resource has a trailing [back]slash, rather than calling expensive GetFileAttributes() */ cchResourceLen = lstrlenA(resource); if(resource[cchResourceLen-1] == '/' || resource[cchResourceLen-1] == '\\') VolumeCaps->dwFileAttributes |= FILE_ATTRIBUTE_DIRECTORY; /* setup privilege usage based on if told we can use privileges, and if so, what privileges we have */ if(VolumeCaps->bUsePrivileges) { if(VolumeCaps->bRemote) { /* use remotely determined privileges */ if(VolumeCaps->dwRemotePrivileges & OVERRIDE_BACKUP) bBackupPrivilege = TRUE; if(VolumeCaps->dwRemotePrivileges & OVERRIDE_SACL) bSaclPrivilege = TRUE; } else { /* use local privileges */ bBackupPrivilege = g_bBackupPrivilege; bSaclPrivilege = g_bZipSaclPrivilege; } } /* always try to read the basic security information: Dacl, Owner, Group */ dwDesiredAccess = READ_CONTROL; RequestedInfo = OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION; /* if we have the SeBackupPrivilege or SeSystemSecurityPrivilege, read the Sacl, too */ if(bBackupPrivilege || bSaclPrivilege) { dwDesiredAccess |= ACCESS_SYSTEM_SECURITY; RequestedInfo |= SACL_SECURITY_INFORMATION; } dwFlags = 0; /* if we have the backup privilege, specify that */ /* opening a directory requires FILE_FLAG_BACKUP_SEMANTICS */ if(bBackupPrivilege || (VolumeCaps->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) dwFlags |= FILE_FLAG_BACKUP_SEMANTICS; hFile = CreateFileA( resource, dwDesiredAccess, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, /* maximum sharing */ NULL, OPEN_EXISTING, dwFlags, NULL ); if(hFile == INVALID_HANDLE_VALUE) return FALSE; if(GetKernelObjectSecurity(hFile, RequestedInfo, sd, *cbBuffer, cbBuffer)) { *cbBuffer = GetSecurityDescriptorLength( sd ); bSuccess = TRUE; } CloseHandle(hFile); return bSuccess; }