|
|
#include <nt.h>
#include <ntrtl.h>
#include <nturtl.h>
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <windows.h>
#define QuadAlign(n) (((n) + (sizeof(LONGLONG) - 1)) & ~(sizeof(LONGLONG) - 1))
#define DwordAlign(n)(((n) + (sizeof(ULONG) - 1)) & ~(sizeof(ULONG) - 1))
#define STRUCT_COUNT(n, type, name_length) \
((((n) * QuadAlign(sizeof(type)) + ((name_length) * sizeof(WCHAR))) + \ sizeof(type) - 1) / \ sizeof(type))
#define SID_MAX_LENGTH \
(FIELD_OFFSET(SID, SubAuthority) + sizeof(ULONG) * SID_MAX_SUB_AUTHORITIES)
#define DISK_EVENT_MODULE "System"
#define IO_FILE_QUOTA_THRESHOLD ((NTSTATUS)0x40040024L)
#define IO_FILE_QUOTA_LIMIT ((NTSTATUS)0x80040025L)
VOID DumpQuota ( IN PFILE_QUOTA_INFORMATION pfqi, IN PCHAR SeverName );
CHAR * FileTimeToString( FILETIME *pft );
VOID PrintError( ULONG ErrorCode );
VOID Usage();
BOOLEAN QuickSid;
VOID STDMETHODVCALLTYPE main( int Argc, char *Argv[] )
{ HANDLE FileHandle; NTSTATUS Status; OBJECT_ATTRIBUTES ObjectAttributes; ANSI_STRING DiskName; UNICODE_STRING NameString; IO_STATUS_BLOCK IoStatus; ULONG BufferSize; ULONG SidListLength; LONG i; PWCHAR Wstr; PEVENTLOGRECORD EventLogRecord; FILE_QUOTA_INFORMATION QuotaInfo[STRUCT_COUNT(10, FILE_QUOTA_INFORMATION, 4)]; FILE_QUOTA_INFORMATION TempQuotaInfo[STRUCT_COUNT(1, FILE_QUOTA_INFORMATION, 32)]; FILE_GET_QUOTA_INFORMATION SidList[STRUCT_COUNT(10, FILE_GET_QUOTA_INFORMATION, 4)]; PFILE_GET_QUOTA_INFORMATION SidListPtr; PFILE_QUOTA_INFORMATION QuotaInfoPtr; FILE_FS_CONTROL_INFORMATION ControlInfo; FILE_FS_CONTROL_INFORMATION TempControlInfo; PCHAR ServerName = NULL; SID_NAME_USE SidNameUse; LARGE_INTEGER TempLargeInt; ULONG ErrorCode; ULONG DomainLength; CHAR Domain[100]; PCHAR TempPtr; BOOLEAN UserGiven = 0; BOOLEAN DriveLetter = 0; BOOLEAN EventLog = 0; BOOLEAN SettingDefault = 0; BOOLEAN DefaultGiven = 0; BOOLEAN DeletingUser = 0;
struct { UCHAR DefaultLimit : 1; UCHAR DefaultThreshold : 1; UCHAR Flags : 1; } DefaultFlags = { 0, 0, 0 };
if (Argc < 2) { printf ( "Processor feature is %d\n", IsProcessorFeaturePresent(0)); Usage(); exit(1); }
RtlZeroMemory(&QuotaInfo, sizeof(QuotaInfo)); QuotaInfoPtr = QuotaInfo; RtlZeroMemory(&SidList, sizeof(SidList)); SidListPtr = SidList;
RtlInitString( &DiskName, "\\DosDevices\\d:\\$Extend\\$Quota:$Q:$INDEX_ALLOCATION" ); RtlAnsiStringToUnicodeString( &NameString, &DiskName, TRUE );
// Look for the d and repleace it with the requested Argument.
for (Wstr = NameString.Buffer; *Wstr != L'd'; Wstr++);
for (i = 1; i < Argc; i++) {
if (*Argv[i] != '-') {
if (DriveLetter || !isalpha(*Argv[i])) { Usage(); exit(1); }
TempPtr = Argv[i]; *Wstr = RtlAnsiCharToUnicodeChar( &TempPtr ); DriveLetter++; continue; }
switch (Argv[i][1]) { case 'd':
DefaultGiven = 1; SettingDefault = 1; break;
case 'e':
if (EventLog) { Usage(); exit(1); }
if (Argv[i][2] == '\0') { i++; if (i < Argc && Argv[i][0] == '\\') { ServerName = Argv[i]; }
} else {
ServerName = &Argv[i][2]; }
EventLog++; break;
case 'u':
QuotaInfoPtr = (PFILE_QUOTA_INFORMATION) ((PCHAR) QuotaInfoPtr + QuotaInfoPtr->NextEntryOffset);
SidListPtr = (PFILE_GET_QUOTA_INFORMATION) ((PCHAR) SidListPtr + SidListPtr->NextEntryOffset);
if (Argv[i][2] == '\0') { i++; if (i >= Argc) { printf("%s: Missing user name\n", Argv[0] ); exit(1); }
TempPtr = Argv[i];
} else {
TempPtr = Argv[i]; TempPtr += 2; }
QuotaInfoPtr->SidLength = SID_MAX_LENGTH; DomainLength = sizeof(Domain);
if (!LookupAccountName( NULL, TempPtr, &QuotaInfoPtr->Sid, &QuotaInfoPtr->SidLength, Domain, &DomainLength, &SidNameUse)) {
printf("%s: Bad acccount name %s. Error = %d\n", Argv[0], TempPtr, ErrorCode = GetLastError());
PrintError( ErrorCode ); exit(1); }
//
// Initialize the values to something resonable.
//
QuotaInfoPtr->QuotaThreshold.QuadPart = ~0I64; QuotaInfoPtr->QuotaLimit.QuadPart = ~0I64;
QuotaInfoPtr->SidLength = RtlLengthSid( &QuotaInfoPtr->Sid);
QuotaInfoPtr->NextEntryOffset = FIELD_OFFSET( FILE_QUOTA_INFORMATION, Sid ) + QuadAlign(QuotaInfoPtr->SidLength);
memcpy( &SidListPtr->Sid, &QuotaInfoPtr->Sid, QuotaInfoPtr->SidLength); SidListPtr->SidLength = QuotaInfoPtr->SidLength;
SidListPtr->NextEntryOffset = FIELD_OFFSET( FILE_GET_QUOTA_INFORMATION, Sid ) + QuadAlign(SidListPtr->SidLength);
SettingDefault = 0; UserGiven++; break;
case 't':
if (Argv[i][2] == '\0') { i++; if (i >= Argc) { printf("%s: Missing Argument\n", Argv[0] ); exit(1); }
TempPtr = Argv[i];
} else {
TempPtr = Argv[i]; TempPtr += 2; }
if (!sscanf( TempPtr, "%I64i", &TempLargeInt)) { printf("%s: Missing threshold value\n", Argv[0] ); exit(1); }
if (SettingDefault) { ControlInfo.DefaultQuotaThreshold = TempLargeInt; DefaultFlags.DefaultThreshold = TRUE;
} else { QuotaInfoPtr->QuotaThreshold = TempLargeInt; }
break;
case 'l':
if (Argv[i][2] == '\0') { i++; if (i >= Argc) { printf("%s: Missing limit value\n", Argv[0] ); exit(1); }
TempPtr = Argv[i];
} else {
TempPtr = Argv[i]; TempPtr += 2; }
if (!sscanf( TempPtr, "%I64i", &TempLargeInt)) { printf("%s: Missing value\n", Argv[0] ); exit(1); }
if (SettingDefault) { ControlInfo.DefaultQuotaLimit = TempLargeInt; DefaultFlags.DefaultLimit = TRUE;
} else { QuotaInfoPtr->QuotaLimit = TempLargeInt;
if (TempLargeInt.QuadPart == -2i64) { DeletingUser = TRUE; } }
break;
case 'q': QuickSid++; break;
case 'f':
if (Argv[i][2] == '\0') { i++; if (i >= Argc) { printf("%s: Missing flag setting\n", Argv[0] ); exit(1); }
TempPtr = Argv[i];
} else {
TempPtr = Argv[i]; TempPtr += 2; }
switch (*TempPtr) { case 'e': ControlInfo.FileSystemControlFlags |= FILE_VC_QUOTA_ENFORCE; break;
case 't': ControlInfo.FileSystemControlFlags |= FILE_VC_QUOTA_TRACK; break;
case 'd': ControlInfo.FileSystemControlFlags &= ~(FILE_VC_QUOTA_MASK | FILE_VC_LOG_QUOTA_LIMIT | FILE_VC_LOG_QUOTA_THRESHOLD); break;
default:
printf("%s: Invalid or missing flag setting.\n", Argv[0] ); Usage(); exit(1); }
while (*++TempPtr != '\0') { switch (*TempPtr) { case 'l': ControlInfo.FileSystemControlFlags |= FILE_VC_LOG_QUOTA_LIMIT; break; case 't': ControlInfo.FileSystemControlFlags |= FILE_VC_LOG_QUOTA_THRESHOLD; break; default:
printf("%s: Invalid flag setting.\n", Argv[0] ); Usage(); exit(1);
}
}
DefaultGiven = 1; DefaultFlags.Flags = TRUE; break;
default: printf("%s: Invalid or missing flag setting.\n", Argv[0] );
case '?': Usage(); exit(1); break;
} }
if (DriveLetter == 0 && EventLog == 0 ) { printf("%s: Missing drive-letter\n", Argv[0] ); }
if (EventLog && (DriveLetter || UserGiven)) { Usage(); exit(1); }
if (EventLog) {
//
// Open the event log and read andy events.
//
FileHandle = OpenEventLog( ServerName, DISK_EVENT_MODULE );
if (FileHandle == NULL) { printf("%s: Event log open failed. %s. Error = %d\n", Argv[0], ServerName == NULL ? "Local machine" : ServerName, ErrorCode = GetLastError());
PrintError( ErrorCode ); exit(1); }
while (ReadEventLog( FileHandle, EVENTLOG_SEQUENTIAL_READ | EVENTLOG_FORWARDS_READ, 0, QuotaInfo, sizeof(QuotaInfo), &BufferSize, &i )) {
if (BufferSize == 0) { break; }
for (EventLogRecord = (PEVENTLOGRECORD) QuotaInfo; (PCHAR) EventLogRecord < (PCHAR) QuotaInfo + BufferSize; EventLogRecord = (PEVENTLOGRECORD)((PCHAR) EventLogRecord + EventLogRecord->Length)) {
if (EventLogRecord->EventID == IO_FILE_QUOTA_THRESHOLD) { printf( "Quota threshold event at: %s", ctime( &EventLogRecord->TimeGenerated )); } else if (EventLogRecord->EventID == IO_FILE_QUOTA_LIMIT) { printf( "Quota limit event at: %s", ctime( &EventLogRecord->TimeGenerated )); } else { continue; }
//
// Look for the device name. It is the second string.
//
TempPtr = ((PCHAR) EventLogRecord + EventLogRecord->StringOffset);
printf( " on device %s\n", TempPtr );
TempPtr = ((PCHAR) EventLogRecord + EventLogRecord->DataOffset + FIELD_OFFSET( IO_ERROR_LOG_PACKET, DumpData ));
//
// Need to align the buffer.
//
RtlCopyMemory( TempQuotaInfo, TempPtr, EventLogRecord->DataLength - FIELD_OFFSET( IO_ERROR_LOG_PACKET, DumpData ));
DumpQuota( TempQuotaInfo, ServerName ); } }
ErrorCode = GetLastError();
if (ErrorCode =! ERROR_HANDLE_EOF) { printf("%s: Event log read failed. Error = %d\n", Argv[0], ErrorCode);
PrintError( ErrorCode ); }
CloseEventLog( FileHandle );
exit(0); }
//
// Terminate the list.
//
BufferSize = (PCHAR) QuotaInfoPtr - (PCHAR) QuotaInfo + QuotaInfoPtr->NextEntryOffset; QuotaInfoPtr->NextEntryOffset = 0;
SidListLength = (PCHAR) SidListPtr - (PCHAR) SidList + SidListPtr->NextEntryOffset; SidListPtr->NextEntryOffset = 0;
SidListPtr = SidList;
InitializeObjectAttributes( &ObjectAttributes, &NameString, OBJ_CASE_INSENSITIVE, NULL, NULL );
Status = NtOpenFile( &FileHandle, FILE_READ_DATA | FILE_WRITE_DATA | SYNCHRONIZE, &ObjectAttributes, &IoStatus, FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_SYNCHRONOUS_IO_ALERT | FILE_OPEN_FOR_BACKUP_INTENT);
if (!NT_SUCCESS( Status )) { printf( "Error opening input file %S; error was: %lx\n", NameString.Buffer, Status ); PrintError( Status ); exit(1); }
if (DefaultGiven) {
Status = NtQueryVolumeInformationFile( FileHandle, &IoStatus, &TempControlInfo, sizeof( FILE_FS_CONTROL_INFORMATION ), FileFsControlInformation );
if (!NT_SUCCESS( Status )) { printf( "Error NtQueryVolumeInformationFile; error was %lx\n", Status ); PrintError( Status ); exit(1); }
if (DefaultFlags.Flags) { TempControlInfo.FileSystemControlFlags &= ~FILE_VC_QUOTA_MASK; TempControlInfo.FileSystemControlFlags |= ControlInfo.FileSystemControlFlags; }
if (DefaultFlags.DefaultLimit) { TempControlInfo.DefaultQuotaLimit = ControlInfo.DefaultQuotaLimit; }
if (DefaultFlags.DefaultThreshold) { TempControlInfo.DefaultQuotaThreshold = ControlInfo.DefaultQuotaThreshold; }
Status = NtSetVolumeInformationFile( FileHandle, &IoStatus, &TempControlInfo, sizeof( FILE_FS_CONTROL_INFORMATION ), FileFsControlInformation );
if (!NT_SUCCESS( Status )) { printf( "Error NtSetVolumeInformationFile; error was %lx\n", Status ); PrintError( Status ); exit(1); } }
Status = NtQueryVolumeInformationFile( FileHandle, &IoStatus, &TempControlInfo, sizeof( FILE_FS_CONTROL_INFORMATION ), FileFsControlInformation );
printf( "FileSystemControlFlags = %8lx\n", TempControlInfo.FileSystemControlFlags); if ((TempControlInfo.FileSystemControlFlags & FILE_VC_QUOTA_MASK) == FILE_VC_QUOTA_NONE) {
TempPtr = "Quotas are disabled on this volume"; } else if ((TempControlInfo.FileSystemControlFlags & FILE_VC_QUOTA_MASK) == FILE_VC_QUOTA_TRACK) {
TempPtr = "Quota tracking is enabled on this volume";
}else if (TempControlInfo.FileSystemControlFlags & FILE_VC_QUOTA_ENFORCE) {
TempPtr = "Quota tracking and enforment is enabled on this volume";
}
printf("%s.\n", TempPtr);
switch (TempControlInfo.FileSystemControlFlags & (FILE_VC_LOG_QUOTA_LIMIT | FILE_VC_LOG_QUOTA_THRESHOLD)) { case FILE_VC_LOG_QUOTA_LIMIT: printf("Logging enable for quota limits.\n"); break; case FILE_VC_LOG_QUOTA_THRESHOLD: printf("Logging enable for quota thresholds.\n"); break; case FILE_VC_LOG_QUOTA_LIMIT | FILE_VC_LOG_QUOTA_THRESHOLD: printf("Logging enable for quota limits and threshold.\n"); break; case 0: printf("Logging for quota events is not enabled.\n"); break; }
if (TempControlInfo.FileSystemControlFlags & FILE_VC_QUOTA_MASK) { if (TempControlInfo.FileSystemControlFlags & FILE_VC_QUOTAS_INCOMPLETE) { TempPtr = "The quota values are incomplete.\n"; } else { TempPtr = "The quota values are up to date.\n"; }
printf(TempPtr); }
printf("Default Quota Threshold = %16I64x\n", TempControlInfo.DefaultQuotaThreshold.QuadPart); printf("Default Quota Limit = %16I64x\n\n", TempControlInfo.DefaultQuotaLimit.QuadPart);
if (UserGiven) {
Status = NtSetQuotaInformationFile( FileHandle, &IoStatus, QuotaInfo, BufferSize );
if (!NT_SUCCESS( Status )) { printf( "Error NtSetVolumeInformationFile; error was %lx\n", Status ); PrintError( Status ); exit(1); }
}
if (!UserGiven || DeletingUser) { SidListPtr = NULL; SidListLength = 0; }
do {
Status = NtQueryQuotaInformationFile( FileHandle, &IoStatus, QuotaInfo, sizeof(QuotaInfo), FALSE, SidListPtr, SidListLength, NULL, FALSE );
if (!NT_SUCCESS( Status ) && Status != STATUS_NO_MORE_ENTRIES) { printf( "Error NtQueryVolumeInformationFile; error was %lx\n", Status ); PrintError( Status ); exit(1); }
QuotaInfoPtr = QuotaInfo;
while (TRUE) {
DumpQuota( QuotaInfoPtr, ServerName );
if (QuotaInfoPtr->NextEntryOffset == 0) { break; }
QuotaInfoPtr = (PFILE_QUOTA_INFORMATION) ((PCHAR) QuotaInfoPtr + QuotaInfoPtr->NextEntryOffset);
} } while ( Status != STATUS_NO_MORE_ENTRIES );
NtClose( FileHandle ); }
VOID DumpQuota ( IN PFILE_QUOTA_INFORMATION FileQuotaInfo, IN PCHAR ServerName ) { SID_NAME_USE SidNameUse; ULONG AccountLength, DomainLength; ULONG ErrorCode; char AccountName[128]; char DomainName[128]; UNICODE_STRING String; NTSTATUS Status;
AccountLength = sizeof(AccountName) - 1; DomainLength = sizeof(DomainName) - 1;
if (FileQuotaInfo->SidLength == 0) {
printf( "Default quota values \n" );
} else if (QuickSid) {
String.Buffer = (PWCHAR) AccountName; String.MaximumLength = sizeof( AccountName ); String.Length = 0;
Status = RtlConvertSidToUnicodeString( &String, &FileQuotaInfo->Sid, FALSE );
if (!NT_SUCCESS(Status)) { printf("DumpQuota: RtlConvertSidToUnicodeString failed. Error = %d\n", Status); PrintError( Status ); } else { printf( "SID Value = %S\n", String.Buffer ); }
} else if (LookupAccountSidA( ServerName, &FileQuotaInfo->Sid, AccountName, &AccountLength, DomainName, &DomainLength, &SidNameUse)) { char *String;
AccountName[AccountLength] = '\0'; DomainName[DomainLength] = '\0'; switch (SidNameUse) { case SidTypeUser: String = "User"; break; case SidTypeGroup: String = "Group"; break; case SidTypeDomain: String = "Domain"; break; case SidTypeAlias: String = "Alias"; break; case SidTypeWellKnownGroup: String = "WellKnownGroup"; break; case SidTypeDeletedAccount: String = "DeletedAccount"; break; case SidTypeInvalid: String = "Invalid"; break; default: String = "Unknown"; break; } printf( "SID Name = %s\\%s (%s)\n", DomainName, AccountName, String);
} else {
printf("DumpQuota: Bad acccount SID. Error = %d\n", ErrorCode = GetLastError()); PrintError( ErrorCode );
}
printf("Change time = %s\n", FileTimeToString((PFILETIME) &FileQuotaInfo->ChangeTime)); printf("Quota Used = %16I64x\n", FileQuotaInfo->QuotaUsed.QuadPart); printf("Quota Threshold = %16I64x\n", FileQuotaInfo->QuotaThreshold.QuadPart); printf("Quota Limit = %16I64x\n\n", FileQuotaInfo->QuotaLimit.QuadPart);
}
char *Days[] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };
char *Months[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
CHAR * FileTimeToString(FILETIME *FileTime) { FILETIME LocalFileTime; SYSTEMTIME SystemTime; static char Buffer[32];
Buffer[0] = '\0'; if (FileTime->dwHighDateTime != 0 || FileTime->dwLowDateTime != 0) { if (!FileTimeToLocalFileTime(FileTime, &LocalFileTime) || !FileTimeToSystemTime(&LocalFileTime, &SystemTime)) { return("Time???"); } sprintf( Buffer, "%s %s %2d %2d:%02d:%02d %4d", Days[SystemTime.wDayOfWeek], Months[SystemTime.wMonth - 1], SystemTime.wDay, SystemTime.wHour, SystemTime.wMinute, SystemTime.wSecond, SystemTime.wYear); } return(Buffer); }
VOID PrintError(ULONG ErrorCode) { UCHAR ErrorBuffer[80]; ULONG Count; HMODULE FileHandle = NULL; ULONG Flags = FORMAT_MESSAGE_FROM_SYSTEM;
if (ErrorCode > MAXLONG) { Flags = FORMAT_MESSAGE_FROM_HMODULE; FileHandle = LoadLibrary( "ntdll" ); if (FileHandle == NULL) { ULONG ErrorCode;
printf("PrintError: LoadLibrary filed. Error = %d\n", ErrorCode = GetLastError());
PrintError( ErrorCode ); }
}
Count = FormatMessage(Flags, FileHandle, ErrorCode, 0, ErrorBuffer, sizeof(ErrorBuffer), NULL );
if (Count != 0) { printf("Error was: %s\n", ErrorBuffer); } else { printf("Format message failed. Error: %d\n", GetLastError()); }
if (FileHandle != NULL) { FreeLibrary( FileHandle ); } }
VOID Usage() { printf( "Usage: %s -e [\\ServerName] | drive-letter [-q ] [ -f e|t|d [lt] ] [-d | -u account-name -t Threshold -l Limit] \n", __argv[0] ); printf( " -e [\\ServerName] Print quota events from specified server default is local.\n"); printf( " [-q] Quick print Sids. \n"); printf( " [-f e|t|d[lt] ] Set volume quota flags (For example -f elt ): \n"); printf( " [e]nforce quota limits.\n" ); printf( " [t]rack quota usage.\n" ); printf( " [d]isable quotas.\n" ); printf( " [l]imit events should be logged.\n" ); printf( " [t]threhold events should be logged.\n" ); printf( " [-d] Set default user quota values.\n"); printf( " [-u AccountName] Set quota values for user. \n"); printf( " [-l Limit] Set 64-Bit limit value preivously specified user. \n"); printf( " A limit of -2 indicates a defunct user can be removed. \n"); printf( " [-t Threshold] Set 64-Bit threshold value preivously specified user. \n\n"); printf( " Example:\n %s d -f elt -d -t 4194304 -l 5242880 -u administrators -l 0xffffffffffffffff -t 0xffffffffffffffff\n", __argv[0] ); }
|