BOOLEAN AFSIsInGroup(PSID Sid) { SECURITY_SUBJECT_CONTEXT subjectContext; PTOKEN_GROUPS groups; PACCESS_TOKEN token; BOOLEAN retVal = FALSE; SeCaptureSubjectContext( &subjectContext ); SeLockSubjectContext( &subjectContext ); token = SeQuerySubjectContextToken( &subjectContext ); if (NT_SUCCESS(SeQueryInformationToken(token, TokenGroups, (PVOID*) &groups))) { ULONG i; for (i = 0; !retVal && i < groups->GroupCount; i++) { retVal = RtlEqualSid(Sid, groups->Groups[i].Sid); } ExFreePool( groups ); } SeUnlockSubjectContext( &subjectContext ); SeReleaseSubjectContext( &subjectContext ); return retVal; }
BOOLEAN AFSIsUser( IN PSID Sid) { SECURITY_SUBJECT_CONTEXT subjectContext; PTOKEN_USER user; PACCESS_TOKEN token; BOOLEAN retVal = FALSE; SeCaptureSubjectContext( &subjectContext); SeLockSubjectContext( &subjectContext); token = SeQuerySubjectContextToken( &subjectContext); if (NT_SUCCESS (SeQueryInformationToken( token, TokenUser, (PVOID*) &user))) { retVal = RtlEqualSid( user->User.Sid, Sid); ExFreePool( user ); } SeUnlockSubjectContext( &subjectContext); SeReleaseSubjectContext( &subjectContext); return retVal; }
NTSTATUS DokanGetAccessToken( __in PDEVICE_OBJECT DeviceObject, __in PIRP Irp ) { KIRQL oldIrql; PLIST_ENTRY thisEntry, nextEntry, listHead; PIRP_ENTRY irpEntry; PDokanVCB vcb; PEVENT_INFORMATION eventInfo; PACCESS_TOKEN accessToken; NTSTATUS status = STATUS_INVALID_PARAMETER; HANDLE handle; PIO_STACK_LOCATION irpSp = NULL; BOOLEAN hasLock = FALSE; ULONG outBufferLen; ULONG inBufferLen; PACCESS_STATE accessState; DDbgPrint("==> DokanGetAccessToken\n"); __try { eventInfo = (PEVENT_INFORMATION)Irp->AssociatedIrp.SystemBuffer; ASSERT(eventInfo != NULL); if (Irp->RequestorMode != UserMode) { DDbgPrint(" needs to be called from user-mode\n"); status = STATUS_INVALID_PARAMETER; __leave; } vcb = DeviceObject->DeviceExtension; if (GetIdentifierType(vcb) != VCB) { DDbgPrint(" GetIdentifierType != VCB\n"); status = STATUS_INVALID_PARAMETER; __leave; } irpSp = IoGetCurrentIrpStackLocation(Irp); outBufferLen = irpSp->Parameters.DeviceIoControl.OutputBufferLength; inBufferLen = irpSp->Parameters.DeviceIoControl.InputBufferLength; if (outBufferLen != sizeof(EVENT_INFORMATION) || inBufferLen != sizeof(EVENT_INFORMATION)) { DDbgPrint(" wrong input or output buffer length\n"); status = STATUS_INVALID_PARAMETER; __leave; } ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL); KeAcquireSpinLock(&vcb->Dcb->PendingIrp.ListLock, &oldIrql); hasLock = TRUE; // search corresponding IRP through pending IRP list listHead = &vcb->Dcb->PendingIrp.ListHead; for (thisEntry = listHead->Flink; thisEntry != listHead; thisEntry = nextEntry) { nextEntry = thisEntry->Flink; irpEntry = CONTAINING_RECORD(thisEntry, IRP_ENTRY, ListEntry); if (irpEntry->SerialNumber != eventInfo->SerialNumber) { continue; } // this irp must be IRP_MJ_CREATE if (irpEntry->IrpSp->Parameters.Create.SecurityContext) { accessState = irpEntry->IrpSp->Parameters.Create.SecurityContext->AccessState; } break; } KeReleaseSpinLock(&vcb->Dcb->PendingIrp.ListLock, oldIrql); hasLock = FALSE; if (accessState == NULL) { DDbgPrint(" can't find pending Irp: %d\n", eventInfo->SerialNumber); __leave; } accessToken = SeQuerySubjectContextToken(&accessState->SubjectSecurityContext); if (accessToken == NULL) { DDbgPrint(" accessToken == NULL\n"); __leave; } // NOTE: Accessing *SeTokenObjectType while acquring sping lock causes // BSOD on Windows XP. status = ObOpenObjectByPointer(accessToken, 0, NULL, GENERIC_ALL, *SeTokenObjectType, KernelMode, &handle); if (!NT_SUCCESS(status)) { DDbgPrint(" ObOpenObjectByPointer failed: 0x%x\n", status); __leave; } eventInfo->AccessToken.Handle = handle; Irp->IoStatus.Information = sizeof(EVENT_INFORMATION); status = STATUS_SUCCESS; } __finally { if (hasLock) { KeReleaseSpinLock(&vcb->Dcb->PendingIrp.ListLock, oldIrql); } } DDbgPrint("<== DokanGetAccessToken\n"); return status; }
FLT_POSTOP_CALLBACK_STATUS claimsmanPostOperation( _Inout_ PFLT_CALLBACK_DATA Data, _In_ PCFLT_RELATED_OBJECTS FltObjects, _In_opt_ PVOID CompletionContext, _In_ FLT_POST_OPERATION_FLAGS Flags ) /*++ Routine Description: This routine is the post-operation completion routine for this miniFilter. This is non-pageable because it may be called at DPC level. Arguments: Data - Pointer to the filter callbackData that is passed to us. FltObjects - Pointer to the FLT_RELATED_OBJECTS data structure containing opaque handles to this filter, instance, its associated volume and file object. CompletionContext - The completion context set in the pre-operation routine. Flags - Denotes whether the completion is successful or is being drained. Return Value: The return value is the status of the operation. --*/ { UNREFERENCED_PARAMETER(Data); UNREFERENCED_PARAMETER(CompletionContext); UNREFERENCED_PARAMETER(Flags); NTSTATUS status; PFLT_FILE_NAME_INFORMATION nameInfo = NULL; PUNICODE_STRING fileName = NULL; PTOKEN_USER pTokenUser = NULL; UNICODE_STRING sidString; LARGE_INTEGER Timeout; Timeout.QuadPart = (LONGLONG)1 * 10 * 1000 * 1000; // If there is no client registered, bail out immediately! // If the event is from kernel, bail out immediately! // If the event check for existence of file, bail out immediately! if ( (ClaimsmanData.ClientPort == NULL) || (Data->RequestorMode == KernelMode) || (Data->IoStatus.Information == FILE_DOES_NOT_EXIST) || (Data->IoStatus.Information == FILE_EXISTS) ) { return FLT_POSTOP_FINISHED_PROCESSING; } // We got a log record, if there is a file object, get its name. if (FltObjects->FileObject != NULL) { status = FltGetFileNameInformation(Data, FLT_FILE_NAME_NORMALIZED | FLT_FILE_NAME_QUERY_DEFAULT, &nameInfo); } else { // Can't get a name when there's no file object status = STATUS_UNSUCCESSFUL; } if (NT_SUCCESS(status)) { FltParseFileNameInformation(nameInfo); fileName = &nameInfo->Name; // Produces way too much logging //PT_DBG_PRINT(PTDBG_TRACE_ROUTINES, // ("claimsman!claimsmanPostOperation: fileName=%wZ\n", fileName)); } else { // No point continuing because we obviously did not get a filename anyways return FLT_POSTOP_FINISHED_PROCESSING; } //The only IRP you can trust for user information is IRP_MJ_CREATE. Things //like write can be in arbitrary thread context, and even if the call works //you can get the wrong SID. status = SeQueryInformationToken(SeQuerySubjectContextToken(&(Data->Iopb->Parameters.Create.SecurityContext->AccessState->SubjectSecurityContext)), TokenUser, &pTokenUser); if (STATUS_SUCCESS == status && RtlValidSid(pTokenUser->User.Sid)) { // Interesting extension? if (ClaimsmanCheckExtension(&nameInfo->Extension)) { CLAIMSMAN_MESSAGE msg; status = RtlConvertSidToUnicodeString(&sidString, pTokenUser->User.Sid, TRUE); if (NT_SUCCESS(status)) { PT_DBG_PRINT(PTDBG_TRACE_ROUTINES, ("claimsman!claimsmanPostOperation: SID=%wZ\n", &sidString)); } else { // No point continuing because we obviously did not get a valid SID FltReleaseFileNameInformation(nameInfo); ExFreePool(pTokenUser); return FLT_POSTOP_FINISHED_PROCESSING; } if (ClaimsmanCheckUserIgnore(&sidString)) { // Ignored user! Bail out! FltReleaseFileNameInformation(nameInfo); ExFreePool(pTokenUser); RtlFreeUnicodeString(&sidString); return FLT_POSTOP_FINISHED_PROCESSING; } LONGLONG size; LONGLONG modified; getSizeModified(FltObjects->Instance, fileName, &size, &modified); InitializeMessage(&msg, &sidString, fileName, FltObjects->FileObject->ReadAccess, FltObjects->FileObject->WriteAccess, FltObjects->FileObject->DeleteAccess, size, modified, Data->IoStatus.Status); // Ready, send the message! // But only if there's a client connected if (ClaimsmanData.ClientPort != NULL) { FltSendMessage(ClaimsmanData.Filter, &ClaimsmanData.ClientPort, &msg, sizeof(msg), NULL, 0, &Timeout ); PT_DBG_PRINT(PTDBG_TRACE_ROUTINES, ("claimsman!claimsmanPostOperation: sent message=%d\n", status)); } else { PT_DBG_PRINT(PTDBG_TRACE_ROUTINES, ("claimsman!claimsmanPostOperation: no client connected!")); } RtlFreeUnicodeString(&sidString); } } FltReleaseFileNameInformation(nameInfo); if (pTokenUser != NULL) { ExFreePool(pTokenUser); } return FLT_POSTOP_FINISHED_PROCESSING; }