static private Boolean FilterCallback(IntPtr sendDataPtr, IntPtr replyDataPtr) { bool retVal = true; try { FilterAPI.MessageSendData messageSend = new FilterAPI.MessageSendData(); messageSend = (FilterAPI.MessageSendData)Marshal.PtrToStructure(sendDataPtr, typeof(FilterAPI.MessageSendData)); if (FilterAPI.MESSAGE_SEND_VERIFICATION_NUMBER != messageSend.VerificationNumber) { EventManager.WriteMessage(139, "FilterCallback", EventLevel.Error, "Received message corrupted.Please check if the MessageSendData structure is correct."); return(false); } if (messageSend.MessageType == (uint)FilterAPI.FilterCommand.FILTER_REQUEST_ENCRYPTION_IV_AND_KEY) { if ((replyDataPtr.ToInt64() != 0)) { //this is the customized tag data which was attahced to the encrypted file when it was created. uint tagDataLength = messageSend.DataBufferLength; byte[] tagData = messageSend.DataBuffer; FilterAPI.MessageReplyData messageReply = (FilterAPI.MessageReplyData)Marshal.PtrToStructure(replyDataPtr, typeof(FilterAPI.MessageReplyData)); messageReply.MessageId = messageSend.MessageId; messageReply.MessageType = messageSend.MessageType; //get permission for secure shared file from server, here just demo the server in local, //in reality, your server could be in remote computer. retVal = DRServer.GetFileAccessPermission(ref messageSend, ref messageReply); if (retVal) { messageReply.ReturnStatus = (uint)FilterAPI.NTSTATUS.STATUS_SUCCESS; } else { //if you don't want to authorize the process to read the encrytped file,you can set the value as below: messageReply.ReturnStatus = (uint)FilterAPI.NTSTATUS.STATUS_ACCESS_DENIED; messageReply.FilterStatus = (uint)FilterAPI.FilterStatus.FILTER_COMPLETE_PRE_OPERATION; } Marshal.StructureToPtr(messageReply, replyDataPtr, true); if (!retVal) { messageSend.Status = (uint)FilterAPI.NTSTATUS.STATUS_ACCESS_DENIED; } } } } catch (Exception ex) { EventManager.WriteMessage(134, "FilterCallback", EventLevel.Error, "filter callback exception." + ex.Message); return(false); } return(retVal); }
public static Boolean FilterCallback(IntPtr sendDataPtr, IntPtr replyDataPtr) { Boolean ret = true; try { FilterAPI.MessageSendData messageSend = new FilterAPI.MessageSendData(); messageSend = (FilterAPI.MessageSendData)Marshal.PtrToStructure(sendDataPtr, typeof(FilterAPI.MessageSendData)); if (FilterAPI.MESSAGE_SEND_VERIFICATION_NUMBER != messageSend.VerificationNumber) { EventManager.WriteMessage(139, "FilterCallback", EventLevel.Error, "Received message corrupted.Please check if the MessageSendData structure is correct."); return(false); } MessageInfo.DisplayFilterMessage(messageSend); if (replyDataPtr.ToInt64() != 0) { FilterAPI.MessageReplyData messageReply = (FilterAPI.MessageReplyData)Marshal.PtrToStructure(replyDataPtr, typeof(FilterAPI.MessageReplyData)); //here you can control the IO behaviour and modify the data. FilterService.IOAccessControl(messageSend, ref messageReply); messageReply.MessageId = messageSend.MessageId; messageReply.MessageType = messageSend.MessageType; messageReply.ReturnStatus = (uint)FilterAPI.NTSTATUS.STATUS_SUCCESS; //to comple the PRE_IO //messageReply.ReturnStatus = (uint)FilterAPI.NTSTATUS.STATUS_ACCESS_DENIED; //messageReply.FilterStatus = (uint)FilterAPI.FilterStatus.FILTER_COMPLETE_PRE_OPERATION; Marshal.StructureToPtr(messageReply, replyDataPtr, true); } return(ret); } catch (Exception ex) { EventManager.WriteMessage(134, "FilterCallback", EventLevel.Error, "filter callback exception." + ex.Message); return(false); } }
Boolean FilterCallback(IntPtr sendDataPtr, IntPtr replyDataPtr) { Boolean ret = true; try { FilterAPI.MessageSendData messageSend = (FilterAPI.MessageSendData)Marshal.PtrToStructure(sendDataPtr, typeof(FilterAPI.MessageSendData)); if (FilterAPI.MESSAGE_SEND_VERIFICATION_NUMBER != messageSend.VerificationNumber) { MessageBoxHelper.PrepToCenterMessageBoxOnForm(this); MessageBox.Show("Received message corrupted.Please check if the MessageSendData structure is correct."); EventManager.WriteMessage(139, "FilterCallback", EventLevel.Error, "Received message corrupted.Please check if the MessageSendData structure is correct."); return(false); } filterMessage.AddMessage(messageSend); if (replyDataPtr.ToInt64() != 0) { FilterAPI.MessageReplyData messageReply = (FilterAPI.MessageReplyData)Marshal.PtrToStructure(replyDataPtr, typeof(FilterAPI.MessageReplyData)); if (messageSend.MessageType == (uint)FilterAPI.FilterCommand.FILTER_SEND_REG_CALLBACK_INFO) { //this is registry callback request RegistryHandler.AuthorizeRegistryAccess(messageSend, ref messageReply); Marshal.StructureToPtr(messageReply, replyDataPtr, true); } } return(ret); } catch (Exception ex) { EventManager.WriteMessage(134, "FilterCallback", EventLevel.Error, "filter callback exception." + ex.Message); return(false); } }
public static bool IOAccessControl(FilterAPI.MessageSendData messageSend, ref FilterAPI.MessageReplyData messageReply) { bool ret = true; try { messageReply.MessageId = messageSend.MessageId; messageReply.MessageType = messageSend.MessageType; // //here you can control all the registered IO requests,block the access or modify the I/O data base on the file IO information from MessageSend struture // // //if you don't want to change anything to this IO request, just let it pass through as below setting: //messageReply.FilterStatus = 0; //messageReply.ReturnStatus = (uint)NtStatus.Status.Success; //if you want to block the access this IO request before it goes down to the file system, you can return the status as below, //it is only for pre IO requests, it means the user IO reuqests will be completed here instead of going down to the file system. //messageReply.FilterStatus = (uint)FilterAPI.FilterStatus.FILTER_COMPLETE_PRE_OPERATION; //messageReply.ReturnStatus = (uint)NtStatus.Status.AccessDenied; //if you want to modify the IO data and complete the pre IO with your own data, you can return status as below: // messageReply.FilterStatus = (uint)FilterAPI.FilterStatus.FILTER_COMPLETE_PRE_OPERATION | (uint)FilterAPI.FilterStatus.FILTER_DATA_BUFFER_IS_UPDATED; // messageReply.DataBufferLength = the return data buffer length. // messageReply.DataBuffer = the data you want to return. // messageReply.ReturnStatus = (uint)NtStatus.Status.Success; FilterAPI.MessageType messageType = (FilterAPI.MessageType)messageSend.MessageType; WinData.FileInfomationClass infoClass = (WinData.FileInfomationClass)messageSend.InfoClass; uint dataLength = messageSend.DataBufferLength; byte[] data = messageSend.DataBuffer; //here is some IO information for your reference: if ((messageSend.CreateOptions & (uint)WinData.CreateOptions.FO_REMOTE_ORIGIN) > 0) { //this is file access request comes from remote network server } //you can check the file create option with this data: //"DesiredAccess: messageSend.DesiredAccess //"Disposition:" + ((WinData.Disposition)messageSend.Disposition).ToString(); //"ShareAccess:" + ((WinData.ShareAccess)messageSend.SharedAccess).ToString(); //"CreateOptions:"messageSend.CreateOptions //Here is the demo to copy file content before it was deleted.----------------------------------------------- bool isFileDeleted = false; if (messageSend.Status == (uint)NtStatus.Status.Success) { if (messageType == FilterAPI.MessageType.POST_CREATE) { if ((messageSend.CreateOptions & (uint)WinData.CreateOptions.FILE_DELETE_ON_CLOSE) > 0) { isFileDeleted = true; } } else if (messageType == FilterAPI.MessageType.POST_SET_INFORMATION) { if (infoClass == WinData.FileInfomationClass.FileDispositionInformation) { isFileDeleted = true; } } if (isFileDeleted) { IntPtr fileHandle = IntPtr.Zero; bool retVal = FilterAPI.GetFileHandleInFilter(messageSend.FileName, (uint)FileAccess.Read, ref fileHandle); if (retVal) { SafeFileHandle sHandle = new SafeFileHandle(fileHandle, true); FileStream fileStream = new FileStream(sHandle, FileAccess.Read); //copy your data here... fileStream.Close(); } } } //End ----------------------------------------------- switch (messageType) { case FilterAPI.MessageType.PRE_CREATE: { //here you reparse the file open to another new file name //string newReparseFileName = "\\??\\c:\\myNewFile.txt"; //byte[] returnData = Encoding.Unicode.GetBytes(newReparseFileName); //Array.Copy(returnData, messageReply.DataBuffer, returnData.Length); //messageReply.DataBufferLength = (uint)returnData.Length; //messageReply.FilterStatus = (uint)FilterAPI.FilterStatus.FILTER_COMPLETE_PRE_OPERATION; //messageReply.ReturnStatus = (uint)NtStatus.Status.Reparse; break; } case FilterAPI.MessageType.PRE_CACHE_READ: case FilterAPI.MessageType.POST_CACHE_READ: case FilterAPI.MessageType.PRE_NOCACHE_READ: case FilterAPI.MessageType.POST_NOCACHE_READ: case FilterAPI.MessageType.PRE_PAGING_IO_READ: case FilterAPI.MessageType.POST_PAGING_IO_READ: case FilterAPI.MessageType.PRE_CACHE_WRITE: case FilterAPI.MessageType.POST_CACHE_WRITE: case FilterAPI.MessageType.PRE_NOCACHE_WRITE: case FilterAPI.MessageType.POST_NOCACHE_WRITE: case FilterAPI.MessageType.PRE_PAGING_IO_WRITE: case FilterAPI.MessageType.POST_PAGING_IO_WRITE: { //byte[] returnData = //new data you want to modify the read/write data; //Array.Copy(returnData, messageReply.DataBuffer, returnData.Length); //messageReply.DataBufferLength = (uint)returnData.Length; ////for pre IO,use this one //// messageReply.FilterStatus = (uint)FilterAPI.FilterStatus.FILTER_COMPLETE_PRE_OPERATION | (uint)FilterAPI.FilterStatus.FILTER_DATA_BUFFER_IS_UPDATED; // messageReply.FilterStatus = (uint)FilterAPI.FilterStatus.FILTER_DATA_BUFFER_IS_UPDATED; // messageReply.ReturnStatus = (uint)NtStatus.Status.Success; break; } case FilterAPI.MessageType.PRE_SET_INFORMATION: case FilterAPI.MessageType.POST_SET_INFORMATION: case FilterAPI.MessageType.PRE_QUERY_INFORMATION: case FilterAPI.MessageType.POST_QUERY_INFORMATION: { ret = true; switch (infoClass) { case WinData.FileInfomationClass.FileRenameInformation: { //you can block file rename as below //messageReply.FilterStatus = (uint)FilterAPI.FilterStatus.FILTER_COMPLETE_PRE_OPERATION; //messageReply.ReturnStatus = (uint)NtStatus.Status.AccessDenied; break; } case WinData.FileInfomationClass.FileDispositionInformation: { //you can block file delete as below //messageReply.FilterStatus = (uint)FilterAPI.FilterStatus.FILTER_COMPLETE_PRE_OPERATION; //messageReply.ReturnStatus = (uint)NtStatus.Status.AccessDenied; break; } case WinData.FileInfomationClass.FileEndOfFileInformation: { //change file size break; } case WinData.FileInfomationClass.FileBasicInformation: { //file basic information break; } case WinData.FileInfomationClass.FileStandardInformation: { //file standard information break; } case WinData.FileInfomationClass.FileNetworkOpenInformation: { //file network information break; } case WinData.FileInfomationClass.FileInternalInformation: { //file internal inofrmation break; } default: { ret = false; break; } } break; } } } catch (Exception ex) { EventManager.WriteMessage(174, "IOAccessControl", EventLevel.Error, "IOAccessControl failed." + ex.Message); } return(ret); }
Boolean FilterCallback(IntPtr sendDataPtr, IntPtr replyDataPtr) { Boolean ret = true; try { //for file access right unit test, to handle the monitor or control IO callback, reference the FileMonitor/FileProtector project FilterAPI.MessageSendData messageSend = (FilterAPI.MessageSendData)Marshal.PtrToStructure(sendDataPtr, typeof(FilterAPI.MessageSendData)); if (messageSend.MessageType == (uint)FilterAPI.MessageType.PRE_CREATE) { ProcessUnitTest.controlIONotification = true; FilterAPI.MessageReplyData messageReply = (FilterAPI.MessageReplyData)Marshal.PtrToStructure(replyDataPtr, typeof(FilterAPI.MessageReplyData)); //if you want to block the file access, you can return below status. //messageReply.ReturnStatus = (uint)FilterAPI.NTSTATUS.STATUS_ACCESS_DENIED; //messageReply.FilterStatus = (uint)FilterAPI.FilterStatus.FILTER_COMPLETE_PRE_OPERATION; messageReply.ReturnStatus = (uint)FilterAPI.NTSTATUS.STATUS_SUCCESS; Marshal.StructureToPtr(messageReply, replyDataPtr, true); return(true); } if (messageSend.MessageType == (uint)FilterAPI.MessageType.POST_CREATE) { ProcessUnitTest.monitorIONotification = true; return(true); } FilterAPI.PROCESS_INFO processInfo = (FilterAPI.PROCESS_INFO)Marshal.PtrToStructure(sendDataPtr, typeof(FilterAPI.PROCESS_INFO)); if (FilterAPI.MESSAGE_SEND_VERIFICATION_NUMBER != processInfo.VerificationNumber) { MessageBoxHelper.PrepToCenterMessageBoxOnForm(this); MessageBox.Show("Received message corrupted.Please check if the PROCESS_INFO structure is correct."); EventManager.WriteMessage(139, "FilterCallback", EventLevel.Error, "Received message corrupted.Please check if the PROCESS_INFO structure is correct."); return(false); } processMessage.AddMessage(processInfo); if (replyDataPtr.ToInt64() != 0) { FilterAPI.MessageReplyData messageReply = (FilterAPI.MessageReplyData)Marshal.PtrToStructure(replyDataPtr, typeof(FilterAPI.MessageReplyData)); if (processInfo.MessageType == (uint)FilterAPI.FilterCommand.FILTER_SEND_PROCESS_CREATION_INFO) { //this is new process creation, you can block it here by returning the STATUS_ACCESS_DENIED. messageReply.ReturnStatus = processInfo.Status; Marshal.StructureToPtr(messageReply, replyDataPtr, true); } } return(ret); } catch (Exception ex) { EventManager.WriteMessage(134, "FilterCallback", EventLevel.Error, "filter callback exception." + ex.Message); return(false); } }
public bool GetUserPermission(FilterAPI.MessageSendData messageSend, ref FilterAPI.MessageReplyData messageReply) { Boolean retVal = true; string userPassword = string.Empty; string fileName = messageSend.FileName; string lastError = string.Empty; string processName = string.Empty; string userName = string.Empty; bool isFirstAccess = false; CacheUserAccessInfo cacheUserAccessInfo = new CacheUserAccessInfo(); try { FilterAPI.DecodeProcessName(messageSend.ProcessId, out processName); FilterAPI.DecodeUserName(messageSend.Sid, out userName); string index = (userName + "_" + processName + "_" + fileName).ToLower(); //cache the same user/process/filename access. lock (userAccessCache) { if (userAccessCache.ContainsKey(index)) { cacheUserAccessInfo = userAccessCache[index]; EventManager.WriteMessage(446, "GetUserPermission", EventLevel.Verbose, "Thread" + Thread.CurrentThread.ManagedThreadId + ",userInfoKey " + index + " exists in the cache table."); } else { isFirstAccess = true; cacheUserAccessInfo.index = index; cacheUserAccessInfo.lastAccessTime = DateTime.Now; userAccessCache.Add(index, cacheUserAccessInfo); EventManager.WriteMessage(435, "GetUserPermission", EventLevel.Verbose, "Thread" + Thread.CurrentThread.ManagedThreadId + ",add userInfoKey " + index + " to the cache table."); } } //synchronize the same file access. if (!cacheUserAccessInfo.syncEvent.WaitOne(new TimeSpan(0, 0, (int)GlobalConfig.ConnectionTimeOut))) { string info = "User name: " + userName + ",processname:" + processName + ",file name:" + fileName + " wait for permission timeout."; EventManager.WriteMessage(402, "GetUserPermission", EventLevel.Warning, info); } TimeSpan timeSpan = DateTime.Now - cacheUserAccessInfo.lastAccessTime; if (!isFirstAccess && timeSpan.TotalSeconds < cacheTimeOutInSeconds) { //the access was cached, return the last access status. retVal = cacheUserAccessInfo.accessStatus; string info = "thread" + Thread.CurrentThread.ManagedThreadId + ", Cached userInfoKey " + index + " in the cache table,return " + retVal; EventManager.WriteMessage(451, "GetUserPermission", EventLevel.Verbose, info); return(retVal); } DRPolicyData drPolicyData = new DRPolicyData(); retVal = GetDRPolicyDataFromDataBuffer(messageSend.DataBuffer, messageSend.Length, ref drPolicyData, ref lastError); if (!retVal) { EventManager.WriteMessage(258, "GetUserPermission", EventLevel.Error, "Process encrypted file failed because of error:" + lastError); } else { if ((drPolicyData.AESFlags & AESFlags.Flags_Enabled_Check_User_Password) == AESFlags.Flags_Enabled_Check_User_Password) { string messageInfo = "User name: " + userName + ",processname:" + processName + ",file name:" + fileName + "\n\n Enter password in password windows."; EventManager.WriteMessage(301, "Request user password.", EventLevel.Verbose, messageInfo); UserPasswordForm userPasswordForm = new UserPasswordForm(userName, processName, fileName); userPasswordForm.BringToFront(); userPasswordForm.Focus(); userPasswordForm.TopMost = true; if (userPasswordForm.ShowDialog() == System.Windows.Forms.DialogResult.OK) { userPassword = userPasswordForm.userPassword; } } if ((drPolicyData.AESFlags & AESFlags.Flags_Enabled_Revoke_Access_Control) == AESFlags.Flags_Enabled_Revoke_Access_Control) { retVal = GetAccessPermissionFromServer(messageSend, drPolicyData, userName, processName, userPassword, ref cacheUserAccessInfo); } else { if (drPolicyData.UserPassword.Length > 0) { if (!string.Equals(userPassword, drPolicyData.UserPassword)) { retVal = false; } } } } cacheUserAccessInfo.accessStatus = retVal; } catch (Exception ex) { EventManager.WriteMessage(340, "GetUserPermission", EventLevel.Error, "filter callback exception." + ex.Message); retVal = false; } finally { if (!string.IsNullOrEmpty(cacheUserAccessInfo.key)) { byte[] encryptKey = Utils.ConvertHexStrToByteArray(cacheUserAccessInfo.key); byte[] encryptIV = Utils.ConvertHexStrToByteArray(cacheUserAccessInfo.iv); //write the iv and key to the reply data buffer with format FilterAPI.AESDataBuffer MemoryStream ms = new MemoryStream(messageReply.DataBuffer); BinaryWriter bw = new BinaryWriter(ms); bw.Write(encryptIV); bw.Write(encryptKey.Length); bw.Write(encryptKey); messageReply.DataBufferLength = (uint)ms.Length; } cacheUserAccessInfo.lastAccessTime = DateTime.Now; cacheUserAccessInfo.syncEvent.Set(); } return(retVal); }
Boolean FilterCallback(IntPtr sendDataPtr, IntPtr replyDataPtr) { Boolean ret = true; try { FilterAPI.MessageSendData messageSend = (FilterAPI.MessageSendData)Marshal.PtrToStructure(sendDataPtr, typeof(FilterAPI.MessageSendData)); if (FilterAPI.MESSAGE_SEND_VERIFICATION_NUMBER != messageSend.VerificationNumber) { MessageBoxHelper.PrepToCenterMessageBoxOnForm(this); MessageBox.Show("Received message corrupted.Please check if the MessageSendData structure is correct."); EventManager.WriteMessage(139, "FilterCallback", EventLevel.Error, "Received message corrupted.Please check if the MessageSendData structure is correct."); return(false); } EventManager.WriteMessage(149, "FilterCallback", EventLevel.Verbose, "Received message Id#" + messageSend.MessageId + " type:" + messageSend.MessageType + " CreateOptions:" + messageSend.CreateOptions.ToString("X") + " infoClass:" + messageSend.InfoClass + " fileName:" + messageSend.FileName); filterMessage.AddMessage(messageSend); FileProtectorUnitTest.FileIOEventHandler(messageSend); if (replyDataPtr.ToInt64() != 0) { FilterAPI.MessageReplyData messageReply = (FilterAPI.MessageReplyData)Marshal.PtrToStructure(replyDataPtr, typeof(FilterAPI.MessageReplyData)); //if (messageSend.MessageType == (uint)FilterAPI.FilterCommand.FILTER_SEND_PROCESS_TERMINATION_INFO) //{ // //the process termination callback, you can get the notification if you register the callback setting of the process filter. //} if (messageSend.MessageType == (uint)FilterAPI.FilterCommand.FILTER_SEND_PROCESS_CREATION_INFO) { //this is new process creation, you can block it here by returning the STATUS_ACCESS_DENIED, below is the process information FilterAPI.PROCESS_INFO processInfo = (FilterAPI.PROCESS_INFO)Marshal.PtrToStructure(sendDataPtr, typeof(FilterAPI.PROCESS_INFO)); messageReply.ReturnStatus = processInfo.Status; Marshal.StructureToPtr(messageReply, replyDataPtr, true); } else if (messageSend.MessageType == (uint)FilterAPI.FilterCommand.FILTER_REQUEST_ENCRYPTION_IV_AND_KEY) { //this is encryption filter rule with boolean config "REQUEST_ENCRYPT_KEY_AND_IV_FROM_SERVICE" enabled. //the filter driver request the IV and key to open or create the encrypted file. //if you want to deny the file open or creation, you set the value as below: //messageReply.ReturnStatus = (uint)FilterAPI.NTSTATUS.STATUS_ACCESS_DENIED; //messageReply.FilterStatus = (uint)FilterAPI.FilterStatus.FILTER_COMPLETE_PRE_OPERATION; EventManager.WriteMessage(200, "filtercallback", EventLevel.Verbose, messageSend.FileName + " FILTER_REQUEST_ENCRYPTION_IV_AND_KEY"); //Here we return the test iv and key to the filter driver, you need to replace with you own iv and key in your code. AESDataBuffer aesData = new AESDataBuffer(); aesData.AccessFlags = FilterAPI.ALLOW_MAX_RIGHT_ACCESS; aesData.IV = FilterAPI.DEFAULT_IV_TAG; aesData.IVLength = (uint)aesData.IV.Length; aesData.EncryptionKey = Utils.GetKeyByPassPhrase(DigitalRightControl.PassPhrase); aesData.EncryptionKeyLength = (uint)aesData.EncryptionKey.Length; byte[] aesDataArray = DigitalRightControl.ConvertAESDataToByteArray(aesData); messageReply.DataBufferLength = (uint)aesDataArray.Length; Array.Copy(aesDataArray, messageReply.DataBuffer, aesDataArray.Length); messageReply.ReturnStatus = (uint)FilterAPI.NTSTATUS.STATUS_SUCCESS; } else if (messageSend.MessageType == (uint)FilterAPI.FilterCommand.FILTER_REQUEST_ENCRYPTION_IV_AND_KEY_AND_TAGDATA) { //this is encryption filter rule with boolean config "REQUEST_ENCRYPT_KEY_IV_AND_TAGDATA_FROM_SERVICE" enabled. //the filter driver request the IV and key to open or create the encrypted file. //if you want to deny the file open or creation, you set the value as below: //messageReply.ReturnStatus = (uint)FilterAPI.NTSTATUS.STATUS_ACCESS_DENIED; //messageReply.FilterStatus = (uint)FilterAPI.FilterStatus.FILTER_COMPLETE_PRE_OPERATION; if (messageSend.DataBufferLength > 0) { //this is the tag data which attached to the encrypted file . string tagDataStr = Encoding.Unicode.GetString(messageSend.DataBuffer); EventManager.WriteMessage(235, "filtercallback", EventLevel.Verbose, "EncryptedFile:" + messageSend.FileName + ",tagData:" + tagDataStr); } //Here we return the test iv ,key and tag data to the filter driver, you need to replace with you own iv and key in your code. AESDataBuffer aesData = new AESDataBuffer(); aesData.AccessFlags = FilterAPI.ALLOW_MAX_RIGHT_ACCESS; aesData.IV = FilterAPI.DEFAULT_IV_TAG; aesData.IVLength = (uint)aesData.IV.Length; aesData.EncryptionKey = Utils.GetKeyByPassPhrase(DigitalRightControl.PassPhrase); aesData.EncryptionKeyLength = (uint)aesData.EncryptionKey.Length; aesData.TagData = Encoding.Unicode.GetBytes("TagData:" + messageSend.FileName); aesData.TagDataLength = (uint)aesData.TagData.Length; byte[] aesDataArray = DigitalRightControl.ConvertAESDataToByteArray(aesData); messageReply.DataBufferLength = (uint)aesDataArray.Length; Array.Copy(aesDataArray, messageReply.DataBuffer, aesDataArray.Length); messageReply.ReturnStatus = (uint)FilterAPI.NTSTATUS.STATUS_SUCCESS; } else { //this is for control filter driver when the pre-IO was registered. //here you can control the IO behaviour and modify the data. if (!FileProtectorUnitTest.UnitTestCallbackHandler(messageSend) || !FilterService.AuthorizeFileAccess(messageSend, ref messageReply)) { //to comple the PRE_IO messageReply.ReturnStatus = (uint)FilterAPI.NTSTATUS.STATUS_ACCESS_DENIED; messageReply.FilterStatus = (uint)FilterAPI.FilterStatus.FILTER_COMPLETE_PRE_OPERATION; EventManager.WriteMessage(160, "FilterCallback", EventLevel.Error, "Return error for I/O request:" + ((FilterAPI.MessageType)messageSend.MessageType).ToString() + ",fileName:" + messageSend.FileName); } else { messageReply.MessageId = messageSend.MessageId; messageReply.MessageType = messageSend.MessageType; messageReply.ReturnStatus = (uint)FilterAPI.NTSTATUS.STATUS_SUCCESS; } } Marshal.StructureToPtr(messageReply, replyDataPtr, true); } return(ret); } catch (Exception ex) { EventManager.WriteMessage(134, "FilterCallback", EventLevel.Error, "filter callback exception." + ex.Message); return(false); } }
static public bool GetFileAccessPermission(ref FilterAPI.MessageSendData messageSend, ref FilterAPI.MessageReplyData messageReply) { Boolean retVal = true; string fileName = messageSend.FileName; string lastError = string.Empty; string processName = string.Empty; string userName = string.Empty; string encryptKey = string.Empty; try { FilterAPI.DecodeProcessName(messageSend.ProcessId, out processName); FilterAPI.DecodeUserName(messageSend.Sid, out userName); //by default the tag data format is "accountName;ivStr" int tagDataLength = (int)messageSend.DataBufferLength; byte[] tagData = messageSend.DataBuffer; Array.Resize(ref tagData, tagDataLength); string tagStr = UnicodeEncoding.Unicode.GetString(tagData); int index = tagStr.IndexOf(";"); byte[] iv = tagData; if (index > 0) { string serverAccount = tagStr.Substring(0, index); string ivStr = tagStr.Substring(index + 1); iv = Utils.ConvertHexStrToByteArray(ivStr); } uint accessFlag = 0; retVal = IsFileAccessAuthorized(fileName, userName, processName, tagStr, ref encryptKey, ref accessFlag, ref lastError); if (retVal && !string.IsNullOrEmpty(encryptKey)) { byte[] keyArray = Utils.ConvertHexStrToByteArray(encryptKey); //write the iv and key to the reply data buffer with format FilterAPI.AESDataBuffer AESDataBuffer aesData = new AESDataBuffer(); if (messageSend.MessageType == (uint)FilterAPI.FilterCommand.FILTER_REQUEST_ENCRYPTION_IV_AND_KEY_AND_ACCESSFLAG) { aesData.AccessFlags = FilterAPI.ALLOW_MAX_RIGHT_ACCESS; } else { aesData.AccessFlags = FilterAPI.ALLOW_MAX_RIGHT_ACCESS; } aesData.IV = iv; aesData.IVLength = (uint)iv.Length; aesData.EncryptionKey = keyArray; aesData.EncryptionKeyLength = (uint)keyArray.Length; byte[] aesDataArray = DigitalRightControl.ConvertAESDataToByteArray(aesData); messageReply.DataBufferLength = (uint)aesDataArray.Length; Array.Copy(aesDataArray, messageReply.DataBuffer, aesDataArray.Length); messageReply.ReturnStatus = (uint)FilterAPI.NTSTATUS.STATUS_SUCCESS; } } catch (Exception ex) { lastError = "GetFileAccessPermission exception." + ex.Message; EventManager.WriteMessage(340, "GetFileAccessPermission", EventLevel.Error, lastError); retVal = false; } if (!retVal) { byte[] errorBuffer = UnicodeEncoding.Unicode.GetBytes(lastError); Array.Copy(errorBuffer, messageSend.DataBuffer, errorBuffer.Length); messageSend.DataBufferLength = (uint)errorBuffer.Length; } return(retVal); }
private bool FilterRequestHandler(ref FilterAPI.MessageSendData messageSend, IntPtr replyDataPtr) { Boolean retVal = true; string fileName = messageSend.FileName; string lastError = string.Empty; try { if ((replyDataPtr.ToInt64() != 0)) { FilterAPI.MessageReplyData messageReply = (FilterAPI.MessageReplyData)Marshal.PtrToStructure(replyDataPtr, typeof(FilterAPI.MessageReplyData)); messageReply.MessageId = messageSend.MessageId; messageReply.MessageType = messageSend.MessageType; if (messageSend.MessageType == (uint)FilterAPI.FilterCommand.FILTER_REQUEST_USER_PERMIT || messageSend.MessageType == (uint)FilterAPI.FilterCommand.FILTER_REQUEST_ENCRYPTION_IV_AND_KEY) { if (null == digitalRightsManagement) { digitalRightsManagement = new DRM(); } //get permission for secure shared file retVal = digitalRightsManagement.GetUserPermission(messageSend, ref messageReply); } else { //control the file I/O here retVal = FilterService.IOAccessControl(messageSend, ref messageReply); } if (retVal) { messageReply.ReturnStatus = (uint)FilterAPI.NTSTATUS.STATUS_SUCCESS; } else { //comple the PRE_CREATE,user get access denied for the file open. messageReply.ReturnStatus = (uint)FilterAPI.NTSTATUS.STATUS_ACCESS_DENIED; messageReply.FilterStatus = (uint)FilterAPI.FilterStatus.FILTER_COMPLETE_PRE_OPERATION; } Marshal.StructureToPtr(messageReply, replyDataPtr, true); if (!retVal) { messageSend.Status = (uint)FilterAPI.NTSTATUS.STATUS_ACCESS_DENIED; } } filterMessage.AddMessage(messageSend); return(retVal); } catch (Exception ex) { EventManager.WriteMessage(134, "FilterRequestHandler", EventLevel.Error, "filter callback exception." + ex.Message); return(false); } }
Boolean FilterCallback(IntPtr sendDataPtr, IntPtr replyDataPtr) { Boolean ret = true; try { FilterAPI.MessageSendData messageSend = (FilterAPI.MessageSendData)Marshal.PtrToStructure(sendDataPtr, typeof(FilterAPI.MessageSendData)); if (FilterAPI.MESSAGE_SEND_VERIFICATION_NUMBER != messageSend.VerificationNumber) { MessageBoxHelper.PrepToCenterMessageBoxOnForm(this); MessageBox.Show("Received message corrupted.Please check if the MessageSendData structure is correct."); EventManager.WriteMessage(139, "FilterCallback", EventLevel.Error, "Received message corrupted.Please check if the MessageSendData structure is correct."); return(false); } EventManager.WriteMessage(149, "FilterCallback", EventLevel.Verbose, "Received message Id#" + messageSend.MessageId + " type:" + messageSend.MessageType + " CreateOptions:" + messageSend.CreateOptions.ToString("X") + " infoClass:" + messageSend.InfoClass + " fileName:" + messageSend.FileName); filterMessage.AddMessage(messageSend); FileProtectorUnitTest.FileIOEventHandler(messageSend); if (replyDataPtr.ToInt64() != 0) { FilterAPI.MessageReplyData messageReply = (FilterAPI.MessageReplyData)Marshal.PtrToStructure(replyDataPtr, typeof(FilterAPI.MessageReplyData)); //here you can control the IO behaviour and modify the data. if (!FileProtectorUnitTest.UnitTestCallbackHandler(messageSend) || !FilterService.IOAccessControl(messageSend, ref messageReply)) { //to comple the PRE_IO messageReply.ReturnStatus = (uint)FilterAPI.NTSTATUS.STATUS_ACCESS_DENIED; messageReply.FilterStatus = (uint)FilterAPI.FilterStatus.FILTER_COMPLETE_PRE_OPERATION; EventManager.WriteMessage(160, "FilterCallback", EventLevel.Error, "Return error for I/O request:" + ((FilterAPI.MessageType)messageSend.MessageType).ToString() + ",fileName:" + messageSend.FileName); } else { messageReply.MessageId = messageSend.MessageId; messageReply.MessageType = messageSend.MessageType; messageReply.ReturnStatus = (uint)FilterAPI.NTSTATUS.STATUS_SUCCESS; } Marshal.StructureToPtr(messageReply, replyDataPtr, true); } string info = "FileProtector process request " + FilterMessage.FormatIOName(messageSend) + ",pid:" + messageSend.ProcessId + " ,filename:" + messageSend.FileName + ",return status:" + FilterMessage.FormatStatus(messageSend.Status); if (messageSend.Status == (uint)NtStatus.Status.Success) { ret = false; EventManager.WriteMessage(98, "FilterCallback", EventLevel.Verbose, info); } else { ret = true; EventManager.WriteMessage(98, "FilterCallback", EventLevel.Error, info); } return(ret); } catch (Exception ex) { EventManager.WriteMessage(134, "FilterCallback", EventLevel.Error, "filter callback exception." + ex.Message); return(false); } }
public static bool AuthorizeRegistryAccess(FilterAPI.MessageSendData messageSend, ref FilterAPI.MessageReplyData messageReply) { bool ret = true; try { messageReply.MessageId = messageSend.MessageId; messageReply.MessageType = messageSend.MessageType; messageReply.ReturnStatus = (uint)FilterAPI.NTSTATUS.STATUS_SUCCESS; // //here you can control registry request,block the access or modify the registry data. // // //if you don't want to change anything to this registry request, just let it pass through as below setting: //messageReply.FilterStatus = 0; //messageReply.ReturnStatus = (uint)NtStatus.Status.Success; //if you want to block the access this registry request, you can return the status as below, //it is only for pre callback requests. //messageReply.FilterStatus = (uint)FilterAPI.FilterStatus.FILTER_COMPLETE_PRE_OPERATION; //messageReply.ReturnStatus = (uint)NtStatus.Status.AccessDenied; //if you want to modify the registry data and complete the pre IO with your own data, you can return status as below: // messageReply.FilterStatus = (uint)FilterAPI.FilterStatus.FILTER_COMPLETE_PRE_OPERATION | (uint)FilterAPI.FilterStatus.FILTER_DATA_BUFFER_IS_UPDATED; // messageReply.DataBufferLength = the return data buffer length. // messageReply.DataBuffer = the data you want to return. // messageReply.ReturnStatus = (uint)NtStatus.Status.Success; FilterAPI.RegCallbackClass regCallbackClass = (FilterAPI.RegCallbackClass)messageSend.Offset; uint dataLength = messageSend.DataBufferLength; byte[] data = messageSend.DataBuffer; switch (regCallbackClass) { case FilterAPI.RegCallbackClass.Reg_Pre_Query_Value_Key: { KEY_VALUE_INFORMATION_CLASS keyValuseInformationClass = (KEY_VALUE_INFORMATION_CLASS)messageSend.InfoClass; IntPtr keyValueInfoPtr = Marshal.UnsafeAddrOfPinnedArrayElement(data, 0); if (messageSend.FileName.IndexOf("EaseFilter") <= 0) { //this is not our unit test key break; } //below code is for unit test to demo how to complete pre-callback registry call with our own data. EventManager.WriteMessage(400, "AuthorizeRegistryAccess", EventLevel.Error, "Reg_Pre_Query_Value_Key keyValuseInformationClass:" + keyValuseInformationClass.ToString()); switch (keyValuseInformationClass) { case KEY_VALUE_INFORMATION_CLASS.KeyValueBasicInformation: { //public struct KEY_VALUE_BASIC_INFORMATION // { // public uint TitleIndex; // public uint Type; // public uint NameLength; // public byte[] Name; // } uint titleIndex = 0; uint type = (uint)VALUE_DATA_TYPE.REG_DWORD; byte[] valueName = Encoding.Unicode.GetBytes("value1"); uint valueNameLength = (uint)valueName.Length; MemoryStream ms = new MemoryStream(messageReply.DataBuffer); BinaryWriter bw = new BinaryWriter(ms); bw.Write(titleIndex); bw.Write(type); bw.Write(valueNameLength); bw.Write(valueName); messageReply.DataBufferLength = (uint)ms.Position; messageReply.FilterStatus = (uint)FilterAPI.FilterStatus.FILTER_COMPLETE_PRE_OPERATION | (uint)FilterAPI.FilterStatus.FILTER_DATA_BUFFER_IS_UPDATED; break; } case KEY_VALUE_INFORMATION_CLASS.KeyValueFullInformation: { //KeyValueFullInformation class structure //public uint TitleIndex; //public uint Type; //public uint DataOffset; //public uint DataLength; //public uint NameLength; //public byte[] Name; uint titleIndex = 0; uint type = (uint)VALUE_DATA_TYPE.REG_DWORD; uint testData = 12345; uint testDataLength = sizeof(uint); byte[] valueName = Encoding.Unicode.GetBytes("value1"); uint valueNameLength = (uint)valueName.Length; uint dataOffset = 5 * sizeof(uint) + valueNameLength; MemoryStream ms = new MemoryStream(messageReply.DataBuffer); BinaryWriter bw = new BinaryWriter(ms); bw.Write(titleIndex); bw.Write(type); bw.Write(dataOffset); bw.Write(testDataLength); bw.Write(valueNameLength); bw.Write(valueName); bw.Write(testData); messageReply.DataBufferLength = (uint)ms.Position; messageReply.FilterStatus = (uint)FilterAPI.FilterStatus.FILTER_COMPLETE_PRE_OPERATION | (uint)FilterAPI.FilterStatus.FILTER_DATA_BUFFER_IS_UPDATED; break; } case KEY_VALUE_INFORMATION_CLASS.KeyValuePartialInformation: { // public struct KEY_VALUE_PARTIAL_INFORMATION //{ // public uint TitleIndex; // public uint Type; // public uint DataLength; // public byte[] Data; //} uint titleIndex = 0; uint type = (uint)VALUE_DATA_TYPE.REG_DWORD; uint testData = 12345; uint testDataLength = sizeof(uint); MemoryStream ms = new MemoryStream(messageReply.DataBuffer); BinaryWriter bw = new BinaryWriter(ms); bw.Write(titleIndex); bw.Write(type); bw.Write(testDataLength); bw.Write(testData); messageReply.DataBufferLength = (uint)ms.Position; messageReply.FilterStatus = (uint)FilterAPI.FilterStatus.FILTER_COMPLETE_PRE_OPERATION | (uint)FilterAPI.FilterStatus.FILTER_DATA_BUFFER_IS_UPDATED; messageReply.ReturnStatus = (uint)FilterAPI.NTSTATUS.STATUS_SUCCESS; break; } default: break; } break; } case FilterAPI.RegCallbackClass.Reg_Pre_Create_KeyEx: case FilterAPI.RegCallbackClass.Reg_Pre_Open_KeyEx: { //this is our unit test key if (messageSend.FileName.IndexOf("EaseFilter") > 0) { //NOT allow to create new registry key. messageReply.FilterStatus = (uint)FilterAPI.FilterStatus.FILTER_COMPLETE_PRE_OPERATION; messageReply.ReturnStatus = (uint)NtStatus.Status.AccessDenied; } break; } default: break; } } catch (Exception ex) { EventManager.WriteMessage(400, "AuthorizeRegistryAccess", EventLevel.Error, "AuthorizeRegistryAccess exception:" + ex.Message); } return(ret); }