|
|
/*++
Copyright (c) 1998 Microsoft Corporation
Module Name:
cmds1.c
Abstract:
This module implements miscellaneous commands.
Author:
Wesley Witt (wesw) 21-Oct-1998
Revision History:
--*/
#include "cmdcons.h"
#pragma hdrstop
BOOLEAN AllowWildCards;
NTSTATUS RcSetFileAttributes( LPCWSTR lpFileName, DWORD dwFileAttributes );
NTSTATUS RcSetFileCompression( LPCWSTR szFileName, BOOLEAN bCompress ); NTSTATUS RcGetFileAttributes( LPCWSTR lpFileName, PULONG FileAttributes );
BOOLEAN pRcCmdEnumDelFiles( IN LPCWSTR Directory, IN PFILE_BOTH_DIR_INFORMATION FileInfo, OUT NTSTATUS *Status, IN PWCHAR DosDirectorySpec );
ULONG RcCmdType( IN PTOKENIZED_LINE TokenizedLine ) { LPCWSTR Arg; HANDLE FileHandle; HANDLE SectionHandle; PVOID ViewBase; ULONG FileSize; ULONG rc; ULONG cbText; WCHAR *pText; NTSTATUS Status;
if (RcCmdParseHelp( TokenizedLine, MSG_TYPE_HELP )) { return 1; }
//
// There should be a token for TYPE and one for the arg.
//
ASSERT(TokenizedLine->TokenCount == 2);
//
// Get the argument and convert it into a full NT pathname.
//
Arg = TokenizedLine->Tokens->Next->String; if (!RcFormFullPath(Arg,_CmdConsBlock->TemporaryBuffer,FALSE)) { RcMessageOut(MSG_INVALID_PATH); return 1; }
if (!RcIsPathNameAllowed(_CmdConsBlock->TemporaryBuffer,TRUE,FALSE)) { RcMessageOut(MSG_ACCESS_DENIED); return 1; }
//
// Get the argument and convert it into a full NT pathname.
//
if (!RcFormFullPath(Arg,_CmdConsBlock->TemporaryBuffer,TRUE)) { RcMessageOut(MSG_INVALID_PATH); return 1; }
//
// Map in the entire file.
//
FileHandle = NULL; Status = SpOpenAndMapFile( _CmdConsBlock->TemporaryBuffer, &FileHandle, &SectionHandle, &ViewBase, &FileSize, FALSE );
if( !NT_SUCCESS(Status) ) { RcNtError(Status,MSG_CANT_OPEN_FILE); return 1; }
//
// See if we think the file is Unicode. We think it's Unicode
// if it's even length and starts with the Unicode text marker.
//
pText = ViewBase; cbText = FileSize;
try { if( (cbText >= sizeof(WCHAR)) && (*pText == 0xfeff) && !(cbText & 1) ) { //
// Assume it's already unicode.
//
pText = SpMemAlloc(cbText); RtlCopyMemory(pText,(WCHAR *)ViewBase+1,cbText-sizeof(WCHAR)); pText[cbText/sizeof(WCHAR)] = 0;
} else { //
// It's not Unicode. Convert it from ANSI to Unicode.
//
// Allocate a buffer large enough to hold the maximum
// unicode text. This max size occurs when
// every character is single-byte, and this size is
// equal to exactly double the size of the single-byte text.
//
pText = SpMemAlloc((cbText+1)*sizeof(WCHAR)); RtlZeroMemory(pText,(cbText+1)*sizeof(WCHAR));
Status = RtlMultiByteToUnicodeN( pText, // output: newly allocated buffer
cbText * sizeof(WCHAR), // max size of output
&cbText, // receives # bytes in unicode text
ViewBase, // input: ANSI text (mapped file)
cbText // size of input
); } }except(IN_PAGE_ERROR) { Status = STATUS_IN_PAGE_ERROR; }
if( NT_SUCCESS(Status) ) { pRcEnableMoreMode(); RcTextOut(pText); pRcDisableMoreMode(); } else { RcNtError(Status,MSG_CANT_READ_FILE); }
if( pText != ViewBase ) { SpMemFree(pText); } SpUnmapFile(SectionHandle,ViewBase); ZwClose(FileHandle);
return 1; }
ULONG RcCmdDelete( IN PTOKENIZED_LINE TokenizedLine ) { WCHAR *Final; BOOLEAN Confirm = FALSE; OBJECT_ATTRIBUTES Obja; UNICODE_STRING UnicodeString; NTSTATUS Status; IO_STATUS_BLOCK IoStatusBlock; HANDLE Handle; PWSTR DelSpec = NULL; PWSTR DosDelSpec = NULL; WCHAR Text[2]; PWSTR YesNo = NULL; ULONG rc;
if (RcCmdParseHelp( TokenizedLine, MSG_DELETE_HELP )) { goto exit; }
//
// Fetch the spec for the file to be deleted and convert it
// into a fully-qualified NT-style path.
//
if (!RcFormFullPath(TokenizedLine->Tokens->Next->String,_CmdConsBlock->TemporaryBuffer,TRUE)) { RcMessageOut(MSG_INVALID_PATH); goto exit; }
//
// Leave room for appending * if necessary.
//
DelSpec = SpMemAlloc((wcslen(_CmdConsBlock->TemporaryBuffer)+3)*sizeof(WCHAR)); wcscpy(DelSpec,_CmdConsBlock->TemporaryBuffer);
//
// Do the same thing, except now we want the DOS-style name.
// This is used for printing in case of errors.
//
if (!RcFormFullPath(TokenizedLine->Tokens->Next->String,_CmdConsBlock->TemporaryBuffer,FALSE)) { RcMessageOut(MSG_INVALID_PATH); goto exit; }
DosDelSpec = SpMemAlloc((wcslen(_CmdConsBlock->TemporaryBuffer)+3)*sizeof(WCHAR)); wcscpy(DosDelSpec,_CmdConsBlock->TemporaryBuffer);
//
// see if the user is authorized to delete this file
//
if (!RcIsPathNameAllowed(_CmdConsBlock->TemporaryBuffer,TRUE,FALSE)) { RcMessageOut(MSG_ACCESS_DENIED); goto exit; }
if (RcDoesPathHaveWildCards(_CmdConsBlock->TemporaryBuffer)) { Confirm = TRUE; if (!AllowWildCards) { RcMessageOut(MSG_DEL_WILDCARD_NOT_SUPPORTED); goto exit; } }
//
// Check to see whether the target specifies a directory.
// If so, add the * so we don't need to special-case
// the confirmation message later.
//
INIT_OBJA(&Obja,&UnicodeString,DelSpec);
Status = ZwOpenFile( &Handle, FILE_READ_ATTRIBUTES, &Obja, &IoStatusBlock, FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_DIRECTORY_FILE ); if( NT_SUCCESS(Status) ) { ZwClose(Handle); SpConcatenatePaths(DelSpec,L"*"); SpConcatenatePaths(DosDelSpec,L"*"); Confirm = TRUE; }
//
// Fetch yes/no text
//
YesNo = SpRetreiveMessageText(ImageBase,MSG_YESNO,NULL,0); if (!YesNo) { Confirm = FALSE; }
if (!InBatchMode) { while( Confirm ) { RcMessageOut(MSG_CONFIRM_DELETE,DosDelSpec); if( RcLineIn(Text,2) ) { if( (Text[0] == YesNo[0]) || (Text[0] == YesNo[1]) ) { //
// Wants to do it.
//
Confirm = FALSE; } else { if( (Text[0] == YesNo[2]) || (Text[0] == YesNo[3]) ) { //
// Doesn't want to do it.
//
goto exit; } } } } }
//
// Trim back the DOS-style path so it's a path to the directory
// containing the file or files to be deleted.
//
*wcsrchr(DosDelSpec,L'\\') = 0;
// Perform deletion via callback.
//
Status = RcEnumerateFiles(TokenizedLine->Tokens->Next->String, DelSpec, pRcCmdEnumDelFiles, DosDelSpec);
if( !NT_SUCCESS(Status) ) { RcNtError(Status,MSG_FILE_ENUM_ERROR); }
exit:
if (DelSpec) { SpMemFree(DelSpec); } if (DosDelSpec) { SpMemFree(DosDelSpec); } if (YesNo) { SpMemFree(YesNo); }
return 1; }
BOOLEAN pRcCmdEnumDelFiles( IN LPCWSTR Directory, IN PFILE_BOTH_DIR_INFORMATION FileInfo, OUT NTSTATUS *Status, IN PWCHAR DosDirectorySpec ) { NTSTATUS status; HANDLE Handle; IO_STATUS_BLOCK IoStatusBlock; UNICODE_STRING UnicodeString; OBJECT_ATTRIBUTES Obja; WCHAR *p; FILE_DISPOSITION_INFORMATION Disposition; unsigned u;
*Status = STATUS_SUCCESS;
//
// Skip directories
//
if( FileInfo->FileAttributes & FILE_ATTRIBUTE_DIRECTORY ) { return(TRUE); }
//
// Form fully qualified NT path of the file to be deleted.
//
u = ((wcslen(Directory)+2)*sizeof(WCHAR)) + FileInfo->FileNameLength; p = SpMemAlloc(u); wcscpy(p,Directory); SpConcatenatePaths(p,FileInfo->FileName);
INIT_OBJA(&Obja,&UnicodeString,p);
status = ZwOpenFile( &Handle, (ACCESS_MASK)DELETE, &Obja, &IoStatusBlock, FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_NON_DIRECTORY_FILE | FILE_OPEN_FOR_BACKUP_INTENT );
if( !NT_SUCCESS(status) ) { RcTextOut(DosDirectorySpec); RcTextOut(L"\\"); RcTextOut(FileInfo->FileName); RcTextOut(L"\r\n"); RcNtError(status,MSG_DELETE_ERROR); SpMemFree(p); return(TRUE); }
#undef DeleteFile
Disposition.DeleteFile = TRUE;
status = ZwSetInformationFile( Handle, &IoStatusBlock, &Disposition, sizeof(FILE_DISPOSITION_INFORMATION), FileDispositionInformation );
ZwClose(Handle);
if( !NT_SUCCESS(status) ) { RcTextOut(DosDirectorySpec); RcTextOut(L"\\"); RcTextOut(FileInfo->FileName); RcTextOut(L"\r\n"); RcNtError(status,MSG_DELETE_ERROR); }
SpMemFree(p);
return(TRUE); }
ULONG RcCmdRename( IN PTOKENIZED_LINE TokenizedLine ) { WCHAR *Arg; WCHAR *p,*q; NTSTATUS Status; ULONG rc;
//
// check for help
//
if (RcCmdParseHelp( TokenizedLine, MSG_RENAME_HELP )) { return 1; }
//
// There should be a token for RENAME and one each for the source and
// target names.
//
if (TokenizedLine->TokenCount != 3) { RcMessageOut(MSG_SYNTAX_ERROR); return 1; }
//
// use the console's temporary buffer
//
p = _CmdConsBlock->TemporaryBuffer;
//
// process the SOURCE filename
//
Arg = TokenizedLine->Tokens->Next->String;
//
// Convert the SOURCE filname into a DOS path so we
// can verify if the path is allowed by our security restrictions.
//
if (!RcFormFullPath(Arg,p,FALSE)) { RcMessageOut(MSG_INVALID_PATH); return 1; }
if (!RcIsPathNameAllowed(p,TRUE,FALSE)) { RcMessageOut(MSG_ACCESS_DENIED); return 1; }
//
// Convert the SOURCE filename into a fully qualified
// NT-style path name.
//
if (!RcFormFullPath(Arg,p,TRUE)) { RcMessageOut(MSG_INVALID_PATH); return 1; }
//
// using the same buffer for the TARGET name
//
q = p + wcslen(p) + 1;
//
// get the TARGET file name
//
Arg = TokenizedLine->Tokens->Next->Next->String;
//
// Verify that the TARGET filename does not contain
// any path seperator characters or drive specifier
// characters.
//
if( wcschr(Arg,L'\\') ) { RcMessageOut(MSG_SYNTAX_ERROR); return 1; } if( RcIsAlpha(Arg[0]) && (Arg[1] == L':') ) { RcMessageOut(MSG_SYNTAX_ERROR); return 1; }
//
// Convert the DESTINATION filename into a DOS path so we
// can verify if the path is allowed by our security restrictions.
//
if (!RcFormFullPath(Arg,q,FALSE)) { RcMessageOut(MSG_INVALID_PATH); return 1; }
if (!RcIsPathNameAllowed(q,TRUE,FALSE)) { RcMessageOut(MSG_ACCESS_DENIED); return 1; }
//
// Convert the SOURCE filename into a fully qualified
// NT-style path name.
//
if (!RcFormFullPath(Arg,q,TRUE)) { RcMessageOut(MSG_INVALID_PATH); return 1; } //
// OK, looks like a plain filename specification.
// Glom it onto the end of the relevent part of the
// source specification so we have 2 fully qualified names.
//
// wcscpy(q,p);
// wcscpy(wcsrchr(q,L'\\')+1,Arg);
//
// Call worker routine to actually do the rename.
//
Status = SpRenameFile(p,q,TRUE);
if( !NT_SUCCESS(Status) ) { RcNtError(Status,MSG_RENAME_ERROR, Arg); }
return 1; }
ULONG RcCmdMkdir( IN PTOKENIZED_LINE TokenizedLine ) { NTSTATUS Status; UNICODE_STRING UnicodeString; IO_STATUS_BLOCK IoStatusBlock; HANDLE Handle; OBJECT_ATTRIBUTES Obja; ULONG rc;
if (RcCmdParseHelp( TokenizedLine, MSG_MAKEDIR_HELP )) { return 1; }
//
// There should be a token for MKDIR and one for the target.
//
ASSERT(TokenizedLine->TokenCount == 2);
//
// Convert the given arg into a fully qualified NT path specification.
//
if (!RcFormFullPath(TokenizedLine->Tokens->Next->String,_CmdConsBlock->TemporaryBuffer,FALSE)) { RcMessageOut(MSG_INVALID_PATH); return 1; }
if (!RcIsPathNameAllowed(_CmdConsBlock->TemporaryBuffer,TRUE,TRUE)) { RcMessageOut(MSG_ACCESS_DENIED); return 1; }
//
// Convert the given arg into a fully qualified NT path specification.
//
if (!RcFormFullPath(TokenizedLine->Tokens->Next->String,_CmdConsBlock->TemporaryBuffer,TRUE)) { RcMessageOut(MSG_INVALID_PATH); return 1; }
//
// Create the directory.
//
INIT_OBJA(&Obja,&UnicodeString,_CmdConsBlock->TemporaryBuffer);
Status = ZwCreateFile( &Handle, FILE_LIST_DIRECTORY | SYNCHRONIZE, &Obja, &IoStatusBlock, NULL, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_CREATE, FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_FOR_BACKUP_INTENT, NULL, 0 );
if( NT_SUCCESS(Status) ) { ZwClose(Handle); } else { RcNtError(Status,MSG_CREATE_DIR_FAILED,TokenizedLine->Tokens->Next->String); }
return 1; }
ULONG RcCmdRmdir( IN PTOKENIZED_LINE TokenizedLine ) { NTSTATUS Status; HANDLE Handle; IO_STATUS_BLOCK IoStatusBlock; UNICODE_STRING UnicodeString; OBJECT_ATTRIBUTES Obja; FILE_DISPOSITION_INFORMATION Disposition; ULONG rc;
if (RcCmdParseHelp( TokenizedLine, MSG_REMOVEDIR_HELP )) { return 1; }
//
// There should be a token for RMDIR and one for the target.
//
ASSERT(TokenizedLine->TokenCount == 2);
//
// Convert the given arg into a fully qualified NT path specification.
//
if (!RcFormFullPath(TokenizedLine->Tokens->Next->String,_CmdConsBlock->TemporaryBuffer,FALSE)) { RcMessageOut(MSG_INVALID_PATH); return 1; }
if (!RcIsPathNameAllowed(_CmdConsBlock->TemporaryBuffer,TRUE,TRUE)) { RcMessageOut(MSG_ACCESS_DENIED); return 1; }
//
// Convert the given arg into a fully qualified NT path specification.
//
if (!RcFormFullPath(TokenizedLine->Tokens->Next->String,_CmdConsBlock->TemporaryBuffer,TRUE)) { RcMessageOut(MSG_INVALID_PATH); return 1; }
INIT_OBJA(&Obja,&UnicodeString,_CmdConsBlock->TemporaryBuffer);
Status = ZwOpenFile( &Handle, DELETE | SYNCHRONIZE, &Obja, &IoStatusBlock, FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_FOR_BACKUP_INTENT );
if( !NT_SUCCESS(Status) ) { RcNtError(Status,MSG_RMDIR_ERROR); return 1; }
Disposition.DeleteFile = TRUE;
Status = ZwSetInformationFile( Handle, &IoStatusBlock, &Disposition, sizeof(FILE_DISPOSITION_INFORMATION), FileDispositionInformation );
ZwClose(Handle);
if( !NT_SUCCESS(Status) ) { RcNtError(Status,MSG_RMDIR_ERROR); }
return 1; }
ULONG RcCmdSetFlags( IN PTOKENIZED_LINE TokenizedLine ) { if (RcCmdParseHelp( TokenizedLine, MSG_SETCMD_HELP )) { return 1; } if (TokenizedLine->TokenCount == 1) { RcTextOut( L"\r\n" ); RcMessageOut(MSG_SET_ALLOW_WILDCARDS,AllowWildCards?L"TRUE":L"FALSE"); RcMessageOut(MSG_SET_ALLOW_ALLPATHS,AllowAllPaths?L"TRUE":L"FALSE"); RcMessageOut(MSG_SET_ALLOW_REMOVABLE_MEDIA,AllowRemovableMedia?L"TRUE":L"FALSE"); RcMessageOut(MSG_SET_NO_COPY_PROMPT,NoCopyPrompt?L"TRUE":L"FALSE"); RcTextOut( L"\r\n" ); return 1; }
//
// should have the priviledge to use the SET command
//
if (TokenizedLine->TokenCount != 4) { RcMessageOut(MSG_SYNTAX_ERROR); return 1; }
if (RcGetSETCommandStatus() != TRUE) { RcMessageOut(MSG_SETCMD_DISABLED); return 1; }
if (_wcsicmp(TokenizedLine->Tokens->Next->String,L"allowallpaths")==0) { if (_wcsicmp(TokenizedLine->Tokens->Next->Next->Next->String,L"true")==0) { AllowAllPaths = TRUE; } else { AllowAllPaths = FALSE; } return 1; }
if (_wcsicmp(TokenizedLine->Tokens->Next->String,L"allowwildcards")==0) { if (_wcsicmp(TokenizedLine->Tokens->Next->Next->Next->String,L"true")==0) { AllowWildCards = TRUE; } else { AllowWildCards = FALSE; } return 1; }
if (_wcsicmp(TokenizedLine->Tokens->Next->String,L"allowremovablemedia")==0) { if (_wcsicmp(TokenizedLine->Tokens->Next->Next->Next->String,L"true")==0) { AllowRemovableMedia = TRUE; } else { AllowRemovableMedia = FALSE; } return 1; }
if (_wcsicmp(TokenizedLine->Tokens->Next->String,L"nocopyprompt")==0) { if (_wcsicmp(TokenizedLine->Tokens->Next->Next->Next->String,L"true")==0) { NoCopyPrompt = TRUE; } else { NoCopyPrompt = FALSE; } return 1; }
RcMessageOut(MSG_SYNTAX_ERROR); return 1; }
ULONG RcCmdAttrib( IN PTOKENIZED_LINE TokenizedLine ) { NTSTATUS Status; PWCHAR AttributeString; ULONG OldAttributes; ULONG NewAttributes; BOOLEAN SetAttribute; BOOLEAN bShowHelp = TRUE; BOOLEAN bChangeCompression = FALSE;
// "attrib -h <filename>" should clear the hidden attribute
// and not show the help
if (TokenizedLine->TokenCount > 2){ PWCHAR szSecondParam = TokenizedLine->Tokens->Next->String;
bShowHelp = !wcscmp( szSecondParam, L"/?" ); } if (bShowHelp && RcCmdParseHelp( TokenizedLine, MSG_ATTRIB_HELP )) { return 1; }
if (TokenizedLine->TokenCount != 3) { RcMessageOut(MSG_SYNTAX_ERROR); return 1; } //
// Fetch the spec for the file to be attribed and convert it
// into a fully-qualified NT-style path.
//
if (!RcFormFullPath(TokenizedLine->Tokens->Next->Next->String,_CmdConsBlock->TemporaryBuffer,FALSE)) { RcMessageOut(MSG_INVALID_PATH); return 1; }
//
// see if the user is authorized to change this file
//
if (!RcIsPathNameAllowed(_CmdConsBlock->TemporaryBuffer,TRUE,FALSE)) { RcMessageOut(MSG_ACCESS_DENIED); return 1; } if (!RcFormFullPath(TokenizedLine->Tokens->Next->Next->String,_CmdConsBlock->TemporaryBuffer,TRUE)) { RcMessageOut(MSG_INVALID_PATH); return 1; }
Status = RcGetFileAttributes( _CmdConsBlock->TemporaryBuffer, &OldAttributes ); if( !NT_SUCCESS(Status) ) { RcNtError(Status,MSG_CANT_OPEN_FILE); return 1; }
NewAttributes = OldAttributes; for(AttributeString = TokenizedLine->Tokens->Next->String; *AttributeString; AttributeString++){ if(*AttributeString == L'+'){ SetAttribute = TRUE; AttributeString++; } else if(*AttributeString == L'-'){ SetAttribute = FALSE; AttributeString++; } else { // attribute change should start with "+" or "-"
if (AttributeString == TokenizedLine->Tokens->Next->String) { RcMessageOut(MSG_SYNTAX_ERROR); return 1; }
// use the old state for setting or resetting (for +rsh
} switch(*AttributeString){ case L'h': case L'H': if (SetAttribute) NewAttributes |= FILE_ATTRIBUTE_HIDDEN; else NewAttributes &= ~FILE_ATTRIBUTE_HIDDEN; break; case L's': case L'S': if (SetAttribute) NewAttributes |= FILE_ATTRIBUTE_SYSTEM; else NewAttributes &= ~FILE_ATTRIBUTE_SYSTEM; break; case L'r': case L'R': if (SetAttribute) NewAttributes |= FILE_ATTRIBUTE_READONLY; else NewAttributes &= ~FILE_ATTRIBUTE_READONLY; break; case L'a': case L'A': if (SetAttribute) NewAttributes |= FILE_ATTRIBUTE_ARCHIVE; else NewAttributes &= ~FILE_ATTRIBUTE_ARCHIVE; break;
case L'c': case L'C': bChangeCompression = TRUE;
if (SetAttribute) NewAttributes |= FILE_ATTRIBUTE_COMPRESSED; else NewAttributes &= ~FILE_ATTRIBUTE_COMPRESSED; break; default: RcMessageOut(MSG_SYNTAX_ERROR); return 1; }
/*
if (SetAttribute) { FileAttributes |= Attribute; } else { FileAttributes &= ~Attribute; } */ }
Status = RcSetFileAttributes( _CmdConsBlock->TemporaryBuffer, NewAttributes ); if( !NT_SUCCESS(Status) ) { RcNtError(Status,MSG_CANT_OPEN_FILE); } else { if (bChangeCompression) { BOOLEAN bCompress = (NewAttributes & FILE_ATTRIBUTE_COMPRESSED) ? TRUE : FALSE; Status = RcSetFileCompression(_CmdConsBlock->TemporaryBuffer, bCompress);
if ( !NT_SUCCESS(Status) ) RcNtError(Status, MSG_ATTRIB_CANNOT_CHANGE_COMPRESSION); } }
return 1; }
NTSTATUS RcSetFileCompression( LPCWSTR szFileName, BOOLEAN bCompress ) { NTSTATUS Status; OBJECT_ATTRIBUTES Obja; HANDLE Handle; IO_STATUS_BLOCK IoStatusBlock; FILE_BASIC_INFORMATION BasicInfo; UNICODE_STRING FileName; USHORT uCompressionType; INIT_OBJA(&Obja,&FileName,szFileName); //
// Open the file inhibiting the reparse behavior.
//
Status = ZwOpenFile( &Handle, (ACCESS_MASK)FILE_WRITE_ATTRIBUTES | SYNCHRONIZE, &Obja, &IoStatusBlock, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_FOR_BACKUP_INTENT );
if (NT_SUCCESS(Status)) { //
// set & reset the compression bit also
//
uCompressionType = bCompress ? COMPRESSION_FORMAT_DEFAULT : COMPRESSION_FORMAT_NONE;
Status = ZwFsControlFile( Handle, // file handle
NULL, // event handle
NULL, // APC rountine pointer
NULL, // APC context
&IoStatusBlock, // IO status block
FSCTL_SET_COMPRESSION, // IOCTL code
&uCompressionType, // input buffer
sizeof(uCompressionType), // input buffer length
NULL, // output buffer pointer
0); // output buffer length
DbgPrint( "ZwDeviceIoControlFile() status : %X\r\n", Status);
ZwClose(Handle); }
return Status; }
NTSTATUS RcSetFileAttributes( LPCWSTR lpFileName, DWORD dwFileAttributes )
/*++
Routine Description:
The attributes of a file can be set using SetFileAttributes.
Arguments:
lpFileName - Supplies the file name of the file whose attributes are to be set.
dwFileAttributes - Specifies the file attributes to be set for the file. Any combination of flags is acceptable except that all other flags override the normal file attribute, FILE_ATTRIBUTE_NORMAL.
FileAttributes Flags:
FILE_ATTRIBUTE_NORMAL - A normal file should be created.
FILE_ATTRIBUTE_READONLY - A read-only file should be created.
FILE_ATTRIBUTE_HIDDEN - A hidden file should be created.
FILE_ATTRIBUTE_SYSTEM - A system file should be created.
FILE_ATTRIBUTE_ARCHIVE - The file should be marked so that it will be archived.
Return Value:
NTStatus of last NT call --*/
{ NTSTATUS Status; OBJECT_ATTRIBUTES Obja; HANDLE Handle; IO_STATUS_BLOCK IoStatusBlock; FILE_BASIC_INFORMATION BasicInfo; UNICODE_STRING FileName; USHORT uCompressionType; INIT_OBJA(&Obja,&FileName,lpFileName); //
// Open the file ihibiting the reparse behavior.
//
Status = ZwOpenFile( &Handle, (ACCESS_MASK)FILE_WRITE_ATTRIBUTES | SYNCHRONIZE, &Obja, &IoStatusBlock, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_FOR_BACKUP_INTENT | FILE_OPEN_REPARSE_POINT );
if ( !NT_SUCCESS(Status) ) { //
// Back level file systems may not support reparse points.
// We infer this is the case when the Status is STATUS_INVALID_PARAMETER.
//
if ( Status == STATUS_INVALID_PARAMETER ) { //
// Open the file without inhibiting the reparse behavior.
//
Status = ZwOpenFile( &Handle, (ACCESS_MASK)FILE_WRITE_ATTRIBUTES | SYNCHRONIZE, &Obja, &IoStatusBlock, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_FOR_BACKUP_INTENT ); if ( !NT_SUCCESS(Status) ) { return Status; }
} else { return Status; } }
//
// Set the basic attributes
//
ZeroMemory(&BasicInfo,sizeof(BasicInfo)); BasicInfo.FileAttributes = (dwFileAttributes & FILE_ATTRIBUTE_VALID_FLAGS) | FILE_ATTRIBUTE_NORMAL;
Status = ZwSetInformationFile( Handle, &IoStatusBlock, &BasicInfo, sizeof(BasicInfo), FileBasicInformation );
ZwClose(Handle);
return Status; }
NTSTATUS RcGetFileAttributes( LPCWSTR lpFileName, PULONG FileAttributes )
/*++
Routine Description:
Arguments:
lpFileName - Supplies the file name of the file whose attributes are to be set.
Return Value:
Not -1 - Returns the attributes of the specified file. Valid returned attributes are:
FILE_ATTRIBUTE_NORMAL - The file is a normal file.
FILE_ATTRIBUTE_READONLY - The file is marked read-only.
FILE_ATTRIBUTE_HIDDEN - The file is marked as hidden.
FILE_ATTRIBUTE_SYSTEM - The file is marked as a system file.
FILE_ATTRIBUTE_ARCHIVE - The file is marked for archive.
FILE_ATTRIBUTE_DIRECTORY - The file is marked as a directory.
FILE_ATTRIBUTE_REPARSE_POINT - The file is marked as a reparse point.
FILE_ATTRIBUTE_VOLUME_LABEL - The file is marked as a volume lable.
0xffffffff - The operation failed. Extended error status is available using GetLastError.
--*/
{ NTSTATUS Status; OBJECT_ATTRIBUTES Obja; UNICODE_STRING FileName; FILE_BASIC_INFORMATION BasicInfo; IO_STATUS_BLOCK IoStatusBlock; HANDLE Handle;
INIT_OBJA(&Obja,&FileName,lpFileName); //
// Open the file inhibiting the reparse behavior.
//
Status = ZwOpenFile( &Handle, (ACCESS_MASK)FILE_READ_ATTRIBUTES | SYNCHRONIZE, &Obja, &IoStatusBlock, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_FOR_BACKUP_INTENT | FILE_OPEN_REPARSE_POINT );
if ( !NT_SUCCESS(Status) ) { //
// Back level file systems may not support reparse points.
// We infer this is the case when the Status is STATUS_INVALID_PARAMETER.
//
if ( Status == STATUS_INVALID_PARAMETER ) { //
// Open the file without inhibiting the reparse behavior.
//
Status = ZwOpenFile( &Handle, (ACCESS_MASK)FILE_READ_ATTRIBUTES | SYNCHRONIZE, &Obja, &IoStatusBlock, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, FILE_SYNCHRONOUS_IO_NONALERT | FILE_OPEN_FOR_BACKUP_INTENT ); if ( !NT_SUCCESS(Status) ) { return Status; } } else { return Status; } }
//
// Query the file
//
Status = ZwQueryInformationFile( Handle, &IoStatusBlock, (PVOID) &BasicInfo, sizeof(BasicInfo), FileBasicInformation ); if (NT_SUCCESS(Status)) { *FileAttributes = BasicInfo.FileAttributes; } ZwClose( Handle );
return Status;
}
ULONG RcCmdNet( IN PTOKENIZED_LINE TokenizedLine ) { WCHAR *Share; WCHAR *User; WCHAR *pwch; WCHAR PasswordBuffer[64]; WCHAR Drive[3]; NTSTATUS Status = STATUS_SUCCESS; IO_STATUS_BLOCK IoStatusBlock; OBJECT_ATTRIBUTES ObjectAttributes;
//
// check for help
//
if (RcCmdParseHelp( TokenizedLine, MSG_NET_USE_HELP )) { return 1; }
//
// There should be a token for NET and USE and one each for the server\share, and possible
// tokens for the /u:domainname\username and password.
//
if ((TokenizedLine->TokenCount < 3) || (TokenizedLine->TokenCount > 5)) { RcMessageOut(MSG_SYNTAX_ERROR); return 1; }
//
// The only NET command supported is USE, so verify that the second token is that.
//
if (_wcsicmp(TokenizedLine->Tokens->Next->String, L"USE")){ RcMessageOut(MSG_SYNTAX_ERROR); return 1; }
//
// Get the first parameter to NET USE
//
Share = TokenizedLine->Tokens->Next->Next->String;
if (*Share == L'\\') { // attempt at making a connection
//
// Verify the share name parameter
//
if (*(Share+1) != L'\\') { RcMessageOut(MSG_SYNTAX_ERROR); return 1; }
//
// get the user logon context
//
if (TokenizedLine->TokenCount > 3) { //
// The command has the context in it, so get it.
//
User = TokenizedLine->Tokens->Next->Next->Next->String;
if (*User != L'/') { RcMessageOut(MSG_SYNTAX_ERROR); return 1; }
User++; pwch = User; while ((*pwch != UNICODE_NULL) && (*pwch != L':')) { pwch++; }
if (*pwch != L':') { RcMessageOut(MSG_SYNTAX_ERROR); return 1; }
*pwch = UNICODE_NULL; pwch++;
if (_wcsicmp(User, L"USER") && _wcsicmp(User, L"U")) { RcMessageOut(MSG_SYNTAX_ERROR); return 1; }
User = pwch;
//
// Get the password
//
if (TokenizedLine->TokenCount == 4) { RcMessageOut( MSG_NET_USE_PROMPT_PASSWORD ); RtlZeroMemory( PasswordBuffer, sizeof(PasswordBuffer) ); RcPasswordIn( PasswordBuffer, 60 );
} else {
if (wcslen(TokenizedLine->Tokens->Next->Next->Next->Next->String) > 60) { RcMessageOut(MSG_SYNTAX_ERROR); return 1; }
wcscpy(PasswordBuffer, TokenizedLine->Tokens->Next->Next->Next->Next->String);
if ((PasswordBuffer[0] == L'*') && (PasswordBuffer[1] == UNICODE_NULL)) {
RcMessageOut( MSG_NET_USE_PROMPT_PASSWORD ); RtlZeroMemory( PasswordBuffer, sizeof(PasswordBuffer) ); RcPasswordIn( PasswordBuffer, 60 );
} else if (PasswordBuffer[0] == L'"') {
pwch = &(PasswordBuffer[1]);
while (*pwch != UNICODE_NULL) { pwch++; }
pwch--;
if ((*pwch == L'"') && (pwch != &(PasswordBuffer[1]))) { *pwch = UNICODE_NULL; }
RtlMoveMemory(PasswordBuffer, &(PasswordBuffer[1]), (PtrToUlong(pwch) - PtrToUlong(PasswordBuffer)) + sizeof(WCHAR)); }
}
} else {
//
// If we allow holding a current context, then we would use that here, but we currently
// don't, so spew a syntax error message.
//
RcMessageOut(MSG_SYNTAX_ERROR); return 1;
}
//
// Call worker routine to make the connection
//
Status = RcDoNetUse(Share, User, PasswordBuffer, Drive); RtlSecureZeroMemory(PasswordBuffer, sizeof(PasswordBuffer));
if( !NT_SUCCESS(Status) ) { RcNtError(Status, MSG_NET_USE_ERROR); } else { RcMessageOut(MSG_NET_USE_DRIVE_LETTER, Share, Drive); }
} else { // attempt to disconnect
//
// Verify drive letter parameter
//
if ((*(Share+1) != L':') || (*(Share + 2) != UNICODE_NULL)) { RcMessageOut(MSG_SYNTAX_ERROR); return 1; }
//
// Verify /d parameter
//
User = TokenizedLine->Tokens->Next->Next->Next->String; if ((*User != L'/') || ((*(User + 1) != L'd') && (*(User + 1) != L'D'))) { RcMessageOut(MSG_SYNTAX_ERROR); return 1; }
//
// Call worker routine to actually do the disconnect.
//
Status = RcNetUnuse(Share);
if( !NT_SUCCESS(Status) ) { RcNtError(Status, MSG_NET_USE_ERROR); } }
return 1; }
|